int Gdb(int argc, char *argv) { int state, quit; uchar *lp, c; static uchar line[1024]; printf("Entering GDB mode, to exit manually type: '$k#00'\n"); lp = (uchar *)0; quit = 0; state = 0; gdbUdp = 0; gdbTrace = Mtrace; while(!quit) { c = getchar(); switch(state) { case 0: /* Wait for start of message */ if (c == '$') { lp = line; *lp++ = c; state = 1; } break; case 1: *lp++ = c; /* This is the command character */ state = 2; break; case 2: if (c == '#') { state = 3; *lp++ = c; } else { *lp++ = c; } break; case 3: *lp++ = c; state = 4; break; case 4: *lp++ = c; *lp = 0; state = 0; if (line[1] == 'k') quit = 1; gdb_cmd(line); break; default: break; } } putchar('\n'); return(CMD_SUCCESS); }
void gdbstub_interactive(void) { bool processed_any = true; char *bp, *ep; ssize_t rd; int rc; execute = false; ASSERT(csock != -1, "x"); do { if (!processed_any) { struct pollfd pfd = { 0 }; pfd.fd = csock; pfd.events = POLLIN; rc = poll(&pfd, 1, -1); ASSERT(rc >= 0, "poll: %s", strerror(errno)); } rd = recv(csock, &clientbuf[cblen], sizeof clientbuf - cblen, MSG_DONTWAIT); if (rd == 0) { printf("Client dropped, exiting.\n"); exit(0); } if (rd < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) err(1, "recv"); goto process; } cblen += (size_t)rd; process: processed_any = false; bp = clientbuf; ep = &clientbuf[cblen]; // We have cblen valid bytes of protocol at p. // Process as many full packets as possible... while (bp < ep) { char *pound; if (*bp == '+' || *bp == '-') { bp++; cblen--; processed_any = true; continue; } pound = memchr(bp, '#', ep - bp); if (pound && (pound + 2) < ep) { gdb_cmd(bp, pound); processed_any = true; bp = pound + 3; if (execute) break; } } if (bp != clientbuf) { cblen = ep - bp; memmove(clientbuf, bp, cblen); } } while (!execute); ASSERT(execute, "we shouldn't leave GDB interactive until we are told to"); }
/* processGDB(): * This is the function that allows a remote gdb host to connect to * the monitor with gdb at the udp level. The connection command in * gdb to do this is: * * target remote udp:TARGET_IP:TARGET_PORT */ int processGDB(struct ether_header *ehdr,ushort size) { char *gdbp; struct ip *ihdr, *ti, *ri; struct Udphdr *uhdr, *tu, *ru; struct ether_header *te; /* If SHOW_GDB is set (via ether -vg), then we dump the trace to * the console; otherwise, we use mtrace. */ #if INCLUDE_ETHERVERBOSE if (EtherVerbose & SHOW_GDB) gdbTrace = printf; else #endif gdbTrace = Mtrace; ihdr = (struct ip *)(ehdr + 1); uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); gdbp = (char *)(uhdr + 1); size = ecs(uhdr->uh_ulen) - sizeof(struct Udphdr); /* Check for ACK/NAK here: */ if (size == 1) { if ((*gdbp == '+') || (*gdbp == '-')) { gdbTrace("GDB_%s\n",*gdbp == '+' ? "ACK" : "NAK"); return(0); } } /* Copy the incoming udp payload (the gdb command) to gdbIbuf[] * and NULL terminate it... */ memcpy((char *)gdbIbuf,(char *)gdbp,size); gdbIbuf[size] = 0; /* Now that we've stored away the GDB command request, we * initially respond with the GDB acknowledgement ('+')... */ te = EtherCopy(ehdr); ti = (struct ip *) (te + 1); ri = (struct ip *) (ehdr + 1); ti->ip_vhl = ri->ip_vhl; ti->ip_tos = ri->ip_tos; ti->ip_len = ecs((1 + (sizeof(struct ip) + sizeof(struct Udphdr)))); ti->ip_id = ipId(); ti->ip_off = ri->ip_off; ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, sizeof(struct in_addr)); memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), sizeof(struct in_addr)); tu = (struct Udphdr *) (ti + 1); ru = (struct Udphdr *) (ri + 1); tu->uh_sport = ru->uh_dport; tu->uh_dport = ru->uh_sport; tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + 1)); gdbp = (char *)(tu+1); *gdbp = '+'; ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + 1); /* Wrap the processing of the incoming packet with a set/clear * of the gdbUdp flag so that the other gdb code can act * accordingly. */ gdbUdp = 1; if (gdb_cmd(gdbIbuf) == 0) { gdbUdp = 0; return(0); } gdbUdp = 0; /* Add 1 to the gdbRlen to include the NULL termination. */ gdbRlen++; /* The second respons is only done if gdb_cmd returns non-zero. * It is the response to the gdb command issued by the debugger * on the host. */ te = EtherCopy(ehdr); ti = (struct ip *) (te + 1); ri = (struct ip *) (ehdr + 1); ti->ip_vhl = ri->ip_vhl; ti->ip_tos = ri->ip_tos; ti->ip_len = ecs((gdbRlen + (sizeof(struct ip) + sizeof(struct Udphdr)))); ti->ip_id = ipId(); ti->ip_off = ri->ip_off; ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, sizeof(struct in_addr)); memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), sizeof(struct in_addr)); tu = (struct Udphdr *) (ti + 1); ru = (struct Udphdr *) (ri + 1); tu->uh_sport = ru->uh_dport; tu->uh_dport = ru->uh_sport; tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + gdbRlen)); memcpy((char *)(tu+1),(char *)gdbRbuf,gdbRlen); ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + gdbRlen); return(1); }