Annotation of sys/arch/arm/arm/db_interface.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: db_interface.c,v 1.5 2006/05/26 17:06:39 miod Exp $ */
! 2: /* $NetBSD: db_interface.c,v 1.34 2003/10/26 23:11:15 chris Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996 Scott K. Stevens
! 6: *
! 7: * Mach Operating System
! 8: * Copyright (c) 1991,1990 Carnegie Mellon University
! 9: * All Rights Reserved.
! 10: *
! 11: * Permission to use, copy, modify and distribute this software and its
! 12: * documentation is hereby granted, provided that both the copyright
! 13: * notice and this permission notice appear in all copies of the
! 14: * software, derivative works or modified versions, and any portions
! 15: * thereof, and that both notices appear in supporting documentation.
! 16: *
! 17: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 18: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
! 19: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
! 20: *
! 21: * Carnegie Mellon requests users of this software to return to
! 22: *
! 23: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
! 24: * School of Computer Science
! 25: * Carnegie Mellon University
! 26: * Pittsburgh PA 15213-3890
! 27: *
! 28: * any improvements or extensions that they make and grant Carnegie the
! 29: * rights to redistribute these changes.
! 30: *
! 31: * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
! 32: */
! 33:
! 34: /*
! 35: * Interface to new debugger.
! 36: */
! 37: #include <sys/param.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/reboot.h>
! 40: #include <sys/systm.h> /* just for boothowto */
! 41: #include <sys/exec.h>
! 42:
! 43: #include <uvm/uvm_extern.h>
! 44:
! 45: #include <arm/db_machdep.h>
! 46: #include <arm/undefined.h>
! 47: #include <ddb/db_access.h>
! 48: #include <ddb/db_command.h>
! 49: #include <ddb/db_output.h>
! 50: #include <ddb/db_variables.h>
! 51: #include <ddb/db_sym.h>
! 52: #include <ddb/db_extern.h>
! 53: #include <ddb/db_interface.h>
! 54: #include <dev/cons.h>
! 55:
! 56: static long nil;
! 57:
! 58: int db_access_und_sp (struct db_variable *, db_expr_t *, int);
! 59: int db_access_abt_sp (struct db_variable *, db_expr_t *, int);
! 60: int db_access_irq_sp (struct db_variable *, db_expr_t *, int);
! 61: u_int db_fetch_reg (int, db_regs_t *);
! 62:
! 63: int db_trapper (u_int, u_int, trapframe_t *, int);
! 64:
! 65: struct db_variable db_regs[] = {
! 66: { "spsr", (long *)&DDB_REGS->tf_spsr, FCN_NULL, },
! 67: { "r0", (long *)&DDB_REGS->tf_r0, FCN_NULL, },
! 68: { "r1", (long *)&DDB_REGS->tf_r1, FCN_NULL, },
! 69: { "r2", (long *)&DDB_REGS->tf_r2, FCN_NULL, },
! 70: { "r3", (long *)&DDB_REGS->tf_r3, FCN_NULL, },
! 71: { "r4", (long *)&DDB_REGS->tf_r4, FCN_NULL, },
! 72: { "r5", (long *)&DDB_REGS->tf_r5, FCN_NULL, },
! 73: { "r6", (long *)&DDB_REGS->tf_r6, FCN_NULL, },
! 74: { "r7", (long *)&DDB_REGS->tf_r7, FCN_NULL, },
! 75: { "r8", (long *)&DDB_REGS->tf_r8, FCN_NULL, },
! 76: { "r9", (long *)&DDB_REGS->tf_r9, FCN_NULL, },
! 77: { "r10", (long *)&DDB_REGS->tf_r10, FCN_NULL, },
! 78: { "r11", (long *)&DDB_REGS->tf_r11, FCN_NULL, },
! 79: { "r12", (long *)&DDB_REGS->tf_r12, FCN_NULL, },
! 80: { "usr_sp", (long *)&DDB_REGS->tf_usr_sp, FCN_NULL, },
! 81: { "usr_lr", (long *)&DDB_REGS->tf_usr_lr, FCN_NULL, },
! 82: { "svc_sp", (long *)&DDB_REGS->tf_svc_sp, FCN_NULL, },
! 83: { "svc_lr", (long *)&DDB_REGS->tf_svc_lr, FCN_NULL, },
! 84: { "pc", (long *)&DDB_REGS->tf_pc, FCN_NULL, },
! 85: { "und_sp", (long *)&nil, db_access_und_sp, },
! 86: { "abt_sp", (long *)&nil, db_access_abt_sp, },
! 87: { "irq_sp", (long *)&nil, db_access_irq_sp, },
! 88: };
! 89:
! 90: extern label_t *db_recover;
! 91:
! 92: struct db_variable * db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
! 93:
! 94: int db_active = 0;
! 95:
! 96: int
! 97: db_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw)
! 98: {
! 99:
! 100: if (rw == DB_VAR_GET)
! 101: *valp = get_stackptr(PSR_UND32_MODE);
! 102: return(0);
! 103: }
! 104:
! 105: int
! 106: db_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw)
! 107: {
! 108:
! 109: if (rw == DB_VAR_GET)
! 110: *valp = get_stackptr(PSR_ABT32_MODE);
! 111: return(0);
! 112: }
! 113:
! 114: int
! 115: db_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw)
! 116: {
! 117:
! 118: if (rw == DB_VAR_GET)
! 119: *valp = get_stackptr(PSR_IRQ32_MODE);
! 120: return(0);
! 121: }
! 122:
! 123: #ifdef DDB
! 124: /*
! 125: * kdb_trap - field a TRACE or BPT trap
! 126: */
! 127: int
! 128: kdb_trap(int type, db_regs_t *regs)
! 129: {
! 130: int s;
! 131:
! 132: switch (type) {
! 133: case T_BREAKPOINT: /* breakpoint */
! 134: case -1: /* keyboard interrupt */
! 135: break;
! 136: default:
! 137: if (db_recover != 0) {
! 138: /* This will longjmp back into db_command_loop() */
! 139: db_error("Faulted in DDB; continuing...\n");
! 140: /*NOTREACHED*/
! 141: }
! 142: }
! 143:
! 144: /* Should switch to kdb`s own stack here. */
! 145:
! 146: ddb_regs = *regs;
! 147:
! 148: s = splhigh();
! 149: db_active++;
! 150: cnpollc(TRUE);
! 151: db_trap(type, 0/*code*/);
! 152: cnpollc(FALSE);
! 153: db_active--;
! 154: splx(s);
! 155:
! 156: *regs = ddb_regs;
! 157:
! 158: return (1);
! 159: }
! 160: #endif
! 161:
! 162:
! 163: static int db_validate_address(vaddr_t addr);
! 164:
! 165: static int
! 166: db_validate_address(vaddr_t addr)
! 167: {
! 168: struct proc *p = curproc;
! 169: struct pmap *pmap;
! 170:
! 171: if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
! 172: #ifndef ARM32_NEW_VM_LAYOUT
! 173: addr >= VM_MAXUSER_ADDRESS
! 174: #else
! 175: addr >= VM_MIN_KERNEL_ADDRESS
! 176: #endif
! 177: )
! 178: pmap = pmap_kernel();
! 179: else
! 180: pmap = p->p_vmspace->vm_map.pmap;
! 181:
! 182: return (pmap_extract(pmap, addr, NULL) == FALSE);
! 183: }
! 184:
! 185: /*
! 186: * Read bytes from kernel address space for debugger.
! 187: */
! 188: void
! 189: db_read_bytes(addr, size, data)
! 190: vaddr_t addr;
! 191: size_t size;
! 192: char *data;
! 193: {
! 194: char *src = (char *)addr;
! 195:
! 196: if (db_validate_address((u_int)src)) {
! 197: db_printf("address %p is invalid\n", src);
! 198: return;
! 199: }
! 200:
! 201: if (size == 4 && (addr & 3) == 0 && ((u_int32_t)data & 3) == 0) {
! 202: *((int*)data) = *((int*)src);
! 203: return;
! 204: }
! 205:
! 206: if (size == 2 && (addr & 1) == 0 && ((u_int32_t)data & 1) == 0) {
! 207: *((short*)data) = *((short*)src);
! 208: return;
! 209: }
! 210:
! 211: while (size-- > 0) {
! 212: if (db_validate_address((u_int)src)) {
! 213: db_printf("address %p is invalid\n", src);
! 214: return;
! 215: }
! 216: *data++ = *src++;
! 217: }
! 218: }
! 219:
! 220: static void
! 221: db_write_text(vaddr_t addr, size_t size, char *data)
! 222: {
! 223: struct pmap *pmap = pmap_kernel();
! 224: pd_entry_t *pde, oldpde, tmppde;
! 225: pt_entry_t *pte, oldpte, tmppte;
! 226: vaddr_t pgva;
! 227: size_t limit, savesize;
! 228: char *dst;
! 229:
! 230: /* XXX: gcc */
! 231: oldpte = 0;
! 232:
! 233: if ((savesize = size) == 0)
! 234: return;
! 235:
! 236: dst = (char *) addr;
! 237:
! 238: do {
! 239: /* Get the PDE of the current VA. */
! 240: if (pmap_get_pde_pte(pmap, (vaddr_t) dst, &pde, &pte) == FALSE)
! 241: goto no_mapping;
! 242: switch ((oldpde = *pde) & L1_TYPE_MASK) {
! 243: case L1_TYPE_S:
! 244: pgva = (vaddr_t)dst & L1_S_FRAME;
! 245: limit = L1_S_SIZE - ((vaddr_t)dst & L1_S_OFFSET);
! 246:
! 247: tmppde = oldpde | L1_S_PROT_W;
! 248: *pde = tmppde;
! 249: PTE_SYNC(pde);
! 250: break;
! 251:
! 252: case L1_TYPE_C:
! 253: pgva = (vaddr_t)dst & L2_S_FRAME;
! 254: limit = L2_S_SIZE - ((vaddr_t)dst & L2_S_OFFSET);
! 255:
! 256: if (pte == NULL)
! 257: goto no_mapping;
! 258: oldpte = *pte;
! 259: tmppte = oldpte | L2_S_PROT_W;
! 260: *pte = tmppte;
! 261: PTE_SYNC(pte);
! 262: break;
! 263:
! 264: default:
! 265: no_mapping:
! 266: printf(" address 0x%08lx not a valid page\n",
! 267: (vaddr_t) dst);
! 268: return;
! 269: }
! 270: cpu_tlb_flushD_SE(pgva);
! 271: cpu_cpwait();
! 272:
! 273: if (limit > size)
! 274: limit = size;
! 275: size -= limit;
! 276:
! 277: /*
! 278: * Page is now writable. Do as much access as we
! 279: * can in this page.
! 280: */
! 281: for (; limit > 0; limit--)
! 282: *dst++ = *data++;
! 283:
! 284: /*
! 285: * Restore old mapping permissions.
! 286: */
! 287: switch (oldpde & L1_TYPE_MASK) {
! 288: case L1_TYPE_S:
! 289: *pde = oldpde;
! 290: PTE_SYNC(pde);
! 291: break;
! 292:
! 293: case L1_TYPE_C:
! 294: *pte = oldpte;
! 295: PTE_SYNC(pte);
! 296: break;
! 297: }
! 298: cpu_tlb_flushD_SE(pgva);
! 299: cpu_cpwait();
! 300:
! 301: } while (size != 0);
! 302:
! 303: /* Sync the I-cache. */
! 304: cpu_icache_sync_range(addr, savesize);
! 305: }
! 306:
! 307: /*
! 308: * Write bytes to kernel address space for debugger.
! 309: */
! 310: void
! 311: db_write_bytes(vaddr_t addr, size_t size, char *data)
! 312: {
! 313: extern char etext[];
! 314: extern char kernel_text[];
! 315: char *dst;
! 316: size_t loop;
! 317:
! 318: /* If any part is in kernel text, use db_write_text() */
! 319: if (addr >= (vaddr_t) kernel_text && addr < (vaddr_t) etext) {
! 320: db_write_text(addr, size, data);
! 321: return;
! 322: }
! 323:
! 324: dst = (char *)addr;
! 325: loop = size;
! 326: while (loop-- > 0) {
! 327: if (db_validate_address((u_int)dst)) {
! 328: db_printf("address %p is invalid\n", dst);
! 329: return;
! 330: }
! 331: *dst++ = *data++;
! 332: }
! 333: /* make sure the caches and memory are in sync */
! 334: cpu_icache_sync_range(addr, size);
! 335:
! 336: /* In case the current page tables have been modified ... */
! 337: cpu_tlb_flushID();
! 338: cpu_cpwait();
! 339: }
! 340:
! 341: void
! 342: Debugger(void)
! 343: {
! 344: asm(".word 0xe7ffffff");
! 345: }
! 346:
! 347: struct db_command db_machine_command_table[] = {
! 348: { "frame", db_show_frame_cmd, 0, NULL },
! 349: #ifdef ARM32_DB_COMMANDS
! 350: ARM32_DB_COMMANDS,
! 351: #endif
! 352: { NULL, NULL, 0, NULL }
! 353: };
! 354:
! 355: int
! 356: db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code)
! 357: {
! 358:
! 359: if (fault_code == 0) {
! 360: if ((inst & ~INSN_COND_MASK) == (BKPT_INST & ~INSN_COND_MASK)) {
! 361: kdb_trap(T_BREAKPOINT, frame);
! 362: frame->tf_pc += INSN_SIZE;
! 363: } else
! 364: kdb_trap(-1, frame);
! 365: } else
! 366: return (1);
! 367: return (0);
! 368: }
! 369:
! 370: extern u_int esym;
! 371: extern u_int end;
! 372:
! 373: static struct undefined_handler db_uh;
! 374:
! 375: void
! 376: db_machine_init(void)
! 377: {
! 378: /*
! 379: * We get called before malloc() is available, so supply a static
! 380: * struct undefined_handler.
! 381: */
! 382: db_uh.uh_handler = db_trapper;
! 383: install_coproc_handler_static(0, &db_uh);
! 384:
! 385: db_machine_commands_install(db_machine_command_table);
! 386: }
! 387:
! 388: u_int
! 389: db_fetch_reg(int reg, db_regs_t *db_regs)
! 390: {
! 391:
! 392: switch (reg) {
! 393: case 0:
! 394: return (db_regs->tf_r0);
! 395: case 1:
! 396: return (db_regs->tf_r1);
! 397: case 2:
! 398: return (db_regs->tf_r2);
! 399: case 3:
! 400: return (db_regs->tf_r3);
! 401: case 4:
! 402: return (db_regs->tf_r4);
! 403: case 5:
! 404: return (db_regs->tf_r5);
! 405: case 6:
! 406: return (db_regs->tf_r6);
! 407: case 7:
! 408: return (db_regs->tf_r7);
! 409: case 8:
! 410: return (db_regs->tf_r8);
! 411: case 9:
! 412: return (db_regs->tf_r9);
! 413: case 10:
! 414: return (db_regs->tf_r10);
! 415: case 11:
! 416: return (db_regs->tf_r11);
! 417: case 12:
! 418: return (db_regs->tf_r12);
! 419: case 13:
! 420: return (db_regs->tf_svc_sp);
! 421: case 14:
! 422: return (db_regs->tf_svc_lr);
! 423: case 15:
! 424: return (db_regs->tf_pc);
! 425: default:
! 426: panic("db_fetch_reg: botch");
! 427: }
! 428: }
! 429:
! 430: db_addr_t
! 431: db_branch_taken(u_int insn, db_addr_t pc, db_regs_t *db_regs)
! 432: {
! 433: u_int addr, nregs;
! 434:
! 435: switch ((insn >> 24) & 0xf) {
! 436: case 0xa: /* b ... */
! 437: case 0xb: /* bl ... */
! 438: addr = ((insn << 2) & 0x03ffffff);
! 439: if (addr & 0x02000000)
! 440: addr |= 0xfc000000;
! 441: return (pc + 8 + addr);
! 442: case 0x7: /* ldr pc, [pc, reg, lsl #2] */
! 443: addr = db_fetch_reg(insn & 0xf, db_regs);
! 444: addr = pc + 8 + (addr << 2);
! 445: db_read_bytes(addr, 4, (char *)&addr);
! 446: return (addr);
! 447: case 0x1: /* mov pc, reg */
! 448: addr = db_fetch_reg(insn & 0xf, db_regs);
! 449: return (addr);
! 450: case 0x8: /* ldmxx reg, {..., pc} */
! 451: case 0x9:
! 452: addr = db_fetch_reg((insn >> 16) & 0xf, db_regs);
! 453: nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555);
! 454: nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333);
! 455: nregs = (nregs + (nregs >> 4)) & 0x0f0f;
! 456: nregs = (nregs + (nregs >> 8)) & 0x001f;
! 457: switch ((insn >> 23) & 0x3) {
! 458: case 0x0: /* ldmda */
! 459: addr = addr - 0;
! 460: break;
! 461: case 0x1: /* ldmia */
! 462: addr = addr + 0 + ((nregs - 1) << 2);
! 463: break;
! 464: case 0x2: /* ldmdb */
! 465: addr = addr - 4;
! 466: break;
! 467: case 0x3: /* ldmib */
! 468: addr = addr + 4 + ((nregs - 1) << 2);
! 469: break;
! 470: }
! 471: db_read_bytes(addr, 4, (char *)&addr);
! 472: return (addr);
! 473: default:
! 474: panic("branch_taken: botch");
! 475: }
! 476: }
CVSweb