void HEX_decode(const char *strin, char *strout, int cbstr) { const char *r = strin; const char *e = r + cbstr - (cbstr % 2); unsigned char *w = (unsigned char *) strout; while (r < e) { *w++ = (hex2i(r[0])<<4) | (hex2i(r[1])); r+=2; } }
/* * 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); }