2000-03-18 06:48:54 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1995, 1996 Cygnus Support
|
|
|
|
*
|
|
|
|
* The authors hereby grant permission to use, copy, modify, distribute,
|
|
|
|
* and license this software and its documentation for any purpose, provided
|
|
|
|
* that existing copyright notices are retained in all copies and that this
|
|
|
|
* notice is included verbatim in any distributions. No written agreement,
|
|
|
|
* license, or royalty fee is required for any of the authorized uses.
|
|
|
|
* Modifications to this software may be copyrighted by their authors
|
|
|
|
* and need not follow the licensing terms described here, provided that
|
|
|
|
* the new terms are clearly indicated on the first page of each file where
|
|
|
|
* they apply.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A debug packet whose contents are <data> looks like:
|
|
|
|
*
|
|
|
|
* $ <data> # CSUM1 CSUM2
|
|
|
|
*
|
|
|
|
* <data> must be ASCII alphanumeric and cannot include characters
|
|
|
|
* '$' or '#'. If <data> starts with two characters followed by
|
|
|
|
* ':', then the existing stubs interpret this as a sequence number.
|
|
|
|
*
|
|
|
|
* CSUM1 and CSUM2 are ascii hex representation of an 8-bit
|
|
|
|
* checksum of <data>, the most significant nibble is sent first.
|
|
|
|
* the hex digits 0-9,a-f are used.
|
|
|
|
*
|
|
|
|
* We respond with:
|
|
|
|
*
|
|
|
|
* + - if CSUM is correct and ready for next packet
|
|
|
|
* - - if CSUM is incorrect
|
|
|
|
*
|
|
|
|
* <data> is as follows:
|
|
|
|
* Most values are encoded in ascii hex digits.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* buffers that hold the packets while they're being constructed.
|
|
|
|
*/
|
|
|
|
char packet_in_buf[BUFMAX];
|
|
|
|
char packet_out_buf[BUFMAX];
|
|
|
|
int packet_index;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* indicate to caller of mem2hex or hex2mem that there has been an error.
|
|
|
|
* 0 means ok, 1 means error
|
|
|
|
*/
|
|
|
|
volatile int mem_err = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 1 means print debugging messages from the target, 0 means be quiet. This is
|
|
|
|
* changed by gdb_debug().
|
|
|
|
*/
|
|
|
|
int remote_debug = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* indicate whether the debug vectors ahave been initialized
|
|
|
|
* 0 means not yet, 1 means yep, it's ready.
|
|
|
|
*/
|
|
|
|
int initialized = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These variables are instantialted in the GDB stub code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* this is a list of signal to exception mappings. */
|
|
|
|
extern struct trap_info hard_trap_info[];
|
|
|
|
|
|
|
|
/* this is a memory fault exception handler, used by mem2hex & hex2mem */
|
|
|
|
extern void set_mem_fault_trap();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print debugging messages. This uses print, rather than one of the
|
|
|
|
* stdio routines, cause if there are stack or memory problems, the
|
|
|
|
* stdio routines don't work.
|
|
|
|
* params are the debug level, and the string to print
|
|
|
|
* it doesn't return anything.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
debuglog(int level, char *msg)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
unsigned char buf[BUFMAX];
|
|
|
|
char newmsg[BUFMAX];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (level > remote_debug)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((level <0) || (level > 100)) {
|
|
|
|
print ("ERROR: debug print level out of range");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert some characters so it'll look right in the log */
|
|
|
|
p = newmsg;
|
|
|
|
for (i = 0 ; msg[i] != '\0'; i++) {
|
|
|
|
if (i > BUFMAX)
|
|
|
|
print ("\r\nERROR: Debug message too long\r\n");
|
|
|
|
switch (msg[i]) {
|
|
|
|
case '\n': /* newlines */
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = 'n';
|
|
|
|
continue;
|
|
|
|
case '\r': /* carriage returns */
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = 'r';
|
|
|
|
continue;
|
|
|
|
case '\033': /* escape */
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = 'e';
|
|
|
|
continue;
|
|
|
|
case '\t': /* tab */
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = 't';
|
|
|
|
continue;
|
|
|
|
case '\b': /* backspace */
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = 'b';
|
|
|
|
continue;
|
|
|
|
default: /* no change */
|
|
|
|
*p++ = msg[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg[i] < 26) { /* modify control characters */
|
|
|
|
*p++ = '^';
|
|
|
|
*p++ = msg[i] + 'A';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (msg[i] >= 127) { /* modify control characters */
|
|
|
|
*p++ = '!';
|
|
|
|
*p++ = msg[i] + 'A';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*p = '\0'; /* terminate the string */
|
|
|
|
print (newmsg);
|
|
|
|
print ("\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert an ascii hex digit to a number.
|
|
|
|
* param is hex digit.
|
|
|
|
* returns a decimal digit.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
hex2digit (int digit)
|
|
|
|
{
|
|
|
|
if (digit == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (digit >= '0' && digit <= '9')
|
|
|
|
return digit - '0';
|
|
|
|
if (digit >= 'a' && digit <= 'f')
|
|
|
|
return digit - 'a' + 10;
|
|
|
|
if (digit >= 'A' && digit <= 'F')
|
|
|
|
return digit - 'A' + 10;
|
|
|
|
|
|
|
|
/* shouldn't ever get this far */
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert number NIB to a hex digit.
|
|
|
|
* param is a decimal digit.
|
|
|
|
* returns a hex digit.
|
|
|
|
*/
|
|
|
|
char
|
|
|
|
digit2hex(int digit)
|
|
|
|
{
|
|
|
|
if (digit < 10)
|
|
|
|
return '0' + digit;
|
|
|
|
else
|
|
|
|
return 'a' + digit - 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the memory pointed to by mem into hex, placing result in buf.
|
|
|
|
* Return a pointer to the last char put in buf (null), in case of mem fault,
|
|
|
|
* return 0.
|
|
|
|
* If MAY_FAULT is non-zero, then we will handle memory faults by returning
|
|
|
|
* a 0, else treat a fault like any other fault in the stub.
|
|
|
|
*/
|
|
|
|
unsigned char *
|
|
|
|
mem2hex(unsigned char *mem, unsigned char *buf, int count, int may_fault)
|
|
|
|
{
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
DEBUG (1, "In mem2hex");
|
|
|
|
|
|
|
|
set_mem_fault_trap(MAY_FAULT);
|
|
|
|
|
|
|
|
while (count-- > 0) {
|
|
|
|
ch = *mem++;
|
|
|
|
if (mem_err) {
|
|
|
|
DEBUG (1, "memory fault in mem2hex");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*buf++ = digit2hex(ch >> 4);
|
|
|
|
*buf++ = digit2hex(ch & 0xf);
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf = 0;
|
|
|
|
|
|
|
|
set_mem_fault_trap(OK);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the hex array pointed to by buf into binary to be placed in mem
|
|
|
|
* return a pointer to the character AFTER the last byte written
|
|
|
|
*/
|
|
|
|
unsigned char *
|
|
|
|
hex2mem(unsigned char *buf, unsigned char *mem, int count, int may_fault)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
DEBUG (1, "In hex2mem");
|
|
|
|
|
|
|
|
set_mem_fault_trap(may_fault);
|
|
|
|
|
|
|
|
for (i=0; i<count; i++) {
|
|
|
|
ch = hex2digit(*buf++) << 4;
|
|
|
|
ch |= hex2digit(*buf++);
|
|
|
|
*mem++ = ch;
|
|
|
|
if (mem_err)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_mem_fault_trap(0);
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* while we find nice hex chars, build an int.
|
|
|
|
* param is a pointer to the string.
|
|
|
|
* returns the int in the param field, and the number of chars processed.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
hex2int (char **ptr, int *intValue)
|
|
|
|
{
|
|
|
|
int numChars = 0;
|
|
|
|
int hexValue;
|
|
|
|
|
|
|
|
*intValue = 0;
|
|
|
|
|
|
|
|
while (**ptr)
|
|
|
|
{
|
|
|
|
hexValue = hex2digit(**ptr);
|
|
|
|
if (hexValue < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
*intValue = (*intValue << 4) | hexValue;
|
|
|
|
numChars ++;
|
|
|
|
(*ptr)++;
|
|
|
|
}
|
|
|
|
return (numChars);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan for the sequence $<data>#<checksum>
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
getpacket(unsigned char *buffer)
|
|
|
|
{
|
|
|
|
unsigned char checksum;
|
|
|
|
unsigned char xmitcsum;
|
|
|
|
int i;
|
|
|
|
int count;
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
do {
|
|
|
|
/* wait around for the start character, ignore all other characters */
|
|
|
|
while ((ch = (inbyte() & 0x7f)) != '$') ;
|
|
|
|
|
|
|
|
checksum = 0;
|
|
|
|
xmitcsum = -1;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
/* now, read until a # or end of buffer is found */
|
|
|
|
while (count < BUFMAX) {
|
|
|
|
ch = inbyte() & 0x7f;
|
|
|
|
if (ch == '#')
|
|
|
|
break;
|
|
|
|
checksum = checksum + ch;
|
|
|
|
buffer[count] = ch;
|
|
|
|
count = count + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count >= BUFMAX)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
buffer[count] = 0;
|
|
|
|
|
|
|
|
if (ch == '#') {
|
|
|
|
xmitcsum = hex2digit(inbyte() & 0x7f) << 4;
|
|
|
|
xmitcsum |= hex2digit(inbyte() & 0x7f);
|
|
|
|
#if 1
|
|
|
|
/* Humans shouldn't have to figure out checksums to type to it. */
|
|
|
|
outbyte ('+');
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
if (checksum != xmitcsum)
|
|
|
|
outbyte('-'); /* failed checksum */
|
|
|
|
else {
|
|
|
|
outbyte('+'); /* successful transfer */
|
|
|
|
/* if a sequence char is present, reply the sequence ID */
|
|
|
|
if (buffer[2] == ':') {
|
|
|
|
outbyte(buffer[0]);
|
|
|
|
outbyte(buffer[1]);
|
|
|
|
/* remove sequence chars from buffer */
|
|
|
|
count = strlen(buffer);
|
|
|
|
for (i=3; i <= count; i++)
|
|
|
|
buffer[i-3] = buffer[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (checksum != xmitcsum);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the packet in buffer.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
putpacket(unsigned char *buffer)
|
|
|
|
{
|
|
|
|
unsigned char checksum;
|
|
|
|
int count;
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
/* $<packet info>#<checksum>. */
|
|
|
|
do {
|
|
|
|
outbyte('$');
|
|
|
|
checksum = 0;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
while (ch = buffer[count]) {
|
|
|
|
if (! outbyte(ch))
|
|
|
|
return;
|
|
|
|
checksum += ch;
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
outbyte('#');
|
|
|
|
outbyte(digit2hex(checksum >> 4));
|
|
|
|
outbyte(digit2hex(checksum & 0xf));
|
|
|
|
|
|
|
|
}
|
|
|
|
while ((inbyte() & 0x7f) != '+');
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gdb_event_loop(int sigval, unsigned long *registers)
|
|
|
|
{
|
|
|
|
int addr;
|
|
|
|
int length;
|
|
|
|
unsigned char *ptr;
|
|
|
|
ptr = packet_out_buf;
|
|
|
|
|
|
|
|
DEBUG (1, "In gdb_event_loop");
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
packet_out_buf[0] = 0;
|
|
|
|
|
|
|
|
getpacket(packet_in_buf);
|
|
|
|
ptr = &packet_in_buf[1];
|
|
|
|
|
|
|
|
switch (packet_in_buf[0]) {
|
|
|
|
case '?': /* get the last known signal */
|
|
|
|
gdb_last_signal(sigval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd': /* toggle debug messages from the stub */
|
|
|
|
gdb_toggle();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'g': /* return the value of the CPU registers */
|
|
|
|
target_read_registers(registers);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'G': /* set the value of the CPU registers - return OK */
|
|
|
|
target_write_registers(registers);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
|
|
|
/* Try to read %x,%x. */
|
|
|
|
if (hex2int((char **)&ptr, &addr)
|
|
|
|
&& *ptr++ == ','
|
|
|
|
&& hex2int((char **)&ptr, &length)) {
|
|
|
|
gdb_read_memory(addr, length);
|
|
|
|
} else {
|
|
|
|
make_return_packet(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
|
|
|
/* Try to read '%x,%x:'. */
|
|
|
|
if (hex2int((char **)&ptr, &addr)
|
|
|
|
&& *ptr++ == ','
|
|
|
|
&& hex2int((char **)&ptr, &length)
|
|
|
|
&& *ptr++ == ':') {
|
|
|
|
gdb_write_memory (addr, length, ptr);
|
|
|
|
} else {
|
|
|
|
make_return_packet(2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c': /* cAA..AA Continue at address AA..AA(optional) */
|
|
|
|
/* try to read optional parameter, pc unchanged if no parm */
|
|
|
|
if (hex2int((char **)&ptr, &addr)) {
|
|
|
|
write_pc(registers, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we need to flush the instruction cache here, as we may have
|
|
|
|
* deposited a breakpoint, and the icache probably has no way of
|
|
|
|
* knowing that a data ref to some location may have changed
|
|
|
|
* something that is in the instruction cache.
|
|
|
|
*/
|
|
|
|
|
|
|
|
flush_i_cache();
|
|
|
|
/* by returning, we pick up execution where we left off */
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* kill the program */
|
|
|
|
case 'k' :
|
|
|
|
gdb_kill();
|
|
|
|
break;
|
|
|
|
case 'r': /* Reset */
|
|
|
|
target_reset();
|
|
|
|
break;
|
|
|
|
} /* switch */
|
|
|
|
|
|
|
|
/* reply to the request */
|
|
|
|
putpacket(packet_out_buf);
|
|
|
|
}
|
|
|
|
DEBUG (1, "Leaving handle_exception()");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the hardware trap type code to a unix signal number. */
|
|
|
|
|
|
|
|
int
|
|
|
|
computeSignal(int tt)
|
|
|
|
{
|
|
|
|
struct trap_info *ht;
|
|
|
|
|
|
|
|
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
|
|
|
|
if (ht->tt == tt)
|
|
|
|
return ht->signo;
|
|
|
|
|
|
|
|
return SIGHUP; /* default for things we don't know about */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up exception handlers for tracing and breakpoints
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
set_debug_traps()
|
|
|
|
{
|
|
|
|
struct trap_info *ht;
|
|
|
|
|
|
|
|
DEBUG (1, "Entering set_debug_traps()");
|
|
|
|
|
|
|
|
if (hard_trap_info->tt == 0) {
|
|
|
|
print ("ERROR: ARG#$@%^&*!! no hard trap info!!\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
|
|
|
|
exception_handler(ht->tt, (unsigned long)default_trap_hook);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In case GDB is started before us, ack any packets (presumably
|
|
|
|
"$?#xx") sitting there. */
|
|
|
|
|
|
|
|
outbyte ('+');
|
|
|
|
initialized = 1;
|
|
|
|
|
|
|
|
DEBUG (1, "Leaving set_debug_traps()");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make a return packet.
|
|
|
|
* param is the value to return.
|
|
|
|
* 0 = OK, any other value is converted to a two digit hex number.
|
|
|
|
* returns a string or "OK" or "ENN", where NN is the error number. Each N
|
|
|
|
* is an ASCII encoded hex digit.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
make_return_packet(int val)
|
|
|
|
{
|
|
|
|
if (val == 0) {
|
|
|
|
packet_out_buf[0] = 'O';
|
|
|
|
packet_out_buf[1] = 'K';
|
|
|
|
packet_out_buf[2] = 0;
|
|
|
|
} else {
|
|
|
|
packet_out_buf[0] = 'E';
|
|
|
|
packet_out_buf[1] = digit2hex((val >> 4) & 0xf);
|
|
|
|
packet_out_buf[2] = digit2hex(val & 0xf);
|
|
|
|
packet_out_buf[3] = 0;
|
|
|
|
}
|
|
|
|
return(packet_out_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* g - read registers.
|
|
|
|
* no params.
|
|
|
|
* returns a vector of words, size is NUM_REGS.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_read_registers()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* G - write registers.
|
|
|
|
* param is a vector of words, size is NUM_REGS.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_write_registers(char *regs)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* m - read memory.
|
|
|
|
* params are the address to start the read at and the number of
|
|
|
|
* bytes to read.
|
|
|
|
* returns a vector of nbytes or an error number.
|
|
|
|
* Can be fewer bytes than requested if able to read only part of the
|
|
|
|
* data.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_read_memory(long addr, int nbytes)
|
|
|
|
{
|
|
|
|
if (mem2hex((char *)addr, packet_out_buf, nbytes, MAY_FAULT))
|
|
|
|
return(packet_out_buf);
|
|
|
|
else {
|
|
|
|
return(make_return_packet(3));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* M write memory
|
|
|
|
* params are the address to start writing to, the number of
|
|
|
|
* bytes to write, and the new values of the bytes.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_write_memory(long addr, int nbytes, char *mem)
|
|
|
|
{
|
|
|
|
if (hex2mem(mem, (char *)addr, nbytes, MAY_FAULT))
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
else {
|
|
|
|
return(make_return_packet(3));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* c - continue at address.
|
|
|
|
* param is the address to start at, and an optional signal. If
|
|
|
|
* sig is zero, then ignore it.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_continue(int sig, long addr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* s - step instruction(s)
|
|
|
|
* param is the address to start at, and an optional signal. If
|
|
|
|
* sig is zero, then ignore it.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_step(int sig, long addr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* k - kill program.
|
|
|
|
* no params.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_kill()
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ? - last signal.
|
|
|
|
* no params.
|
|
|
|
* returns the last signal number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_last_signal(int val)
|
|
|
|
{
|
|
|
|
DEBUG (1, "Entering gdb_last_signal()");
|
|
|
|
|
|
|
|
packet_out_buf[0] = 'S';
|
|
|
|
packet_out_buf[1] = digit2hex(val >> 4);
|
|
|
|
packet_out_buf[2] = digit2hex(val & 0xf);
|
|
|
|
packet_out_buf[3] = 0;
|
|
|
|
|
|
|
|
DEBUG (1, "Leaving gdb_last_signal()");
|
|
|
|
return (packet_out_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* b - change baud rate.
|
|
|
|
* param is the new baudrate
|
|
|
|
* returns the baud rate.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_baudrate(int baud)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* T - dump state.
|
|
|
|
* no params.
|
|
|
|
* returns the signal number, the registers, the thread ID, and
|
|
|
|
* possible extensions in a vector that looks like:
|
|
|
|
* TAAn...:r...;n...:r...;n...:r...; where:
|
|
|
|
* AA = signal number
|
|
|
|
* n... = register number (hex)
|
|
|
|
* r... = register contents
|
|
|
|
* n... = `thread'
|
|
|
|
* r... = thread process ID. This is a hex integer.
|
|
|
|
* n... = other string not starting with valid hex digit.
|
|
|
|
* gdb should ignore this n,r pair and go on to
|
|
|
|
* the next. This way we can extend the protocol.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_dump_state()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* D - host requests a detach
|
|
|
|
* no params.
|
|
|
|
* returns either a S, T, W, or X command.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_detach()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* H - set thread.
|
|
|
|
* params are the command to execute and the thread ID.
|
|
|
|
* cmd = 'c' for thread used in step and continue;
|
|
|
|
* cmd = 'g' for thread used in other operations.
|
|
|
|
* tid = -1 for all threads.
|
|
|
|
* tid = zero, pick a thread,any thread.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_set_thread(int cmd, int tid)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* p - read one register.
|
|
|
|
* param is the register number.
|
|
|
|
* returns the register value or ENN.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_read_reg(int reg)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* P - write one register.
|
2023-12-26 07:17:38 +08:00
|
|
|
* params are the register number, and its new value.
|
2000-03-18 06:48:54 +08:00
|
|
|
* returns the register value or ENN.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_write_reg(int reg, long val)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* W - process exited.
|
|
|
|
* no params.
|
|
|
|
* returns the exit status.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_exited()
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* X - process terminated.
|
|
|
|
* no params.
|
|
|
|
* returns the last signal.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_terminated()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* O - hex encoding.
|
|
|
|
* params are a vector of bytes, and the number of bytes to encode.
|
|
|
|
* returns a vector of ASCII encoded hex numbers.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_hex(char *str, int nbytes)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A - tread alive request.
|
|
|
|
* param is the thread ID.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_thread_alive(int tid)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ! - extended protocol.
|
|
|
|
* no params.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_extended()
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* d - toggle gdb stub diagnostics.
|
|
|
|
* no params.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_debug()
|
|
|
|
{
|
|
|
|
if (remote_debug > 0)
|
|
|
|
remote_debug = 0;
|
|
|
|
else
|
|
|
|
remote_debug = 1;
|
|
|
|
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* d - toggle gdb stub.
|
|
|
|
* no params.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_toggle()
|
|
|
|
{
|
|
|
|
static int level = 0;
|
|
|
|
|
|
|
|
if (remote_debug) {
|
|
|
|
level = remote_debug;
|
|
|
|
remote_debug = 0;
|
|
|
|
} else {
|
|
|
|
remote_debug = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* r - reset target
|
|
|
|
* no params.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_reset()
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* t - search backwards.
|
|
|
|
* params are the address to start searching from, a pattern to match, and
|
|
|
|
* the mask to use.
|
|
|
|
* FIXME: not entirely sure what this is supposed to return.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_search(long addr, long pat, long mask)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* q - general get query.
|
|
|
|
* param is a string, that's the query to be executed.
|
|
|
|
* FIXME: not entirely sure what this is supposed to return.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_get_query(char *query)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Q - general set query
|
|
|
|
* param is a string, that's the query to be executed.
|
|
|
|
* FIXME: not entirely sure what this means.
|
|
|
|
* returns an OK or an error number.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gdb_set(char *query)
|
|
|
|
{
|
|
|
|
/* generically, we can't do anything for this command */
|
|
|
|
return(make_return_packet(OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
|