diff options
Diffstat (limited to 'gdb/stubs')
-rw-r--r-- | gdb/stubs/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/stubs/i386-stub.c | 952 | ||||
-rw-r--r-- | gdb/stubs/m32r-stub.c | 1779 | ||||
-rw-r--r-- | gdb/stubs/m68k-stub.c | 1098 | ||||
-rw-r--r-- | gdb/stubs/sh-stub.c | 1583 | ||||
-rw-r--r-- | gdb/stubs/sparc-stub.c | 778 |
6 files changed, 6198 insertions, 0 deletions
diff --git a/gdb/stubs/ChangeLog b/gdb/stubs/ChangeLog index 1a8b2b7..a0f175e 100644 --- a/gdb/stubs/ChangeLog +++ b/gdb/stubs/ChangeLog @@ -1,3 +1,11 @@ +2012-03-08 Tristan Gingold <gingold@adacore.com> + + * sparc-stub.c: Move from .. + * sh-stub.c: Likewise. + * m68k-stub.c: Likewise. + * m32r-stub.c: Likewise. + * i386-stub.c: Likewise. + 2012-03-05 Tristan Gingold <gingold@adacore.com> * buildvms.com: New file. diff --git a/gdb/stubs/i386-stub.c b/gdb/stubs/i386-stub.c new file mode 100644 index 0000000..04996b7 --- /dev/null +++ b/gdb/stubs/i386-stub.c @@ -0,0 +1,952 @@ +/**************************************************************************** + + 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 386 by Jim Kingdon, Cygnus Support. + * + * 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 external function exceptionHandler() is + * used to attach a specific handler to a specific 386 vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * 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 + * + * $<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 <stdio.h> +#include <string.h> + +/************************************************************************ + * + * external low-level support routines + */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ +extern void exceptionHandler(); /* assign an exception handler */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* Number of registers. */ +#define NUMREGS 16 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) + +enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, + PC /* also known as eip */, + PS /* also known as eflags */, + CS, SS, DS, ES, FS, GS}; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGS]; + +#define STACKSIZE 10000 +int remcomStack[STACKSIZE/sizeof(int)]; +static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +extern void +return_to_prog (); + +/* Restore the program's registers (including the stack pointer, which + means we get the right stack and don't have to worry about popping our + return address and any stack frames and so on) and return. */ +asm(".text"); +asm(".globl _return_to_prog"); +asm("_return_to_prog:"); +asm(" movw _registers+44, %ss"); +asm(" movl _registers+16, %esp"); +asm(" movl _registers+4, %ecx"); +asm(" movl _registers+8, %edx"); +asm(" movl _registers+12, %ebx"); +asm(" movl _registers+20, %ebp"); +asm(" movl _registers+24, %esi"); +asm(" movl _registers+28, %edi"); +asm(" movw _registers+48, %ds"); +asm(" movw _registers+52, %es"); +asm(" movw _registers+56, %fs"); +asm(" movw _registers+60, %gs"); +asm(" movl _registers+36, %eax"); +asm(" pushl %eax"); /* saved eflags */ +asm(" movl _registers+40, %eax"); +asm(" pushl %eax"); /* saved cs */ +asm(" movl _registers+32, %eax"); +asm(" pushl %eax"); /* saved eip */ +asm(" movl _registers, %eax"); +/* use iret to restore pc and flags together so + that trace flag works right. */ +asm(" iret"); + +#define BREAKPOINT() asm(" int $3"); + +/* Put the error code here just in case the user cares. */ +int gdb_i386errcode; +/* Likewise, the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_i386vector = -1; + +/* GDB stores segment registers in 32-bit words (that's just the way + m-i386v.h is written). So zero the appropriate areas in registers. */ +#define SAVE_REGISTERS1() \ + asm ("movl %eax, _registers"); \ + asm ("movl %ecx, _registers+4"); \ + asm ("movl %edx, _registers+8"); \ + asm ("movl %ebx, _registers+12"); \ + asm ("movl %ebp, _registers+20"); \ + asm ("movl %esi, _registers+24"); \ + asm ("movl %edi, _registers+28"); \ + asm ("movw $0, %ax"); \ + asm ("movw %ds, _registers+48"); \ + asm ("movw %ax, _registers+50"); \ + asm ("movw %es, _registers+52"); \ + asm ("movw %ax, _registers+54"); \ + asm ("movw %fs, _registers+56"); \ + asm ("movw %ax, _registers+58"); \ + asm ("movw %gs, _registers+60"); \ + asm ("movw %ax, _registers+62"); +#define SAVE_ERRCODE() \ + asm ("popl %ebx"); \ + asm ("movl %ebx, _gdb_i386errcode"); +#define SAVE_REGISTERS2() \ + asm ("popl %ebx"); /* old eip */ \ + asm ("movl %ebx, _registers+32"); \ + asm ("popl %ebx"); /* old cs */ \ + asm ("movl %ebx, _registers+40"); \ + asm ("movw %ax, _registers+42"); \ + asm ("popl %ebx"); /* old eflags */ \ + asm ("movl %ebx, _registers+36"); \ + /* Now that we've done the pops, we can save the stack pointer."); */ \ + asm ("movw %ss, _registers+44"); \ + asm ("movw %ax, _registers+46"); \ + asm ("movl %esp, _registers+16"); + +/* See if mem_fault_routine is set, if so just IRET to that address. */ +#define CHECK_FAULT() \ + asm ("cmpl $0, _mem_fault_routine"); \ + asm ("jne mem_fault"); + +asm (".text"); +asm ("mem_fault:"); +/* OK to clobber temp registers; we're just going to end up in set_mem_err. */ +/* Pop error code from the stack and save it. */ +asm (" popl %eax"); +asm (" movl %eax, _gdb_i386errcode"); + +asm (" popl %eax"); /* eip */ +/* We don't want to return there, we want to return to the function + pointed to by mem_fault_routine instead. */ +asm (" movl _mem_fault_routine, %eax"); +asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */ +asm (" popl %edx"); /* eflags */ + +/* Remove this stack frame; when we do the iret, we will be going to + the start of a function, so we want the stack to look just like it + would after a "call" instruction. */ +asm (" leave"); + +/* Push the stuff that iret wants. */ +asm (" pushl %edx"); /* eflags */ +asm (" pushl %ecx"); /* cs */ +asm (" pushl %eax"); /* eip */ + +/* Zero mem_fault_routine. */ +asm (" movl $0, %eax"); +asm (" movl %eax, _mem_fault_routine"); + +asm ("iret"); + +#define CALL_HOOK() asm("call _remcomHandler"); + +/* This function is called when a i386 exception occurs. It saves + * all the cpu regs in the _registers array, munges the stack a bit, + * and invokes an exception handler (remcom_handler). + * + * stack on entry: stack on exit: + * old eflags vector number + * old cs (zero-filled to 32 bits) + * old eip + * + */ +extern void _catchException3(); +asm(".text"); +asm(".globl __catchException3"); +asm("__catchException3:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $3"); +CALL_HOOK(); + +/* Same thing for exception 1. */ +extern void _catchException1(); +asm(".text"); +asm(".globl __catchException1"); +asm("__catchException1:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $1"); +CALL_HOOK(); + +/* Same thing for exception 0. */ +extern void _catchException0(); +asm(".text"); +asm(".globl __catchException0"); +asm("__catchException0:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $0"); +CALL_HOOK(); + +/* Same thing for exception 4. */ +extern void _catchException4(); +asm(".text"); +asm(".globl __catchException4"); +asm("__catchException4:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $4"); +CALL_HOOK(); + +/* Same thing for exception 5. */ +extern void _catchException5(); +asm(".text"); +asm(".globl __catchException5"); +asm("__catchException5:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $5"); +CALL_HOOK(); + +/* Same thing for exception 6. */ +extern void _catchException6(); +asm(".text"); +asm(".globl __catchException6"); +asm("__catchException6:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $6"); +CALL_HOOK(); + +/* Same thing for exception 7. */ +extern void _catchException7(); +asm(".text"); +asm(".globl __catchException7"); +asm("__catchException7:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $7"); +CALL_HOOK(); + +/* Same thing for exception 8. */ +extern void _catchException8(); +asm(".text"); +asm(".globl __catchException8"); +asm("__catchException8:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $8"); +CALL_HOOK(); + +/* Same thing for exception 9. */ +extern void _catchException9(); +asm(".text"); +asm(".globl __catchException9"); +asm("__catchException9:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $9"); +CALL_HOOK(); + +/* Same thing for exception 10. */ +extern void _catchException10(); +asm(".text"); +asm(".globl __catchException10"); +asm("__catchException10:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $10"); +CALL_HOOK(); + +/* Same thing for exception 12. */ +extern void _catchException12(); +asm(".text"); +asm(".globl __catchException12"); +asm("__catchException12:"); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $12"); +CALL_HOOK(); + +/* Same thing for exception 16. */ +extern void _catchException16(); +asm(".text"); +asm(".globl __catchException16"); +asm("__catchException16:"); +SAVE_REGISTERS1(); +SAVE_REGISTERS2(); +asm ("pushl $16"); +CALL_HOOK(); + +/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */ + +/* Same thing for exception 13. */ +extern void _catchException13 (); +asm (".text"); +asm (".globl __catchException13"); +asm ("__catchException13:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $13"); +CALL_HOOK(); + +/* Same thing for exception 11. */ +extern void _catchException11 (); +asm (".text"); +asm (".globl __catchException11"); +asm ("__catchException11:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $11"); +CALL_HOOK(); + +/* Same thing for exception 14. */ +extern void _catchException14 (); +asm (".text"); +asm (".globl __catchException14"); +asm ("__catchException14:"); +CHECK_FAULT(); +SAVE_REGISTERS1(); +SAVE_ERRCODE(); +SAVE_REGISTERS2(); +asm ("pushl $14"); +CALL_HOOK(); + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use. + */ +asm("_remcomHandler:"); +asm(" popl %eax"); /* pop off return address */ +asm(" popl %eax"); /* get the exception number */ +asm(" movl _stackPtr, %esp"); /* move to remcom stack area */ +asm(" pushl %eax"); /* push exception onto stack */ +asm(" call _handle_exception"); /* this never returns */ + +void +_returnFromException () +{ + return_to_prog (); +} + +int +hex (ch) + 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 $<data>#<checksum> */ + +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); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + fprintf (stderr, + "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + 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. */ + +void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $<packet info>#<checksum>. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + + } + while (getDebugChar () != '+'); +} + +void +debug_error (format, parm) + char *format; + char *parm; +{ + if (remote_debug) + fprintf (stderr, format, parm); +} + +/* Address of a routine to RTE to if we get a memory fault. */ +static void (*volatile mem_fault_routine) () = NULL; + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; + +void +set_mem_err (void) +{ + mem_err = 1; +} + +/* These are separate functions so that they are so short and sweet + that the compiler won't save any registers (if there is a fault + to mem_fault, they won't get restored, so there better not be any + saved). */ +int +get_char (char *addr) +{ + return *addr; +} + +void +set_char (char *addr, int val) +{ + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex (mem, buf, count, may_fault) + char *mem; + char *buf; + int count; + int may_fault; +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = get_char (mem++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_fault_routine = NULL; + 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 */ +char * +hex2mem (buf, mem, count, may_fault) + char *buf; + char *mem; + int count; + int may_fault; +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + set_char (mem++, ch); + if (may_fault && mem_err) + return (mem); + } + if (may_fault) + mem_fault_routine = NULL; + return (mem); +} + +/* this function takes the 386 exception vector and attempts to + translate this number into a unix compatible signal value */ +int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case 0: + sigval = 8; + break; /* divide by zero */ + case 1: + sigval = 5; + break; /* debug exception */ + case 3: + sigval = 5; + break; /* breakpoint */ + case 4: + sigval = 16; + break; /* into instruction (overflow) */ + case 5: + sigval = 16; + break; /* bound instruction */ + case 6: + sigval = 4; + break; /* Invalid opcode */ + case 7: + sigval = 8; + break; /* coprocessor not available */ + case 8: + sigval = 7; + break; /* double fault */ + case 9: + sigval = 11; + break; /* coprocessor segment overrun */ + case 10: + sigval = 11; + break; /* Invalid TSS */ + case 11: + sigval = 11; + break; /* Segment not present */ + case 12: + sigval = 11; + break; /* stack exception */ + case 13: + sigval = 11; + break; /* general protection */ + case 14: + sigval = 11; + break; /* page fault */ + case 16: + sigval = 7; + break; /* coprocessor error */ + default: + sigval = 7; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt (char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + int newPC; + + gdb_i386vector = exceptionVector; + + if (remote_debug) + { + printf ("vector=%d, sr=0x%x, pc=0x%x\n", + exceptionVector, registers[PS], registers[PC]); + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + + ptr = remcomOutBuffer; + + *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[ESP]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */ + *ptr++ = ';'; + + *ptr++ = hexchars[EBP]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[PC]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */ + *ptr++ = ';'; + + *ptr = '\0' + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES, 0); + strcpy (remcomOutBuffer, "OK"); + break; + case 'P': /* set the value of a single CPU register - return OK */ + { + int regno; + + if (hexToInt (&ptr, ®no) && *ptr++ == '=') + if (regno >= 0 && regno < NUMREGS) + { + hex2mem (ptr, (char *) ®isters[regno], 4, 0); + strcpy (remcomOutBuffer, "OK"); + break; + } + + strcpy (remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem_err = 0; + mem2hex ((char *) addr, remcomOutBuffer, length, 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + debug_error ("memory fault"); + } + } + + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + mem_err = 0; + hex2mem (ptr, (char *) addr, length, 1); + + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + debug_error ("memory fault"); + } + else + { + strcpy (remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + newPC = registers[PC]; + + /* clear the trace bit */ + registers[PS] &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (stepping) + registers[PS] |= 0x100; + + _returnFromException (); /* this is a jump */ + break; + + /* kill the program */ + case 'k': /* do nothing */ +#if 0 + /* Huh? This doesn't look like "nothing". + m68k-stub.c and sparc-stub.c don't have it. */ + BREAKPOINT (); +#endif + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps (void) +{ + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + exceptionHandler (0, _catchException0); + exceptionHandler (1, _catchException1); + exceptionHandler (3, _catchException3); + exceptionHandler (4, _catchException4); + exceptionHandler (5, _catchException5); + exceptionHandler (6, _catchException6); + exceptionHandler (7, _catchException7); + exceptionHandler (8, _catchException8); + exceptionHandler (9, _catchException9); + exceptionHandler (10, _catchException10); + exceptionHandler (11, _catchException11); + exceptionHandler (12, _catchException12); + exceptionHandler (13, _catchException13); + exceptionHandler (14, _catchException14); + exceptionHandler (16, _catchException16); + + initialized = 1; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + if (initialized) + BREAKPOINT (); +} diff --git a/gdb/stubs/m32r-stub.c b/gdb/stubs/m32r-stub.c new file mode 100644 index 0000000..4d54f72 --- /dev/null +++ b/gdb/stubs/m32r-stub.c @@ -0,0 +1,1779 @@ +/**************************************************************************** + + 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 M32R by Michael Snyder, Cygnus Support. + * + * 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 external function exceptionHandler() is + * used to attach a specific handler to a specific M32R vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * 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 + * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN + * AA..AA + * + * 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 + * + * $<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 + * + ****************************************************************************/ + + +/************************************************************************ + * + * external low-level support routines + */ +extern void putDebugChar (); /* write a single character */ +extern int getDebugChar (); /* read and return a single char */ +extern void exceptionHandler (); /* assign an exception handler */ + +/***************************************************************************** + * BUFMAX defines the maximum number of characters in inbound/outbound buffers + * at least NUMREGBYTES*2 are needed for register packets + */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const unsigned char hexchars[] = "0123456789abcdef"; + +#define NUMREGS 24 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames +{ R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, R11, R12, R13, R14, R15, + PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH +}; + +enum SYS_calls +{ + SYS_null, + SYS_exit, + SYS_open, + SYS_close, + SYS_read, + SYS_write, + SYS_lseek, + SYS_unlink, + SYS_getpid, + SYS_kill, + SYS_fstat, + SYS_sbrk, + SYS_fork, + SYS_execve, + SYS_wait4, + SYS_link, + SYS_chdir, + SYS_stat, + SYS_utime, + SYS_chown, + SYS_chmod, + SYS_time, + SYS_pipe +}; + +static int registers[NUMREGS]; + +#define STACKSIZE 8096 +static unsigned char remcomInBuffer[BUFMAX]; +static unsigned char remcomOutBuffer[BUFMAX]; +static int remcomStack[STACKSIZE / sizeof (int)]; +static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + +static unsigned int save_vectors[18]; /* previous exception vectors */ + +/* Indicate to caller of mem2hex or hex2mem that there has been an error. */ +static volatile int mem_err = 0; + +/* Store the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_m32r_vector = -1; + +#if 0 +#include "syscall.h" /* for SYS_exit, SYS_write etc. */ +#endif + +/* Global entry points: + */ + +extern void handle_exception (int); +extern void set_debug_traps (void); +extern void breakpoint (void); + +/* Local functions: + */ + +static int computeSignal (int); +static void putpacket (unsigned char *); +static unsigned char *getpacket (void); + +static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int); +static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int); +static int hexToInt (unsigned char **, int *); +static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int); +static void stash_registers (void); +static void restore_registers (void); +static int prepare_to_step (int); +static int finish_from_step (void); +static unsigned long crc32 (unsigned char *, int, unsigned long); + +static void gdb_error (char *, char *); +static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int); + +static unsigned char *strcpy (unsigned char *, const unsigned char *); +static int strlen (const unsigned char *); + +/* + * This function does all command procesing for interfacing to gdb. + */ + +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length, i; + unsigned char *ptr; + unsigned char buf[16]; + int binary; + + if (!finish_from_step ()) + return; /* "false step": let the target continue */ + + gdb_m32r_vector = exceptionVector; + + if (remote_debug) + { + mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0); + gdb_error ("Handle exception %s, ", buf); + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + gdb_error ("PC == 0x%s\n", buf); + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + + ptr = remcomOutBuffer; + + *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */ + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */ + *ptr++ = ';'; + *ptr++ = 0; + + if (exceptionVector == 0) /* simulated SYS call stuff */ + { + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + switch (registers[R0]) + { + case SYS_exit: + gdb_error ("Target program has exited at %s\n", buf); + ptr = remcomOutBuffer; + *ptr++ = 'W'; + sigval = registers[R1] & 0xff; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + *ptr++ = 0; + break; + case SYS_open: + gdb_error ("Target attempts SYS_open call at %s\n", buf); + break; + case SYS_close: + gdb_error ("Target attempts SYS_close call at %s\n", buf); + break; + case SYS_read: + gdb_error ("Target attempts SYS_read call at %s\n", buf); + break; + case SYS_write: + if (registers[R1] == 1 || /* write to stdout */ + registers[R1] == 2) /* write to stderr */ + { /* (we can do that) */ + registers[R0] = + gdb_write ((void *) registers[R2], registers[R3]); + return; + } + else + gdb_error ("Target attempts SYS_write call at %s\n", buf); + break; + case SYS_lseek: + gdb_error ("Target attempts SYS_lseek call at %s\n", buf); + break; + case SYS_unlink: + gdb_error ("Target attempts SYS_unlink call at %s\n", buf); + break; + case SYS_getpid: + gdb_error ("Target attempts SYS_getpid call at %s\n", buf); + break; + case SYS_kill: + gdb_error ("Target attempts SYS_kill call at %s\n", buf); + break; + case SYS_fstat: + gdb_error ("Target attempts SYS_fstat call at %s\n", buf); + break; + default: + gdb_error ("Target attempts unknown SYS call at %s\n", buf); + break; + } + } + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + binary = 0; + switch (*ptr++) + { + default: /* Unknown code. Return an empty reply message. */ + break; + case 'R': + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + strcpy (remcomOutBuffer, "OK"); + break; + case '!': + strcpy (remcomOutBuffer, "OK"); + break; + case 'X': /* XAA..AA,LLLL:<binary data>#cs */ + binary = 1; + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + { + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + mem_err = 0; + if (binary) + bin2mem (ptr, (unsigned char *) addr, length, 1); + else + hex2mem (ptr, (unsigned char *) addr, length, 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + else + { + strcpy (remcomOutBuffer, "OK"); + } + ptr = 0; + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + } + break; + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem_err = 0; + mem2hex ((unsigned char *) addr, remcomOutBuffer, length, + 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + } + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + break; + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES, + 0); + break; + case 'P': /* set the value of a single CPU register - return OK */ + { + int regno; + + if (hexToInt (&ptr, ®no) && *ptr++ == '=') + if (regno >= 0 && regno < NUMREGS) + { + int stackmode; + + hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0); + /* + * Since we just changed a single CPU register, let's + * make sure to keep the several stack pointers consistant. + */ + stackmode = registers[PSW] & 0x80; + if (regno == R15) /* stack pointer changed */ + { /* need to change SPI or SPU */ + if (stackmode == 0) + registers[SPI] = registers[R15]; + else + registers[SPU] = registers[R15]; + } + else if (regno == SPU) /* "user" stack pointer changed */ + { + if (stackmode != 0) /* stack in user mode: copy SP */ + registers[R15] = registers[SPU]; + } + else if (regno == SPI) /* "interrupt" stack pointer changed */ + { + if (stackmode == 0) /* stack in interrupt mode: copy SP */ + registers[R15] = registers[SPI]; + } + else if (regno == PSW) /* stack mode may have changed! */ + { /* force SP to either SPU or SPI */ + if (stackmode == 0) /* stack in user mode */ + registers[R15] = registers[SPI]; + else /* stack in interrupt mode */ + registers[R15] = registers[SPU]; + } + strcpy (remcomOutBuffer, "OK"); + break; + } + strcpy (remcomOutBuffer, "E01"); + break; + } + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0); + strcpy (remcomOutBuffer, "OK"); + break; + case 's': /* sAA..AA Step one instruction from AA..AA(optional) */ + stepping = 1; + case 'c': /* cAA..AA Continue from address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + if (stepping) /* single-stepping */ + { + if (!prepare_to_step (0)) /* set up for single-step */ + { + /* prepare_to_step has already emulated the target insn: + Send SIGTRAP to gdb, don't resume the target at all. */ + ptr = remcomOutBuffer; + *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */ + *ptr++ = '0'; + *ptr++ = '5'; + + *ptr++ = hexchars[PC >> 4]; /* send PC */ + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; /* send FP */ + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; /* send SP */ + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); + *ptr++ = ';'; + *ptr++ = 0; + + break; + } + } + else /* continuing, not single-stepping */ + { + /* OK, about to do a "continue". First check to see if the + target pc is on an odd boundary (second instruction in the + word). If so, we must do a single-step first, because + ya can't jump or return back to an odd boundary! */ + if ((registers[PC] & 2) != 0) + prepare_to_step (1); + } + + return; + + case 'D': /* Detach */ +#if 0 + /* I am interpreting this to mean, release the board from control + by the remote stub. To do this, I am restoring the original + (or at least previous) exception vectors. + */ + for (i = 0; i < 18; i++) + exceptionHandler (i, save_vectors[i]); + putpacket ("OK"); + return; /* continue the inferior */ +#else + strcpy (remcomOutBuffer, "OK"); + break; +#endif + case 'q': + if (*ptr++ == 'C' && + *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':') + { + unsigned long start, len, our_crc; + + if (hexToInt (&ptr, (int *) &start) && + *ptr++ == ',' && hexToInt (&ptr, (int *) &len)) + { + remcomOutBuffer[0] = 'C'; + our_crc = crc32 ((unsigned char *) start, len, 0xffffffff); + mem2hex ((char *) &our_crc, + &remcomOutBuffer[1], sizeof (long), 0); + } /* else do nothing */ + } /* else do nothing */ + break; + + case 'k': /* kill the program */ + continue; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + +/* qCRC support */ + +/* Table used by the crc32 function to calcuate the checksum. */ +static unsigned long crc32_table[256] = { 0, 0 }; + +static unsigned long +crc32 (unsigned char *buf, int len, unsigned long crc) +{ + if (!crc32_table[1]) + { + /* Initialize the CRC table and the decoding table. */ + int i, j; + unsigned long c; + + for (i = 0; i < 256; i++) + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + crc32_table[i] = c; + } + } + + while (len--) + { + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; + buf++; + } + return crc; +} + +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); +} + +/* scan for the sequence $<data>#<checksum> */ + +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); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + unsigned char buf[16]; + + mem2hex ((unsigned char *) &checksum, buf, 4, 0); + gdb_error ("Bad checksum: my count = %s, ", buf); + mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0); + gdb_error ("sent count = %s\n", buf); + gdb_error (" -- Bad buffer: \"%s\"\n", buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + 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; + char ch; + + /* $<packet info>#<checksum>. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + } + while (getDebugChar () != '+'); +} + +/* Address of a routine to RTE to if we get a memory fault. */ + +static void (*volatile mem_fault_routine) () = 0; + +static void +set_mem_err (void) +{ + mem_err = 1; +} + +/* Check the address for safe access ranges. As currently defined, + this routine will reject the "expansion bus" address range(s). + To make those ranges useable, someone must implement code to detect + whether there's anything connected to the expansion bus. */ + +static int +mem_safe (unsigned char *addr) +{ +#define BAD_RANGE_ONE_START ((unsigned char *) 0x600000) +#define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000) +#define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000) +#define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000) + + if (addr < BAD_RANGE_ONE_START) + return 1; /* safe */ + if (addr < BAD_RANGE_ONE_END) + return 0; /* unsafe */ + if (addr < BAD_RANGE_TWO_START) + return 1; /* safe */ + if (addr < BAD_RANGE_TWO_END) + return 0; /* unsafe */ +} + +/* These are separate functions so that they are so short and sweet + that the compiler won't save any registers (if there is a fault + to mem_fault, they won't get restored, so there better not be any + saved). */ +static int +get_char (unsigned char *addr) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return 0; + } +#endif + return *addr; +} + +static void +set_char (unsigned char *addr, unsigned char val) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return; + } +#endif + *addr = val; +} + +/* Convert the memory pointed to by mem into hex, placing result in buf. + Return a pointer to the last char put in buf (null). + If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero 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) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = get_char (mem++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_fault_routine = 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 unsigned char * +hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + set_char (mem++, ch); + if (may_fault && mem_err) + return (mem); + } + if (may_fault) + mem_fault_routine = 0; + return (mem); +} + +/* Convert the binary stream in BUF to memory. + + Gdb will escape $, #, and the escape char (0x7d). + COUNT is the total number of bytes to write into + memory. */ +static unsigned char * +bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + /* Check for any escaped characters. Be paranoid and + only unescape chars that should be escaped. */ + if (*buf == 0x7d) + { + switch (*(buf + 1)) + { + case 0x3: /* # */ + case 0x4: /* $ */ + case 0x5d: /* escape char */ + buf++; + *buf |= 0x20; + break; + default: + /* nothing */ + break; + } + } + + set_char (mem++, *buf++); + + if (may_fault && mem_err) + return mem; + } + + if (may_fault) + mem_fault_routine = 0; + return mem; +} + +/* this function takes the m32r exception vector and attempts to + translate this number into a unix compatible signal value */ + +static int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case 0: + sigval = 23; + break; /* I/O trap */ + case 1: + sigval = 5; + break; /* breakpoint */ + case 2: + sigval = 5; + break; /* breakpoint */ + case 3: + sigval = 5; + break; /* breakpoint */ + case 4: + sigval = 5; + break; /* breakpoint */ + case 5: + sigval = 5; + break; /* breakpoint */ + case 6: + sigval = 5; + break; /* breakpoint */ + case 7: + sigval = 5; + break; /* breakpoint */ + case 8: + sigval = 5; + break; /* breakpoint */ + case 9: + sigval = 5; + break; /* breakpoint */ + case 10: + sigval = 5; + break; /* breakpoint */ + case 11: + sigval = 5; + break; /* breakpoint */ + case 12: + sigval = 5; + break; /* breakpoint */ + case 13: + sigval = 5; + break; /* breakpoint */ + case 14: + sigval = 5; + break; /* breakpoint */ + case 15: + sigval = 5; + break; /* breakpoint */ + case 16: + sigval = 10; + break; /* BUS ERROR (alignment) */ + case 17: + sigval = 2; + break; /* INTerrupt */ + default: + sigval = 7; + break; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +static int +hexToInt (unsigned char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + (*ptr)++; + } + return (numChars); +} + +/* + Table of branch instructions: + + 10B6 RTE return from trap or exception + 1FCr JMP jump + 1ECr JL jump and link + 7Fxx BRA branch + FFxxxxxx BRA branch (long) + B09rxxxx BNEZ branch not-equal-zero + Br1rxxxx BNE branch not-equal + 7Dxx BNC branch not-condition + FDxxxxxx BNC branch not-condition (long) + B0Arxxxx BLTZ branch less-than-zero + B0Crxxxx BLEZ branch less-equal-zero + 7Exx BL branch and link + FExxxxxx BL branch and link (long) + B0Drxxxx BGTZ branch greater-than-zero + B0Brxxxx BGEZ branch greater-equal-zero + B08rxxxx BEQZ branch equal-zero + Br0rxxxx BEQ branch equal + 7Cxx BC branch condition + FCxxxxxx BC branch condition (long) + */ + +static int +isShortBranch (unsigned char *instr) +{ + unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */ + + if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */ + return 1; /* return from trap or exception */ + + if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */ + if ((instr[1] & 0xF0) == 0xC0) + return 2; /* jump thru a register */ + + if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */ + instr0 == 0x7E || instr0 == 0x7F) + return 3; /* eight bit PC offset */ + + return 0; +} + +static int +isLongBranch (unsigned char *instr) +{ + if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */ + instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */ + return 4; + if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */ + { + if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */ + (instr[1] & 0xF0) == 0x10) + return 5; + if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */ + if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 || + (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 || + (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0) + return 6; + } + return 0; +} + +/* if address is NOT on a 4-byte boundary, or high-bit of instr is zero, + then it's a 2-byte instruction, else it's a 4-byte instruction. */ + +#define INSTRUCTION_SIZE(addr) \ + ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4) + +static int +isBranch (unsigned char *instr) +{ + if (INSTRUCTION_SIZE (instr) == 2) + return isShortBranch (instr); + else + return isLongBranch (instr); +} + +static int +willBranch (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 0: + return 0; /* not a branch */ + case 1: + return 1; /* RTE */ + case 2: + return 1; /* JL or JMP */ + case 3: /* BC, BNC, BL, BRA (short) */ + case 4: /* BC, BNC, BL, BRA (long) */ + switch (instr[0] & 0x0F) + { + case 0xC: /* Branch if Condition Register */ + return (registers[CBR] != 0); + case 0xD: /* Branch if NOT Condition Register */ + return (registers[CBR] == 0); + case 0xE: /* Branch and Link */ + case 0xF: /* Branch (unconditional) */ + return 1; + default: /* oops? */ + return 0; + } + case 5: /* BNE, BEQ */ + switch (instr[1] & 0xF0) + { + case 0x00: /* Branch if r1 equal to r2 */ + return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]); + case 0x10: /* Branch if r1 NOT equal to r2 */ + return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]); + default: /* oops? */ + return 0; + } + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */ + switch (instr[1] & 0xF0) + { + case 0x80: /* Branch if reg equal to zero */ + return (registers[instr[1] & 0x0F] == 0); + case 0x90: /* Branch if reg NOT equal to zero */ + return (registers[instr[1] & 0x0F] != 0); + case 0xA0: /* Branch if reg less than zero */ + return (registers[instr[1] & 0x0F] < 0); + case 0xB0: /* Branch if reg greater or equal to zero */ + return (registers[instr[1] & 0x0F] >= 0); + case 0xC0: /* Branch if reg less than or equal to zero */ + return (registers[instr[1] & 0x0F] <= 0); + case 0xD0: /* Branch if reg greater than zero */ + return (registers[instr[1] & 0x0F] > 0); + default: /* oops? */ + return 0; + } + default: /* oops? */ + return 0; + } +} + +static int +branchDestination (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + default: + case 0: /* not a branch */ + return 0; + case 1: /* RTE */ + return registers[BPC] & ~3; /* pop BPC into PC */ + case 2: /* JL or JMP */ + return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */ + case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */ + return (((int) instr) & ~3) + ((char) instr[1] << 2); + case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */ + return ((int) instr + + ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) << + 2)); + case 5: /* BNE, BEQ (16-bit relative offset) */ + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */ + return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2)); + } + + /* An explanatory note: in the last three return expressions, I have + cast the most-significant byte of the return offset to char. + What this accomplishes is sign extension. If the other + less-significant bytes were signed as well, they would get sign + extended too and, if negative, their leading bits would clobber + the bits of the more-significant bytes ahead of them. There are + other ways I could have done this, but sign extension from + odd-sized integers is always a pain. */ +} + +static void +branchSideEffects (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 1: /* RTE */ + return; /* I <THINK> this is already handled... */ + case 2: /* JL (or JMP) */ + case 3: /* BL (or BC, BNC, BRA) */ + case 4: + if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */ + registers[R14] = (registers[PC] & ~3) + 4; + return; + default: /* any other branch has no side effects */ + return; + } +} + +static struct STEPPING_CONTEXT +{ + int stepping; /* true when we've started a single-step */ + unsigned long target_addr; /* the instr we're trying to execute */ + unsigned long target_size; /* the size of the target instr */ + unsigned long noop_addr; /* where we've inserted a no-op, if any */ + unsigned long trap1_addr; /* the trap following the target instr */ + unsigned long trap2_addr; /* the trap at a branch destination, if any */ + unsigned short noop_save; /* instruction overwritten by our no-op */ + unsigned short trap1_save; /* instruction overwritten by trap1 */ + unsigned short trap2_save; /* instruction overwritten by trap2 */ + unsigned short continue_p; /* true if NOT returning to gdb after step */ +} stepping; + +/* Function: prepare_to_step + Called from handle_exception to prepare the user program to single-step. + Places a trap instruction after the target instruction, with special + extra handling for branch instructions and for instructions in the + second half-word of a word. + + Returns: True if we should actually execute the instruction; + False if we are going to emulate executing the instruction, + in which case we simply report to GDB that the instruction + has already been executed. */ + +#define TRAP1 0x10f1; /* trap #1 instruction */ +#define NOOP 0x7000; /* noop instruction */ + +static unsigned short trap1 = TRAP1; +static unsigned short noop = NOOP; + +static int +prepare_to_step (continue_p) + int continue_p; /* if this isn't REALLY a single-step (see below) */ +{ + unsigned long pc = registers[PC]; + int branchCode = isBranch ((unsigned char *) pc); + unsigned char *p; + + /* zero out the stepping context + (paranoia -- it should already be zeroed) */ + for (p = (unsigned char *) &stepping; + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + if (branchCode != 0) /* next instruction is a branch */ + { + branchSideEffects ((unsigned char *) pc, branchCode); + if (willBranch ((unsigned char *) pc, branchCode)) + registers[PC] = branchDestination ((unsigned char *) pc, branchCode); + else + registers[PC] = pc + INSTRUCTION_SIZE (pc); + return 0; /* branch "executed" -- just notify GDB */ + } + else if (((int) pc & 2) != 0) /* "second-slot" instruction */ + { + /* insert no-op before pc */ + stepping.noop_addr = pc - 2; + stepping.noop_save = *(unsigned short *) stepping.noop_addr; + *(unsigned short *) stepping.noop_addr = noop; + /* insert trap after pc */ + stepping.trap1_addr = pc + 2; + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + else /* "first-slot" instruction */ + { + /* insert trap after pc */ + stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc); + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + /* "continue_p" means that we are actually doing a continue, and not + being requested to single-step by GDB. Sometimes we have to do + one single-step before continuing, because the PC is on a half-word + boundary. There's no way to simply resume at such an address. */ + stepping.continue_p = continue_p; + stepping.stepping = 1; /* starting a single-step */ + return 1; +} + +/* Function: finish_from_step + Called from handle_exception to finish up when the user program + returns from a single-step. Replaces the instructions that had + been overwritten by traps or no-ops, + + Returns: True if we should notify GDB that the target stopped. + False if we only single-stepped because we had to before we + could continue (ie. we were trying to continue at a + half-word boundary). In that case don't notify GDB: + just "continue continuing". */ + +static int +finish_from_step (void) +{ + if (stepping.stepping) /* anything to do? */ + { + int continue_p = stepping.continue_p; + unsigned char *p; + + if (stepping.noop_addr) /* replace instr "under" our no-op */ + *(unsigned short *) stepping.noop_addr = stepping.noop_save; + if (stepping.trap1_addr) /* replace instr "under" our trap */ + *(unsigned short *) stepping.trap1_addr = stepping.trap1_save; + if (stepping.trap2_addr) /* ditto our other trap, if any */ + *(unsigned short *) stepping.trap2_addr = stepping.trap2_save; + + for (p = (unsigned char *) &stepping; /* zero out the stepping context */ + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + return !(continue_p); + } + else /* we didn't single-step, therefore this must be a legitimate stop */ + return 1; +} + +struct PSWreg +{ /* separate out the bit flags in the PSW register */ + int pad1:16; + int bsm:1; + int bie:1; + int pad2:5; + int bc:1; + int sm:1; + int ie:1; + int pad3:5; + int c:1; +} *psw; + +/* Upon entry the value for LR to save has been pushed. + We unpush that so that the value for the stack pointer saved is correct. + Upon entry, all other registers are assumed to have not been modified + since the interrupt/trap occured. */ + +asm ("\n\ +stash_registers:\n\ + push r0\n\ + push r1\n\ + seth r1, #shigh(registers)\n\ + add3 r1, r1, #low(registers)\n\ + pop r0 ; r1\n\ + st r0, @(4,r1)\n\ + pop r0 ; r0\n\ + st r0, @r1\n\ + addi r1, #4 ; only add 4 as subsequent saves are `pre inc'\n\ + st r2, @+r1\n\ + st r3, @+r1\n\ + st r4, @+r1\n\ + st r5, @+r1\n\ + st r6, @+r1\n\ + st r7, @+r1\n\ + st r8, @+r1\n\ + st r9, @+r1\n\ + st r10, @+r1\n\ + st r11, @+r1\n\ + st r12, @+r1\n\ + st r13, @+r1 ; fp\n\ + pop r0 ; lr (r14)\n\ + st r0, @+r1\n\ + st sp, @+r1 ; sp contains right value at this point\n\ + mvfc r0, cr0\n\ + st r0, @+r1 ; cr0 == PSW\n\ + mvfc r0, cr1\n\ + st r0, @+r1 ; cr1 == CBR\n\ + mvfc r0, cr2\n\ + st r0, @+r1 ; cr2 == SPI\n\ + mvfc r0, cr3\n\ + st r0, @+r1 ; cr3 == SPU\n\ + mvfc r0, cr6\n\ + st r0, @+r1 ; cr6 == BPC\n\ + st r0, @+r1 ; PC == BPC\n\ + mvfaclo r0\n\ + st r0, @+r1 ; ACCL\n\ + mvfachi r0\n\ + st r0, @+r1 ; ACCH\n\ + jmp lr"); + +/* C routine to clean up what stash_registers did. + It is called after calling stash_registers. + This is separate from stash_registers as we want to do this in C + but doing stash_registers in C isn't straightforward. */ + +static void +cleanup_stash (void) +{ + psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */ + psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */ + psw->ie = psw->bie; + psw->c = psw->bc; + registers[CBR] = psw->bc; /* fix up pre-trap "C" register */ + +#if 0 /* FIXME: Was in previous version. Necessary? + (Remember that we use the "rte" insn to return from the + trap/interrupt so the values of bsm, bie, bc are important. */ + psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */ +#endif + + /* FIXME: Copied from previous version. This can probably be deleted + since methinks stash_registers has already done this. */ + registers[PC] = registers[BPC]; /* pre-trap PC */ + + /* FIXME: Copied from previous version. Necessary? */ + if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */ + registers[SPU] = registers[R15]; + else + registers[SPI] = registers[R15]; +} + +asm ("\n\ +restore_and_return:\n\ + seth r0, #shigh(registers+8)\n\ + add3 r0, r0, #low(registers+8)\n\ + ld r2, @r0+ ; restore r2\n\ + ld r3, @r0+ ; restore r3\n\ + ld r4, @r0+ ; restore r4\n\ + ld r5, @r0+ ; restore r5\n\ + ld r6, @r0+ ; restore r6\n\ + ld r7, @r0+ ; restore r7\n\ + ld r8, @r0+ ; restore r8\n\ + ld r9, @r0+ ; restore r9\n\ + ld r10, @r0+ ; restore r10\n\ + ld r11, @r0+ ; restore r11\n\ + ld r12, @r0+ ; restore r12\n\ + ld r13, @r0+ ; restore r13\n\ + ld r14, @r0+ ; restore r14\n\ + ld r15, @r0+ ; restore r15\n\ + ld r1, @r0+ ; restore cr0 == PSW\n\ + mvtc r1, cr0\n\ + ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)\n\ + mvtc r1, cr1\n\ + ld r1, @r0+ ; restore cr2 == SPI\n\ + mvtc r1, cr2\n\ + ld r1, @r0+ ; restore cr3 == SPU\n\ + mvtc r1, cr3\n\ + addi r0, #4 ; skip BPC\n\ + ld r1, @r0+ ; restore cr6 (BPC) == PC\n\ + mvtc r1, cr6\n\ + ld r1, @r0+ ; restore ACCL\n\ + mvtaclo r1\n\ + ld r1, @r0+ ; restore ACCH\n\ + mvtachi r1\n\ + seth r0, #shigh(registers)\n\ + add3 r0, r0, #low(registers)\n\ + ld r1, @(4,r0) ; restore r1\n\ + ld r0, @r0 ; restore r0\n\ + rte"); + +/* General trap handler, called after the registers have been stashed. + NUM is the trap/exception number. */ + +static void +process_exception (int num) +{ + cleanup_stash (); + asm volatile ("\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + mv r0, %0\n\ + bl handle_exception\n\ + bl restore_and_return"::"r" (num):"r0", "r1"); +} + +void _catchException0 (); + +asm ("\n\ +_catchException0:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #0\n\ + bl process_exception"); + +void _catchException1 (); + +asm ("\n\ +_catchException1:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + bl cleanup_stash\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + seth r1, #shigh(registers + 21*4) ; PC\n\ + add3 r1, r1, #low(registers + 21*4)\n\ + ld r0, @r1\n\ + addi r0, #-4 ; back up PC for breakpoint trap.\n\ + st r0, @r1 ; FIXME: what about bp in right slot?\n\ + ldi r0, #1\n\ + bl handle_exception\n\ + bl restore_and_return"); + +void _catchException2 (); + +asm ("\n\ +_catchException2:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #2\n\ + bl process_exception"); + +void _catchException3 (); + +asm ("\n\ +_catchException3:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #3\n\ + bl process_exception"); + +void _catchException4 (); + +asm ("\n\ +_catchException4:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #4\n\ + bl process_exception"); + +void _catchException5 (); + +asm ("\n\ +_catchException5:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #5\n\ + bl process_exception"); + +void _catchException6 (); + +asm ("\n\ +_catchException6:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #6\n\ + bl process_exception"); + +void _catchException7 (); + +asm ("\n\ +_catchException7:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #7\n\ + bl process_exception"); + +void _catchException8 (); + +asm ("\n\ +_catchException8:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #8\n\ + bl process_exception"); + +void _catchException9 (); + +asm ("\n\ +_catchException9:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #9\n\ + bl process_exception"); + +void _catchException10 (); + +asm ("\n\ +_catchException10:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #10\n\ + bl process_exception"); + +void _catchException11 (); + +asm ("\n\ +_catchException11:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #11\n\ + bl process_exception"); + +void _catchException12 (); + +asm ("\n\ +_catchException12:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #12\n\ + bl process_exception"); + +void _catchException13 (); + +asm ("\n\ +_catchException13:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #13\n\ + bl process_exception"); + +void _catchException14 (); + +asm ("\n\ +_catchException14:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #14\n\ + bl process_exception"); + +void _catchException15 (); + +asm ("\n\ +_catchException15:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #15\n\ + bl process_exception"); + +void _catchException16 (); + +asm ("\n\ +_catchException16:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #16\n\ + bl process_exception"); + +void _catchException17 (); + +asm ("\n\ +_catchException17:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #17\n\ + bl process_exception"); + + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps (void) +{ + /* extern void remcomHandler(); */ + int i; + + for (i = 0; i < 18; i++) /* keep a copy of old vectors */ + if (save_vectors[i] == 0) /* only copy them the first time */ + save_vectors[i] = getExceptionHandler (i); + + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + exceptionHandler (0, _catchException0); + exceptionHandler (1, _catchException1); + exceptionHandler (2, _catchException2); + exceptionHandler (3, _catchException3); + exceptionHandler (4, _catchException4); + exceptionHandler (5, _catchException5); + exceptionHandler (6, _catchException6); + exceptionHandler (7, _catchException7); + exceptionHandler (8, _catchException8); + exceptionHandler (9, _catchException9); + exceptionHandler (10, _catchException10); + exceptionHandler (11, _catchException11); + exceptionHandler (12, _catchException12); + exceptionHandler (13, _catchException13); + exceptionHandler (14, _catchException14); + exceptionHandler (15, _catchException15); + exceptionHandler (16, _catchException16); + /* exceptionHandler (17, _catchException17); */ + + initialized = 1; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +#define BREAKPOINT() asm volatile (" trap #2"); + +void +breakpoint (void) +{ + if (initialized) + BREAKPOINT (); +} + +/* STDOUT section: + Stuff pertaining to simulating stdout by sending chars to gdb to be echoed. + Functions: gdb_putchar(char ch) + gdb_puts(char *str) + gdb_write(char *str, int len) + gdb_error(char *format, char *parm) + */ + +/* Function: gdb_putchar(int) + Make gdb write a char to stdout. + Returns: the char */ + +static int +gdb_putchar (int ch) +{ + char buf[4]; + + buf[0] = 'O'; + buf[1] = hexchars[ch >> 4]; + buf[2] = hexchars[ch & 0x0F]; + buf[3] = 0; + putpacket (buf); + return ch; +} + +/* Function: gdb_write(char *, int) + Make gdb write n bytes to stdout (not assumed to be null-terminated). + Returns: number of bytes written */ + +static int +gdb_write (char *data, int len) +{ + char *buf, *cpy; + int i; + + buf = remcomOutBuffer; + buf[0] = 'O'; + i = 0; + while (i < len) + { + for (cpy = buf + 1; + i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++) + { + *cpy++ = hexchars[data[i] >> 4]; + *cpy++ = hexchars[data[i] & 0x0F]; + } + *cpy = 0; + putpacket (buf); + } + return len; +} + +/* Function: gdb_puts(char *) + Make gdb write a null-terminated string to stdout. + Returns: the length of the string */ + +static int +gdb_puts (char *str) +{ + return gdb_write (str, strlen (str)); +} + +/* Function: gdb_error(char *, char *) + Send an error message to gdb's stdout. + First string may have 1 (one) optional "%s" in it, which + will cause the optional second string to be inserted. */ + +static void +gdb_error (char *format, char *parm) +{ + char buf[400], *cpy; + int len; + + if (remote_debug) + { + if (format && *format) + len = strlen (format); + else + return; /* empty input */ + + if (parm && *parm) + len += strlen (parm); + + for (cpy = buf; *format;) + { + if (format[0] == '%' && format[1] == 's') /* include second string */ + { + format += 2; /* advance two chars instead of just one */ + while (parm && *parm) + *cpy++ = *parm++; + } + else + *cpy++ = *format++; + } + *cpy = '\0'; + gdb_puts (buf); + } +} + +static unsigned char * +strcpy (unsigned char *dest, const unsigned char *src) +{ + unsigned char *ret = dest; + + if (dest && src) + { + while (*src) + *dest++ = *src++; + *dest = 0; + } + return ret; +} + +static int +strlen (const unsigned char *src) +{ + int ret; + + for (ret = 0; *src; src++) + ret++; + + return ret; +} + +#if 0 +void +exit (code) + int code; +{ + _exit (code); +} + +int +atexit (void *p) +{ + return 0; +} + +void +abort (void) +{ + _exit (1); +} +#endif diff --git a/gdb/stubs/m68k-stub.c b/gdb/stubs/m68k-stub.c new file mode 100644 index 0000000..4ef4069 --- /dev/null +++ b/gdb/stubs/m68k-stub.c @@ -0,0 +1,1098 @@ +/**************************************************************************** + + 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 $ + * + * 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 breakpoint instruction + * is hardwired to trap #1 because not to do so is a compatibility problem-- + * there either should be a standard breakpoint instruction, or the protocol + * should be extended to provide some means to communicate which breakpoint + * instruction is in use (or have the stub insert the breakpoint). + * + * Some explanation is probably necessary to explain how exceptions are + * handled. When an exception is encountered the 68000 pushes the current + * program counter and status register onto the supervisor stack and then + * transfers execution to a location specified in it's vector table. + * The handlers for the exception vectors are hardwired to jmp to an address + * given by the relation: (exception - 256) * 6. These are decending + * addresses starting from -6, -12, -18, ... By allowing 6 bytes for + * each entry, a jsr, jmp, bsr, ... can be used to enter the exception + * handler. Using a jsr to handle an exception has an added benefit of + * allowing a single handler to service several exceptions and use the + * return address as the key differentiation. The vector number can be + * computed from the return address by [ exception = (addr + 1530) / 6 ]. + * The sole purpose of the routine _catchException is to compute the + * exception number and push it on the stack in place of the return address. + * The external function exceptionHandler() is + * used to attach a specific handler to a specific m68k exception. + * For 68020 machines, the ability to have a return address around just + * so the vector can be determined is not necessary because the '020 pushes an + * extra word onto the stack containing the vector offset + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * 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 + * + * $<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 <stdio.h> +#include <string.h> +#include <setjmp.h> + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ + +extern Function exceptionHandler(); /* assign an exception handler */ +extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ + +/************************/ +/* FORWARD DECLARATIONS */ +/************************/ +static void +initializeRemcomErrorFrame (); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* there are 180 bytes of registers on a 68020 w/68881 */ +/* many of the fpa registers are 12 byte (96 bit) registers */ +#define NUMREGBYTES 180 +enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, + A0,A1,A2,A3,A4,A5,A6,A7, + PS,PC, + FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, + FPCONTROL,FPSTATUS,FPIADDR + }; + + +/* We keep a whole frame cache here. "Why?", I hear you cry, "doesn't + GDB handle that sort of thing?" Well, yes, I believe the only + reason for this cache is to save and restore floating point state + (fsave/frestore). A cleaner way to do this would be to make the + fsave data part of the registers which GDB deals with like any + other registers. This should not be a performance problem if the + ability to read individual registers is added to the protocol. */ + +typedef struct FrameStruct +{ + struct FrameStruct *previous; + int exceptionPC; /* pc value when this frame created */ + int exceptionVector; /* cpu vector causing exception */ + short frameSize; /* size of cpu frame in words */ + short sr; /* for 68000, this not always sr */ + int pc; + short format; + int fsaveHeader; + int morejunk[0]; /* exception frame, fp save... */ +} Frame; + +#define FRAMESIZE 500 +int gdbFrameStack[FRAMESIZE]; +static Frame *lastFrame; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGBYTES/4]; +int superStack; + +#define STACKSIZE 10000 +int remcomStack[STACKSIZE/sizeof(int)]; +static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +/* + * In many cases, the system will want to continue exception processing + * when a continue command is given. + * oldExceptionHook is a function to invoke in this case. + */ + +static ExceptionHook oldExceptionHook; + +#ifdef mc68020 +/* the size of the exception stack on the 68020 varies with the type of + * exception. The following table is the number of WORDS used + * for each exception format. + */ +const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 }; +#endif + +#ifdef mc68332 +static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 }; +#endif + +/************* jump buffer used for setjmp/longjmp **************************/ +jmp_buf remcomEnv; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +#ifdef __HAVE_68881__ +/* do an fsave, then remember the address to begin a restore from */ +#define SAVE_FP_REGS() asm(" fsave a0@-"); \ + asm(" fmovemx fp0-fp7,_registers+72"); \ + asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); +#define RESTORE_FP_REGS() \ +asm(" \n\ + fmoveml _registers+168,fpcr/fpsr/fpi \n\ + fmovemx _registers+72,fp0-fp7 \n\ + cmpl #-1,a0@ | skip frestore flag set ? \n\ + beq skip_frestore \n\ + frestore a0@+ \n\ +skip_frestore: \n\ +"); + +#else +#define SAVE_FP_REGS() +#define RESTORE_FP_REGS() +#endif /* __HAVE_68881__ */ + +void return_to_super(); +void return_to_user(); + +asm(" +.text +.globl _return_to_super +_return_to_super: + movel _registers+60,sp /* get new stack pointer */ + movel _lastFrame,a0 /* get last frame info */ + bra return_to_any + +.globl _return_to_user +_return_to_user: + movel _registers+60,a0 /* get usp */ + movel a0,usp /* set usp */ + movel _superStack,sp /* get original stack pointer */ + +return_to_any: + movel _lastFrame,a0 /* get last frame info */ + movel a0@+,_lastFrame /* link in previous frame */ + addql #8,a0 /* skip over pc, vector#*/ + movew a0@+,d0 /* get # of words in cpu frame */ + addw d0,a0 /* point to end of data */ + addw d0,a0 /* point to end of data */ + movel a0,a1 +# +# copy the stack frame + subql #1,d0 +copyUserLoop: + movew a1@-,sp@- + dbf d0,copyUserLoop +"); + RESTORE_FP_REGS() + asm(" moveml _registers,d0-d7/a0-a6"); + asm(" rte"); /* pop and go! */ + +#define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr"); +#define BREAKPOINT() asm(" trap #1"); + +/* this function is called immediately when a level 7 interrupt occurs */ +/* if the previous interrupt level was 7 then we're already servicing */ +/* this interrupt and an rte is in order to return to the debugger. */ +/* For the 68000, the offset for sr is 6 due to the jsr return address */ +asm(" +.text +.globl __debug_level7 +__debug_level7: + movew d0,sp@-"); +#if defined (mc68020) || defined (mc68332) +asm(" movew sp@(2),d0"); +#else +asm(" movew sp@(6),d0"); +#endif +asm(" andiw #0x700,d0 + cmpiw #0x700,d0 + beq _already7 + movew sp@+,d0 + bra __catchException +_already7: + movew sp@+,d0"); +#if !defined (mc68020) && !defined (mc68332) +asm(" lea sp@(4),sp"); /* pull off 68000 return address */ +#endif +asm(" rte"); + +extern void _catchException (); + +#if defined (mc68020) || defined (mc68332) +/* This function is called when a 68020 exception occurs. It saves + * all the cpu and fpcp regs in the _registers array, creates a frame on a + * linked list of frames which has the cpu and fpcp stack frames needed + * to properly restore the context of these processors, and invokes + * an exception handler (remcom_handler). + * + * stack on entry: stack on exit: + * N bytes of junk exception # MSWord + * Exception Format Word exception # MSWord + * Program counter LSWord + * Program counter MSWord + * Status Register + * + * + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movew sp@,d1 /* get status register */ + movew d1,a5@(66) /* save sr */ + movel sp@(2),a4 /* save pc in a4 for later use */ + movel a4,a5@(68) /* save pc in _regisers[] */ + +# +# figure out how many bytes in the stack frame + movew sp@(6),d0 /* get '020 exception format */ + movew d0,d2 /* make a copy of format word */ + andiw #0xf000,d0 /* mask off format type */ + rolw #5,d0 /* rotate into the low byte *2 */ + lea _exceptionSize,a1 + addw d0,a1 /* index into the table */ + movew a1@,d0 /* get number of words in frame */ + movew d0,d3 /* save it */ + subw d0,a0 /* adjust save pointer */ + subw d0,a0 /* adjust save pointer(bytes) */ + movel a0,a1 /* copy save pointer */ + subql #1,d0 /* predecrement loop counter */ +# +# copy the frame +saveFrameLoop: + movew sp@+,a1@+ + dbf d0,saveFrameLoop +# +# now that the stack has been clenaed, +# save the a7 in use at time of exception + movel sp,_superStack /* save supervisor sp */ + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra a7saveDone +userMode: + movel usp,a1 + movel a1,a5@(60) /* save user stack pointer */ +a7saveDone: + +# +# save size of frame + movew d3,a0@- + +# +# compute exception number + andl #0xfff,d2 /* mask off vector offset */ + lsrw #2,d2 /* divide by 4 to get vect num */ + movel d2,a0@- /* save it */ +# +# save pc causing exception + movel a4,a0@- +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + clrl sp@ /* replace exception num parm with frame ptr */ + jbsr __returnFromException /* jbsr, but never returns */ +"); +#else /* mc68000 */ +/* This function is called when an exception occurs. It translates the + * return address found on the stack into an exception vector # which + * is then handled by either handle_exception or a system handler. + * _catchException provides a front end for both. + * + * stack on entry: stack on exit: + * Program counter MSWord exception # MSWord + * Program counter LSWord exception # MSWord + * Status Register + * Return Address MSWord + * Return Address LSWord + */ +asm(" +.text +.globl __catchException +__catchException:"); +DISABLE_INTERRUPTS(); +asm(" + moveml d0-d7/a0-a6,_registers /* save registers */ + movel _lastFrame,a0 /* last frame pointer */ +"); +SAVE_FP_REGS(); +asm(" + lea _registers,a5 /* get address of registers */ + movel sp@+,d2 /* pop return address */ + addl #1530,d2 /* convert return addr to */ + divs #6,d2 /* exception number */ + extl d2 + + moveql #3,d3 /* assume a three word frame */ + + cmpiw #3,d2 /* bus error or address error ? */ + bgt normal /* if >3 then normal error */ + movel sp@+,a0@- /* copy error info to frame buff*/ + movel sp@+,a0@- /* these are never used */ + moveql #7,d3 /* this is a 7 word frame */ + +normal: + movew sp@+,d1 /* pop status register */ + movel sp@+,a4 /* pop program counter */ + movew d1,a5@(66) /* save sr */ + movel a4,a5@(68) /* save pc in _regisers[] */ + movel a4,a0@- /* copy pc to frame buffer */ + movew d1,a0@- /* copy sr to frame buffer */ + + movel sp,_superStack /* save supervisor sp */ + + andiw #0x2000,d1 /* were we in supervisor mode ? */ + beq userMode + movel a7,a5@(60) /* save a7 */ + bra saveDone +userMode: + movel usp,a1 /* save user stack pointer */ + movel a1,a5@(60) /* save user stack pointer */ +saveDone: + + movew d3,a0@- /* push frame size in words */ + movel d2,a0@- /* push vector number */ + movel a4,a0@- /* push exception pc */ + +# +# save old frame link and set the new value + movel _lastFrame,a1 /* last frame pointer */ + movel a1,a0@- /* save pointer to prev frame */ + movel a0,_lastFrame + + movel d2,sp@- /* push exception num */ + movel _exceptionHook,a0 /* get address of handler */ + jbsr a0@ /* and call it */ + clrl sp@ /* replace exception num parm with frame ptr */ + jbsr __returnFromException /* jbsr, but never returns */ +"); +#endif + + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use in case the + * breakpoint happened in supervisor mode. + */ +asm("_remcomHandler:"); +asm(" addl #4,sp"); /* pop off return address */ +asm(" movel sp@+,d0"); /* get the exception number */ +asm(" movel _stackPtr,sp"); /* move to remcom stack area */ +asm(" movel d0,sp@-"); /* push exception onto stack */ +asm(" jbsr _handle_exception"); /* this never returns */ +asm(" rts"); /* return */ + +void +_returnFromException (Frame * frame) +{ + /* if no passed in frame, use the last one */ + if (!frame) + { + frame = lastFrame; + frame->frameSize = 4; + frame->format = 0; + frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info */ + } + +#if !defined (mc68020) && !defined (mc68332) + /* a 68000 cannot use the internal info pushed onto a bus error + * or address error frame when doing an RTE so don't put this info + * onto the stack or the stack will creep every time this happens. + */ + frame->frameSize = 3; +#endif + + /* throw away any frames in the list after this frame */ + lastFrame = frame; + + frame->sr = registers[(int) PS]; + frame->pc = registers[(int) PC]; + + if (registers[(int) PS] & 0x2000) + { + /* return to supervisor mode... */ + return_to_super (); + } + else + { /* return to user mode */ + return_to_user (); + } +} + +int +hex (ch) + 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 $<data>#<checksum> */ + +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); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + fprintf (stderr, + "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + 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. */ + +void +putpacket (buffer) + char *buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $<packet info>#<checksum>. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + + } + while (getDebugChar () != '+'); + +} + +void +debug_error (format, parm) + char *format; + char *parm; +{ + if (remote_debug) + fprintf (stderr, format, parm); +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +char * +mem2hex (mem, buf, count) + char *mem; + char *buf; + int count; +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *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 */ +char * +hex2mem (buf, mem, count) + char *buf; + char *mem; + int count; +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } + return (mem); +} + +/* a bus error has occurred, perform a longjmp + to return execution and allow handling of the error */ + +void +handle_buserror () +{ + longjmp (remcomEnv, 1); +} + +/* this function takes the 68000 exception number and attempts to + translate this number into a unix compatible signal value */ +int +computeSignal (exceptionVector) + int exceptionVector; +{ + int sigval; + switch (exceptionVector) + { + case 2: + sigval = 10; + break; /* bus error */ + case 3: + sigval = 10; + break; /* address error */ + case 4: + sigval = 4; + break; /* illegal instruction */ + case 5: + sigval = 8; + break; /* zero divide */ + case 6: + sigval = 8; + break; /* chk instruction */ + case 7: + sigval = 8; + break; /* trapv instruction */ + case 8: + sigval = 11; + break; /* privilege violation */ + case 9: + sigval = 5; + break; /* trace trap */ + case 10: + sigval = 4; + break; /* line 1010 emulator */ + case 11: + sigval = 4; + break; /* line 1111 emulator */ + + /* Coprocessor protocol violation. Using a standard MMU or FPU + this cannot be triggered by software. Call it a SIGBUS. */ + case 13: + sigval = 10; + break; + + case 31: + sigval = 2; + break; /* interrupt */ + case 33: + sigval = 5; + break; /* breakpoint */ + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + case 40: + sigval = 8; + break; /* floating point err */ + + case 48: + sigval = 8; + break; /* floating point err */ + case 49: + sigval = 8; + break; /* floating point err */ + case 50: + sigval = 8; + break; /* zero divide */ + case 51: + sigval = 8; + break; /* underflow */ + case 52: + sigval = 8; + break; /* operand error */ + case 53: + sigval = 8; + break; /* overflow */ + case 54: + sigval = 8; + break; /* NAN */ + default: + sigval = 7; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt (char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + int newPC; + Frame *frame; + + if (remote_debug) + printf ("vector=%d, sr=0x%x, pc=0x%x\n", + exceptionVector, registers[PS], registers[PC]); + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + if (setjmp (remcomEnv) == 0) + { + exceptionHandler (2, handle_buserror); + + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem2hex ((char *) addr, remcomOutBuffer, length); + } + + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + } + else + { + exceptionHandler (2, _catchException); + strcpy (remcomOutBuffer, "E03"); + debug_error ("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler (2, _catchException); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + if (setjmp (remcomEnv) == 0) + { + exceptionHandler (2, handle_buserror); + + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + hex2mem (ptr, (char *) addr, length); + ptr = 0; + strcpy (remcomOutBuffer, "OK"); + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + } + else + { + exceptionHandler (2, _catchException); + strcpy (remcomOutBuffer, "E03"); + debug_error ("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler (2, _catchException); + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + newPC = registers[PC]; + + /* clear the trace bit */ + registers[PS] &= 0x7fff; + + /* set the trace bit if we're stepping */ + if (stepping) + registers[PS] |= 0x8000; + + /* + * look for newPC in the linked list of exception frames. + * if it is found, use the old frame it. otherwise, + * fake up a dummy frame in returnFromException(). + */ + if (remote_debug) + printf ("new pc = 0x%x\n", newPC); + frame = lastFrame; + while (frame) + { + if (remote_debug) + printf ("frame at 0x%x has pc=0x%x, except#=%d\n", + frame, frame->exceptionPC, frame->exceptionVector); + if (frame->exceptionPC == newPC) + break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC + 2))) + break; + if (frame == frame->previous) + { + frame = 0; /* no match found */ + break; + } + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[PC]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + if (remote_debug) + printf ("frame at 0x%x has pc=0x%x, except#=%d\n", + frame, frame->exceptionPC, + frame->exceptionVector); + /* re-use the last frame, we're skipping it (longjump?) */ + frame = (Frame *) 0; + _returnFromException (frame); /* this is a jump */ + } + } + } + + /* if we couldn't find a frame, create one */ + if (frame == 0) + { + frame = lastFrame - 1; + + /* by using a bunch of print commands with breakpoints, + it's possible for the frame stack to creep down. If it creeps + too far, give up and reset it to the top. Normal use should + not see this happen. + */ + if ((unsigned int) (frame - 2) < (unsigned int) &gdbFrameStack) + { + initializeRemcomErrorFrame (); + frame = lastFrame; + } + frame->previous = lastFrame; + lastFrame = frame; + frame = 0; /* null so _return... will properly initialize it */ + } + + _returnFromException (frame); /* this is a jump */ + + break; + + /* kill the program */ + case 'k': /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + + +void +initializeRemcomErrorFrame (void) +{ + lastFrame = ((Frame *) & gdbFrameStack[FRAMESIZE - 1]) - 1; + lastFrame->previous = lastFrame; +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps () +{ + extern void _debug_level7 (); + extern void remcomHandler (); + int exception; + + initializeRemcomErrorFrame (); + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + for (exception = 2; exception <= 23; exception++) + exceptionHandler (exception, _catchException); + + /* level 7 interrupt */ + exceptionHandler (31, _debug_level7); + + /* breakpoint exception (trap #1) */ + exceptionHandler (33, _catchException); + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + exceptionHandler (40, _catchException); + + /* 48 to 54 are floating point coprocessor errors */ + for (exception = 48; exception <= 54; exception++) + exceptionHandler (exception, _catchException); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint () +{ + if (initialized) + BREAKPOINT (); +} diff --git a/gdb/stubs/sh-stub.c b/gdb/stubs/sh-stub.c new file mode 100644 index 0000000..76c98a5 --- /dev/null +++ b/gdb/stubs/sh-stub.c @@ -0,0 +1,1583 @@ +/* sh-stub.c -- debugging stub for the Renesas-SH. + + NOTE!! This code has to be compiled with optimization, otherwise the + function inlining which generates the exception handlers won't work. + +*/ + +/* This is originally based on an m68k software stub written by Glenn + Engel at HP, but has changed quite a bit. + + Modifications for the SH by Ben Lee and Steve Chamberlain + +*/ + +/**************************************************************************** + + 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. + +****************************************************************************/ + + +/* Remote communication protocol. + + A debug packet whose contents are <data> + is encapsulated for transmission in the form: + + $ <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. + + Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + + <data> is as follows: + All values are encoded in ascii hex digits. + + Request Packet + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + write reg Pn...=r... Write register n... with value r..., + which contains two hex digits for each + byte in the register (target byte + order). + reply OK for success + ENN for an error + (not supported by all stubs). + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + Can be fewer bytes than requested + if able to read only part of the data. + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error (this includes the case + where only part of the data was + written). + + cont cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + last signal ? Reply the current reason for stopping. + This is the same reply as is generated + for step or cont : SAA where AA is the + signal number. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the "signal number" + + or... TAAn...:r...;n:r...;n...:r...; + AA = signal number + n... = register number + r... = register contents + or... WAA The process exited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + kill request k + + toggle debug d toggle debug flag (see 386 & 68k stubs) + reset r reset -- see sparc stub. + reserved <other> On other requests, the stub should + ignore the request and send an empty + response ($#<checksum>). This way + we can extend the protocol and GDB + can tell whether the stub it is + talking to uses the old or the new. + search tAA:PP,MM Search backwards starting at address + AA for a match with pattern PP and + mask MM. PP and MM are 4 bytes. + Not supported by all stubs. + + general query qXXXX Request info about XXXX. + general set QXXXX=yyyy Set value of XXXX to yyyy. + query sect offs qOffsets Get section offsets. Reply is + Text=xxx;Data=yyy;Bss=zzz + console output Otext Send text to stdout. Only comes from + remote target. + + Responses can be run-length encoded to save space. A '*' means that + the next character is an ASCII encoding giving a repeat count which + stands for that many repititions of the character preceding the '*'. + The encoding is n+29, yielding a printable character where n >=3 + (which is where rle starts to win). Don't use an n > 126. + + So + "0* " means the same as "0000". */ + +#include <string.h> +#include <setjmp.h> + +/* Renesas SH architecture instruction encoding masks */ + +#define COND_BR_MASK 0xff00 +#define UCOND_DBR_MASK 0xe000 +#define UCOND_RBR_MASK 0xf0df +#define TRAPA_MASK 0xff00 + +#define COND_DISP 0x00ff +#define UCOND_DISP 0x0fff +#define UCOND_REG 0x0f00 + +/* Renesas SH instruction opcodes */ + +#define BF_INSTR 0x8b00 +#define BT_INSTR 0x8900 +#define BRA_INSTR 0xa000 +#define BSR_INSTR 0xb000 +#define JMP_INSTR 0x402b +#define JSR_INSTR 0x400b +#define RTS_INSTR 0x000b +#define RTE_INSTR 0x002b +#define TRAPA_INSTR 0xc300 +#define SSTEP_INSTR 0xc3ff + +/* Renesas SH processor register masks */ + +#define T_BIT_MASK 0x0001 + +/* + * BUFMAX defines the maximum number of characters in inbound/outbound + * buffers. At least NUMREGBYTES*2 are needed for register packets. + */ +#define BUFMAX 1024 + +/* + * Number of bytes for registers + */ +#define NUMREGBYTES 112 /* 92 */ + +/* + * typedef + */ +typedef void (*Function) (); + +/* + * Forward declarations + */ + +static int hex (char); +static char *mem2hex (char *, char *, int); +static char *hex2mem (char *, char *, int); +static int hexToInt (char **, int *); +static unsigned char *getpacket (void); +static void putpacket (char *); +static void handle_buserror (void); +static int computeSignal (int exceptionVector); +static void handle_exception (int exceptionVector); +void init_serial(); + +void putDebugChar (char); +char getDebugChar (void); + +/* These are in the file but in asm statements so the compiler can't see them */ +void catch_exception_4 (void); +void catch_exception_6 (void); +void catch_exception_9 (void); +void catch_exception_10 (void); +void catch_exception_11 (void); +void catch_exception_32 (void); +void catch_exception_33 (void); +void catch_exception_255 (void); + + + +#define catch_exception_random catch_exception_255 /* Treat all odd ones like 255 */ + +void breakpoint (void); + + +#define init_stack_size 8*1024 /* if you change this you should also modify BINIT */ +#define stub_stack_size 8*1024 + +int init_stack[init_stack_size] __attribute__ ((section ("stack"))) = {0}; +int stub_stack[stub_stack_size] __attribute__ ((section ("stack"))) = {0}; + + +void INIT (); +void BINIT (); + +#define CPU_BUS_ERROR_VEC 9 +#define DMA_BUS_ERROR_VEC 10 +#define NMI_VEC 11 +#define INVALID_INSN_VEC 4 +#define INVALID_SLOT_VEC 6 +#define TRAP_VEC 32 +#define IO_VEC 33 +#define USER_VEC 255 + + + +char in_nmi; /* Set when handling an NMI, so we don't reenter */ +int dofault; /* Non zero, bus errors will raise exception */ + +int *stub_sp; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int remote_debug; + +/* jump buffer used for setjmp/longjmp */ +jmp_buf remcomEnv; + +enum regnames + { + R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, R11, R12, R13, R14, + R15, PC, PR, GBR, VBR, MACH, MACL, SR, + TICKS, STALLS, CYCLES, INSTS, PLR + }; + +typedef struct + { + short *memAddr; + short oldInstr; + } +stepData; + +int registers[NUMREGBYTES / 4]; +stepData instrBuffer; +char stepped; +static const char hexchars[] = "0123456789abcdef"; +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +char lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +/* + * Assembly macros + */ + +#define BREAKPOINT() asm("trapa #0x20"::); + + +/* + * Routines to handle hex data + */ + +static int +hex (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); +} + +/* convert the memory, pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +static char * +mem2hex (char *mem, char *buf, int count) +{ + int i; + int ch; + for (i = 0; i < count; i++) + { + ch = *mem++; + *buf++ = highhex (ch); + *buf++ = lowhex (ch); + } + *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 (char *buf, char *mem, int count) +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } + return (mem); +} + +/**********************************************/ +/* 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) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * Routines to get and put packets + */ + +/* scan for the sequence $<data>#<checksum> */ + +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); + + if (checksum != xmitcsum) + { + putDebugChar ('-'); /* failed checksum */ + } + else + { + 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 (char *buffer) +{ + int checksum; + int count; + + /* $<packet info>#<checksum>. */ + do + { + char *src = buffer; + putDebugChar ('$'); + checksum = 0; + + while (*src) + { + int runlen; + + /* Do run length encoding */ + for (runlen = 0; runlen < 100; runlen ++) + { + if (src[0] != src[runlen]) + { + if (runlen > 3) + { + int encode; + /* Got a useful amount */ + putDebugChar (*src); + checksum += *src; + putDebugChar ('*'); + checksum += '*'; + checksum += (encode = runlen + ' ' - 4); + putDebugChar (encode); + src += runlen; + } + else + { + putDebugChar (*src); + checksum += *src; + src++; + } + break; + } + } + } + + + putDebugChar ('#'); + putDebugChar (highhex(checksum)); + putDebugChar (lowhex(checksum)); + } + while (getDebugChar() != '+'); +} + + +/* a bus error has occurred, perform a longjmp + to return execution and allow handling of the error */ + +void +handle_buserror (void) +{ + longjmp (remcomEnv, 1); +} + +/* + * this function takes the SH-1 exception number and attempts to + * translate this number into a unix compatible signal value + */ +static int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case INVALID_INSN_VEC: + sigval = 4; + break; + case INVALID_SLOT_VEC: + sigval = 4; + break; + case CPU_BUS_ERROR_VEC: + sigval = 10; + break; + case DMA_BUS_ERROR_VEC: + sigval = 10; + break; + case NMI_VEC: + sigval = 2; + break; + + case TRAP_VEC: + case USER_VEC: + sigval = 5; + break; + + default: + sigval = 7; /* "software generated"*/ + break; + } + return (sigval); +} + +void +doSStep (void) +{ + short *instrMem; + int displacement; + int reg; + unsigned short opcode; + + instrMem = (short *) registers[PC]; + + opcode = *instrMem; + stepped = 1; + + if ((opcode & COND_BR_MASK) == BT_INSTR) + { + if (registers[SR] & T_BIT_MASK) + { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) + displacement |= 0xffffff00; + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + else + instrMem += 1; + } + else if ((opcode & COND_BR_MASK) == BF_INSTR) + { + if (registers[SR] & T_BIT_MASK) + instrMem += 1; + else + { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) + displacement |= 0xffffff00; + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + } + else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR) + { + displacement = (opcode & UCOND_DISP) << 1; + if (displacement & 0x0800) + displacement |= 0xfffff000; + + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (registers[PC] + displacement + 4); + } + else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR) + { + reg = (char) ((opcode & UCOND_REG) >> 8); + + instrMem = (short *) registers[reg]; + } + else if (opcode == RTS_INSTR) + instrMem = (short *) registers[PR]; + else if (opcode == RTE_INSTR) + instrMem = (short *) registers[15]; + else if ((opcode & TRAPA_MASK) == TRAPA_INSTR) + instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2); + else + instrMem += 1; + + instrBuffer.memAddr = instrMem; + instrBuffer.oldInstr = *instrMem; + *instrMem = SSTEP_INSTR; +} + + +/* Undo the effect of a previous doSStep. If we single stepped, + restore the old instruction. */ + +void +undoSStep (void) +{ + if (stepped) + { short *instrMem; + instrMem = instrBuffer.memAddr; + *instrMem = instrBuffer.oldInstr; + } + stepped = 0; +} + +/* +This function does all exception handling. It only does two things - +it figures out why it was called and tells gdb, and then it reacts +to gdb's requests. + +When in the monitor mode we talk a human on the serial line rather than gdb. + +*/ + + +void +gdb_handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length; + char *ptr; + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = highhex(sigval); + remcomOutBuffer[2] = lowhex (sigval); + remcomOutBuffer[3] = 0; + + putpacket (remcomOutBuffer); + + /* + * exception 255 indicates a software trap + * inserted in place of code ... so back up + * PC by one instruction, since this instruction + * will later be replaced by its original one! + */ + if (exceptionVector == 0xff + || exceptionVector == 0x20) + registers[PC] -= 2; + + /* + * Do the thangs needed to undo + * any stepping we may have done! + */ + undoSStep (); + + stepping = 0; + + while (1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + + switch (*ptr++) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = highhex (sigval); + remcomOutBuffer[2] = lowhex (sigval); + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (char *) registers, NUMREGBYTES); + strcpy (remcomOutBuffer, "OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + if (setjmp (remcomEnv) == 0) + { + dofault = 0; + /* TRY, TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem2hex ((char *) addr, remcomOutBuffer, length); + } + if (ptr) + strcpy (remcomOutBuffer, "E01"); + } + else + strcpy (remcomOutBuffer, "E03"); + + /* restore handler for bus error */ + dofault = 1; + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + if (setjmp (remcomEnv) == 0) + { + dofault = 0; + + /* TRY, TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + hex2mem (ptr, (char *) addr, length); + ptr = 0; + strcpy (remcomOutBuffer, "OK"); + } + if (ptr) + strcpy (remcomOutBuffer, "E02"); + } + else + strcpy (remcomOutBuffer, "E03"); + + /* restore handler for bus error */ + dofault = 1; + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 's': + stepping = 1; + case 'c': + { + /* tRY, to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + if (stepping) + doSStep (); + } + return; + break; + + /* kill the program */ + case 'k': /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + + +#define GDBCOOKIE 0x5ac +static int ingdbmode; +/* We've had an exception - choose to go into the monitor or + the gdb stub */ +void handle_exception(int exceptionVector) +{ +#ifdef MONITOR + if (ingdbmode != GDBCOOKIE) + monitor_handle_exception (exceptionVector); + else +#endif + gdb_handle_exception (exceptionVector); + +} + +void +gdb_mode (void) +{ + ingdbmode = GDBCOOKIE; + breakpoint(); +} +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + BREAKPOINT (); +} + +/**** Processor-specific routines start here ****/ +/**** Processor-specific routines start here ****/ +/**** Processor-specific routines start here ****/ + +/* Note: + + The Renesas SH family uses two exception architectures: + + SH1 & SH2: + + These processors utilize an exception vector table. + Exceptions are vectored to the address stored at VBR + (exception_num * 4) + + SH3, SH3E, & SH4: + + These processors have fixed entry points relative to the VBR for + various exception classes. +*/ + +#if defined(__sh1__) || defined(__sh2__) + +/* SH1/SH2 exception vector table format */ + +typedef struct + { + void (*func_cold) (); + int *stack_cold; + void (*func_warm) (); + int *stack_warm; + void (*(handler[256 - 4])) (); + } +vec_type; + +/* vectable is the SH1/SH2 vector table. It must be at address 0 + or wherever your vbr points. */ + +const vec_type vectable = +{ + &BINIT, /* 0: Power-on reset PC */ + init_stack + init_stack_size, /* 1: Power-on reset SP */ + &BINIT, /* 2: Manual reset PC */ + init_stack + init_stack_size, /* 3: Manual reset SP */ +{ + &catch_exception_4, /* 4: General invalid instruction */ + &catch_exception_random, /* 5: Reserved for system */ + &catch_exception_6, /* 6: Invalid slot instruction */ + &catch_exception_random, /* 7: Reserved for system */ + &catch_exception_random, /* 8: Reserved for system */ + &catch_exception_9, /* 9: CPU bus error */ + &catch_exception_10, /* 10: DMA bus error */ + &catch_exception_11, /* 11: NMI */ + &catch_exception_random, /* 12: User break */ + &catch_exception_random, /* 13: Reserved for system */ + &catch_exception_random, /* 14: Reserved for system */ + &catch_exception_random, /* 15: Reserved for system */ + &catch_exception_random, /* 16: Reserved for system */ + &catch_exception_random, /* 17: Reserved for system */ + &catch_exception_random, /* 18: Reserved for system */ + &catch_exception_random, /* 19: Reserved for system */ + &catch_exception_random, /* 20: Reserved for system */ + &catch_exception_random, /* 21: Reserved for system */ + &catch_exception_random, /* 22: Reserved for system */ + &catch_exception_random, /* 23: Reserved for system */ + &catch_exception_random, /* 24: Reserved for system */ + &catch_exception_random, /* 25: Reserved for system */ + &catch_exception_random, /* 26: Reserved for system */ + &catch_exception_random, /* 27: Reserved for system */ + &catch_exception_random, /* 28: Reserved for system */ + &catch_exception_random, /* 29: Reserved for system */ + &catch_exception_random, /* 30: Reserved for system */ + &catch_exception_random, /* 31: Reserved for system */ + &catch_exception_32, /* 32: Trap instr (user vectors) */ + &catch_exception_33, /* 33: Trap instr (user vectors) */ + &catch_exception_random, /* 34: Trap instr (user vectors) */ + &catch_exception_random, /* 35: Trap instr (user vectors) */ + &catch_exception_random, /* 36: Trap instr (user vectors) */ + &catch_exception_random, /* 37: Trap instr (user vectors) */ + &catch_exception_random, /* 38: Trap instr (user vectors) */ + &catch_exception_random, /* 39: Trap instr (user vectors) */ + &catch_exception_random, /* 40: Trap instr (user vectors) */ + &catch_exception_random, /* 41: Trap instr (user vectors) */ + &catch_exception_random, /* 42: Trap instr (user vectors) */ + &catch_exception_random, /* 43: Trap instr (user vectors) */ + &catch_exception_random, /* 44: Trap instr (user vectors) */ + &catch_exception_random, /* 45: Trap instr (user vectors) */ + &catch_exception_random, /* 46: Trap instr (user vectors) */ + &catch_exception_random, /* 47: Trap instr (user vectors) */ + &catch_exception_random, /* 48: Trap instr (user vectors) */ + &catch_exception_random, /* 49: Trap instr (user vectors) */ + &catch_exception_random, /* 50: Trap instr (user vectors) */ + &catch_exception_random, /* 51: Trap instr (user vectors) */ + &catch_exception_random, /* 52: Trap instr (user vectors) */ + &catch_exception_random, /* 53: Trap instr (user vectors) */ + &catch_exception_random, /* 54: Trap instr (user vectors) */ + &catch_exception_random, /* 55: Trap instr (user vectors) */ + &catch_exception_random, /* 56: Trap instr (user vectors) */ + &catch_exception_random, /* 57: Trap instr (user vectors) */ + &catch_exception_random, /* 58: Trap instr (user vectors) */ + &catch_exception_random, /* 59: Trap instr (user vectors) */ + &catch_exception_random, /* 60: Trap instr (user vectors) */ + &catch_exception_random, /* 61: Trap instr (user vectors) */ + &catch_exception_random, /* 62: Trap instr (user vectors) */ + &catch_exception_random, /* 63: Trap instr (user vectors) */ + &catch_exception_random, /* 64: IRQ0 */ + &catch_exception_random, /* 65: IRQ1 */ + &catch_exception_random, /* 66: IRQ2 */ + &catch_exception_random, /* 67: IRQ3 */ + &catch_exception_random, /* 68: IRQ4 */ + &catch_exception_random, /* 69: IRQ5 */ + &catch_exception_random, /* 70: IRQ6 */ + &catch_exception_random, /* 71: IRQ7 */ + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_random, + &catch_exception_255}}; + +#define BCR (*(volatile short *)(0x05FFFFA0)) /* Bus control register */ +#define BAS (0x800) /* Byte access select */ +#define WCR1 (*(volatile short *)(0x05ffffA2)) /* Wait state control register */ + +asm ("_BINIT: mov.l L1,r15"); +asm ("bra _INIT"); +asm ("nop"); +asm ("L1: .long _init_stack + 8*1024*4"); +void +INIT (void) +{ + /* First turn on the ram */ + WCR1 = 0; /* Never sample wait */ + BCR = BAS; /* use lowbyte/high byte */ + + init_serial(); + +#ifdef MONITOR + reset_hook (); +#endif + + + in_nmi = 0; + dofault = 1; + stepped = 0; + + stub_sp = stub_stack + stub_stack_size; + breakpoint (); + + while (1) + ; +} + + +static void sr() +{ + + + /* Calling Reset does the same as pressing the button */ + asm (".global _Reset + .global _WarmReset +_Reset: +_WarmReset: + mov.l L_sp,r15 + bra _INIT + nop + .align 2 +L_sp: .long _init_stack + 8000"); + + asm("saveRegisters: + mov.l @(L_reg, pc), r0 + mov.l @r15+, r1 ! pop R0 + mov.l r2, @(0x08, r0) ! save R2 + mov.l r1, @r0 ! save R0 + mov.l @r15+, r1 ! pop R1 + mov.l r3, @(0x0c, r0) ! save R3 + mov.l r1, @(0x04, r0) ! save R1 + mov.l r4, @(0x10, r0) ! save R4 + mov.l r5, @(0x14, r0) ! save R5 + mov.l r6, @(0x18, r0) ! save R6 + mov.l r7, @(0x1c, r0) ! save R7 + mov.l r8, @(0x20, r0) ! save R8 + mov.l r9, @(0x24, r0) ! save R9 + mov.l r10, @(0x28, r0) ! save R10 + mov.l r11, @(0x2c, r0) ! save R11 + mov.l r12, @(0x30, r0) ! save R12 + mov.l r13, @(0x34, r0) ! save R13 + mov.l r14, @(0x38, r0) ! save R14 + mov.l @r15+, r4 ! save arg to handleException + add #8, r15 ! hide PC/SR values on stack + mov.l r15, @(0x3c, r0) ! save R15 + add #-8, r15 ! save still needs old SP value + add #92, r0 ! readjust register pointer + mov r15, r2 + add #4, r2 + mov.l @r2, r2 ! R2 has SR + mov.l @r15, r1 ! R1 has PC + mov.l r2, @-r0 ! save SR + sts.l macl, @-r0 ! save MACL + sts.l mach, @-r0 ! save MACH + stc.l vbr, @-r0 ! save VBR + stc.l gbr, @-r0 ! save GBR + sts.l pr, @-r0 ! save PR + mov.l @(L_stubstack, pc), r2 + mov.l @(L_hdl_except, pc), r3 + mov.l @r2, r15 + jsr @r3 + mov.l r1, @-r0 ! save PC + mov.l @(L_stubstack, pc), r0 + mov.l @(L_reg, pc), r1 + bra restoreRegisters + mov.l r15, @r0 ! save __stub_stack + + .align 2 +L_reg: + .long _registers +L_stubstack: + .long _stub_sp +L_hdl_except: + .long _handle_exception"); + +} + +static void rr() +{ +asm(" + .align 2 + .global _resume +_resume: + mov r4,r1 +restoreRegisters: + add #8, r1 ! skip to R2 + mov.l @r1+, r2 ! restore R2 + mov.l @r1+, r3 ! restore R3 + mov.l @r1+, r4 ! restore R4 + mov.l @r1+, r5 ! restore R5 + mov.l @r1+, r6 ! restore R6 + mov.l @r1+, r7 ! restore R7 + mov.l @r1+, r8 ! restore R8 + mov.l @r1+, r9 ! restore R9 + mov.l @r1+, r10 ! restore R10 + mov.l @r1+, r11 ! restore R11 + mov.l @r1+, r12 ! restore R12 + mov.l @r1+, r13 ! restore R13 + mov.l @r1+, r14 ! restore R14 + mov.l @r1+, r15 ! restore programs stack + mov.l @r1+, r0 + add #-8, r15 ! uncover PC/SR on stack + mov.l r0, @r15 ! restore PC onto stack + lds.l @r1+, pr ! restore PR + ldc.l @r1+, gbr ! restore GBR + ldc.l @r1+, vbr ! restore VBR + lds.l @r1+, mach ! restore MACH + lds.l @r1+, macl ! restore MACL + mov.l @r1, r0 + add #-88, r1 ! readjust reg pointer to R1 + mov.l r0, @(4, r15) ! restore SR onto stack+4 + mov.l r2, @-r15 + mov.l L_in_nmi, r0 + mov #0, r2 + mov.b r2, @r0 + mov.l @r15+, r2 + mov.l @r1+, r0 ! restore R0 + rte + mov.l @r1, r1 ! restore R1 + +"); +} + + +static __inline__ void code_for_catch_exception(int n) +{ + asm(" .globl _catch_exception_%O0" : : "i" (n) ); + asm(" _catch_exception_%O0:" :: "i" (n) ); + + asm(" add #-4, r15 ! reserve spot on stack "); + asm(" mov.l r1, @-r15 ! push R1 "); + + if (n == NMI_VEC) + { + /* Special case for NMI - make sure that they don't nest */ + asm(" mov.l r0, @-r15 ! push R0"); + asm(" mov.l L_in_nmi, r0"); + asm(" tas.b @r0 ! Fend off against addtnl NMIs"); + asm(" bt noNMI"); + asm(" mov.l @r15+, r0"); + asm(" mov.l @r15+, r1"); + asm(" add #4, r15"); + asm(" rte"); + asm(" nop"); + asm(".align 2"); + asm("L_in_nmi: .long _in_nmi"); + asm("noNMI:"); + } + else + { + + if (n == CPU_BUS_ERROR_VEC) + { + /* Exception 9 (bus errors) are disasbleable - so that you + can probe memory and get zero instead of a fault. + Because the vector table may be in ROM we don't revector + the interrupt like all the other stubs, we check in here + */ + asm("mov.l L_dofault,r1"); + asm("mov.l @r1,r1"); + asm("tst r1,r1"); + asm("bf faultaway"); + asm("bsr _handle_buserror"); + asm(".align 2"); + asm("L_dofault: .long _dofault"); + asm("faultaway:"); + } + asm(" mov #15<<4, r1 "); + asm(" ldc r1, sr ! disable interrupts "); + asm(" mov.l r0, @-r15 ! push R0 "); + } + + /* Prepare for saving context, we've already pushed r0 and r1, stick exception number + into the frame */ + asm(" mov r15, r0 "); + asm(" add #8, r0 "); + asm(" mov %0,r1" :: "i" (n) ); + asm(" extu.b r1,r1 "); + asm(" bra saveRegisters ! save register values "); + asm(" mov.l r1, @r0 ! save exception # "); +} + + +static void +exceptions (void) +{ + code_for_catch_exception (CPU_BUS_ERROR_VEC); + code_for_catch_exception (DMA_BUS_ERROR_VEC); + code_for_catch_exception (INVALID_INSN_VEC); + code_for_catch_exception (INVALID_SLOT_VEC); + code_for_catch_exception (NMI_VEC); + code_for_catch_exception (TRAP_VEC); + code_for_catch_exception (USER_VEC); + code_for_catch_exception (IO_VEC); +} + + + + + + +/* Support for Serial I/O using on chip uart */ + +#define SMR0 (*(volatile char *)(0x05FFFEC0)) /* Channel 0 serial mode register */ +#define BRR0 (*(volatile char *)(0x05FFFEC1)) /* Channel 0 bit rate register */ +#define SCR0 (*(volatile char *)(0x05FFFEC2)) /* Channel 0 serial control register */ +#define TDR0 (*(volatile char *)(0x05FFFEC3)) /* Channel 0 transmit data register */ +#define SSR0 (*(volatile char *)(0x05FFFEC4)) /* Channel 0 serial status register */ +#define RDR0 (*(volatile char *)(0x05FFFEC5)) /* Channel 0 receive data register */ + +#define SMR1 (*(volatile char *)(0x05FFFEC8)) /* Channel 1 serial mode register */ +#define BRR1 (*(volatile char *)(0x05FFFEC9)) /* Channel 1 bit rate register */ +#define SCR1 (*(volatile char *)(0x05FFFECA)) /* Channel 1 serial control register */ +#define TDR1 (*(volatile char *)(0x05FFFECB)) /* Channel 1 transmit data register */ +#define SSR1 (*(volatile char *)(0x05FFFECC)) /* Channel 1 serial status register */ +#define RDR1 (*(volatile char *)(0x05FFFECD)) /* Channel 1 receive data register */ + +/* + * Serial mode register bits + */ + +#define SYNC_MODE 0x80 +#define SEVEN_BIT_DATA 0x40 +#define PARITY_ON 0x20 +#define ODD_PARITY 0x10 +#define STOP_BITS_2 0x08 +#define ENABLE_MULTIP 0x04 +#define PHI_64 0x03 +#define PHI_16 0x02 +#define PHI_4 0x01 + +/* + * Serial control register bits + */ +#define SCI_TIE 0x80 /* Transmit interrupt enable */ +#define SCI_RIE 0x40 /* Receive interrupt enable */ +#define SCI_TE 0x20 /* Transmit enable */ +#define SCI_RE 0x10 /* Receive enable */ +#define SCI_MPIE 0x08 /* Multiprocessor interrupt enable */ +#define SCI_TEIE 0x04 /* Transmit end interrupt enable */ +#define SCI_CKE1 0x02 /* Clock enable 1 */ +#define SCI_CKE0 0x01 /* Clock enable 0 */ + +/* + * Serial status register bits + */ +#define SCI_TDRE 0x80 /* Transmit data register empty */ +#define SCI_RDRF 0x40 /* Receive data register full */ +#define SCI_ORER 0x20 /* Overrun error */ +#define SCI_FER 0x10 /* Framing error */ +#define SCI_PER 0x08 /* Parity error */ +#define SCI_TEND 0x04 /* Transmit end */ +#define SCI_MPB 0x02 /* Multiprocessor bit */ +#define SCI_MPBT 0x01 /* Multiprocessor bit transfer */ + + +/* + * Port B IO Register (PBIOR) + */ +#define PBIOR (*(volatile char *)(0x05FFFFC6)) +#define PB15IOR 0x8000 +#define PB14IOR 0x4000 +#define PB13IOR 0x2000 +#define PB12IOR 0x1000 +#define PB11IOR 0x0800 +#define PB10IOR 0x0400 +#define PB9IOR 0x0200 +#define PB8IOR 0x0100 +#define PB7IOR 0x0080 +#define PB6IOR 0x0040 +#define PB5IOR 0x0020 +#define PB4IOR 0x0010 +#define PB3IOR 0x0008 +#define PB2IOR 0x0004 +#define PB1IOR 0x0002 +#define PB0IOR 0x0001 + +/* + * Port B Control Register (PBCR1) + */ +#define PBCR1 (*(volatile short *)(0x05FFFFCC)) +#define PB15MD1 0x8000 +#define PB15MD0 0x4000 +#define PB14MD1 0x2000 +#define PB14MD0 0x1000 +#define PB13MD1 0x0800 +#define PB13MD0 0x0400 +#define PB12MD1 0x0200 +#define PB12MD0 0x0100 +#define PB11MD1 0x0080 +#define PB11MD0 0x0040 +#define PB10MD1 0x0020 +#define PB10MD0 0x0010 +#define PB9MD1 0x0008 +#define PB9MD0 0x0004 +#define PB8MD1 0x0002 +#define PB8MD0 0x0001 + +#define PB15MD PB15MD1|PB14MD0 +#define PB14MD PB14MD1|PB14MD0 +#define PB13MD PB13MD1|PB13MD0 +#define PB12MD PB12MD1|PB12MD0 +#define PB11MD PB11MD1|PB11MD0 +#define PB10MD PB10MD1|PB10MD0 +#define PB9MD PB9MD1|PB9MD0 +#define PB8MD PB8MD1|PB8MD0 + +#define PB_TXD1 PB11MD1 +#define PB_RXD1 PB10MD1 +#define PB_TXD0 PB9MD1 +#define PB_RXD0 PB8MD1 + +/* + * Port B Control Register (PBCR2) + */ +#define PBCR2 0x05FFFFCE +#define PB7MD1 0x8000 +#define PB7MD0 0x4000 +#define PB6MD1 0x2000 +#define PB6MD0 0x1000 +#define PB5MD1 0x0800 +#define PB5MD0 0x0400 +#define PB4MD1 0x0200 +#define PB4MD0 0x0100 +#define PB3MD1 0x0080 +#define PB3MD0 0x0040 +#define PB2MD1 0x0020 +#define PB2MD0 0x0010 +#define PB1MD1 0x0008 +#define PB1MD0 0x0004 +#define PB0MD1 0x0002 +#define PB0MD0 0x0001 + +#define PB7MD PB7MD1|PB7MD0 +#define PB6MD PB6MD1|PB6MD0 +#define PB5MD PB5MD1|PB5MD0 +#define PB4MD PB4MD1|PB4MD0 +#define PB3MD PB3MD1|PB3MD0 +#define PB2MD PB2MD1|PB2MD0 +#define PB1MD PB1MD1|PB1MD0 +#define PB0MD PB0MD1|PB0MD0 + + +#ifdef MHZ +#define BPS 32 * 9600 * MHZ / ( BAUD * 10) +#else +#define BPS 32 /* 9600 for 10 Mhz */ +#endif + +void handleError (char theSSR); + +void +nop (void) +{ + +} +void +init_serial (void) +{ + int i; + + /* Clear TE and RE in Channel 1's SCR */ + SCR1 &= ~(SCI_TE | SCI_RE); + + /* Set communication to be async, 8-bit data, no parity, 1 stop bit and use internal clock */ + + SMR1 = 0; + BRR1 = BPS; + + SCR1 &= ~(SCI_CKE1 | SCI_CKE0); + + /* let the hardware settle */ + + for (i = 0; i < 1000; i++) + nop (); + + /* Turn on in and out */ + SCR1 |= SCI_RE | SCI_TE; + + /* Set the PFC to make RXD1 (pin PB8) an input pin and TXD1 (pin PB9) an output pin */ + PBCR1 &= ~(PB_TXD1 | PB_RXD1); + PBCR1 |= PB_TXD1 | PB_RXD1; +} + + +int +getDebugCharReady (void) +{ + char mySSR; + mySSR = SSR1 & ( SCI_PER | SCI_FER | SCI_ORER ); + if ( mySSR ) + handleError ( mySSR ); + return SSR1 & SCI_RDRF ; +} + +char +getDebugChar (void) +{ + char ch; + char mySSR; + + while ( ! getDebugCharReady()) + ; + + ch = RDR1; + SSR1 &= ~SCI_RDRF; + + mySSR = SSR1 & (SCI_PER | SCI_FER | SCI_ORER); + + if (mySSR) + handleError (mySSR); + + return ch; +} + +int +putDebugCharReady (void) +{ + return (SSR1 & SCI_TDRE); +} + +void +putDebugChar (char ch) +{ + while (!putDebugCharReady()) + ; + + /* + * Write data into TDR and clear TDRE + */ + TDR1 = ch; + SSR1 &= ~SCI_TDRE; +} + +void +handleError (char theSSR) +{ + SSR1 &= ~(SCI_ORER | SCI_PER | SCI_FER); +} + +#endif diff --git a/gdb/stubs/sparc-stub.c b/gdb/stubs/sparc-stub.c new file mode 100644 index 0000000..c12d436 --- /dev/null +++ b/gdb/stubs/sparc-stub.c @@ -0,0 +1,778 @@ +/**************************************************************************** + + 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 + * + * $<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> + +/************************************************************************ + * + * external low-level support routines + */ + +extern void putDebugChar(); /* write a single character */ +extern int getDebugChar(); /* read and return a single char */ + +/************************************************************************/ +/* 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 void set_mem_fault_trap(); + +static const char hexchars[]="0123456789abcdef"; + +#define NUMREGS 72 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames {G0, G1, G2, G3, G4, G5, G6, G7, + O0, O1, O2, O3, O4, O5, SP, O7, + L0, L1, L2, L3, L4, L5, L6, L7, + I0, I1, I2, I3, I4, I5, FP, I7, + + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, + Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR }; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* */ + +extern void trap_low(); + +asm(" + .reserve trapstack, 1000 * 4, \"bss\", 8 + + .data + .align 4 + +in_trap_handler: + .word 0 + + .text + .align 4 + +! This function is called when any SPARC trap (except window overflow or +! underflow) occurs. It makes sure that the invalid register window is still +! available before jumping into C code. It will also restore the world if you +! return from handle_exception. + + .globl _trap_low +_trap_low: + mov %psr, %l0 + mov %wim, %l3 + + srl %l3, %l0, %l4 ! wim >> cwp + cmp %l4, 1 + bne window_fine ! Branch if not in the invalid window + nop + +! Handle window overflow + + mov %g1, %l4 ! Save g1, we use it to hold the wim + srl %l3, 1, %g1 ! Rotate wim right + tst %g1 + bg good_wim ! Branch if new wim is non-zero + nop + +! At this point, we need to bring a 1 into the high order bit of the wim. +! Since we don't want to make any assumptions about the number of register +! windows, we figure it out dynamically so as to setup the wim correctly. + + not %g1 ! Fill g1 with ones + mov %g1, %wim ! Fill the wim with ones + nop + nop + nop + mov %wim, %g1 ! Read back the wim + inc %g1 ! Now g1 has 1 just to left of wim + srl %g1, 1, %g1 ! Now put 1 at top of wim + mov %g0, %wim ! Clear wim so that subsequent save + nop ! won't trap + nop + nop + +good_wim: + save %g0, %g0, %g0 ! Slip into next window + mov %g1, %wim ! Install the new wim + + std %l0, [%sp + 0 * 4] ! save L & I registers + std %l2, [%sp + 2 * 4] + std %l4, [%sp + 4 * 4] + std %l6, [%sp + 6 * 4] + + std %i0, [%sp + 8 * 4] + std %i2, [%sp + 10 * 4] + std %i4, [%sp + 12 * 4] + std %i6, [%sp + 14 * 4] + + restore ! Go back to trap window. + mov %l4, %g1 ! Restore %g1 + +window_fine: + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + tst %l5 + bg recursive_trap + inc %l5 + + set trapstack+1000*4, %sp ! Switch to trap stack + +recursive_trap: + st %l5, [%lo(in_trap_handler) + %l4] + sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals + ! + hidden arg + arg spill + ! + doubleword alignment + ! + registers[72] local var + + std %g0, [%sp + (24 + 0) * 4] ! registers[Gx] + std %g2, [%sp + (24 + 2) * 4] + std %g4, [%sp + (24 + 4) * 4] + std %g6, [%sp + (24 + 6) * 4] + + std %i0, [%sp + (24 + 8) * 4] ! registers[Ox] + std %i2, [%sp + (24 + 10) * 4] + std %i4, [%sp + (24 + 12) * 4] + std %i6, [%sp + (24 + 14) * 4] + ! F0->F31 not implemented + mov %y, %l4 + mov %tbr, %l5 + st %l4, [%sp + (24 + 64) * 4] ! Y + st %l0, [%sp + (24 + 65) * 4] ! PSR + st %l3, [%sp + (24 + 66) * 4] ! WIM + st %l5, [%sp + (24 + 67) * 4] ! TBR + st %l1, [%sp + (24 + 68) * 4] ! PC + st %l2, [%sp + (24 + 69) * 4] ! NPC + + ! CPSR and FPSR not impl + + or %l0, 0xf20, %l4 + mov %l4, %psr ! Turn on traps, disable interrupts + + call _handle_exception + add %sp, 24 * 4, %o0 ! Pass address of registers + +! Reload all of the registers that aren't on the stack + + ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx] + ldd [%sp + (24 + 2) * 4], %g2 + ldd [%sp + (24 + 4) * 4], %g4 + ldd [%sp + (24 + 6) * 4], %g6 + + ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox] + ldd [%sp + (24 + 10) * 4], %i2 + ldd [%sp + (24 + 12) * 4], %i4 + ldd [%sp + (24 + 14) * 4], %i6 + + ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR + ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC + + restore ! Ensure that previous window is valid + save %g0, %g0, %g0 ! by causing a window_underflow trap + + mov %l0, %y + mov %l1, %psr ! Make sure that traps are disabled + ! for rett + + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + dec %l5 + st %l5, [%lo(in_trap_handler) + %l4] + + jmpl %l2, %g0 ! Restore old PC + rett %l3 ! Restore old nPC +"); + +/* 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 $<data>#<checksum> */ + +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); + + if (checksum != xmitcsum) + { + putDebugChar ('-'); /* failed checksum */ + } + else + { + 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; + + /* $<packet info>#<checksum>. */ + 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; + + set_mem_fault_trap(may_fault); + + while (count-- > 0) + { + ch = *mem++; + if (mem_err) + return 0; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + + *buf = 0; + + set_mem_fault_trap(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; + + set_mem_fault_trap(may_fault); + + for (i=0; i<count; i++) + { + ch = hex(*buf++) << 4; + ch |= hex(*buf++); + *mem++ = ch; + if (mem_err) + return 0; + } + + set_mem_fault_trap(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[] = { + {1, SIGSEGV}, /* instruction access error */ + {2, SIGILL}, /* privileged instruction */ + {3, SIGILL}, /* illegal instruction */ + {4, SIGEMT}, /* fp disabled */ + {36, SIGEMT}, /* cp disabled */ + {7, SIGBUS}, /* mem address not aligned */ + {9, SIGSEGV}, /* data access exception */ + {10, SIGEMT}, /* tag overflow */ + {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */ + {0, 0} /* Must be last */ +}; + +/* Set up exception handlers for tracing and breakpoints */ + +void +set_debug_traps (void) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + exceptionHandler(ht->tt, trap_low); + + initialized = 1; +} + +asm (" +! Trap handler for memory errors. This just sets mem_err to be non-zero. It +! assumes that %l1 is non-zero. This should be safe, as it is doubtful that +! 0 would ever contain code that could mem fault. This routine will skip +! past the faulting instruction after setting mem_err. + + .text + .align 4 + +_fltr_set_mem_err: + sethi %hi(_mem_err), %l0 + st %l1, [%l0 + %lo(_mem_err)] + jmpl %l2, %g0 + rett %l2+4 +"); + +static void +set_mem_fault_trap (int enable) +{ + extern void fltr_set_mem_err(); + mem_err = 0; + + if (enable) + exceptionHandler(9, fltr_set_mem_err); + else + exceptionHandler(9, trap_low); +} + +/* Convert the SPARC hardware trap type code to a unix signal number. */ + +static int +computeSignal (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 does all command procesing for interfacing to gdb. It + * returns 1 if you should skip the instruction at the trap address, 0 + * otherwise. + */ + +extern void breakinst(); + +static void +handle_exception (unsigned long *registers) +{ + int tt; /* Trap type */ + int sigval; + int addr; + int length; + char *ptr; + unsigned long *sp; + +/* First, we must force all of the windows to be spilled out */ + + asm(" save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + save %sp, -64, %sp + restore + restore + restore + restore + restore + restore + restore + restore +"); + + if (registers[PC] == (unsigned long)breakinst) + { + registers[PC] = registers[NPC]; + registers[NPC] += 4; + } + + sp = (unsigned long *)registers[SP]; + + tt = (registers[TBR] >> 4) & 0xff; + + /* 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[FP >> 4]; + *ptr++ = hexchars[FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[SP >> 4]; + *ptr++ = hexchars[SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&sp, ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[NPC >> 4]; + *ptr++ = hexchars[NPC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[O7 >> 4]; + *ptr++ = hexchars[O7 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[O7], 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; + ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */ + ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */ + memset(ptr, '0', 32 * 8); /* Floating point */ + mem2hex((char *)®isters[Y], + ptr + 32 * 4 * 2, + 8 * 4, + 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + } + break; + + case 'G': /* set the value of the CPU registers - return OK */ + { + unsigned long *newsp, psr; + + psr = registers[PSR]; + + hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */ + hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */ + hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], + 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + + /* 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[SP]; + if (sp != newsp) + sp = memcpy(newsp, sp, 16 * 4); + + /* Don't allow CWP to be modified. */ + + if (psr != registers[PSR]) + registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f); + + 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; + registers[NPC] = addr + 4; + } + +/* 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 */ + asm (" std %f30,[%sp]"); + break; +#endif + case 'r': /* Reset */ + asm ("call 0 + nop "); + break; + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint (void) +{ + if (!initialized) + return; + + asm(" .globl _breakinst + + _breakinst: ta 1 + "); +} |