gdb.c
来自「umon bootloader source code, support mip」· C语言 代码 · 共 676 行 · 第 1/2 页
C
676 行
/* gdb.c:
* The code in this file allows a gdb debugger on a host to connect to the
* monitor. It supports both serial and network (udp) connections.
* Note that this is only the cpu-independent portion of the GDB debug
* protocol. The following commands in gdb have been verified to work
* with this code:
*
* - target remote com1
* - target remote udp:135.222.140.68:1234
* - load and c
* - info registers
* - x/16x 0xff800000
* - print varname
*
* I'm sure other commands work, but these are the ones I've tested.
*
* This interface was written from scratch.
* References used were:
* Bill Gatliff's ESP article and a description of the GDB Remote
* Serial Protocol I found at:
* http://developer/apple.com/documentation/DeveloperTools/gdb/gdb/gdb_32.htm
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Note1: the majority of this code was edited with 4-space tabs.
* Note2: as more and more contributions are accepted, the term "author"
* is becoming a mis-representation of credit.
*
* Original author: Ed Sutter
* Email: esutter@lucent.com
* Phone: 908-582-2351
*/
#include "config.h"
#include "genlib.h"
#include "ether.h"
#include "stddefs.h"
#include "endian.h"
#include "cli.h"
#if INCLUDE_GDB
#include "gdbregs.c" /* CPU-specific register name table */
#define REGTBL_SIZE (sizeof(gdb_regtbl)/sizeof(char *))
#define GDBERR_NOHASH 1 /* no '#' in command */
#define GDBERR_BADCSUM 2 /* bad checksum */
#define GDBERR_GENERR 3 /* general confusion */
#define GDBERR_BADXFMT 4 /* unexpected 'X' command format */
#define GDBERR_RNUMOOR 5 /* register number out of range */
#define GDBERR_NOSPACE 6 /* buffer not big enough for response */
/* gdbIbuf[]:
* Input buffer used for storage of the incoming command from
* the gdb debugger.
*/
static uchar gdbIbuf[512];
/* gdbRbuf[]:
* Response buffer used for the complete response destined
* for the gdb host.
*/
static uchar gdbRbuf[1024];
static int gdbRlen;
static void (*gdbContinueFptr)();
/* gdbUdp:
* Set if the gdb interaction is via UDP, else zero.
* Obviously this code assumes there is no reentrancy to deal with.
*/
static int gdbUdp;
/* gdbTrace():
* This is a function pointer that is loaded with either printf
* or Mtrace... Use printf if gdb is running via UDP; else use
* printf.
*/
static int (*gdbTrace)(char *, ...);
/* gdb_response():
* Utility function used by the other response functions to format
* the complete response back to the gdb host. All interaction with
* the host is in ASCII. The response message is preceded by '+$'
* and and terminated with '#CC' where 'CC' is a checksum.
*/
int
gdb_response(char *line)
{
uchar csum, *resp;
csum = 0;
resp = gdbRbuf;
*resp++ = '$';
while(*line) {
csum += *line;
*resp++ = *line++;
}
resp += sprintf(resp,"#%02x",csum);
*resp = 0;
/* If gdbUdp is clear, then we assume that the gdb host is tied
* to the target's serial port, so just use printf to send the
* response.
* If gdbUdp is set, then we assume the calling function will
* send the response (via ethernet).
*/
if (!gdbUdp)
printf(gdbRbuf);
gdbRlen = strlen(gdbRbuf);
if (gdbRlen < 128)
gdbTrace("GDB_RSP: %s\n",gdbRbuf);
else
gdbTrace("GDB_RSP: BIG\n");
return(gdbRlen);
}
int
gdb_ok(void)
{
return(gdb_response("OK"));
}
int
gdb_sig(int signal)
{
char buf[8];
sprintf(buf,"S%02d",signal);
return(gdb_response(buf));
}
int
gdb_err(int errno)
{
char buf[8];
sprintf(buf,"E%02d",errno);
return(gdb_response(buf));
}
/* gdb_m():
* GDB memory read command...
* Incoming command format is...
*
* mADDR,LEN#CC
*
* where:
* 'm' is the "memory read" request
* 'ADDR' is the address from which the data is to be read
* 'LEN' is the number of bytes to be read
*
*/
int
gdb_m(char *line)
{
int len, i;
char *lp;
uchar *addr, *resp, buf[128];
addr = (uchar *)strtol(line+1,&lp,16);
len = (int)strtol(lp+1,0,16);
if (len) {
if (len*2 >= sizeof(buf)) {
gdb_err(GDBERR_NOSPACE);
}
else {
resp = buf;
for(i=0;i<len;i++,addr++)
resp += sprintf(resp,"%02x",*addr);
gdb_response(buf);
}
}
else
gdb_ok();
return(0);
}
/* gdb_M():
* GDB memory write command...
* Incoming command format is...
*
* MADDR,LEN:DATA#CC
*
* where:
* 'M' is the "memory read" request
* 'ADDR' is the address from which the data is to be read
* 'LEN' is the number of bytes to be read
* 'DATA' is the ascii data
*
* STATUS: This function has been tested with m68k-elf-gdb (xtools)
* and appears to work ok.
*/
int
gdb_M(char *line)
{
int len, i;
char *lp;
uchar *addr, buf[3];
addr = (uchar *)strtol(line+1,&lp,16);
len = (int)strtol(lp+1,&lp,16);
lp++;
buf[2] = 0;
for(i=0;i<len;i++) {
buf[0] = *lp++;
buf[1] = *lp++;
*addr++ = (uchar)strtol(buf,0,16);
}
gdb_ok();
return(0);
}
/* gdb_X():
* Similar to gdb_M() except that the data is in binary.
* The characters '$', '#' and 0x7d are escaped using 0x7d.
*/
int
gdb_X(char *line)
{
int len, i;
char *lp;
uchar *addr;
addr = (uchar *)strtol(line+1,&lp,16);
len = (int)strtol(lp+1,&lp,16);
lp++;
for(i=0;i<len;i++) {
if ((*lp == 0x7d) &&
((*(lp+1) == 0x03) || (*(lp+1) == 0x04) || (*(lp+1) == 0x5d))) {
*addr++ = *(lp+1) | 0x20;
lp += 2;
}
else
*addr++ = *lp++;
}
gdb_ok();
return(0);
}
/* gdb_q():
* Query. Not sure what this is for, but according to Gatliff's
* article, just do it...
*/
int
gdb_q(char *line)
{
line++;
if (strncmp(line,"Offsets",7) == 0)
return(gdb_response("Text=0;Data=0;Bss=0"));
else
return(gdb_ok());
}
/* gdb_g():
* Get all registers.
* GDB at the host expects to see a buffer of ASCII-coded hex values
* with each register being 8-bytes (forming one 32-bit value).
* The order of these registers is defined by the table included
* in the file gdbregs.c above.
*/
int
gdb_g(char *line)
{
int i;
ulong reg;
char *resp, buf[(REGTBL_SIZE * 8) + 1];
resp = buf;
for(i=0;i<REGTBL_SIZE;i++) {
if (gdb_regtbl[i] != 0)
getreg(gdb_regtbl[i],®);
else
reg = 0;
self_ecl(reg);
resp += sprintf(resp,"%08lx",reg);
}
return(gdb_response(buf));
}
/* gdb_P():
* Store to a register.
*/
int
gdb_P(char *line)
{
char *lp;
int rnum;
ulong rval;
line++;
rnum = strtol(line,&lp,16);
if (rnum >= REGTBL_SIZE) {
gdb_err(GDBERR_RNUMOOR);
return(-1);
}
lp++;
rval = strtol(lp,0,16);
self_ecl(rval);
putreg(gdb_regtbl[rnum],rval);
gdb_ok();
return(0);
}
/* gdb_c():
* This is the function that is called as a result of the 'c' (continue)
* command.
*/
int
gdb_c(char *line)
{
ulong addr;
void (*func)();
line++;
if (*line == '#')
getreg(CPU_PC_REG,&addr);
else
addr = strtol(line,0,16);
func = (void(*)())addr;
func();
return(0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?