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 descending
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 */
116typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
117typedef void (*Function)();           /* pointer to a function */
118
119extern void putDebugChar();	/* write a single character      */
120extern int getDebugChar();	/* read and return a single char */
121
122extern Function exceptionHandler();  /* assign an exception handler */
123extern ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
124
125/************************/
126/* FORWARD DECLARATIONS */
127/************************/
128static void
129initializeRemcomErrorFrame ();
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
136static char initialized;  /* boolean flag. != 0 means we've been initialized */
137
138int     remote_debug;
139/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
140
141static 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
146enum 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
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
162typedef 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
176int   gdbFrameStack[FRAMESIZE];
177static Frame *lastFrame;
178
179/*
180 * these should not be static cuz they can be used outside this module
181 */
182int registers[NUMREGBYTES/4];
183int superStack;
184
185#define STACKSIZE 10000
186int remcomStack[STACKSIZE/sizeof(int)];
187static 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
195static ExceptionHook oldExceptionHook;
196
197#ifdef mc68020
198/* the size of the exception stack on the 68020 varies with the type of
199 * exception.  The following table is the number of WORDS used
200 * for each exception format.
201 */
202const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
203#endif
204
205#ifdef mc68332
206static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 };
207#endif
208
209/************* jump buffer used for setjmp/longjmp **************************/
210jmp_buf remcomEnv;
211
212/***************************  ASSEMBLY CODE MACROS *************************/
213/* 									   */
214
215#ifdef __HAVE_68881__
216/* do an fsave, then remember the address to begin a restore from */
217#define SAVE_FP_REGS()    asm(" fsave   a0@-");		\
218			  asm(" fmovemx fp0-fp7,_registers+72");        \
219			  asm(" fmoveml fpcr/fpsr/fpi,_registers+168");
220#define RESTORE_FP_REGS()                              \
221asm("                                                \n\
222    fmoveml  _registers+168,fpcr/fpsr/fpi            \n\
223    fmovemx  _registers+72,fp0-fp7                   \n\
224    cmpl     #-1,a0@     |  skip frestore flag set ? \n\
225    beq      skip_frestore                           \n\
226    frestore a0@+                                    \n\
227skip_frestore:                                       \n\
228");
229
230#else
231#define SAVE_FP_REGS()
232#define RESTORE_FP_REGS()
233#endif /* __HAVE_68881__ */
234
235void return_to_super();
236void return_to_user();
237
238asm("
239.text
240.globl _return_to_super
241_return_to_super:
242        movel   _registers+60,sp /* get new stack pointer */
243        movel   _lastFrame,a0   /* get last frame info  */
244        bra     return_to_any
245
246.globl _return_to_user
247_return_to_user:
248        movel   _registers+60,a0 /* get usp */
249        movel   a0,usp           /* set usp */
250        movel   _superStack,sp  /* get original stack pointer */
251
252return_to_any:
253        movel   _lastFrame,a0   /* get last frame info  */
254        movel   a0@+,_lastFrame /* link in previous frame     */
255        addql   #8,a0           /* skip over pc, vector#*/
256        movew   a0@+,d0         /* get # of words in cpu frame */
257        addw    d0,a0           /* point to end of data        */
258        addw    d0,a0           /* point to end of data        */
259        movel   a0,a1
260#
261# copy the stack frame
262        subql   #1,d0
263copyUserLoop:
264        movew   a1@-,sp@-
265        dbf     d0,copyUserLoop
266");
267        RESTORE_FP_REGS()
268   asm("   moveml  _registers,d0-d7/a0-a6");
269   asm("   rte");  /* pop and go! */
270
271#define DISABLE_INTERRUPTS()   asm("         oriw   #0x0700,sr");
272#define BREAKPOINT() asm("   trap #1");
273
274/* this function is called immediately when a level 7 interrupt occurs */
275/* if the previous interrupt level was 7 then we're already servicing  */
276/* this interrupt and an rte is in order to return to the debugger.    */
277/* For the 68000, the offset for sr is 6 due to the jsr return address */
278asm("
279.text
280.globl __debug_level7
281__debug_level7:
282	movew   d0,sp@-");
283#if defined (mc68020) || defined (mc68332)
284asm("	movew   sp@(2),d0");
285#else
286asm("	movew   sp@(6),d0");
287#endif
288asm("	andiw   #0x700,d0
289	cmpiw   #0x700,d0
290	beq     _already7
291        movew   sp@+,d0
292        bra     __catchException
293_already7:
294	movew   sp@+,d0");
295#if !defined (mc68020) && !defined (mc68332)
296asm("	lea     sp@(4),sp");     /* pull off 68000 return address */
297#endif
298asm("	rte");
299
300extern void _catchException ();
301
302#if defined (mc68020) || defined (mc68332)
303/* This function is called when a 68020 exception occurs.  It saves
304 * all the cpu and fpcp regs in the _registers array, creates a frame on a
305 * linked list of frames which has the cpu and fpcp stack frames needed
306 * to properly restore the context of these processors, and invokes
307 * an exception handler (remcom_handler).
308 *
309 * stack on entry:                       stack on exit:
310 *   N bytes of junk                     exception # MSWord
311 *   Exception Format Word               exception # MSWord
312 *   Program counter LSWord
313 *   Program counter MSWord
314 *   Status Register
315 *
316 *
317 */
318asm("
319.text
320.globl __catchException
321__catchException:");
322DISABLE_INTERRUPTS();
323asm("
324        moveml  d0-d7/a0-a6,_registers /* save registers        */
325	movel	_lastFrame,a0	/* last frame pointer */
326");
327SAVE_FP_REGS();
328asm("
329	lea     _registers,a5   /* get address of registers     */
330        movew   sp@,d1          /* get status register          */
331        movew   d1,a5@(66)      /* save sr		 	*/
332	movel   sp@(2),a4       /* save pc in a4 for later use  */
333        movel   a4,a5@(68)      /* save pc in _regisers[]      	*/
334
335#
336# figure out how many bytes in the stack frame
337	movew   sp@(6),d0	/* get '020 exception format	*/
338        movew   d0,d2           /* make a copy of format word   */
339        andiw   #0xf000,d0      /* mask off format type         */
340        rolw    #5,d0           /* rotate into the low byte *2  */
341        lea     _exceptionSize,a1
342        addw    d0,a1           /* index into the table         */
343	movew   a1@,d0          /* get number of words in frame */
344        movew   d0,d3           /* save it                      */
345        subw    d0,a0		/* adjust save pointer          */
346        subw    d0,a0		/* adjust save pointer(bytes)   */
347	movel   a0,a1           /* copy save pointer            */
348	subql   #1,d0           /* predecrement loop counter    */
349#
350# copy the frame
351saveFrameLoop:
352	movew  	sp@+,a1@+
353	dbf     d0,saveFrameLoop
354#
355# now that the stack has been clenaed,
356# save the a7 in use at time of exception
357        movel   sp,_superStack  /* save supervisor sp           */
358        andiw   #0x2000,d1      /* were we in supervisor mode ? */
359        beq     userMode
360        movel   a7,a5@(60)      /* save a7                  */
361        bra     a7saveDone
362userMode:
363	movel   usp,a1
364        movel   a1,a5@(60)      /* save user stack pointer	*/
365a7saveDone:
366
367#
368# save size of frame
369        movew   d3,a0@-
370
371#
372# compute exception number
373	andl    #0xfff,d2   	/* mask off vector offset	*/
374	lsrw    #2,d2   	/* divide by 4 to get vect num	*/
375        movel   d2,a0@-         /* save it                      */
376#
377# save pc causing exception
378        movel   a4,a0@-
379#
380# save old frame link and set the new value
381	movel	_lastFrame,a1	/* last frame pointer */
382	movel   a1,a0@-		/* save pointer to prev frame	*/
383        movel   a0,_lastFrame
384
385        movel   d2,sp@-		/* push exception num           */
386	movel   _exceptionHook,a0  /* get address of handler */
387        jbsr    a0@             /* and call it */
388        clrl    sp@             /* replace exception num parm with frame ptr */
389        jbsr     __returnFromException   /* jbsr, but never returns */
390");
391#else /* mc68000 */
392/* This function is called when an exception occurs.  It translates the
393 * return address found on the stack into an exception vector # which
394 * is then handled by either handle_exception or a system handler.
395 * _catchException provides a front end for both.
396 *
397 * stack on entry:                       stack on exit:
398 *   Program counter MSWord              exception # MSWord
399 *   Program counter LSWord              exception # MSWord
400 *   Status Register
401 *   Return Address  MSWord
402 *   Return Address  LSWord
403 */
404asm("
405.text
406.globl __catchException
407__catchException:");
408DISABLE_INTERRUPTS();
409asm("
410        moveml d0-d7/a0-a6,_registers  /* save registers               */
411	movel	_lastFrame,a0	/* last frame pointer */
412");
413SAVE_FP_REGS();
414asm("
415        lea     _registers,a5   /* get address of registers     */
416        movel   sp@+,d2         /* pop return address           */
417	addl 	#1530,d2        /* convert return addr to 	*/
418	divs 	#6,d2   	/*  exception number		*/
419	extl    d2
420
421        moveql  #3,d3           /* assume a three word frame     */
422
423        cmpiw   #3,d2           /* bus error or address error ? */
424        bgt     normal          /* if >3 then normal error      */
425        movel   sp@+,a0@-       /* copy error info to frame buff*/
426        movel   sp@+,a0@-       /* these are never used         */
427        moveql  #7,d3           /* this is a 7 word frame       */
428
429normal:
430	movew   sp@+,d1         /* pop status register          */
431        movel   sp@+,a4         /* pop program counter          */
432        movew   d1,a5@(66)      /* save sr		 	*/
433        movel   a4,a5@(68)      /* save pc in _regisers[]      	*/
434        movel   a4,a0@-         /* copy pc to frame buffer      */
435	movew   d1,a0@-         /* copy sr to frame buffer      */
436
437        movel   sp,_superStack  /* save supervisor sp          */
438
439        andiw   #0x2000,d1      /* were we in supervisor mode ? */
440        beq     userMode
441        movel   a7,a5@(60)      /* save a7                  */
442        bra     saveDone
443userMode:
444        movel   usp,a1    	/* save user stack pointer 	*/
445        movel   a1,a5@(60)      /* save user stack pointer	*/
446saveDone:
447
448        movew   d3,a0@-         /* push frame size in words     */
449        movel   d2,a0@-         /* push vector number           */
450        movel   a4,a0@-         /* push exception pc            */
451
452#
453# save old frame link and set the new value
454	movel	_lastFrame,a1	/* last frame pointer */
455	movel   a1,a0@-		/* save pointer to prev frame	*/
456        movel   a0,_lastFrame
457
458        movel   d2,sp@-		/* push exception num           */
459	movel   _exceptionHook,a0  /* get address of handler */
460        jbsr    a0@             /* and call it */
461        clrl    sp@             /* replace exception num parm with frame ptr */
462        jbsr     __returnFromException   /* jbsr, but never returns */
463");
464#endif
465
466
467/*
468 * remcomHandler is a front end for handle_exception.  It moves the
469 * stack pointer into an area reserved for debugger use in case the
470 * breakpoint happened in supervisor mode.
471 */
472asm("_remcomHandler:");
473asm("           addl    #4,sp");        /* pop off return address     */
474asm("           movel   sp@+,d0");      /* get the exception number   */
475asm("		movel   _stackPtr,sp"); /* move to remcom stack area  */
476asm("		movel   d0,sp@-");	/* push exception onto stack  */
477asm("		jbsr    _handle_exception");    /* this never returns */
478asm("           rts");                  /* return */
479
480void
481_returnFromException (Frame * frame)
482{
483  /* if no passed in frame, use the last one */
484  if (!frame)
485    {
486      frame = lastFrame;
487      frame->frameSize = 4;
488      frame->format = 0;
489      frame->fsaveHeader = -1;	/* restore regs, but we dont have fsave info */
490    }
491
492#if !defined (mc68020) && !defined (mc68332)
493  /* a 68000 cannot use the internal info pushed onto a bus error
494   * or address error frame when doing an RTE so don't put this info
495   * onto the stack or the stack will creep every time this happens.
496   */
497  frame->frameSize = 3;
498#endif
499
500  /* throw away any frames in the list after this frame */
501  lastFrame = frame;
502
503  frame->sr = registers[(int) PS];
504  frame->pc = registers[(int) PC];
505
506  if (registers[(int) PS] & 0x2000)
507    {
508      /* return to supervisor mode... */
509      return_to_super ();
510    }
511  else
512    {				/* return to user mode */
513      return_to_user ();
514    }
515}
516
517int
518hex (ch)
519     char ch;
520{
521  if ((ch >= 'a') && (ch <= 'f'))
522    return (ch - 'a' + 10);
523  if ((ch >= '0') && (ch <= '9'))
524    return (ch - '0');
525  if ((ch >= 'A') && (ch <= 'F'))
526    return (ch - 'A' + 10);
527  return (-1);
528}
529
530static char remcomInBuffer[BUFMAX];
531static char remcomOutBuffer[BUFMAX];
532
533/* scan for the sequence $<data>#<checksum>     */
534
535unsigned char *
536getpacket (void)
537{
538  unsigned char *buffer = &remcomInBuffer[0];
539  unsigned char checksum;
540  unsigned char xmitcsum;
541  int count;
542  char ch;
543
544  while (1)
545    {
546      /* wait around for the start character, ignore all other characters */
547      while ((ch = getDebugChar ()) != '$')
548	;
549
550    retry:
551      checksum = 0;
552      xmitcsum = -1;
553      count = 0;
554
555      /* now, read until a # or end of buffer is found */
556      while (count < BUFMAX - 1)
557	{
558	  ch = getDebugChar ();
559	  if (ch == '$')
560	    goto retry;
561	  if (ch == '#')
562	    break;
563	  checksum = checksum + ch;
564	  buffer[count] = ch;
565	  count = count + 1;
566	}
567      buffer[count] = 0;
568
569      if (ch == '#')
570	{
571	  ch = getDebugChar ();
572	  xmitcsum = hex (ch) << 4;
573	  ch = getDebugChar ();
574	  xmitcsum += hex (ch);
575
576	  if (checksum != xmitcsum)
577	    {
578	      if (remote_debug)
579		{
580		  fprintf (stderr,
581			   "bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
582			   checksum, xmitcsum, buffer);
583		}
584	      putDebugChar ('-');	/* failed checksum */
585	    }
586	  else
587	    {
588	      putDebugChar ('+');	/* successful transfer */
589
590	      /* if a sequence char is present, reply the sequence ID */
591	      if (buffer[2] == ':')
592		{
593		  putDebugChar (buffer[0]);
594		  putDebugChar (buffer[1]);
595
596		  return &buffer[3];
597		}
598
599	      return &buffer[0];
600	    }
601	}
602    }
603}
604
605/* send the packet in buffer. */
606
607void
608putpacket (buffer)
609     char *buffer;
610{
611  unsigned char checksum;
612  int count;
613  char ch;
614
615  /*  $<packet info>#<checksum>. */
616  do
617    {
618      putDebugChar ('$');
619      checksum = 0;
620      count = 0;
621
622      while (ch = buffer[count])
623	{
624	  putDebugChar (ch);
625	  checksum += ch;
626	  count += 1;
627	}
628
629      putDebugChar ('#');
630      putDebugChar (hexchars[checksum >> 4]);
631      putDebugChar (hexchars[checksum % 16]);
632
633    }
634  while (getDebugChar () != '+');
635
636}
637
638void
639debug_error (format, parm)
640     char *format;
641     char *parm;
642{
643  if (remote_debug)
644    fprintf (stderr, format, parm);
645}
646
647/* convert the memory pointed to by mem into hex, placing result in buf */
648/* return a pointer to the last char put in buf (null) */
649char *
650mem2hex (mem, buf, count)
651     char *mem;
652     char *buf;
653     int count;
654{
655  int i;
656  unsigned char ch;
657  for (i = 0; i < count; i++)
658    {
659      ch = *mem++;
660      *buf++ = hexchars[ch >> 4];
661      *buf++ = hexchars[ch % 16];
662    }
663  *buf = 0;
664  return (buf);
665}
666
667/* convert the hex array pointed to by buf into binary to be placed in mem */
668/* return a pointer to the character AFTER the last byte written */
669char *
670hex2mem (buf, mem, count)
671     char *buf;
672     char *mem;
673     int count;
674{
675  int i;
676  unsigned char ch;
677  for (i = 0; i < count; i++)
678    {
679      ch = hex (*buf++) << 4;
680      ch = ch + hex (*buf++);
681      *mem++ = ch;
682    }
683  return (mem);
684}
685
686/* a bus error has occurred, perform a longjmp
687   to return execution and allow handling of the error */
688
689void
690handle_buserror ()
691{
692  longjmp (remcomEnv, 1);
693}
694
695/* this function takes the 68000 exception number and attempts to
696   translate this number into a unix compatible signal value */
697int
698computeSignal (exceptionVector)
699     int exceptionVector;
700{
701  int sigval;
702  switch (exceptionVector)
703    {
704    case 2:
705      sigval = 10;
706      break;			/* bus error           */
707    case 3:
708      sigval = 10;
709      break;			/* address error       */
710    case 4:
711      sigval = 4;
712      break;			/* illegal instruction */
713    case 5:
714      sigval = 8;
715      break;			/* zero divide         */
716    case 6:
717      sigval = 8;
718      break;			/* chk instruction     */
719    case 7:
720      sigval = 8;
721      break;			/* trapv instruction   */
722    case 8:
723      sigval = 11;
724      break;			/* privilege violation */
725    case 9:
726      sigval = 5;
727      break;			/* trace trap          */
728    case 10:
729      sigval = 4;
730      break;			/* line 1010 emulator  */
731    case 11:
732      sigval = 4;
733      break;			/* line 1111 emulator  */
734
735      /* Coprocessor protocol violation.  Using a standard MMU or FPU
736         this cannot be triggered by software.  Call it a SIGBUS.  */
737    case 13:
738      sigval = 10;
739      break;
740
741    case 31:
742      sigval = 2;
743      break;			/* interrupt           */
744    case 33:
745      sigval = 5;
746      break;			/* breakpoint          */
747
748      /* This is a trap #8 instruction.  Apparently it is someone's software
749         convention for some sort of SIGFPE condition.  Whose?  How many
750         people are being screwed by having this code the way it is?
751         Is there a clean solution?  */
752    case 40:
753      sigval = 8;
754      break;			/* floating point err  */
755
756    case 48:
757      sigval = 8;
758      break;			/* floating point err  */
759    case 49:
760      sigval = 8;
761      break;			/* floating point err  */
762    case 50:
763      sigval = 8;
764      break;			/* zero divide         */
765    case 51:
766      sigval = 8;
767      break;			/* underflow           */
768    case 52:
769      sigval = 8;
770      break;			/* operand error       */
771    case 53:
772      sigval = 8;
773      break;			/* overflow            */
774    case 54:
775      sigval = 8;
776      break;			/* NAN                 */
777    default:
778      sigval = 7;		/* "software generated" */
779    }
780  return (sigval);
781}
782
783/**********************************************/
784/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
785/* RETURN NUMBER OF CHARS PROCESSED           */
786/**********************************************/
787int
788hexToInt (char **ptr, int *intValue)
789{
790  int numChars = 0;
791  int hexValue;
792
793  *intValue = 0;
794
795  while (**ptr)
796    {
797      hexValue = hex (**ptr);
798      if (hexValue >= 0)
799	{
800	  *intValue = (*intValue << 4) | hexValue;
801	  numChars++;
802	}
803      else
804	break;
805
806      (*ptr)++;
807    }
808
809  return (numChars);
810}
811
812/*
813 * This function does all command procesing for interfacing to gdb.
814 */
815void
816handle_exception (int exceptionVector)
817{
818  int sigval, stepping;
819  int addr, length;
820  char *ptr;
821  int newPC;
822  Frame *frame;
823
824  if (remote_debug)
825    printf ("vector=%d, sr=0x%x, pc=0x%x\n",
826	    exceptionVector, registers[PS], registers[PC]);
827
828  /* reply to host that an exception has occurred */
829  sigval = computeSignal (exceptionVector);
830  remcomOutBuffer[0] = 'S';
831  remcomOutBuffer[1] = hexchars[sigval >> 4];
832  remcomOutBuffer[2] = hexchars[sigval % 16];
833  remcomOutBuffer[3] = 0;
834
835  putpacket (remcomOutBuffer);
836
837  stepping = 0;
838
839  while (1 == 1)
840    {
841      remcomOutBuffer[0] = 0;
842      ptr = getpacket ();
843      switch (*ptr++)
844	{
845	case '?':
846	  remcomOutBuffer[0] = 'S';
847	  remcomOutBuffer[1] = hexchars[sigval >> 4];
848	  remcomOutBuffer[2] = hexchars[sigval % 16];
849	  remcomOutBuffer[3] = 0;
850	  break;
851	case 'd':
852	  remote_debug = !(remote_debug);	/* toggle debug flag */
853	  break;
854	case 'g':		/* return the value of the CPU registers */
855	  mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES);
856	  break;
857	case 'G':		/* set the value of the CPU registers - return OK */
858	  hex2mem (ptr, (char *) registers, NUMREGBYTES);
859	  strcpy (remcomOutBuffer, "OK");
860	  break;
861
862	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
863	case 'm':
864	  if (setjmp (remcomEnv) == 0)
865	    {
866	      exceptionHandler (2, handle_buserror);
867
868	      /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
869	      if (hexToInt (&ptr, &addr))
870		if (*(ptr++) == ',')
871		  if (hexToInt (&ptr, &length))
872		    {
873		      ptr = 0;
874		      mem2hex ((char *) addr, remcomOutBuffer, length);
875		    }
876
877	      if (ptr)
878		{
879		  strcpy (remcomOutBuffer, "E01");
880		}
881	    }
882	  else
883	    {
884	      exceptionHandler (2, _catchException);
885	      strcpy (remcomOutBuffer, "E03");
886	      debug_error ("bus error");
887	    }
888
889	  /* restore handler for bus error */
890	  exceptionHandler (2, _catchException);
891	  break;
892
893	  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
894	case 'M':
895	  if (setjmp (remcomEnv) == 0)
896	    {
897	      exceptionHandler (2, handle_buserror);
898
899	      /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
900	      if (hexToInt (&ptr, &addr))
901		if (*(ptr++) == ',')
902		  if (hexToInt (&ptr, &length))
903		    if (*(ptr++) == ':')
904		      {
905			hex2mem (ptr, (char *) addr, length);
906			ptr = 0;
907			strcpy (remcomOutBuffer, "OK");
908		      }
909	      if (ptr)
910		{
911		  strcpy (remcomOutBuffer, "E02");
912		}
913	    }
914	  else
915	    {
916	      exceptionHandler (2, _catchException);
917	      strcpy (remcomOutBuffer, "E03");
918	      debug_error ("bus error");
919	    }
920
921	  /* restore handler for bus error */
922	  exceptionHandler (2, _catchException);
923	  break;
924
925	  /* cAA..AA    Continue at address AA..AA(optional) */
926	  /* sAA..AA   Step one instruction from AA..AA(optional) */
927	case 's':
928	  stepping = 1;
929	case 'c':
930	  /* try to read optional parameter, pc unchanged if no parm */
931	  if (hexToInt (&ptr, &addr))
932	    registers[PC] = addr;
933
934	  newPC = registers[PC];
935
936	  /* clear the trace bit */
937	  registers[PS] &= 0x7fff;
938
939	  /* set the trace bit if we're stepping */
940	  if (stepping)
941	    registers[PS] |= 0x8000;
942
943	  /*
944	   * look for newPC in the linked list of exception frames.
945	   * if it is found, use the old frame it.  otherwise,
946	   * fake up a dummy frame in returnFromException().
947	   */
948	  if (remote_debug)
949	    printf ("new pc = 0x%x\n", newPC);
950	  frame = lastFrame;
951	  while (frame)
952	    {
953	      if (remote_debug)
954		printf ("frame at 0x%x has pc=0x%x, except#=%d\n",
955			frame, frame->exceptionPC, frame->exceptionVector);
956	      if (frame->exceptionPC == newPC)
957		break;		/* bingo! a match */
958	      /*
959	       * for a breakpoint instruction, the saved pc may
960	       * be off by two due to re-executing the instruction
961	       * replaced by the trap instruction.  Check for this.
962	       */
963	      if ((frame->exceptionVector == 33) &&
964		  (frame->exceptionPC == (newPC + 2)))
965		break;
966	      if (frame == frame->previous)
967		{
968		  frame = 0;	/* no match found */
969		  break;
970		}
971	      frame = frame->previous;
972	    }
973
974	  /*
975	   * If we found a match for the PC AND we are not returning
976	   * as a result of a breakpoint (33),
977	   * trace exception (9), nmi (31), jmp to
978	   * the old exception handler as if this code never ran.
979	   */
980	  if (frame)
981	    {
982	      if ((frame->exceptionVector != 9) &&
983		  (frame->exceptionVector != 31) &&
984		  (frame->exceptionVector != 33))
985		{
986		  /*
987		   * invoke the previous handler.
988		   */
989		  if (oldExceptionHook)
990		    (*oldExceptionHook) (frame->exceptionVector);
991		  newPC = registers[PC];	/* pc may have changed  */
992		  if (newPC != frame->exceptionPC)
993		    {
994		      if (remote_debug)
995			printf ("frame at 0x%x has pc=0x%x, except#=%d\n",
996				frame, frame->exceptionPC,
997				frame->exceptionVector);
998		      /* re-use the last frame, we're skipping it (longjump?) */
999		      frame = (Frame *) 0;
1000		      _returnFromException (frame);	/* this is a jump */
1001		    }
1002		}
1003	    }
1004
1005	  /* if we couldn't find a frame, create one */
1006	  if (frame == 0)
1007	    {
1008	      frame = lastFrame - 1;
1009
1010	      /* by using a bunch of print commands with breakpoints,
1011	         it's possible for the frame stack to creep down.  If it creeps
1012	         too far, give up and reset it to the top.  Normal use should
1013	         not see this happen.
1014	       */
1015	      if ((unsigned int) (frame - 2) < (unsigned int) &gdbFrameStack)
1016		{
1017		  initializeRemcomErrorFrame ();
1018		  frame = lastFrame;
1019		}
1020	      frame->previous = lastFrame;
1021	      lastFrame = frame;
1022	      frame = 0;	/* null so _return... will properly initialize it */
1023	    }
1024
1025	  _returnFromException (frame);	/* this is a jump */
1026
1027	  break;
1028
1029	  /* kill the program */
1030	case 'k':		/* do nothing */
1031	  break;
1032	}			/* switch */
1033
1034      /* reply to the request */
1035      putpacket (remcomOutBuffer);
1036    }
1037}
1038
1039
1040void
1041initializeRemcomErrorFrame (void)
1042{
1043  lastFrame = ((Frame *) & gdbFrameStack[FRAMESIZE - 1]) - 1;
1044  lastFrame->previous = lastFrame;
1045}
1046
1047/* this function is used to set up exception handlers for tracing and
1048   breakpoints */
1049void
1050set_debug_traps ()
1051{
1052  extern void _debug_level7 ();
1053  extern void remcomHandler ();
1054  int exception;
1055
1056  initializeRemcomErrorFrame ();
1057  stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
1058
1059  for (exception = 2; exception <= 23; exception++)
1060    exceptionHandler (exception, _catchException);
1061
1062  /* level 7 interrupt              */
1063  exceptionHandler (31, _debug_level7);
1064
1065  /* breakpoint exception (trap #1) */
1066  exceptionHandler (33, _catchException);
1067
1068  /* This is a trap #8 instruction.  Apparently it is someone's software
1069     convention for some sort of SIGFPE condition.  Whose?  How many
1070     people are being screwed by having this code the way it is?
1071     Is there a clean solution?  */
1072  exceptionHandler (40, _catchException);
1073
1074  /* 48 to 54 are floating point coprocessor errors */
1075  for (exception = 48; exception <= 54; exception++)
1076    exceptionHandler (exception, _catchException);
1077
1078  if (oldExceptionHook != remcomHandler)
1079    {
1080      oldExceptionHook = exceptionHook;
1081      exceptionHook = remcomHandler;
1082    }
1083
1084  initialized = 1;
1085
1086}
1087
1088/* This function will generate a breakpoint exception.  It is used at the
1089   beginning of a program to sync up with a debugger and can be used
1090   otherwise as a quick means to stop program execution and "break" into
1091   the debugger. */
1092
1093void
1094breakpoint ()
1095{
1096  if (initialized)
1097    BREAKPOINT ();
1098}
1099