From f882fd5bb95b04618c796eb8d0a225125bc6baa4 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 16 Jan 2017 19:25:38 +0000 Subject: [PATCH] - added git-svn-id: http://moon:8086/svn/mips@88 a8ebac50-d88d-4704-bea3-6648445a41b3 --- src/libsys/gdb_stub.c | 601 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 601 insertions(+) create mode 100644 src/libsys/gdb_stub.c diff --git a/src/libsys/gdb_stub.c b/src/libsys/gdb_stub.c new file mode 100644 index 0000000..9974804 --- /dev/null +++ b/src/libsys/gdb_stub.c @@ -0,0 +1,601 @@ +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * This code has been extensively tested on the Fujitsu SPARClite demo board. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ + +extern void dbg_putchar(char c); /* write a single character */ +extern char dbg_getchar(); /* read and return a single char */ +extern void ICACHE_invalidate_all(); + +extern void flush_i_cache(); + +void putDebugChar(char c) +{ + dbg_putchar(c); +} + +int getDebugChar() +{ + return (int)dbg_getchar(); +} + +void flush_i_cache() +{ + ICACHE_invalidate_all(); +} + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 2048 + +static int initialized = 0; /* !0 means we've been initialized */ +static const char hexchars[]="0123456789abcdef"; + +#define NUMREGS 72 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) + +enum regnames +{ + START_CPU_REGS = 0, + SR = START_CPU_REGS, + CR, + PC, + BV, + R00, + R01, + R02, + R03, + R04, + R05, + R06, + R07, + R08, + R09, + R10, + R11, + R12, + R13, + R14, + R15, + R16, + R17, + R18, + R19, + R20, + R21, + R22, + R23, + R24, + R25, + R26, + R27, + R28, + R29, + R30, + R31, + LO, + HI, + NUM_REGS +}; + +/* Convert ch from a hex digit to an int */ +static int +hex (unsigned char ch) +{ + if (ch >= 'a' && ch <= 'f') + return ch-'a'+10; + + if (ch >= '0' && ch <= '9') + return ch-'0'; + + if (ch >= 'A' && ch <= 'F') + return ch-'A'+10; + + return -1; +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + +retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX - 1) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + +#ifdef WITH_CHECKSUM_CHECK + if (checksum != xmitcsum) + { + putDebugChar ('-'); /* failed checksum */ + } + else +#endif + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +static void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $#. */ + do + { + putDebugChar('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum & 0xf]); + + } while (getDebugChar() != '+'); +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; + +/* 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. + */ + +static unsigned char * +mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) +{ + unsigned char ch; + + while (count-- > 0) + { + ch = *mem++; + if (mem_err) + return 0; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + *buf = 0; + 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 */ + +static char * +hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + for (i=0; i> 2) & 0x1f; + + /* reply to host that an exception has occurred */ + sigval = computeSignal(tt); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R29 >> 4]; + *ptr++ = hexchars[R29 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)sp, ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + while (1) + { + remcomOutBuffer[0] = 0; + + ptr = getpacket(); + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; + + case 'd': /* toggle debug flag */ + break; + + case 'g': /* return the value of the CPU registers */ + { + ptr = remcomOutBuffer; + /* R00 .. R31 */ + ptr = mem2hex((char *)®isters[R00], ptr, 4*32, 0); + /* SR, HI, LO, BADVADDR, CR, PC */ + ptr = mem2hex((char *)®isters[SR], ptr, 4, 0); + ptr = mem2hex((char *)®isters[HI], ptr, 4, 0); + ptr = mem2hex((char *)®isters[LO], ptr, 4, 0); + ptr = mem2hex((char *)®isters[BV], ptr, 4, 0); + ptr = mem2hex((char *)®isters[CR], ptr, 4, 0); + ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); + /* Floating point F00 .. F31*/ + memset(ptr, '0', 8 * 32); + ptr += 8*32; + /* FCSR, FIR, RESTART*/ + memset(ptr, '0', 8 * 3); + ptr += 8*3; + *ptr = 0; + } + break; + + case 'G': /* set the value of the CPU registers - return OK */ + { + unsigned long *newsp, sr; + sr = registers[SR]; + + hex2mem(ptr, (char *)®isters[R00], 4*32, 0); /* R00 .. R31 */ + ptr += 4*32 * 2; + /* SR, HI, LO, BADVADDR, CR, PC */ + hex2mem(ptr, (char *)®isters[SR], 4, 0); + ptr += 4 * 2; + hex2mem(ptr, (char *)®isters[HI], 4, 0); + ptr += 4 * 2; + hex2mem(ptr, (char *)®isters[LO], 4, 0); + ptr += 4 * 2; + hex2mem(ptr, (char *)®isters[BV], 4, 0); + ptr += 4 * 2; + hex2mem(ptr, (char *)®isters[CR], 4, 0); + ptr += 4 * 2; + hex2mem(ptr, (char *)®isters[PC], 4, 0); + ptr += 4 * 2; + *ptr = 0; + /* See if the stack pointer has moved. If so, then copy the saved + locals and ins to the new location. This keeps the window + overflow and underflow routines happy. */ + + newsp = (unsigned long *)registers[R29]; + if (sp != newsp) + { + sp = memcpy(newsp, sp, 16 * 4); + } + + /* Don't allow SR:iec, SR:kuc to be modified. */ + if (sr != registers[SR]) + { + registers[SR] = (sr & ~0x3); + } + strcpy(remcomOutBuffer,"OK"); + } + break; + + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) + { + if (mem2hex((char *)addr, remcomOutBuffer, length, 1)) + { + break; + } + strcpy (remcomOutBuffer, "E03"); + } + else + { + strcpy(remcomOutBuffer,"E01"); + } + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* Try to read '%x,%x:'. */ + + if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':') + { + if (hex2mem(ptr, (char *)addr, length, 1)) + { + strcpy(remcomOutBuffer, "OK"); + } + else + { + strcpy(remcomOutBuffer, "E03"); + } + } + else + { + strcpy(remcomOutBuffer, "E02"); + } + break; + + case 'c': /* cAA..AA Continue at address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + + if (hexToInt(&ptr, &addr)) + { + registers[PC] = addr; + } + + /* 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(); + return; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + #if 0 + case 't': /* Test feature */ + break; + #endif + case 'r': /* Reset */ + // Perform reset + break; + } /* switch */ + /* reply to the request */ + putpacket(remcomOutBuffer); + } +}