1 unsigned long sp_ptr;
2 unsigned long pc_ptr;
3 int cnt;
4 #define UNWIND asm ("movel %/sp, %0" : "=g" (sp_ptr));\
5     printf ("\n\t\t== Starting at 0x%x ==\n", sp_ptr);\
6     for (cnt=4; cnt <=32; cnt+=4) {\
7       printf ("+%d(0x%x): 0x%x\t\t-%d(0x%x): 0x%x\n",\
8 	      cnt, (sp_ptr + cnt), *(unsigned long *)(sp_ptr + cnt),\
9 	      cnt, (sp_ptr - cnt), *(unsigned long *)(sp_ptr - cnt)\
10 	      ); }; fflush (stdout);
11 
12 /****************************************************************************
13 
14 		THIS SOFTWARE IS NOT COPYRIGHTED
15 
16    HP offers the following for use in the public domain.  HP makes no
17    warranty with regard to the software or it's performance and the
18    user accepts the software "AS IS" with all faults.
19 
20    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
21    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 
24 ****************************************************************************/
25 
26 /****************************************************************************
27  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
28  *
29  *  Module name: remcom.c $
30  *  Revision: 1.34 $
31  *  Date: 91/03/09 12:29:49 $
32  *  Contributor:     Lake Stevens Instrument Division$
33  *
34  *  Description:     low level support for gdb debugger. $
35  *
36  *  Considerations:  only works on target hardware $
37  *
38  *  Written by:      Glenn Engel $
39  *  ModuleState:     Experimental $
40  *
41  *  NOTES:           See Below $
42  *
43  *  To enable debugger support, two things need to happen.  One, a
44  *  call to set_debug_traps() is necessary in order to allow any breakpoints
45  *  or error conditions to be properly intercepted and reported to gdb.
46  *  Two, a breakpoint needs to be generated to begin communication.  This
47  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
48  *  simulates a breakpoint by executing a trap #1.
49  *
50  *  Some explanation is probably necessary to explain how exceptions are
51  *  handled.  When an exception is encountered the 68000 pushes the current
52  *  program counter and status register onto the supervisor stack and then
53  *  transfers execution to a location specified in it's vector table.
54  *  The handlers for the exception vectors are hardwired to jmp to an address
55  *  given by the relation:  (exception - 256) * 6.  These are decending
56  *  addresses starting from -6, -12, -18, ...  By allowing 6 bytes for
57  *  each entry, a jsr, jmp, bsr, ... can be used to enter the exception
58  *  handler.  Using a jsr to handle an exception has an added benefit of
59  *  allowing a single handler to service several exceptions and use the
60  *  return address as the key differentiation.  The vector number can be
61  *  computed from the return address by [ exception = (addr + 1530) / 6 ].
62  *  The sole purpose of the routine _catchException is to compute the
63  *  exception number and push it on the stack in place of the return address.
64  *  The external function exceptionHandler() is
65  *  used to attach a specific handler to a specific 68k exception.
66  *  For 68020 machines, the ability to have a return address around just
67  *  so the vector can be determined is not necessary because the '020 pushes an
68  *  extra word onto the stack containing the vector offset
69  *
70  *  Because gdb will sometimes write to the stack area to execute function
71  *  calls, this program cannot rely on using the supervisor stack so it
72  *  uses it's own stack area reserved in the int array remcomStack.
73  *
74  *************
75  *
76  *    The following gdb commands are supported:
77  *
78  * command          function                               Return value
79  *
80  *    g             return the value of the CPU registers  hex data or ENN
81  *    G             set the value of the CPU registers     OK or ENN
82  *
83  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
84  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
85  *
86  *    c             Resume at current address              SNN   ( signal NN)
87  *    cAA..AA       Continue at address AA..AA             SNN
88  *
89  *    s             Step one instruction                   SNN
90  *    sAA..AA       Step one instruction from AA..AA       SNN
91  *
92  *    k             kill
93  *
94  *    ?             What was the last sigval ?             SNN   (signal NN)
95  *
96  * All commands and responses are sent with a packet which includes a
97  * checksum.  A packet consists of
98  *
99  * $<packet info>#<checksum>.
100  *
101  * where
102  * <packet info> :: <characters representing the command or response>
103  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
104  *
105  * When a packet is received, it is first acknowledged with either '+' or '-'.
106  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
107  *
108  * Example:
109  *
110  * Host:                  Reply:
111  * $m0,10#2a               +$00010203040506070809101112131415#42
112  *
113  ****************************************************************************/
114 
115 #include <stdio.h>
116 #include <string.h>
117 #include <setjmp.h>
118 #include <_ansi.h>
119 
120 /************************************************************************
121  *
122  * external low-level support routines
123  */
124 typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
125 typedef void (*Function)();           /* pointer to a function */
126 
127 extern int  putDebugChar();   /* write a single character      */
128 extern char getDebugChar();   /* read and return a single char */
129 
130 ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
131 
132 /************************/
133 /* FORWARD DECLARATIONS */
134 /************************/
135 /** static void initializeRemcomErrorFrame PARAMS ((void)); **/
136 static void _DEFUN_VOID (initializeRemcomErrorFrame);
137 
138 /************************************************************************/
139 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
140 /* at least NUMREGBYTES*2 are needed for register packets */
141 #define BUFMAX 400
142 
143 static char initialized;  /* boolean flag. != 0 means we've been initialized */
144 
145 int     remote_debug = 0; /*** Robs Thu Sep 24 22:18:51 PDT 1992 ***/
146 /*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
147 
148 static const char hexchars[]="0123456789abcdef";
149 
150 /* there are 180 bytes of registers on a 68020 w/68881      */
151 /* many of the fpa registers are 12 byte (96 bit) registers */
152 #define NUMREGBYTES 180
153 enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
154                A0,A1,A2,A3,A4,A5,A6,A7,
155                PS,PC,
156                FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
157                FPCONTROL,FPSTATUS,FPIADDR
158               };
159 
160 typedef struct FrameStruct
161 {
162     struct FrameStruct  *previous;
163     int       exceptionPC;      /* pc value when this frame created */
164     int       exceptionVector;  /* cpu vector causing exception     */
165     short     frameSize;        /* size of cpu frame in words       */
166     short     sr;               /* for 68000, this not always sr    */
167     int       pc;
168     short     format;
169     int       fsaveHeader;
170     int       morejunk[0];        /* exception frame, fp save... */
171 } Frame;
172 
173 #define FRAMESIZE 500
174 int   gdbFrameStack[FRAMESIZE];
175 Frame *lastFrame;
176 
177 /*
178  * these should not be static cuz they can be used outside this module
179  */
180 int registers[NUMREGBYTES/4];
181 int superStack;
182 
183 #define STACKSIZE 10000
184 int remcomStack[STACKSIZE/sizeof(int)];
185 int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
186 
187 /*
188  * In many cases, the system will want to continue exception processing
189  * when a continue command is given.
190  * oldExceptionHook is a function to invoke in this case.
191  */
192 
193 static ExceptionHook oldExceptionHook;
194 
195 /* the size of the exception stack on the 68020 varies with the type of
196  * exception.  The following table is the number of WORDS used
197  * for each exception format.
198  */
199 const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
200 
201 /************* jump buffer used for setjmp/longjmp **************************/
202 jmp_buf remcomEnv;
203 
204 #define BREAKPOINT() asm("   trap #1");
205 
206 extern void _DEFUN_VOID (return_to_super);
207 extern void _DEFUN_VOID (return_to_user);
208 extern void _DEFUN_VOID (_catchException);
209 
_returnFromException(Frame * frame)210 void _returnFromException( Frame *frame )
211 {
212     /* if no passed in frame, use the last one */
213     if (! frame)
214     {
215         frame = lastFrame;
216 	frame->frameSize = 4;
217         frame->format = 0;
218         frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/
219     }
220 
221 #ifndef mc68020
222     /* a 68000 cannot use the internal info pushed onto a bus error
223      * or address error frame when doing an RTE so don't put this info
224      * onto the stack or the stack will creep every time this happens.
225      */
226     frame->frameSize=3;
227 #endif
228 
229     /* throw away any frames in the list after this frame */
230     lastFrame = frame;
231 
232     frame->sr = registers[(int) PS];
233     frame->pc = registers[(int) PC];
234 
235     if (registers[(int) PS] & 0x2000)
236     {
237         /* return to supervisor mode... */
238         return_to_super();
239     }
240     else
241     { /* return to user mode */
242         return_to_user();
243     }
244 }
245 
hex(ch)246 int hex(ch)
247 char ch;
248 {
249   if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
250   if ((ch >= '0') && (ch <= '9')) return (ch-'0');
251   if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
252   return (-1);
253 }
254 
255 
256 /* scan for the sequence $<data>#<checksum>     */
getpacket(buffer)257 void getpacket(buffer)
258 char * buffer;
259 {
260   unsigned char checksum;
261   unsigned char xmitcsum;
262   int  i;
263   int  count;
264   char ch;
265 
266   if (remote_debug) {
267     printf("\nGETPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
268 	   registers[ PS ],
269 	   registers[ PC ],
270 	   registers[ A7 ]
271 	   ); fflush (stdout);
272     UNWIND
273   }
274 
275   do {
276     /* wait around for the start character, ignore all other characters */
277     while ((ch = getDebugChar()) != '$');
278      checksum = 0;
279     xmitcsum = -1;
280 
281     count = 0;
282 
283     /* now, read until a # or end of buffer is found */
284     while (count < BUFMAX) {
285       ch = getDebugChar();
286       if (ch == '#') break;
287       checksum = checksum + ch;
288       buffer[count] = ch;
289       count = count + 1;
290       }
291     buffer[count] = 0;
292 
293     if (ch == '#') {
294       xmitcsum = hex(getDebugChar()) << 4;
295       xmitcsum += hex(getDebugChar());
296       if ((remote_debug ) && (checksum != xmitcsum)) {
297         fprintf(stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
298 						     checksum,xmitcsum,buffer);
299       }
300 
301       if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
302       else {
303 	 putDebugChar('+');  /* successful transfer */
304 	 /* if a sequence char is present, reply the sequence ID */
305 	 if (buffer[2] == ':') {
306 	    putDebugChar( buffer[0] );
307 	    putDebugChar( buffer[1] );
308 	    /* remove sequence chars from buffer */
309 	    count = strlen(buffer);
310 	    for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
311 	 }
312       }
313     }
314   } while (checksum != xmitcsum);
315 
316 }
317 
318 /* send the packet in buffer.  The host get's one chance to read it.
319    This routine does not wait for a positive acknowledge.  */
320 
putpacket(buffer)321 void putpacket(buffer)
322 char * buffer;
323 {
324   unsigned char checksum;
325   int  count;
326   char ch;
327 
328   /*  $<packet info>#<checksum>. */
329   /***  do {***/
330   putDebugChar('$');
331   checksum = 0;
332   count    = 0;
333 
334   while (ch=buffer[count]) {
335     if (! putDebugChar(ch)) return;
336     checksum += ch;
337     count += 1;
338   }
339 
340   putDebugChar('#');
341   putDebugChar(hexchars[checksum >> 4]);
342   putDebugChar(hexchars[checksum % 16]);
343 
344   if (remote_debug) {
345     printf("\nPUTPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
346 	   registers[ PS ],
347 	   registers[ PC ],
348 	   registers[ A7 ]
349 	   ); fflush (stdout);
350     UNWIND
351   }
352 
353 /*** } while (getDebugChar() != '+'); ***/
354 /** } while (1 == 0);  (getDebugChar() != '+'); **/
355 
356 }
357 
358 char  remcomInBuffer[BUFMAX];
359 char  remcomOutBuffer[BUFMAX];
360 static short error;
361 
362 
debug_error(format,parm)363 void debug_error(format, parm)
364 char * format;
365 char * parm;
366 {
367   if (remote_debug) fprintf(stderr,format,parm);
368 }
369 
370 /* convert the memory pointed to by mem into hex, placing result in buf */
371 /* return a pointer to the last char put in buf (null) */
mem2hex(mem,buf,count)372 char* mem2hex(mem, buf, count)
373 char* mem;
374 char* buf;
375 int   count;
376 {
377       int i;
378       unsigned char ch;
379       for (i=0;i<count;i++) {
380           ch = *mem++;
381           *buf++ = hexchars[ch >> 4];
382           *buf++ = hexchars[ch % 16];
383       }
384       *buf = 0;
385       return(buf);
386 }
387 
388 /* convert the hex array pointed to by buf into binary to be placed in mem */
389 /* return a pointer to the character AFTER the last byte written */
hex2mem(buf,mem,count)390 char* hex2mem(buf, mem, count)
391 char* buf;
392 char* mem;
393 int   count;
394 {
395       int i;
396       unsigned char ch;
397       for (i=0;i<count;i++) {
398           ch = hex(*buf++) << 4;
399           ch = ch + hex(*buf++);
400           *mem++ = ch;
401       }
402       return(mem);
403 }
404 
405 /* a bus error has occurred, perform a longjmp
406    to return execution and allow handling of the error */
407 
handle_buserror()408 void handle_buserror()
409 {
410   longjmp(remcomEnv,1);
411 }
412 
413 /* this function takes the 68000 exception number and attempts to
414    translate this number into a unix compatible signal value */
computeSignal(exceptionVector)415 int computeSignal( exceptionVector )
416 int exceptionVector;
417 {
418   int sigval;
419   switch (exceptionVector) {
420     case 2 : sigval = 10; break; /* bus error           */
421     case 3 : sigval = 10; break; /* address error       */
422     case 4 : sigval = 4;  break; /* illegal instruction */
423     case 5 : sigval = 8;  break; /* zero divide         */
424     case 6 : sigval = 16; break; /* chk instruction     */
425     case 7 : sigval = 16; break; /* trapv instruction   */
426     case 8 : sigval = 11; break; /* privilege violation */
427     case 9 : sigval = 5;  break; /* trace trap          */
428     case 10: sigval = 4;  break; /* line 1010 emulator  */
429     case 11: sigval = 4;  break; /* line 1111 emulator  */
430     case 13: sigval = 8;  break; /* floating point err  */
431     case 31: sigval = 2;  break; /* interrupt           */
432     case 33: sigval = 5;  break; /* breakpoint          */
433     case 40: sigval = 8;  break; /* floating point err  */
434     case 48: sigval = 8;  break; /* floating point err  */
435     case 49: sigval = 8;  break; /* floating point err  */
436     case 50: sigval = 8;  break; /* zero divide         */
437     case 51: sigval = 8;  break; /* underflow           */
438     case 52: sigval = 8;  break; /* operand error       */
439     case 53: sigval = 8;  break; /* overflow            */
440     case 54: sigval = 8;  break; /* NAN                 */
441     default:
442       sigval = 7;         /* "software generated"*/
443   }
444   return (sigval);
445 }
446 
447 /**********************************************/
448 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
449 /* RETURN NUMBER OF CHARS PROCESSED           */
450 /**********************************************/
hexToInt(char ** ptr,int * intValue)451 int hexToInt(char **ptr, int *intValue)
452 {
453     int numChars = 0;
454     int hexValue;
455 
456     *intValue = 0;
457 
458     while (**ptr)
459     {
460         hexValue = hex(**ptr);
461         if (hexValue >=0)
462         {
463             *intValue = (*intValue <<4) | hexValue;
464             numChars ++;
465         }
466         else
467             break;
468 
469         (*ptr)++;
470     }
471 
472     return (numChars);
473 }
474 
475 /*
476  * This function does all command procesing for interfacing to gdb.
477  */
handle_exception(int exceptionVector)478 void handle_exception(int exceptionVector)
479 {
480   int    sigval;
481   int    addr, length;
482   char * ptr;
483   int    newPC;
484   Frame  *frame;
485 
486   if (remote_debug)    printf("\nHANDLE_EXCEPTION: vector=%d, sr=0x%x, pc=0x%x, sp=0x%x\n",
487 			    exceptionVector,
488 			    registers[ PS ],
489 			    registers[ PC ],
490 			    registers[ A7 ]
491 			      ); fflush (stdout);
492 
493   /* reply to host that an exception has occurred */
494   sigval = computeSignal( exceptionVector );
495   remcomOutBuffer[0] = 'S';
496   remcomOutBuffer[1] =  hexchars[sigval >> 4];
497   remcomOutBuffer[2] =  hexchars[sigval % 16];
498   remcomOutBuffer[3] = 0;
499 
500   putpacket(remcomOutBuffer);
501 
502   while (1==1) {
503     error = 0;
504     remcomOutBuffer[0] = 0;
505     getpacket(remcomInBuffer);
506     switch (remcomInBuffer[0]) {
507       case '?' :   remcomOutBuffer[0] = 'S';
508                    remcomOutBuffer[1] =  hexchars[sigval >> 4];
509                    remcomOutBuffer[2] =  hexchars[sigval % 16];
510                    remcomOutBuffer[3] = 0;
511                  break;
512       case 'd' : remote_debug = !(remote_debug);  /* toggle debug flag */
513                  break;
514       case 'g' : /* return the value of the CPU registers */
515                 mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES);
516                 break;
517       case 'G' : /* set the value of the CPU registers - return OK */
518                 hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES);
519                 strcpy(remcomOutBuffer,"OK");
520                 break;
521 
522       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
523       case 'm' :
524 	        if (setjmp(remcomEnv) == 0)
525                 {
526                     exceptionHandler(2,handle_buserror);
527 
528 		    /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
529                     ptr = &remcomInBuffer[1];
530                     if (hexToInt(&ptr,&addr))
531                         if (*(ptr++) == ',')
532                             if (hexToInt(&ptr,&length))
533                             {
534                                 ptr = 0;
535                                 mem2hex((char*) addr, remcomOutBuffer, length);
536                             }
537 
538                     if (ptr)
539                     {
540 		      strcpy(remcomOutBuffer,"E01");
541 		      debug_error("malformed read memory command: %s",remcomInBuffer);
542                   }
543                 }
544 		else {
545 		  exceptionHandler(2,_catchException);
546 		  strcpy(remcomOutBuffer,"E03");
547 		  debug_error("bus error");
548 		  }
549 
550 		/* restore handler for bus error */
551 		exceptionHandler(2,_catchException);
552 		break;
553 
554       /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
555       case 'M' :
556 	        if (setjmp(remcomEnv) == 0) {
557 		    exceptionHandler(2,handle_buserror);
558 
559 		    /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
560                     ptr = &remcomInBuffer[1];
561                     if (hexToInt(&ptr,&addr))
562                         if (*(ptr++) == ',')
563                             if (hexToInt(&ptr,&length))
564                                 if (*(ptr++) == ':')
565                                 {
566                                     hex2mem(ptr, (char*) addr, length);
567                                     ptr = 0;
568                                     strcpy(remcomOutBuffer,"OK");
569                                 }
570                     if (ptr)
571                     {
572 		      strcpy(remcomOutBuffer,"E02");
573 		      debug_error("malformed write memory command: %s",remcomInBuffer);
574 		      }
575                 }
576 		else {
577 		  exceptionHandler(2,_catchException);
578 		  strcpy(remcomOutBuffer,"E03");
579 		  debug_error("bus error");
580 		  }
581 
582                 /* restore handler for bus error */
583                 exceptionHandler(2,_catchException);
584                 break;
585 
586      /* cAA..AA    Continue at address AA..AA(optional) */
587      /* sAA..AA   Step one instruction from AA..AA(optional) */
588      case 'c' :
589      case 's' :
590           /* try to read optional parameter, pc unchanged if no parm */
591          ptr = &remcomInBuffer[1];
592          if (hexToInt(&ptr,&addr))
593              registers[ PC ] = addr;
594 
595           newPC = registers[ PC];
596 
597           /* clear the trace bit */
598           registers[ PS ] &= 0x7fff;
599 
600           /* set the trace bit if we're stepping */
601           if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000;
602 
603           /*
604            * look for newPC in the linked list of exception frames.
605            * if it is found, use the old frame it.  otherwise,
606            * fake up a dummy frame in returnFromException().
607            */
608           if (remote_debug) printf("new pc = 0x%x\n",newPC);
609           frame = lastFrame;
610           while (frame)
611           {
612               if (remote_debug)
613                   printf("frame at 0x%x has pc=0x%x, except#=%d\n",
614                          frame,frame->exceptionPC,
615                          frame->exceptionVector);
616               if (frame->exceptionPC == newPC) break;  /* bingo! a match */
617               /*
618                * for a breakpoint instruction, the saved pc may
619                * be off by two due to re-executing the instruction
620                * replaced by the trap instruction.  Check for this.
621                */
622               if ((frame->exceptionVector == 33) &&
623                   (frame->exceptionPC == (newPC+2))) break;
624               if (frame == frame->previous)
625 	      {
626 	          frame = 0; /* no match found */
627 	          break;
628 	      }
629 	      frame = frame->previous;
630           }
631 
632           /*
633            * If we found a match for the PC AND we are not returning
634            * as a result of a breakpoint (33),
635            * trace exception (9), nmi (31), jmp to
636            * the old exception handler as if this code never ran.
637            */
638           if (frame)
639           {
640               if ((frame->exceptionVector != 9)  &&
641                   (frame->exceptionVector != 31) &&
642                   (frame->exceptionVector != 33))
643               {
644                   /*
645                    * invoke the previous handler.
646                    */
647                   if (oldExceptionHook)
648                       (*oldExceptionHook) (frame->exceptionVector);
649                   newPC = registers[ PC ];    /* pc may have changed  */
650                   if (newPC != frame->exceptionPC)
651                   {
652                       if (remote_debug)
653                           printf("frame at 0x%x has pc=0x%x, except#=%d\n",
654                                  frame,frame->exceptionPC,
655                                  frame->exceptionVector);
656                       /* re-use the last frame, we're skipping it (longjump?)*/
657 		      frame = (Frame *) 0;
658 	              _returnFromException( frame );  /* this is a jump */
659                   }
660               }
661           }
662 
663     	  /* if we couldn't find a frame, create one */
664           if (frame == 0)
665 	  {
666     	      frame = lastFrame -1 ;
667 
668 	      /* by using a bunch of print commands with breakpoints,
669     	         it's possible for the frame stack to creep down.  If it creeps
670 		 too far, give up and reset it to the top.  Normal use should
671     	         not see this happen.
672     	      */
673 	      if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack)
674     	      {
675     	         initializeRemcomErrorFrame();
676     	         frame = lastFrame;
677 	      }
678     	      frame->previous = lastFrame;
679               lastFrame = frame;
680               frame = 0;  /* null so _return... will properly initialize it */
681 	  }
682 
683 	  _returnFromException( frame ); /* this is a jump */
684 
685           break;
686 
687       /* kill the program */
688       case 'k' :  /* do nothing */
689                 break;
690       } /* switch */
691 
692     /* reply to the request */
693     putpacket(remcomOutBuffer);
694     }
695 }
696 
697 
initializeRemcomErrorFrame()698 void initializeRemcomErrorFrame()
699 {
700     lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
701     lastFrame->previous = lastFrame;
702 }
703 
704 /* this function is used to set up exception handlers for tracing and
705    breakpoints */
set_debug_traps()706 void set_debug_traps()
707 {
708 extern void _debug_level7();
709 extern void remcomHandler();
710 int exception;
711 
712   initializeRemcomErrorFrame();
713   stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
714 
715   setup_vectors();
716 
717   if (oldExceptionHook != remcomHandler)
718   {
719       oldExceptionHook = exceptionHook;
720       exceptionHook    = remcomHandler;
721   }
722 
723   initialized = 1;
724 
725 }
726 /* This function will generate a breakpoint exception.  It is used at the
727    beginning of a program to sync up with a debugger and can be used
728    otherwise as a quick means to stop program execution and "break" into
729    the debugger. */
730 
breakpoint()731 void breakpoint()
732 {
733   if (initialized) BREAKPOINT();
734 }
735