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