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