/* * Receive a packet. */ static int kgdb_recv(u_char *bp, int maxlen) { u_char *p; int c, csum, tmpcsum; int len; DPRINTF(("kgdb_recv: ")); do { p = bp; csum = len = 0; while ((c = GETC()) != KGDB_START) DPRINTF(("%c",c)); DPRINTF(("%c Start ",c)); while ((c = GETC()) != KGDB_END && len < maxlen) { DPRINTF(("%c",c)); c &= 0x7f; csum += c; *p++ = c; len++; } csum &= 0xff; *p = '\0'; DPRINTF(("%c End ", c)); if (len >= maxlen) { DPRINTF(("Long- ")); PUTC(KGDB_BADP); continue; } tmpcsum = csum; c = GETC(); DPRINTF(("%c",c)); csum -= digit2i(c) * 16; c = GETC(); DPRINTF(("%c",c)); csum -= digit2i(c); if (csum == 0) { DPRINTF(("Good+ ")); PUTC(KGDB_GOODP); /* Sequence present? */ if (bp[2] == ':') { DPRINTF(("Seq %c%c ", bp[0], bp[1])); PUTC(bp[0]); PUTC(bp[1]); len -= 3; kgdb_copy(bp + 3, bp, len); } break; } DPRINTF((" Bad(wanted %x, off by %d)- ", tmpcsum, csum)); __USE(tmpcsum); PUTC(KGDB_BADP); } while (1); DPRINTF(("kgdb_recv: %s\n", bp)); return (len); }
/* * Receive a packet. */ static int kgdb_recv(u_char *bp, int maxlen) { u_char *p; int c, csum; int len; do { p = bp; csum = len = 0; while ((c = GETC()) != KGDB_START) ; while ((c = GETC()) != KGDB_END && len < maxlen) { c &= 0x7f; csum += c; *p++ = c; len++; } csum &= 0xff; *p = '\0'; if (len >= maxlen) { PUTC(KGDB_BADP); continue; } csum -= digit2i(GETC()) * 16; csum -= digit2i(GETC()); if (csum == 0) { PUTC(KGDB_GOODP); /* Sequence present? */ if (bp[2] == ':') { PUTC(bp[0]); PUTC(bp[1]); len -= 3; kgdb_copy(bp + 3, bp, len); } break; } PUTC(KGDB_BADP); } while (1); #ifdef DEBUG_KGDB printf("kgdb_recv: %s\n", bp); #endif return (len); }
/* * This function does all command procesing for interfacing to * a remote gdb. */ int kgdb_trap(int type, struct frame *frame) { u_long len; u_char *addr; u_char *cp; u_char out, in; int outlen; int inlen; u_long gdb_regs[NUM_REGS]; if ((int)kgdb_dev < 0) { /* not debugging */ return (0); } if (kgdb_active == 0) { if (type != T_TRAP15) { /* No debugger active -- let trap handle this. */ return (0); } kgdb_getc = 0; for (inlen = 0; constab[inlen].cn_probe; inlen++) if (major(constab[inlen].cn_dev) == major(kgdb_dev)) { kgdb_getc = constab[inlen].cn_getc; kgdb_putc = constab[inlen].cn_putc; break; } if (kgdb_getc == 0 || kgdb_putc == 0) return (0); /* * If the packet that woke us up isn't an exec packet, * ignore it since there is no active debugger. Also, * we check that it's not an ack to be sure that the * remote side doesn't send back a response after the * local gdb has exited. Otherwise, the local host * could trap into gdb if it's running a gdb kernel too. */ in = GETC; /* * If we came in asynchronously through the serial line, * the framing character is eaten by the receive interrupt, * but if we come in through a synchronous trap (i.e., via * kgdb_connect()), we will see the extra character. */ if (in == FRAME_START) in = GETC; /* * Check that this is a debugger exec message. If so, * slurp up the entire message then ack it, and fall * through to the recv loop. */ if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0) return (0); while (GETC != FRAME_END) ; /* * Do the printf *before* we ack the message. This way * we won't drop any inbound characters while we're * doing the polling printf. */ printf("kgdb started from device %x\n", kgdb_dev); kgdb_send(in | KGDB_ACK, (u_char *)0, 0); kgdb_active = 1; } /* * Stick frame regs into our reg cache then tell remote host * that an exception has occurred. */ regs_to_gdb(frame, gdb_regs); if (type != T_TRAP15) { /* * Only send an asynchronous SIGNAL message when we hit * a breakpoint. Otherwise, we will drop the incoming * packet while we output this one (and on entry the other * side isn't interested in the SIGNAL type -- if it is, * it will have used a signal packet.) */ outbuffer[0] = computeSignal(type); kgdb_send(KGDB_SIGNAL, outbuffer, 1); } while (1) { in = kgdb_recv(inbuffer, &inlen); if (in == 0 || (in & KGDB_ACK)) /* Ignore inbound acks and error conditions. */ continue; out = in | KGDB_ACK; switch (KGDB_CMD(in)) { 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". (Note * that without the length check, we could * loop here forever if the ourput line is * looped back or the remote host is echoing.) */ if (inlen == 0) { outbuffer[0] = computeSignal(type); kgdb_send(KGDB_SIGNAL, outbuffer, 1); } continue; case KGDB_REG_R: case KGDB_REG_R | KGDB_DELTA: cp = outbuffer; outlen = 0; for (len = inbuffer[0]; len < NUM_REGS; ++len) { if (reg_cache[len] != gdb_regs[len] || (in & KGDB_DELTA) == 0) { if (outlen + 5 > SL_MAXDATA) { out |= KGDB_MORE; break; } cp[outlen] = len; kgdb_copy((u_char *)&gdb_regs[len], &cp[outlen + 1], 4); reg_cache[len] = gdb_regs[len]; outlen += 5; } } break; case KGDB_REG_W: case KGDB_REG_W | KGDB_DELTA: cp = inbuffer; for (len = 0; len < inlen; len += 5) { int j = cp[len]; kgdb_copy(&cp[len + 1], (u_char *)&gdb_regs[j], 4); reg_cache[j] = gdb_regs[j]; } gdb_to_regs(frame, gdb_regs); outlen = 0; break; case KGDB_MEM_R: len = inbuffer[0]; kgdb_copy(&inbuffer[1], (u_char *)&addr, 4); if (len > SL_MAXDATA) { outlen = 1; outbuffer[0] = E2BIG; } else if (!kgdb_acc(addr, len, B_READ)) { outlen = 1; outbuffer[0] = EFAULT; } else { outlen = len + 1; outbuffer[0] = 0; kgdb_copy(addr, &outbuffer[1], len); } break; case KGDB_MEM_W: len = inlen - 4; kgdb_copy(inbuffer, (u_char *)&addr, 4); outlen = 1; if (!kgdb_acc(addr, len, B_READ)) outbuffer[0] = EFAULT; else { outbuffer[0] = 0; if (!kgdb_acc(addr, len, B_WRITE)) chgkprot(addr, len, B_WRITE); kgdb_copy(&inbuffer[4], addr, len); ICIA(); } break; case KGDB_KILL: kgdb_active = 0; printf("kgdb detached\n"); /* fall through */ case KGDB_CONT: kgdb_send(out, 0, 0); frame->f_sr &=~ PSL_T; return (1); case KGDB_STEP: kgdb_send(out, 0, 0); frame->f_sr |= PSL_T; return (1); case KGDB_EXEC: default: /* Unknown command. Ack with a null message. */ outlen = 0; break; } /* Send the reply */ kgdb_send(out, outbuffer, outlen); } }
static inline void gdb_to_regs(struct frame *fp, u_long *regs) { kgdb_copy((u_char *)regs, (u_char *)fp->f_regs, 16*4); kgdb_copy((u_char *)®s[GDB_SR], (u_char *)&fp->f_stackadj, 2*4); }