gdb.c
来自「umon bootloader source code, support mip」· C语言 代码 · 共 676 行 · 第 1/2 页
C
676 行
}
/* gdb_cmd():
* First function called out of the monitor's command interpreter. It
* does a basic syntax verification and then passes parameters to the
* appropriate handler above.
* Incoming syntax is
*
* $ CMD # CSUM (of CMD)
*
* where:
* $ is the ascii '$' character (0x24)
* # is the ascii '#' character (0x23)
* CMD is some command line consisting of a command and arguments
* CSUM is the checksum of the characters in CMD
*
* for example:
*
* $m4015bc,2#5a
*
* Returns...
* 0 if command is not processed;
* 1 if command is processed;
* -1 if command is processed but has an error;
*
* If this code detects an error, then send an error code back to GDB.
* According to the article, there are no defined error codes in GDB so
* we will use the following...
* 1 indicates a missing '#' at the end of the incoming cmd string.
* 2 indicates a bad checksum calculation.
* 3 indicates some command processing error.
* 4 indicates bad 'X' command parsing.
*/
int
gdb_cmd(uchar *line)
{
char *comma, *colon, *cp, *bp, buf[32];
int len, clen, err, i;
uchar mycsum, incsum;
gdbContinueFptr = (void(*)())0;
/* If the command is 'X', then we have to treat it "special" because
* it contains binary data...
*/
if (line[1] == 'X') {
comma = strchr(line,',');
colon = strchr(line,':');
if ((comma) && (colon)) {
bp = buf;
cp = line;
while(cp <= colon)
*bp++ = *cp++;
*bp = 0;
gdbTrace("GDB_CMD: '%s'\n",buf);
}
else {
gdbTrace("GDB_CMD: 'X'\n");
gdb_err(GDBERR_BADXFMT); /* Unexpected 'X' command format */
}
}
else if (line[0] == 0x03) {
gdbTrace("GDB_CTRLC\n");
gdb_sig(2);
return(1);
}
else {
gdbTrace("GDB_CMD: '%s'\n",line);
len = strlen(line);
if (line[len-3] != '#') {
gdb_err(GDBERR_NOHASH); /* Missing ending '#' */
return(-1);
}
clen = len - 3;
mycsum = 0;
for(i=1;i<clen;i++)
mycsum += line[i];
incsum = (uchar)strtol(line+len-2,(char **)0,16);
if (mycsum != incsum) {
gdb_err(GDBERR_BADCSUM); /* Checksum failure */
return(-1);
}
}
err = 0;
line++;
switch(*line) {
case 'm': /* Memory read */
err = gdb_m(line);
break;
case 'M': /* Memory write (Ascii-coded-hex) */
err = gdb_M(line);
break;
case 'X': /* Memory write (Binary) */
err = gdb_X(line);
break;
case 's': /* Step */
gdb_response("S05");
break;
case 'c': /* Continue */
gdb_c(line);
break;
case '?': /* Last signal */
gdb_response("S05");
break;
case 'g': /* get all registers */
gdb_g(line);
break;
case 'q': /* Query */
gdb_q(line);
break;
case 'P': /* PRR=HHHHHHHH... reg*/
gdb_P(line);
break;
case 'H': /* Thread */
gdb_ok();
break;
case 'k': /* Quit */
gdb_ok();
break;
default: /* Unknown... return empty response. */
gdb_response("");
break;
}
if (err) {
gdb_err(GDBERR_GENERR); /* Command processing error */
}
return(1);
}
/* Gdb():
* This is the command at the CLI that allows the monitor to connect
* to a gdb debugger via the serial port. It currently assumes that
* the console port is the same port as is being used for the gdb
* connection. Eventually this needs to be modified to provide an
* option for the gdb protocol to run on some serial port other than
* the console.
*
* The connection command in gdb to connect to via serial port (PC)
* is:
* target remote com1
*/
char *GdbHelp[] = {
"Enter gdb mode",
"(no options)",
0,
};
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);
}
#if INCLUDE_ETHERNET
/* 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 (EtherVerbose & SHOW_GDB)
gdbTrace = printf;
else
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(gdbIbuf,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),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);
}
#endif
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?