]> Git Repo - binutils.git/blob - gdb/m68k-stub.c
Initial revision
[binutils.git] / gdb / m68k-stub.c
1 /****************************************************************************
2
3                 THIS SOFTWARE IS NOT COPYRIGHTED  
4    
5    HP offers the following for use in the public domain.  HP makes no
6    warranty with regard to the software or it's performance and the 
7    user accepts the software "AS IS" with all faults.
8
9    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16  *  $Header$                   
17  *
18  *  $Module name: remcom.c $  
19  *  $Revision$
20  *  $Date$
21  *  $Contributor:     Lake Stevens Instrument Division$
22  *  
23  *  $Description:     low level support for gdb debugger. $
24  *
25  *  $Considerations:  only works on target hardware $
26  *
27  *  $Written by:      Glenn Engel $
28  *  $ModuleState:     Experimental $ 
29  *
30  *  $NOTES:           See Below $
31  * 
32  *  To enable debugger support, two things need to happen.  One, a
33  *  call to set_debug_traps() is necessary in order to allow any breakpoints
34  *  or error conditions to be properly intercepted and reported to gdb.
35  *  Two, a breakpoint needs to be generated to begin communication.  This
36  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
37  *  simulates a breakpoint by executing a trap #1.
38  *  
39  *  Some explanation is probably necessary to explain how exceptions are
40  *  handled.  When an exception is encountered the 68000 pushes the current
41  *  program counter and status register onto the supervisor stack and then
42  *  transfers execution to a location specified in it's vector table.
43  *  The handlers for the exception vectors are hardwired to jmp to an address
44  *  given by the relation:  (exception - 256) * 6.  These are decending 
45  *  addresses starting from -6, -12, -18, ...  By allowing 6 bytes for
46  *  each entry, a jsr, jmp, bsr, ... can be used to enter the exception 
47  *  handler.  Using a jsr to handle an exception has an added benefit of
48  *  allowing a single handler to service several exceptions and use the
49  *  return address as the key differentiation.  The vector number can be
50  *  computed from the return address by [ exception = (addr + 1530) / 6 ].
51  *  The sole purpose of the routine _catchException is to compute the
52  *  exception number and push it on the stack in place of the return address.
53  *  The external function exceptionHandler() is
54  *  used to attach a specific handler to a specific 68k exception.
55  *  For 68020 machines, the ability to have a return address around just
56  *  so the vector can be determined is not necessary because the '020 pushes an
57  *  extra word onto the stack containing the vector offset
58  * 
59  *  Because gdb will sometimes write to the stack area to execute function
60  *  calls, this program cannot rely on using the supervisor stack so it
61  *  uses it's own stack area reserved in the int array remcomStack.  
62  * 
63  *************
64  *
65  *    The following gdb commands are supported:
66  * 
67  * command          function                               Return value
68  * 
69  *    g             return the value of the CPU registers  hex data or ENN
70  *    G             set the value of the CPU registers     OK or ENN
71  * 
72  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
73  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
74  * 
75  *    c             Resume at current address              SNN   ( signal NN)
76  *    cAA..AA       Continue at address AA..AA             SNN
77  * 
78  *    s             Step one instruction                   SNN
79  *    sAA..AA       Step one instruction from AA..AA       SNN
80  * 
81  *    k             kill
82  *
83  *    ?             What was the last sigval ?             SNN   (signal NN)
84  * 
85  * All commands and responses are sent with a packet which includes a 
86  * checksum.  A packet consists of 
87  * 
88  * $<packet info>#<checksum>.
89  * 
90  * where
91  * <packet info> :: <characters representing the command or response>
92  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
93  * 
94  * When a packet is received, it is first acknowledged with either '+' or '-'.
95  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
96  * 
97  * Example:
98  * 
99  * Host:                  Reply:
100  * $m0,10#2a               +$00010203040506070809101112131415#42
101  * 
102  ****************************************************************************/
103
104 #include <stdio.h>
105 #include <string.h>
106 #include <setjmp.h>
107
108 /************************************************************************
109  *
110  * external low-level support routines 
111  */
112 typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
113 typedef void (*Function)();           /* pointer to a function */
114
115 extern putDebugChar();   /* write a single character      */
116 extern getDebugChar();   /* read and return a single char */
117
118 extern Function exceptionHandler();  /* assign an exception handler */
119 extern ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
120
121 /************************/
122 /* FORWARD DECLARATIONS */
123 /************************/
124 void initializeRemcomErrorFrame(void);
125
126 /************************************************************************/
127 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
128 /* at least NUMREGBYTES*2 are needed for register packets */
129 #define BUFMAX 400
130
131 static char initialized;  /* boolean flag. != 0 means we've been initialized */
132
133 int     remote_debug;
134 /*  debug >  0 prints ill-formed commands in valid packets & checksum errors */ 
135
136 static const char hexchars[]="0123456789abcdef";
137
138 /* there are 180 bytes of registers on a 68020 w/68881      */
139 /* many of the fpa registers are 12 byte (96 bit) registers */
140 #define NUMREGBYTES 180
141 enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, 
142                A0,A1,A2,A3,A4,A5,A6,A7, 
143                PS,PC,
144                FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
145                FPCONTROL,FPSTATUS,FPIADDR
146               };
147
148 typedef struct FrameStruct
149 {
150     struct FrameStruct  *previous;
151     int       exceptionPC;      /* pc value when this frame created */
152     int       exceptionVector;  /* cpu vector causing exception     */
153     short     frameSize;        /* size of cpu frame in words       */
154     short     sr;               /* for 68000, this not always sr    */
155     int       pc;
156     short     format;
157     int       fsaveHeader;
158     int       morejunk[0];        /* exception frame, fp save... */
159 } Frame;
160
161 #define FRAMESIZE 500
162 int   gdbFrameStack[FRAMESIZE];
163 static Frame *lastFrame;
164
165 /*
166  * these should not be static cuz they can be used outside this module
167  */
168 int registers[NUMREGBYTES/4];
169 int superStack;
170
171 #define STACKSIZE 10000
172 int remcomStack[STACKSIZE/sizeof(int)];
173 static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
174
175 /*
176  * In many cases, the system will want to continue exception processing
177  * when a continue command is given.  
178  * oldExceptionHook is a function to invoke in this case.
179  */
180
181 static ExceptionHook oldExceptionHook;
182
183 /* the size of the exception stack on the 68020 varies with the type of
184  * exception.  The following table is the number of WORDS used
185  * for each exception format.
186  */
187 const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
188
189 /************* jump buffer used for setjmp/longjmp **************************/
190 jmp_buf remcomEnv;
191
192 /***************************  ASSEMBLY CODE MACROS *************************/
193 /*                                                                         */
194
195 #ifdef __HAVE_68881__
196 /* do an fsave, then remember the address to begin a restore from */
197 #define SAVE_FP_REGS()    asm(" fsave   a0@-");         \
198                           asm(" fmovemx fp0-fp7,_registers+72");        \
199                           asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); 
200 #define RESTORE_FP_REGS()                              \
201 asm("                                                \n\
202     fmoveml  _registers+168,fpcr/fpsr/fpi            \n\
203     fmovemx  _registers+72,fp0-fp7                   \n\
204     cmpl     #-1,a0@     |  skip frestore flag set ? \n\
205     beq      skip_frestore                           \n\
206     frestore a0@+                                    \n\
207 skip_frestore:                                       \n\
208 ");
209
210 #else
211 #define SAVE_FP_REGS()
212 #define RESTORE_FP_REGS()
213 #endif /* __HAVE_68881__ */
214
215 void return_to_super(void);
216 void return_to_user(void);
217
218 asm("
219 .text
220 .globl _return_to_super
221 _return_to_super:
222         movel   _registers+60,sp /* get new stack pointer */        
223         movel   _lastFrame,a0   /* get last frame info  */              
224         bra     return_to_any
225
226 .globl _return_to_user
227 _return_to_user:
228         movel   _registers+60,a0 /* get usp */                          
229         movel   a0,usp           /* set usp */                          
230         movel   _superStack,sp  /* get original stack pointer */        
231
232 return_to_any:
233         movel   _lastFrame,a0   /* get last frame info  */              
234         movel   a0@+,_lastFrame /* link in previous frame     */        
235         addql   #8,a0           /* skip over pc, vector#*/              
236         movew   a0@+,d0         /* get # of words in cpu frame */       
237         addw    d0,a0           /* point to end of data        */       
238         addw    d0,a0           /* point to end of data        */       
239         movel   a0,a1                                                   
240 #                                                                       
241 # copy the stack frame                                                  
242         subql   #1,d0                                                   
243 copyUserLoop:                                                               
244         movew   a1@-,sp@-                                               
245         dbf     d0,copyUserLoop                                             
246 ");                                                                     
247         RESTORE_FP_REGS()                                              
248    asm("   moveml  _registers,d0-d7/a0-a6");                            
249    asm("   rte");  /* pop and go! */                                    
250
251 #define DISABLE_INTERRUPTS()   asm("         oriw   #0x0700,sr");
252 #define BREAKPOINT() asm("   trap #1");
253
254 /* this function is called immediately when a level 7 interrupt occurs */
255 /* if the previous interrupt level was 7 then we're already servicing  */
256 /* this interrupt and an rte is in order to return to the debugger.    */
257 /* For the 68000, the offset for sr is 6 due to the jsr return address */
258 asm("
259 .text
260 .globl __debug_level7
261 __debug_level7:
262         movew   d0,sp@-");
263 #ifdef mc68020
264 asm("   movew   sp@(2),d0");
265 #else
266 asm("   movew   sp@(6),d0");
267 #endif
268 asm("   andiw   #0x700,d0
269         cmpiw   #0x700,d0
270         beq     _already7
271         movew   sp@+,d0 
272         bra     __catchException
273 _already7:
274         movew   sp@+,d0");
275 #ifndef mc68020
276 asm("   lea     sp@(4),sp");     /* pull off 68000 return address */
277 #endif
278 asm("   rte");
279
280 extern void _catchException();
281
282 #ifdef mc68020
283 /* This function is called when a 68020 exception occurs.  It saves
284  * all the cpu and fpcp regs in the _registers array, creates a frame on a
285  * linked list of frames which has the cpu and fpcp stack frames needed
286  * to properly restore the context of these processors, and invokes
287  * an exception handler (remcom_handler).
288  *
289  * stack on entry:                       stack on exit:
290  *   N bytes of junk                     exception # MSWord
291  *   Exception Format Word               exception # MSWord
292  *   Program counter LSWord              
293  *   Program counter MSWord             
294  *   Status Register                    
295  *                                       
296  *                                       
297  */
298 asm(" 
299 .text
300 .globl __catchException
301 __catchException:");
302 DISABLE_INTERRUPTS();
303 asm("
304         moveml  d0-d7/a0-a6,_registers /* save registers        */
305         movel   _lastFrame,a0   /* last frame pointer */
306 ");
307 SAVE_FP_REGS();        
308 asm("
309         lea     _registers,a5   /* get address of registers     */
310         movew   sp@,d1          /* get status register          */
311         movew   d1,a5@(66)      /* save sr                      */      
312         movel   sp@(2),a4       /* save pc in a4 for later use  */
313         movel   a4,a5@(68)      /* save pc in _regisers[]       */
314
315 #
316 # figure out how many bytes in the stack frame
317         movew   sp@(6),d0       /* get '020 exception format    */
318         movew   d0,d2           /* make a copy of format word   */
319         andiw   #0xf000,d0      /* mask off format type         */
320         rolw    #5,d0           /* rotate into the low byte *2  */
321         lea     _exceptionSize,a1   
322         addw    d0,a1           /* index into the table         */
323         movew   a1@,d0          /* get number of words in frame */
324         movew   d0,d3           /* save it                      */
325         subw    d0,a0           /* adjust save pointer          */
326         subw    d0,a0           /* adjust save pointer(bytes)   */
327         movel   a0,a1           /* copy save pointer            */
328         subql   #1,d0           /* predecrement loop counter    */
329 #
330 # copy the frame
331 saveFrameLoop:
332         movew   sp@+,a1@+
333         dbf     d0,saveFrameLoop
334 #
335 # now that the stack has been clenaed,
336 # save the a7 in use at time of exception
337         movel   sp,_superStack  /* save supervisor sp           */
338         andiw   #0x2000,d1      /* were we in supervisor mode ? */
339         beq     userMode       
340         movel   a7,a5@(60)      /* save a7                  */
341         bra     a7saveDone
342 userMode:  
343         movel   usp,a1          
344         movel   a1,a5@(60)      /* save user stack pointer      */
345 a7saveDone:
346
347 #
348 # save size of frame
349         movew   d3,a0@-
350
351 #
352 # compute exception number
353         andl    #0xfff,d2       /* mask off vector offset       */
354         lsrw    #2,d2           /* divide by 4 to get vect num  */
355         movel   d2,a0@-         /* save it                      */
356 #
357 # save pc causing exception
358         movel   a4,a0@-
359 #
360 # save old frame link and set the new value
361         movel   _lastFrame,a1   /* last frame pointer */
362         movel   a1,a0@-         /* save pointer to prev frame   */
363         movel   a0,_lastFrame
364
365         movel   d2,sp@-         /* push exception num           */
366         movel   _exceptionHook,a0  /* get address of handler */
367         jbsr    a0@             /* and call it */
368         clrl    sp@             /* replace exception num parm with frame ptr */
369         jbsr     __returnFromException   /* jbsr, but never returns */
370 ");
371 #else /* mc68000 */
372 /* This function is called when an exception occurs.  It translates the
373  * return address found on the stack into an exception vector # which
374  * is then handled by either handle_exception or a system handler.
375  * _catchException provides a front end for both.  
376  *
377  * stack on entry:                       stack on exit:
378  *   Program counter MSWord              exception # MSWord 
379  *   Program counter LSWord              exception # MSWord
380  *   Status Register                     
381  *   Return Address  MSWord              
382  *   Return Address  LSWord             
383  */
384 asm("
385 .text
386 .globl __catchException
387 __catchException:");
388 DISABLE_INTERRUPTS();
389 asm("
390         moveml d0-d7/a0-a6,_registers  /* save registers               */
391         movel   _lastFrame,a0   /* last frame pointer */
392 ");
393 SAVE_FP_REGS();        
394 asm("
395         lea     _registers,a5   /* get address of registers     */
396         movel   sp@+,d2         /* pop return address           */
397         addl    #1530,d2        /* convert return addr to       */
398         divs    #6,d2           /*  exception number            */
399         extl    d2   
400
401         moveql  #3,d3           /* assume a three word frame     */
402
403         cmpiw   #3,d2           /* bus error or address error ? */
404         bgt     normal          /* if >3 then normal error      */
405         movel   sp@+,a0@-       /* copy error info to frame buff*/
406         movel   sp@+,a0@-       /* these are never used         */
407         moveql  #7,d3           /* this is a 7 word frame       */
408      
409 normal:   
410         movew   sp@+,d1         /* pop status register          */
411         movel   sp@+,a4         /* pop program counter          */
412         movew   d1,a5@(66)      /* save sr                      */      
413         movel   a4,a5@(68)      /* save pc in _regisers[]       */
414         movel   a4,a0@-         /* copy pc to frame buffer      */
415         movew   d1,a0@-         /* copy sr to frame buffer      */
416
417         movel   sp,_superStack  /* save supervisor sp          */
418
419         andiw   #0x2000,d1      /* were we in supervisor mode ? */
420         beq     userMode       
421         movel   a7,a5@(60)      /* save a7                  */
422         bra     saveDone             
423 userMode:
424         movel   usp,a1          /* save user stack pointer      */
425         movel   a1,a5@(60)      /* save user stack pointer      */
426 saveDone:
427
428         movew   d3,a0@-         /* push frame size in words     */
429         movel   d2,a0@-         /* push vector number           */
430         movel   a4,a0@-         /* push exception pc            */
431
432 #
433 # save old frame link and set the new value
434         movel   _lastFrame,a1   /* last frame pointer */
435         movel   a1,a0@-         /* save pointer to prev frame   */
436         movel   a0,_lastFrame
437
438         movel   d2,sp@-         /* push exception num           */
439         movel   _exceptionHook,a0  /* get address of handler */
440         jbsr    a0@             /* and call it */
441         clrl    sp@             /* replace exception num parm with frame ptr */
442         jbsr     __returnFromException   /* jbsr, but never returns */
443 ");
444 #endif
445
446
447 /*
448  * remcomHandler is a front end for handle_exception.  It moves the
449  * stack pointer into an area reserved for debugger use in case the
450  * breakpoint happened in supervisor mode.
451  */
452 asm("_remcomHandler:");
453 asm("           addl    #4,sp");        /* pop off return address     */
454 asm("           movel   sp@+,d0");      /* get the exception number   */
455 asm("           movel   _stackPtr,sp"); /* move to remcom stack area  */
456 asm("           movel   d0,sp@-");      /* push exception onto stack  */
457 asm("           jbsr    _handle_exception");    /* this never returns */
458 asm("           rts");                  /* return */
459
460 void _returnFromException( Frame *frame )
461 {
462     /* if no passed in frame, use the last one */
463     if (! frame)
464     {
465         frame = lastFrame;
466         frame->frameSize = 4;
467         frame->format = 0;
468         frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/
469     }
470
471 #ifndef mc68020
472     /* a 68000 cannot use the internal info pushed onto a bus error
473      * or address error frame when doing an RTE so don't put this info
474      * onto the stack or the stack will creep every time this happens.
475      */
476     frame->frameSize=3;
477 #endif
478
479     /* throw away any frames in the list after this frame */
480     lastFrame = frame;
481
482     frame->sr = registers[(int) PS];
483     frame->pc = registers[(int) PC];
484
485     if (registers[(int) PS] & 0x2000)
486     { 
487         /* return to supervisor mode... */
488         return_to_super();
489     }
490     else
491     { /* return to user mode */
492         return_to_user();
493     }
494 }
495
496 int hex(ch)
497 char ch;
498 {
499   if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
500   if ((ch >= '0') && (ch <= '9')) return (ch-'0');
501   if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
502   return (-1);
503 }
504
505
506 /* scan for the sequence $<data>#<checksum>     */
507 void getpacket(buffer)
508 char * buffer;
509 {
510   unsigned char checksum;
511   unsigned char xmitcsum;
512   int  i;
513   int  count;
514   char ch;
515   
516   do {
517     /* wait around for the start character, ignore all other characters */
518     while ((ch = getDebugChar()) != '$'); 
519     checksum = 0;
520     xmitcsum = -1;
521     
522     count = 0;
523     
524     /* now, read until a # or end of buffer is found */
525     while (count < BUFMAX) {
526       ch = getDebugChar();
527       if (ch == '#') break;
528       checksum = checksum + ch;
529       buffer[count] = ch;
530       count = count + 1;
531       }
532     buffer[count] = 0;
533
534     if (ch == '#') {
535       xmitcsum = hex(getDebugChar()) << 4;
536       xmitcsum += hex(getDebugChar());
537       if ((remote_debug ) && (checksum != xmitcsum)) {
538         fprintf(stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
539                                                      checksum,xmitcsum,buffer);
540       }
541       
542       if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */ 
543       else {
544          putDebugChar('+');  /* successful transfer */
545          /* if a sequence char is present, reply the sequence ID */
546          if (buffer[2] == ':') {
547             putDebugChar( buffer[0] );
548             putDebugChar( buffer[1] );
549             /* remove sequence chars from buffer */
550             count = strlen(buffer);
551             for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
552          } 
553       } 
554     } 
555   } while (checksum != xmitcsum);
556   
557 }
558
559 /* send the packet in buffer.  The host get's one chance to read it.  
560    This routine does not wait for a positive acknowledge.  */
561
562
563 void putpacket(buffer)
564 char * buffer;
565 {
566   unsigned char checksum;
567   int  count;
568   char ch;
569   
570   /*  $<packet info>#<checksum>. */
571   do {
572   putDebugChar('$');
573   checksum = 0;
574   count    = 0;
575   
576   while (ch=buffer[count]) {
577     if (! putDebugChar(ch)) return;
578     checksum += ch;
579     count += 1;
580   }
581   
582   putDebugChar('#');
583   putDebugChar(hexchars[checksum >> 4]);
584   putDebugChar(hexchars[checksum % 16]);
585
586   } while (1 == 0);  /* (getDebugChar() != '+'); */
587   
588 }
589
590 char  remcomInBuffer[BUFMAX];
591 char  remcomOutBuffer[BUFMAX];
592 static short error;
593
594
595 void debug_error(format, parm)
596 char * format;
597 char * parm;
598 {
599   if (remote_debug) fprintf(stderr,format,parm);
600 }
601
602 /* convert the memory pointed to by mem into hex, placing result in buf */
603 /* return a pointer to the last char put in buf (null) */
604 char* mem2hex(mem, buf, count)
605 char* mem;
606 char* buf;
607 int   count;
608 {
609       int i;
610       unsigned char ch;
611       for (i=0;i<count;i++) {
612           ch = *mem++;
613           *buf++ = hexchars[ch >> 4];
614           *buf++ = hexchars[ch % 16];
615       }
616       *buf = 0; 
617       return(buf);
618 }
619
620 /* convert the hex array pointed to by buf into binary to be placed in mem */
621 /* return a pointer to the character AFTER the last byte written */
622 char* hex2mem(buf, mem, count)
623 char* buf;
624 char* mem;
625 int   count;
626 {
627       int i;
628       unsigned char ch;
629       for (i=0;i<count;i++) {
630           ch = hex(*buf++) << 4;
631           ch = ch + hex(*buf++);
632           *mem++ = ch;
633       }
634       return(mem);
635 }
636
637 /* a bus error has occurred, perform a longjmp
638    to return execution and allow handling of the error */
639
640 void handle_buserror()
641 {
642   longjmp(remcomEnv,1);
643 }
644
645 /* this function takes the 68000 exception number and attempts to 
646    translate this number into a unix compatible signal value */
647 int computeSignal( exceptionVector )
648 int exceptionVector;
649 {
650   int sigval;
651   switch (exceptionVector) {
652     case 2 : sigval = 10; break; /* bus error           */
653     case 3 : sigval = 10; break; /* address error       */
654     case 4 : sigval = 4;  break; /* illegal instruction */
655     case 5 : sigval = 8;  break; /* zero divide         */
656     case 6 : sigval = 16; break; /* chk instruction     */
657     case 7 : sigval = 16; break; /* trapv instruction   */
658     case 8 : sigval = 11; break; /* privilege violation */
659     case 9 : sigval = 5;  break; /* trace trap          */
660     case 10: sigval = 4;  break; /* line 1010 emulator  */
661     case 11: sigval = 4;  break; /* line 1111 emulator  */
662     case 13: sigval = 8;  break; /* floating point err  */
663     case 31: sigval = 2;  break; /* interrupt           */
664     case 33: sigval = 5;  break; /* breakpoint          */
665     case 40: sigval = 8;  break; /* floating point err  */
666     case 48: sigval = 8;  break; /* floating point err  */
667     case 49: sigval = 8;  break; /* floating point err  */
668     case 50: sigval = 8;  break; /* zero divide         */
669     case 51: sigval = 8;  break; /* underflow           */
670     case 52: sigval = 8;  break; /* operand error       */
671     case 53: sigval = 8;  break; /* overflow            */
672     case 54: sigval = 8;  break; /* NAN                 */
673     default: 
674       sigval = 7;         /* "software generated"*/
675   }
676   return (sigval);
677 }
678
679 /**********************************************/
680 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
681 /* RETURN NUMBER OF CHARS PROCESSED           */
682 /**********************************************/
683 int hexToInt(char **ptr, int *intValue)
684 {
685     int numChars = 0;
686     int hexValue;
687     
688     *intValue = 0;
689
690     while (**ptr)
691     {
692         hexValue = hex(**ptr);
693         if (hexValue >=0)
694         {
695             *intValue = (*intValue <<4) | hexValue;
696             numChars ++;
697         }
698         else
699             break;
700         
701         (*ptr)++;
702     }
703
704     return (numChars);
705 }
706
707 /*
708  * This function does all command procesing for interfacing to gdb.
709  */
710 void handle_exception(int exceptionVector)
711 {
712   int    sigval;
713   int    addr, length;
714   char * ptr;
715   int    newPC;
716   Frame  *frame;
717   
718   if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n", 
719                             exceptionVector,
720                             registers[ PS ], 
721                             registers[ PC ]);
722
723   /* reply to host that an exception has occurred */
724   sigval = computeSignal( exceptionVector );
725   remcomOutBuffer[0] = 'S';
726   remcomOutBuffer[1] =  hexchars[sigval >> 4];
727   remcomOutBuffer[2] =  hexchars[sigval % 16];
728   remcomOutBuffer[3] = 0;
729
730   putpacket(remcomOutBuffer); 
731
732   while (1==1) { 
733     error = 0;
734     remcomOutBuffer[0] = 0;
735     getpacket(remcomInBuffer);
736     switch (remcomInBuffer[0]) {
737       case '?' :   remcomOutBuffer[0] = 'S';
738                    remcomOutBuffer[1] =  hexchars[sigval >> 4];
739                    remcomOutBuffer[2] =  hexchars[sigval % 16];
740                    remcomOutBuffer[3] = 0;
741                  break; 
742       case 'd' : remote_debug = !(remote_debug);  /* toggle debug flag */
743                  break; 
744       case 'g' : /* return the value of the CPU registers */
745                 mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES);
746                 break;
747       case 'G' : /* set the value of the CPU registers - return OK */
748                 hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES);
749                 strcpy(remcomOutBuffer,"OK");
750                 break;
751       
752       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
753       case 'm' : 
754                 if (setjmp(remcomEnv) == 0)
755                 {
756                     exceptionHandler(2,handle_buserror); 
757
758                     /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
759                     ptr = &remcomInBuffer[1];
760                     if (hexToInt(&ptr,&addr))
761                         if (*(ptr++) == ',')
762                             if (hexToInt(&ptr,&length)) 
763                             {
764                                 ptr = 0;
765                                 mem2hex((char*) addr, remcomOutBuffer, length);
766                             }
767
768                     if (ptr)
769                     {
770                       strcpy(remcomOutBuffer,"E01");
771                       debug_error("malformed read memory command: %s",remcomInBuffer);
772                   }     
773                 } 
774                 else {
775                   exceptionHandler(2,_catchException);   
776                   strcpy(remcomOutBuffer,"E03");
777                   debug_error("bus error");
778                   }     
779                 
780                 /* restore handler for bus error */
781                 exceptionHandler(2,_catchException);   
782                 break;
783       
784       /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
785       case 'M' : 
786                 if (setjmp(remcomEnv) == 0) {
787                     exceptionHandler(2,handle_buserror); 
788                     
789                     /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
790                     ptr = &remcomInBuffer[1];
791                     if (hexToInt(&ptr,&addr))
792                         if (*(ptr++) == ',')
793                             if (hexToInt(&ptr,&length))
794                                 if (*(ptr++) == ':')
795                                 {
796                                     hex2mem(ptr, (char*) addr, length);
797                                     ptr = 0;
798                                     strcpy(remcomOutBuffer,"OK");
799                                 }
800                     if (ptr)
801                     {
802                       strcpy(remcomOutBuffer,"E02");
803                       debug_error("malformed write memory command: %s",remcomInBuffer);
804                       }     
805                 } 
806                 else {
807                   exceptionHandler(2,_catchException);   
808                   strcpy(remcomOutBuffer,"E03");
809                   debug_error("bus error");
810                   }     
811
812                 /* restore handler for bus error */
813                 exceptionHandler(2,_catchException);   
814                 break;
815      
816      /* cAA..AA    Continue at address AA..AA(optional) */
817      /* sAA..AA   Step one instruction from AA..AA(optional) */
818      case 'c' : 
819      case 's' : 
820           /* try to read optional parameter, pc unchanged if no parm */
821          ptr = &remcomInBuffer[1];
822          if (hexToInt(&ptr,&addr))
823              registers[ PC ] = addr;
824              
825           newPC = registers[ PC];
826           
827           /* clear the trace bit */
828           registers[ PS ] &= 0x7fff;
829           
830           /* set the trace bit if we're stepping */
831           if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000;
832           
833           /*
834            * look for newPC in the linked list of exception frames.
835            * if it is found, use the old frame it.  otherwise,
836            * fake up a dummy frame in returnFromException().
837            */
838           if (remote_debug) printf("new pc = 0x%x\n",newPC);
839           frame = lastFrame;
840           while (frame)
841           {
842               if (remote_debug)
843                   printf("frame at 0x%x has pc=0x%x, except#=%d\n",
844                          frame,frame->exceptionPC,
845                          frame->exceptionVector);
846               if (frame->exceptionPC == newPC) break;  /* bingo! a match */
847               /*
848                * for a breakpoint instruction, the saved pc may
849                * be off by two due to re-executing the instruction
850                * replaced by the trap instruction.  Check for this.
851                */
852               if ((frame->exceptionVector == 33) &&
853                   (frame->exceptionPC == (newPC+2))) break;
854               if (frame == frame->previous)
855               {
856                   frame = 0; /* no match found */ 
857                   break; 
858               }
859               frame = frame->previous;
860           }
861           
862           /*
863            * If we found a match for the PC AND we are not returning
864            * as a result of a breakpoint (33),
865            * trace exception (9), nmi (31), jmp to
866            * the old exception handler as if this code never ran.
867            */
868           if (frame) 
869           {
870               if ((frame->exceptionVector != 9)  && 
871                   (frame->exceptionVector != 31) && 
872                   (frame->exceptionVector != 33))
873               { 
874                   /*
875                    * invoke the previous handler.
876                    */
877                   if (oldExceptionHook)
878                       (*oldExceptionHook) (frame->exceptionVector);
879                   newPC = registers[ PC ];    /* pc may have changed  */
880                   if (newPC != frame->exceptionPC)
881                   {
882                       if (remote_debug)
883                           printf("frame at 0x%x has pc=0x%x, except#=%d\n",
884                                  frame,frame->exceptionPC,
885                                  frame->exceptionVector);
886                       /* re-use the last frame, we're skipping it (longjump?)*/
887                       frame = (Frame *) 0;
888                       _returnFromException( frame );  /* this is a jump */
889                   }
890               }
891           }         
892
893           /* if we couldn't find a frame, create one */
894           if (frame == 0)
895           {
896               frame = lastFrame -1 ;
897               
898               /* by using a bunch of print commands with breakpoints,
899                  it's possible for the frame stack to creep down.  If it creeps
900                  too far, give up and reset it to the top.  Normal use should
901                  not see this happen.
902               */
903               if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack)
904               {
905                  initializeRemcomErrorFrame();
906                  frame = lastFrame; 
907               }
908               frame->previous = lastFrame;
909               lastFrame = frame;
910               frame = 0;  /* null so _return... will properly initialize it */ 
911           }    
912           
913           _returnFromException( frame ); /* this is a jump */
914
915           break;
916           
917       /* kill the program */
918       case 'k' :  /* do nothing */
919                 break;
920       } /* switch */ 
921     
922     /* reply to the request */
923     putpacket(remcomOutBuffer); 
924     }
925 }
926
927
928 void initializeRemcomErrorFrame(void)
929 {
930     lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
931     lastFrame->previous = lastFrame;
932 }
933
934 /* this function is used to set up exception handlers for tracing and 
935    breakpoints */
936 void set_debug_traps()
937 {
938 extern void _debug_level7();
939 extern void remcomHandler();
940 int exception;
941
942   initializeRemcomErrorFrame();
943   stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
944
945   for (exception = 2; exception <= 23; exception++)
946       exceptionHandler(exception,_catchException);   
947
948   /* level 7 interrupt              */
949   exceptionHandler(31,_debug_level7);    
950   
951   /* breakpoint exception (trap #1) */
952   exceptionHandler(33,_catchException);
953   
954   /* floating point error (trap #8) */
955   exceptionHandler(40,_catchException);
956   
957   /* 48 to 54 are floating point coprocessor errors */
958   for (exception = 48; exception <= 54; exception++)
959       exceptionHandler(exception,_catchException);   
960
961   if (oldExceptionHook != remcomHandler)
962   {
963       oldExceptionHook = exceptionHook;
964       exceptionHook    = remcomHandler;
965   }
966   
967   initialized = 1;
968
969 }
970
971 /* This function will generate a breakpoint exception.  It is used at the
972    beginning of a program to sync up with a debugger and can be used
973    otherwise as a quick means to stop program execution and "break" into
974    the debugger. */
975    
976 void breakpoint()
977 {
978   if (initialized) BREAKPOINT();
979 }
980
This page took 0.076652 seconds and 4 git commands to generate.