/* * This function does all command processing for interfacing to * a remote gdb. Note that the error codes are ignored by gdb * at present, but might eventually become meaningful. (XXX) * It might makes sense to use POSIX errno values, because * that is what the gdb/remote.c functions want to return. */ int kgdb_trap(int type, db_regs_t *regs) { label_t jmpbuf; vaddr_t addr; size_t len; u_char *p; kgdb_entry_notice(type, regs); if (kgdb_dev == NODEV || kgdb_getc == NULL) { /* not debugging */ return (0); } db_clear_single_step(regs); if (db_trap_callback) db_trap_callback(1); /* Detect and recover from unexpected traps. */ if (kgdb_recover != 0) { printf("kgdb: caught trap 0x%x at %p\n", type, (void*)PC_REGS(regs)); kgdb_send("E0E"); /* 14==EFAULT */ longjmp(kgdb_recover); } /* * The first entry to this function is normally through * a breakpoint trap in kgdb_connect(), in which case we * must advance past the breakpoint because gdb will not. * * Machines vary as to where they leave the PC after a * breakpoint trap. Those that leave the PC set to the * address of the trap instruction (i.e. pc532) will not * define FIXUP_PC_AFTER_BREAK(), and therefore will just * advance the PC. On machines that leave the PC set to * the instruction after the trap, FIXUP_PC_AFTER_BREAK * will be defined to back-up the PC, so that after the * "first-time" part of the if statement below has run, * the PC will be the same as it was on entry. * * On the first entry here, we expect that gdb is not yet * listening to us, so just enter the interaction loop. * After the debugger is "active" (connected) it will be * waiting for a "signaled" message from us. */ if (kgdb_active == 0) { if (!IS_BREAKPOINT_TRAP(type, 0)) { /* No debugger active -- let trap handle this. */ if (db_trap_callback) db_trap_callback(0); return (0); } /* Make the PC point at the breakpoint... */ #ifdef FIXUP_PC_AFTER_BREAK FIXUP_PC_AFTER_BREAK(regs); #endif /* ... and then advance past it. */ #ifdef PC_ADVANCE PC_ADVANCE(regs); #else PC_REGS(regs) += BKPT_SIZE; #endif kgdb_active = 1; } else { /* Tell remote host that an exception has occurred. */ snprintf(buffer, sizeof(buffer), "S%02x", kgdb_signal(type)); kgdb_send(buffer); } /* Stick frame regs into our reg cache. */ kgdb_getregs(regs, gdb_regs); /* * Interact with gdb until it lets us go. * If we cause a trap, resume here. */ (void)setjmp((kgdb_recover = &jmpbuf)); for (;;) { kgdb_recv(buffer, sizeof(buffer)); switch (buffer[0]) { default: /* Unknown command. */ kgdb_send(""); continue; case KGDB_SIGNAL: /* * if this command came from a running gdb, * answer it -- the other guy has no way of * knowing if we're in or out of this loop * when he issues a "remote-signal". */ snprintf(buffer, sizeof(buffer), "S%02x", kgdb_signal(type)); kgdb_send(buffer); continue; case KGDB_REG_R: mem2hex(buffer, gdb_regs, sizeof(gdb_regs)); kgdb_send(buffer); continue; case KGDB_REG_W: p = hex2mem(gdb_regs, buffer + 1, sizeof(gdb_regs)); if (p == NULL || *p != '\0') kgdb_send("E01"); else { kgdb_setregs(regs, gdb_regs); kgdb_send("OK"); } continue; case KGDB_MEM_R: p = buffer + 1; addr = hex2i(&p); if (*p++ != ',') { kgdb_send("E02"); continue; } len = hex2i(&p); if (*p != '\0') { kgdb_send("E03"); continue; } if (len > sizeof(buffer) / 2) { kgdb_send("E04"); continue; } if (kgdb_acc(addr, len) == 0) { kgdb_send("E05"); continue; } char *ptr = (char *)buffer + sizeof(buffer) / 2; db_read_bytes(addr, len, ptr); mem2hex(buffer, ptr, len); kgdb_send(buffer); continue; case KGDB_MEM_W: p = buffer + 1; addr = hex2i(&p); if (*p++ != ',') { kgdb_send("E06"); continue; } len = hex2i(&p); if (*p++ != ':') { kgdb_send("E07"); continue; } if (len > (sizeof(buffer) - (p - buffer))) { kgdb_send("E08"); continue; } p = hex2mem(buffer, p, sizeof(buffer)); if (p == NULL) { kgdb_send("E09"); continue; } if (kgdb_acc(addr, len) == 0) { kgdb_send("E0A"); continue; } db_write_bytes(addr, len, (char *)buffer); kgdb_send("OK"); continue; case KGDB_DETACH: case KGDB_KILL: kgdb_active = 0; printf("kgdb detached\n"); db_clear_single_step(regs); kgdb_send("OK"); goto out; case KGDB_CONT: if (buffer[1]) { p = buffer + 1; addr = hex2i(&p); if (*p) { kgdb_send("E0B"); continue; } PC_REGS(regs) = addr; DPRINTF(("kgdb: continuing at %08lx\n", addr)); } else { DPRINTF(( "kgdb: continuing at old address %08lx\n", (vaddr_t)PC_REGS(regs))); } db_clear_single_step(regs); goto out; case KGDB_STEP: if (buffer[1]) { p = buffer + 1; addr = hex2i(&p); if (*p) { kgdb_send("E0B"); continue; } PC_REGS(regs) = addr; } db_set_single_step(regs); goto out; } } out: if (db_trap_callback) db_trap_callback(0); kgdb_recover = 0; return (1); }
void db_dump_trap(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) { struct trapframe *tf, *ktf, ltf; const char *cp = modif; bool lwpaddr = false; char c; char buf[64]; tf = DDB_REGS; while ((c = *cp++) != 0) { if (c == 'l') lwpaddr = true; } /* Or an arbitrary trapframe */ if (have_addr) { if (lwpaddr) { lwp_t l; db_read_bytes(addr, sizeof(l), (char *)&l); ktf = (struct trapframe *)l.l_md.md_regs; } else { ktf = (struct trapframe *)addr; } db_read_bytes((db_addr_t)ktf, sizeof(ltf), (char *)<f); tf = <f; } db_printf("General registers\n"); db_printf("r00-03 %08x %08x %08x %08x\n", 0, tf->tf_r1, tf->tf_rp, tf->tf_r3); db_printf("r04-07 %08x %08x %08x %08x\n", tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7); db_printf("r08-11 %08x %08x %08x %08x\n", tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11); db_printf("r12-15 %08x %08x %08x %08x\n", tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); db_printf("r16-19 %08x %08x %08x %08x\n", tf->tf_r16, tf->tf_r17, tf->tf_r18, tf->tf_t4); db_printf("r20-23 %08x %08x %08x %08x\n", tf->tf_t3, tf->tf_t2, tf->tf_t1, tf->tf_arg3); db_printf("r24-27 %08x %08x %08x %08x\n", tf->tf_arg2, tf->tf_arg1, tf->tf_arg0, tf->tf_dp); db_printf("r28-31 %08x %08x %08x %08x\n", tf->tf_ret0, tf->tf_ret1, tf->tf_sp, tf->tf_r31); db_printf("\n"); db_printf("Space registers\n"); db_printf("s00-03 %08x %08x %08x %08x\n", tf->tf_sr0, tf->tf_sr1, tf->tf_sr2, tf->tf_sr3); db_printf("s04-07 %08x %08x %08x %08x\n", tf->tf_sr4, tf->tf_sr5, tf->tf_sr6, tf->tf_sr7); db_printf("\n"); db_printf("Instruction queues\n"); db_printf("iisq: %08x %08x\niioq: %08x %08x\n", tf->tf_iisq_head, tf->tf_iisq_tail, tf->tf_iioq_head, tf->tf_iioq_tail); db_printf("\n"); db_printf("Interrupt state\n"); db_printf("isr: %08x\nior: %08x\niir: %08x\n", tf->tf_isr, tf->tf_ior, tf->tf_iir); db_printf("\n"); db_printf("Other state\n"); db_printf("eiem: %08x\n", tf->tf_eiem); snprintb(buf, sizeof(buf), PSW_BITS, tf->tf_ipsw); db_printf("ipsw: %s\n", buf); db_printf("flags: %08x\n", tf->tf_flags); db_printf("sar: %08x\n", tf->tf_sar); db_printf("pidr1: %08x\n", tf->tf_pidr1); /* cr8 */ db_printf("pidr2: %08x\n", tf->tf_pidr2); /* cr9 */ #if pbably_not_worth_it db_printf("pidr3: %08x\n", tf->tf_pidr3); /* cr12 */ db_printf("pidr4: %08x\n", tf->tf_pidr4); /* cr13 */ #endif db_printf("rctr: %08x\n", tf->tf_rctr); /* cr0 */ db_printf("ccr: %08x\n", tf->tf_ccr); /* cr10 */ db_printf("eirr: %08x\n", tf->tf_eirr); /* cr23 - DDB */ db_printf("cr24: %08x\n", tf->tf_cr24); /* cr24 - DDB */ db_printf("vtop: %08x\n", tf->tf_vtop); /* cr25 - DDB */ db_printf("cr27: %08x\n", tf->tf_cr27); /* - DDB */ db_printf("cr28: %08x\n", tf->tf_cr28); /* - DDB */ db_printf("cr30: %08x\n", tf->tf_cr30); /* uaddr */ }