From: Tristan Gingold Date: Thu, 8 Mar 2012 14:43:24 +0000 (+0000) Subject: gdb/ X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a0ba0aa22f971c4a181e25e2f487e0f04f5a2018;p=binutils-gdb.git gdb/ 2012-03-08 Tristan Gingold * sparc-stub.c: Move to stubs/ * sh-stub.c: Likewise. * m68k-stub.c: Likewise. * m32r-stub.c: Likewise. * i386-stub.c: Likewise. gdb/stubs/ 2012-03-08 Tristan Gingold * sparc-stub.c: Move from .. * sh-stub.c: Likewise. * m68k-stub.c: Likewise. * m32r-stub.c: Likewise. * i386-stub.c: Likewise. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 711b8d2fd7f..0964c5fcdc8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2012-03-08 Tristan Gingold + + * sparc-stub.c: Move to stubs/ + * sh-stub.c: Likewise. + * m68k-stub.c: Likewise. + * m32r-stub.c: Likewise. + * i386-stub.c: Likewise. + 2012-03-08 Andreas Schwab * m68klinux-tdep.c (m68k_linux_init_abi): Register diff --git a/gdb/i386-stub.c b/gdb/i386-stub.c deleted file mode 100644 index 04996b75cf6..00000000000 --- a/gdb/i386-stub.c +++ /dev/null @@ -1,952 +0,0 @@ -/**************************************************************************** - - 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 - * - * $#. - * - * where - * :: - * :: < two hex digits computed as modulo 256 sum of > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include - -/************************************************************************ - * - * external low-level support routines - */ - -extern void 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 $# */ - -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; - - /* $#. */ - 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/m32r-stub.c b/gdb/m32r-stub.c deleted file mode 100644 index 4d54f72d60b..00000000000 --- a/gdb/m32r-stub.c +++ /dev/null @@ -1,1779 +0,0 @@ -/**************************************************************************** - - 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 - * - * $#. - * - * where - * :: - * :: > - * - * 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:#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 $# */ - -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; - - /* $#. */ - 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 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/m68k-stub.c b/gdb/m68k-stub.c deleted file mode 100644 index 4ef4069bc3d..00000000000 --- a/gdb/m68k-stub.c +++ /dev/null @@ -1,1098 +0,0 @@ -/**************************************************************************** - - 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 - * - * $#. - * - * where - * :: - * :: < two hex digits computed as modulo 256 sum of > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include -#include - -/************************************************************************ - * - * 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 $# */ - -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; - - /* $#. */ - 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/sh-stub.c b/gdb/sh-stub.c deleted file mode 100644 index 76c98a5e8ad..00000000000 --- a/gdb/sh-stub.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* 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 - is encapsulated for transmission in the form: - - $ # CSUM1 CSUM2 - - must be ASCII alphanumeric and cannot include characters - '$' or '#'. If 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 , 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 - - 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 On other requests, the stub should - ignore the request and send an empty - response ($#). 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 -#include - -/* 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 $# */ - -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; - - /* $#. */ - 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/sparc-stub.c b/gdb/sparc-stub.c deleted file mode 100644 index c12d4360a4b..00000000000 --- a/gdb/sparc-stub.c +++ /dev/null @@ -1,778 +0,0 @@ -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or it's performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ - * - * Module name: remcom.c $ - * Revision: 1.34 $ - * Date: 91/03/09 12:29:49 $ - * Contributor: Lake Stevens Instrument Division$ - * - * Description: low level support for gdb debugger. $ - * - * Considerations: only works on target hardware $ - * - * Written by: Glenn Engel $ - * ModuleState: Experimental $ - * - * NOTES: See Below $ - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * This code has been extensively tested on the Fujitsu SPARClite demo board. - * - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a trap #1. - * - ************* - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $#. - * - * where - * :: - * :: < two hex digits computed as modulo 256 sum of > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include - -/************************************************************************ - * - * external low-level support routines - */ - -extern void 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 $# */ - -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; - - /* $#. */ - 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; itt && 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 - "); -} diff --git a/gdb/stubs/ChangeLog b/gdb/stubs/ChangeLog index 1a8b2b702b3..a0f175e30df 100644 --- a/gdb/stubs/ChangeLog +++ b/gdb/stubs/ChangeLog @@ -1,3 +1,11 @@ +2012-03-08 Tristan Gingold + + * 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 * buildvms.com: New file. diff --git a/gdb/stubs/i386-stub.c b/gdb/stubs/i386-stub.c new file mode 100644 index 00000000000..04996b75cf6 --- /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 + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ + +extern void 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 $# */ + +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; + + /* $#. */ + 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 00000000000..4d54f72d60b --- /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 + * + * $#. + * + * where + * :: + * :: > + * + * 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:#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 $# */ + +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; + + /* $#. */ + 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 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 00000000000..4ef4069bc3d --- /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 + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include + +/************************************************************************ + * + * 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 $# */ + +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; + + /* $#. */ + 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 00000000000..76c98a5e8ad --- /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 + is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#'. If 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 , 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 + + 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 On other requests, the stub should + ignore the request and send an empty + response ($#). 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 +#include + +/* 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 $# */ + +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; + + /* $#. */ + 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 00000000000..c12d4360a4b --- /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 + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ + +extern void 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 $# */ + +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; + + /* $#. */ + 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; itt && 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 + "); +}