735 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			735 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
| unsigned long sp_ptr;
 | |
| unsigned long pc_ptr;
 | |
| int cnt;
 | |
| #define UNWIND asm ("movel %/sp, %0" : "=g" (sp_ptr));\
 | |
|     printf ("\n\t\t== Starting at 0x%x ==\n", sp_ptr);\
 | |
|     for (cnt=4; cnt <=32; cnt+=4) {\
 | |
|       printf ("+%d(0x%x): 0x%x\t\t-%d(0x%x): 0x%x\n",\
 | |
| 	      cnt, (sp_ptr + cnt), *(unsigned long *)(sp_ptr + cnt),\
 | |
| 	      cnt, (sp_ptr - cnt), *(unsigned long *)(sp_ptr - cnt)\
 | |
| 	      ); }; fflush (stdout);
 | |
| 
 | |
| /****************************************************************************
 | |
| 
 | |
| 		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.
 | |
|  *  
 | |
|  *  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 68k 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>
 | |
| #include <_ansi.h>
 | |
| 
 | |
| /************************************************************************
 | |
|  *
 | |
|  * external low-level support routines 
 | |
|  */
 | |
| typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
 | |
| typedef void (*Function)();           /* pointer to a function */
 | |
| 
 | |
| extern int  putDebugChar();   /* write a single character      */
 | |
| extern char getDebugChar();   /* read and return a single char */
 | |
| 
 | |
| ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
 | |
| 
 | |
| /************************/
 | |
| /* FORWARD DECLARATIONS */
 | |
| /************************/
 | |
| /** static void initializeRemcomErrorFrame PARAMS ((void)); **/
 | |
| static void _DEFUN_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 = 0; /*** Robs Thu Sep 24 22:18:51 PDT 1992 ***/
 | |
| /*  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
 | |
|               };
 | |
| 
 | |
| 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];
 | |
| 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)];
 | |
| 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;
 | |
| 
 | |
| /* 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 };
 | |
| 
 | |
| /************* jump buffer used for setjmp/longjmp **************************/
 | |
| jmp_buf remcomEnv;
 | |
| 
 | |
| #define BREAKPOINT() asm("   trap #1");
 | |
| 
 | |
| extern void _DEFUN_VOID (return_to_super);
 | |
| extern void _DEFUN_VOID (return_to_user);
 | |
| extern void _DEFUN_VOID (_catchException);
 | |
| 
 | |
| 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*/
 | |
|     }
 | |
| 
 | |
| #ifndef mc68020
 | |
|     /* 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);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* scan for the sequence $<data>#<checksum>     */
 | |
| void getpacket(buffer)
 | |
| char * buffer;
 | |
| {
 | |
|   unsigned char checksum;
 | |
|   unsigned char xmitcsum;
 | |
|   int  i;
 | |
|   int  count;
 | |
|   char ch;
 | |
|   
 | |
|   if (remote_debug) {
 | |
|     printf("\nGETPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
 | |
| 	   registers[ PS ], 
 | |
| 	   registers[ PC ],
 | |
| 	   registers[ A7 ]
 | |
| 	   ); fflush (stdout);
 | |
|     UNWIND
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     /* wait around for the start character, ignore all other characters */
 | |
|     while ((ch = getDebugChar()) != '$'); 
 | |
|      checksum = 0;
 | |
|     xmitcsum = -1;
 | |
|     
 | |
|     count = 0;
 | |
|     
 | |
|     /* now, read until a # or end of buffer is found */
 | |
|     while (count < BUFMAX) {
 | |
|       ch = getDebugChar();
 | |
|       if (ch == '#') break;
 | |
|       checksum = checksum + ch;
 | |
|       buffer[count] = ch;
 | |
|       count = count + 1;
 | |
|       }
 | |
|     buffer[count] = 0;
 | |
| 
 | |
|     if (ch == '#') {
 | |
|       xmitcsum = hex(getDebugChar()) << 4;
 | |
|       xmitcsum += hex(getDebugChar());
 | |
|       if ((remote_debug ) && (checksum != xmitcsum)) {
 | |
|         fprintf(stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
 | |
| 						     checksum,xmitcsum,buffer);
 | |
|       }
 | |
|       
 | |
|       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] );
 | |
| 	    /* remove sequence chars from buffer */
 | |
| 	    count = strlen(buffer);
 | |
| 	    for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
 | |
| 	 } 
 | |
|       } 
 | |
|     } 
 | |
|   } while (checksum != xmitcsum);
 | |
|   
 | |
| }
 | |
| 
 | |
| /* send the packet in buffer.  The host get's one chance to read it.  
 | |
|    This routine does not wait for a positive acknowledge.  */
 | |
| 
 | |
| 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]) {
 | |
|     if (! putDebugChar(ch)) return;
 | |
|     checksum += ch;
 | |
|     count += 1;
 | |
|   }
 | |
|   
 | |
|   putDebugChar('#');
 | |
|   putDebugChar(hexchars[checksum >> 4]);
 | |
|   putDebugChar(hexchars[checksum % 16]);
 | |
| 
 | |
|   if (remote_debug) {
 | |
|     printf("\nPUTPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
 | |
| 	   registers[ PS ], 
 | |
| 	   registers[ PC ],
 | |
| 	   registers[ A7 ]
 | |
| 	   ); fflush (stdout);
 | |
|     UNWIND
 | |
|   }
 | |
| 
 | |
| /*** } while (getDebugChar() != '+'); ***/
 | |
| /** } while (1 == 0);  (getDebugChar() != '+'); **/
 | |
| 
 | |
| }
 | |
| 
 | |
| char  remcomInBuffer[BUFMAX];
 | |
| char  remcomOutBuffer[BUFMAX];
 | |
| static short error;
 | |
| 
 | |
| 
 | |
| 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 = 16; break; /* chk instruction     */
 | |
|     case 7 : sigval = 16; 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  */
 | |
|     case 13: sigval = 8;  break; /* floating point err  */
 | |
|     case 31: sigval = 2;  break; /* interrupt           */
 | |
|     case 33: sigval = 5;  break; /* breakpoint          */
 | |
|     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;
 | |
|   int    addr, length;
 | |
|   char * ptr;
 | |
|   int    newPC;
 | |
|   Frame  *frame;
 | |
| 
 | |
|   if (remote_debug)    printf("\nHANDLE_EXCEPTION: vector=%d, sr=0x%x, pc=0x%x, sp=0x%x\n",
 | |
| 			    exceptionVector,
 | |
| 			    registers[ PS ], 
 | |
| 			    registers[ PC ],
 | |
| 			    registers[ A7 ]
 | |
| 			      ); fflush (stdout);
 | |
| 
 | |
|   /* 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); 
 | |
| 
 | |
|   while (1==1) { 
 | |
|     error = 0;
 | |
|     remcomOutBuffer[0] = 0;
 | |
|     getpacket(remcomInBuffer);
 | |
|     switch (remcomInBuffer[0]) {
 | |
|       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(&remcomInBuffer[1], (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 */
 | |
|                     ptr = &remcomInBuffer[1];
 | |
|                     if (hexToInt(&ptr,&addr))
 | |
|                         if (*(ptr++) == ',')
 | |
|                             if (hexToInt(&ptr,&length)) 
 | |
|                             {
 | |
|                                 ptr = 0;
 | |
|                                 mem2hex((char*) addr, remcomOutBuffer, length);
 | |
|                             }
 | |
| 
 | |
|                     if (ptr)
 | |
|                     {
 | |
| 		      strcpy(remcomOutBuffer,"E01");
 | |
| 		      debug_error("malformed read memory command: %s",remcomInBuffer);
 | |
|                   }     
 | |
|                 } 
 | |
| 		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 */
 | |
|                     ptr = &remcomInBuffer[1];
 | |
|                     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");
 | |
| 		      debug_error("malformed write memory command: %s",remcomInBuffer);
 | |
| 		      }     
 | |
|                 } 
 | |
| 		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 'c' : 
 | |
|      case 's' : 
 | |
|           /* try to read optional parameter, pc unchanged if no parm */
 | |
|          ptr = &remcomInBuffer[1];
 | |
|          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 (remcomInBuffer[0] == 's') 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()
 | |
| {
 | |
|     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];
 | |
| 
 | |
|   setup_vectors();
 | |
| 
 | |
|   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();
 | |
| }
 |