diff options
author | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
---|---|---|
committer | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
commit | 03261851a10dd2d6900a0a00a7515a0a46fb5d76 (patch) | |
tree | 7c22ac6cbbc99fd5cd1b5426853be8d4fd7bfcf1 /libgloss/mips/lsi33k-stub.c | |
parent | fae4c299f14fc23e2829c8656992eba21f79242a (diff) | |
download | cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.gz cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.bz2 cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.zip |
20000317 sourceware import
Diffstat (limited to 'libgloss/mips/lsi33k-stub.c')
-rw-r--r-- | libgloss/mips/lsi33k-stub.c | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/libgloss/mips/lsi33k-stub.c b/libgloss/mips/lsi33k-stub.c new file mode 100644 index 000000000..dc0b86ac6 --- /dev/null +++ b/libgloss/mips/lsi33k-stub.c @@ -0,0 +1,595 @@ +/**************************************************************************** + * + * 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) + * + * bBB..BB Set baud rate to BB..BB OK or BNN, then sets + * baud rate + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $<packet info>#<checksum>. + * + * where + * <packet info> :: <characters representing the command or response> + * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> + * + * 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 <string.h> +#include <signal.h> +#include "dbgmon.h" +#include "parser.h" +#include "ctype.h" + +/************************************************************************ + * + * external low-level support routines + */ + +extern putchar(); /* write a single character */ +extern getchar(); /* read and return a single char */ + +/************************************************************************/ + +/* Stuff for stdio-like gets_debugger_check() */ + +#define CTRL(x) ('x'&0x1f) +#define DEL 0x7f +#define INTR CTRL(C) +#define BELL 0x7 +#define PROMPT "? " + +#define BUFSIZE 512 /* Big enough for register packets */ + +static int initialized = 0; /* !0 means we've been initialized */ + +static char hexchars[]="0123456789abcdef"; + +extern unsigned int _regs[]; /* Saved registers from client */ + +/* Convert ch from a hex digit to an int */ + +static int +hex(ch) + 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; +} + +/* scan for the sequence $<data>#<checksum> */ + +static void +getpacket(buffer) + char *buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + /* At this point, the start character ($) has been received through + * the debug monitor parser. Get the remaining characters and + * process them. + */ + + checksum = 0; + xmitcsum = -1; + count = 0; + + /* read until a # or end of buffer is found */ + + while (count < BUFSIZE) + { + ch = getchar(); + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + + if (count >= BUFSIZE) + buffer[count] = 0; + + if (ch == '#') + { + xmitcsum = hex(getchar()) << 4; + xmitcsum |= hex(getchar()); +#if 0 + /* Humans shouldn't have to figure out checksums to type to it. */ + putchar ('+'); + return; +#endif + + if (checksum != xmitcsum) + { + putchar('-'); /* failed checksum */ + return; /* Back to monitor loop */ + } + else + { + putchar('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + + if (buffer[2] == ':') + { + putchar(buffer[0]); + putchar(buffer[1]); + + /* remove sequence chars from buffer */ + + count = strlen(buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + + /* Buffer command received- go and process it. */ + + + } + } +} + + +/* send the packet in buffer. */ + +static void +putpacket(buffer) + unsigned char *buffer; +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $<packet info>#<checksum>. */ + do + { + putchar('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + if (! putchar(ch)) + return; + checksum += ch; + count += 1; + } + + putchar('#'); + putchar(hexchars[checksum >> 4]); + putchar(hexchars[checksum & 0xf]); + + } + while (getchar() != '+'); +} + +static char remcomInBuffer[BUFSIZE]; +static char remcomOutBuffer[BUFSIZE]; + +/* 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(mem, buf, count, may_fault) + 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(buf, mem, count, may_fault) + unsigned char *buf; + unsigned char *mem; + int count; + int may_fault; +{ + int i; + unsigned char ch; + + for (i=0; i<count; i++) + { + ch = hex(*buf++) << 4; + ch |= hex(*buf++); + *mem++ = ch; + if (mem_err) + return 0; + } + + return mem; +} + +/* This table contains the mapping between SPARC hardware trap types, and + signals, which are primarily what GDB understands. It also indicates + which hardware traps we need to commandeer when initializing the stub. */ + +static struct hard_trap_info +{ + unsigned char tt; /* Trap type code for SPARClite */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + {0x06, SIGSEGV}, /* instruction access error */ + {0x0a, SIGILL}, /* privileged instruction */ + {0x0a, SIGILL}, /* illegal instruction */ + {0x0b, SIGEMT}, /* cp disabled */ + {0x07, SIGSEGV}, /* data access exception */ + {0x09, SIGTRAP}, /* ta 1 - normal breakpoint instruction */ + {0, 0} /* Must be last */ +}; + +/* Convert the SPARC hardware trap type code to a unix signal number. */ + +static int +computeSignal(tt) + int tt; +{ + struct hard_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 */ +} + +/* + * While we find nice hex chars, build an int. + * Return number of chars processed. + */ + +static int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex(**ptr); + if (hexValue < 0) + break; + + *intValue = (*intValue << 4) | hexValue; + numChars ++; + + (*ptr)++; + } + + return (numChars); +} + +/* This function lets GDB know that an exception has occured. */ + +static void +debug_handle_exception () +{ + int tt; /* Trap type */ + int sigval; + char *ptr; + + tt = (_regs[R_CAUSE] >> 2) & 0x0f; + + /* 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[R_EPC >> 4]; + *ptr++ = hexchars[R_EPC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&_regs[R_EPC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R_FP >> 4]; + *ptr++ = hexchars[R_FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&_regs[R_FP], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R_SP >> 4]; + *ptr++ = hexchars[R_SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&_regs[R_SP], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + return; +} + + +void process_packet() +{ + + char *ptr; + int length; + int addr; + int sigval; + int tt; /* Trap type */ + + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) + { + +/* Return Last SIGVAL */ + +case '?': + tt = (_regs[R_CAUSE] >> 2) & 0x0f; + sigval = computeSignal(tt); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; + + /* toggle debug flag */ + + case 'd': + break; + + /* Return the values of the CPU registers */ + + case 'g': + ptr = remcomOutBuffer; + ptr = mem2hex((char *)_regs, ptr, 32 * 4, 0); /* General Purpose Registers */ + ptr = mem2hex((char *)&_regs[R_EPC], ptr, 9 * 4, 0); /* CP0 Registers */ + break; + + /* set the value of the CPU registers - return OK */ + + case 'G': + ptr = &remcomInBuffer[1]; + hex2mem(ptr, (char *)_regs, 32 * 4, 0); /* General Purpose Registers */ + hex2mem(ptr + 32 * 4 * 2, (char *)&_regs[R_EPC], 9 * 4, 0); /* CP0 Registers */ + strcpy(remcomOutBuffer,"OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + + case 'm': + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) + { + if (mem2hex((char *)addr, remcomOutBuffer, length, 1)) + break; + strcpy (remcomOutBuffer, "E03"); + } + else + strcpy(remcomOutBuffer,"E01"); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + + case 'M': + ptr = &remcomInBuffer[1]; + 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; + + /* cAA..AA Continue at address AA..AA(optional) */ + + case 'c': + + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) + { + gdb_go ( addr ); + } + else + { + dbg_cont(); + } + return; + + /* kill the program */ + + case 'k': + break; + + /* Reset */ + + case 'r': + break; + + /* switch */ + + } + + /* Reply to the request */ + + putpacket(remcomOutBuffer); +} + + +/* + * gets_debugger_check - This is the same as the stdio gets, but we also + * check for a leading $ in the buffer. This so we + * gracefully handle the GDB protocol packets. + */ + +char * +gets_debugger_check(buf) +char *buf; +{ + register char c; + char *bufp; + + bufp = buf; + for (;;) + { + c = getchar(); + switch (c) + { + + /* quote next char */ + + case '$': + if ( buf == bufp ) + process_packet(); + break; + + case CTRL(V): + c = getchar(); + if (bufp < &buf[LINESIZE-3]) + { + rmw_byte (bufp++,c); + showchar(c); + } + else + { + putchar(BELL); + } + break; + + case '\n': + case '\r': + putchar('\n'); + rmw_byte (bufp,0); + return(buf); + + case CTRL(H): + case DEL: + if (bufp > buf) + { + bufp--; + putchar(CTRL(H)); + putchar(' '); + putchar(CTRL(H)); + } + break; + + case CTRL(U): + if (bufp > buf) + { + printf("^U\n%s", PROMPT); + bufp = buf; + } + break; + + case '\t': + c = ' '; + + default: + /* + * Make sure there's room for this character + * plus a trailing \n and 0 byte + */ + if (isprint(c) && bufp < &buf[LINESIZE-3]) + { + rmw_byte ( bufp++, c ); + putchar(c); + } + else + { + putchar(BELL); + } + break; + } + } +} |