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 *  Modified for 386 by Jim Kingdon, Cygnus Support.
33 *
34 *  To enable debugger support, two things need to happen.  One, a
35 *  call to set_debug_traps() is necessary in order to allow any breakpoints
36 *  or error conditions to be properly intercepted and reported to gdb.
37 *  Two, a breakpoint needs to be generated to begin communication.  This
38 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
39 *  simulates a breakpoint by executing a trap #1.
40 *
41 *  The external function exceptionHandler() is
42 *  used to attach a specific handler to a specific 386 vector number.
43 *  It should use the same privilege level it runs at.  It should
44 *  install it as an interrupt gate so that interrupts are masked
45 *  while the handler runs.
46 *
47 *  Because gdb will sometimes write to the stack area to execute function
48 *  calls, this program cannot rely on using the supervisor stack so it
49 *  uses it's own stack area reserved in the int array remcomStack.
50 *
51 *************
52 *
53 *    The following gdb commands are supported:
54 *
55 * command          function                               Return value
56 *
57 *    g             return the value of the CPU registers  hex data or ENN
58 *    G             set the value of the CPU registers     OK or ENN
59 *
60 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
61 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
62 *
63 *    c             Resume at current address              SNN   ( signal NN)
64 *    cAA..AA       Continue at address AA..AA             SNN
65 *
66 *    s             Step one instruction                   SNN
67 *    sAA..AA       Step one instruction from AA..AA       SNN
68 *
69 *    k             kill
70 *
71 *    ?             What was the last sigval ?             SNN   (signal NN)
72 *
73 * All commands and responses are sent with a packet which includes a
74 * checksum.  A packet consists of
75 *
76 * $<packet info>#<checksum>.
77 *
78 * where
79 * <packet info> :: <characters representing the command or response>
80 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
81 *
82 * When a packet is received, it is first acknowledged with either '+' or '-'.
83 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
84 *
85 * Example:
86 *
87 * Host:                  Reply:
88 * $m0,10#2a               +$00010203040506070809101112131415#42
89 *
90 ****************************************************************************/
91
92#include <stdio.h>
93#include <string.h>
94
95/************************************************************************
96 *
97 * external low-level support routines
98 */
99
100extern void putDebugChar();	/* write a single character      */
101extern int getDebugChar();	/* read and return a single char */
102extern void exceptionHandler();	/* assign an exception handler   */
103
104/************************************************************************/
105/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
106/* at least NUMREGBYTES*2 are needed for register packets */
107#define BUFMAX 400
108
109static char initialized;  /* boolean flag. != 0 means we've been initialized */
110
111int     remote_debug;
112/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
113
114static const char hexchars[]="0123456789abcdef";
115
116/* Number of registers.  */
117#define NUMREGS	16
118
119/* Number of bytes of registers.  */
120#define NUMREGBYTES (NUMREGS * 4)
121
122enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
123	       PC /* also known as eip */,
124	       PS /* also known as eflags */,
125	       CS, SS, DS, ES, FS, GS};
126
127/*
128 * these should not be static cuz they can be used outside this module
129 */
130int registers[NUMREGS];
131
132#define STACKSIZE 10000
133int remcomStack[STACKSIZE/sizeof(int)];
134static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
135
136/***************************  ASSEMBLY CODE MACROS *************************/
137/* 									   */
138
139extern void
140return_to_prog ();
141
142/* Restore the program's registers (including the stack pointer, which
143   means we get the right stack and don't have to worry about popping our
144   return address and any stack frames and so on) and return.  */
145asm(".text");
146asm(".globl _return_to_prog");
147asm("_return_to_prog:");
148asm("        movw _registers+44, %ss");
149asm("        movl _registers+16, %esp");
150asm("        movl _registers+4, %ecx");
151asm("        movl _registers+8, %edx");
152asm("        movl _registers+12, %ebx");
153asm("        movl _registers+20, %ebp");
154asm("        movl _registers+24, %esi");
155asm("        movl _registers+28, %edi");
156asm("        movw _registers+48, %ds");
157asm("        movw _registers+52, %es");
158asm("        movw _registers+56, %fs");
159asm("        movw _registers+60, %gs");
160asm("        movl _registers+36, %eax");
161asm("        pushl %eax");  /* saved eflags */
162asm("        movl _registers+40, %eax");
163asm("        pushl %eax");  /* saved cs */
164asm("        movl _registers+32, %eax");
165asm("        pushl %eax");  /* saved eip */
166asm("        movl _registers, %eax");
167/* use iret to restore pc and flags together so
168   that trace flag works right.  */
169asm("        iret");
170
171#define BREAKPOINT() asm("   int $3");
172
173/* Put the error code here just in case the user cares.  */
174int gdb_i386errcode;
175/* Likewise, the vector number here (since GDB only gets the signal
176   number through the usual means, and that's not very specific).  */
177int gdb_i386vector = -1;
178
179/* GDB stores segment registers in 32-bit words (that's just the way
180   m-i386v.h is written).  So zero the appropriate areas in registers.  */
181#define SAVE_REGISTERS1() \
182  asm ("movl %eax, _registers");                                   	  \
183  asm ("movl %ecx, _registers+4");			  		     \
184  asm ("movl %edx, _registers+8");			  		     \
185  asm ("movl %ebx, _registers+12");			  		     \
186  asm ("movl %ebp, _registers+20");			  		     \
187  asm ("movl %esi, _registers+24");			  		     \
188  asm ("movl %edi, _registers+28");			  		     \
189  asm ("movw $0, %ax");							     \
190  asm ("movw %ds, _registers+48");			  		     \
191  asm ("movw %ax, _registers+50");					     \
192  asm ("movw %es, _registers+52");			  		     \
193  asm ("movw %ax, _registers+54");					     \
194  asm ("movw %fs, _registers+56");			  		     \
195  asm ("movw %ax, _registers+58");					     \
196  asm ("movw %gs, _registers+60");			  		     \
197  asm ("movw %ax, _registers+62");
198#define SAVE_ERRCODE() \
199  asm ("popl %ebx");                                  \
200  asm ("movl %ebx, _gdb_i386errcode");
201#define SAVE_REGISTERS2() \
202  asm ("popl %ebx"); /* old eip */			  		     \
203  asm ("movl %ebx, _registers+32");			  		     \
204  asm ("popl %ebx");	 /* old cs */			  		     \
205  asm ("movl %ebx, _registers+40");			  		     \
206  asm ("movw %ax, _registers+42");                                           \
207  asm ("popl %ebx");	 /* old eflags */		  		     \
208  asm ("movl %ebx, _registers+36");			 		     \
209  /* Now that we've done the pops, we can save the stack pointer.");  */   \
210  asm ("movw %ss, _registers+44");					     \
211  asm ("movw %ax, _registers+46");     	       	       	       	       	     \
212  asm ("movl %esp, _registers+16");
213
214/* See if mem_fault_routine is set, if so just IRET to that address.  */
215#define CHECK_FAULT() \
216  asm ("cmpl $0, _mem_fault_routine");					   \
217  asm ("jne mem_fault");
218
219asm (".text");
220asm ("mem_fault:");
221/* OK to clobber temp registers; we're just going to end up in set_mem_err.  */
222/* Pop error code from the stack and save it.  */
223asm ("     popl %eax");
224asm ("     movl %eax, _gdb_i386errcode");
225
226asm ("     popl %eax"); /* eip */
227/* We don't want to return there, we want to return to the function
228   pointed to by mem_fault_routine instead.  */
229asm ("     movl _mem_fault_routine, %eax");
230asm ("     popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits).  */
231asm ("     popl %edx"); /* eflags */
232
233/* Remove this stack frame; when we do the iret, we will be going to
234   the start of a function, so we want the stack to look just like it
235   would after a "call" instruction.  */
236asm ("     leave");
237
238/* Push the stuff that iret wants.  */
239asm ("     pushl %edx"); /* eflags */
240asm ("     pushl %ecx"); /* cs */
241asm ("     pushl %eax"); /* eip */
242
243/* Zero mem_fault_routine.  */
244asm ("     movl $0, %eax");
245asm ("     movl %eax, _mem_fault_routine");
246
247asm ("iret");
248
249#define CALL_HOOK() asm("call _remcomHandler");
250
251/* This function is called when a i386 exception occurs.  It saves
252 * all the cpu regs in the _registers array, munges the stack a bit,
253 * and invokes an exception handler (remcom_handler).
254 *
255 * stack on entry:                       stack on exit:
256 *   old eflags                          vector number
257 *   old cs (zero-filled to 32 bits)
258 *   old eip
259 *
260 */
261extern void _catchException3();
262asm(".text");
263asm(".globl __catchException3");
264asm("__catchException3:");
265SAVE_REGISTERS1();
266SAVE_REGISTERS2();
267asm ("pushl $3");
268CALL_HOOK();
269
270/* Same thing for exception 1.  */
271extern void _catchException1();
272asm(".text");
273asm(".globl __catchException1");
274asm("__catchException1:");
275SAVE_REGISTERS1();
276SAVE_REGISTERS2();
277asm ("pushl $1");
278CALL_HOOK();
279
280/* Same thing for exception 0.  */
281extern void _catchException0();
282asm(".text");
283asm(".globl __catchException0");
284asm("__catchException0:");
285SAVE_REGISTERS1();
286SAVE_REGISTERS2();
287asm ("pushl $0");
288CALL_HOOK();
289
290/* Same thing for exception 4.  */
291extern void _catchException4();
292asm(".text");
293asm(".globl __catchException4");
294asm("__catchException4:");
295SAVE_REGISTERS1();
296SAVE_REGISTERS2();
297asm ("pushl $4");
298CALL_HOOK();
299
300/* Same thing for exception 5.  */
301extern void _catchException5();
302asm(".text");
303asm(".globl __catchException5");
304asm("__catchException5:");
305SAVE_REGISTERS1();
306SAVE_REGISTERS2();
307asm ("pushl $5");
308CALL_HOOK();
309
310/* Same thing for exception 6.  */
311extern void _catchException6();
312asm(".text");
313asm(".globl __catchException6");
314asm("__catchException6:");
315SAVE_REGISTERS1();
316SAVE_REGISTERS2();
317asm ("pushl $6");
318CALL_HOOK();
319
320/* Same thing for exception 7.  */
321extern void _catchException7();
322asm(".text");
323asm(".globl __catchException7");
324asm("__catchException7:");
325SAVE_REGISTERS1();
326SAVE_REGISTERS2();
327asm ("pushl $7");
328CALL_HOOK();
329
330/* Same thing for exception 8.  */
331extern void _catchException8();
332asm(".text");
333asm(".globl __catchException8");
334asm("__catchException8:");
335SAVE_REGISTERS1();
336SAVE_ERRCODE();
337SAVE_REGISTERS2();
338asm ("pushl $8");
339CALL_HOOK();
340
341/* Same thing for exception 9.  */
342extern void _catchException9();
343asm(".text");
344asm(".globl __catchException9");
345asm("__catchException9:");
346SAVE_REGISTERS1();
347SAVE_REGISTERS2();
348asm ("pushl $9");
349CALL_HOOK();
350
351/* Same thing for exception 10.  */
352extern void _catchException10();
353asm(".text");
354asm(".globl __catchException10");
355asm("__catchException10:");
356SAVE_REGISTERS1();
357SAVE_ERRCODE();
358SAVE_REGISTERS2();
359asm ("pushl $10");
360CALL_HOOK();
361
362/* Same thing for exception 12.  */
363extern void _catchException12();
364asm(".text");
365asm(".globl __catchException12");
366asm("__catchException12:");
367SAVE_REGISTERS1();
368SAVE_ERRCODE();
369SAVE_REGISTERS2();
370asm ("pushl $12");
371CALL_HOOK();
372
373/* Same thing for exception 16.  */
374extern void _catchException16();
375asm(".text");
376asm(".globl __catchException16");
377asm("__catchException16:");
378SAVE_REGISTERS1();
379SAVE_REGISTERS2();
380asm ("pushl $16");
381CALL_HOOK();
382
383/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff.  */
384
385/* Same thing for exception 13.  */
386extern void _catchException13 ();
387asm (".text");
388asm (".globl __catchException13");
389asm ("__catchException13:");
390CHECK_FAULT();
391SAVE_REGISTERS1();
392SAVE_ERRCODE();
393SAVE_REGISTERS2();
394asm ("pushl $13");
395CALL_HOOK();
396
397/* Same thing for exception 11.  */
398extern void _catchException11 ();
399asm (".text");
400asm (".globl __catchException11");
401asm ("__catchException11:");
402CHECK_FAULT();
403SAVE_REGISTERS1();
404SAVE_ERRCODE();
405SAVE_REGISTERS2();
406asm ("pushl $11");
407CALL_HOOK();
408
409/* Same thing for exception 14.  */
410extern void _catchException14 ();
411asm (".text");
412asm (".globl __catchException14");
413asm ("__catchException14:");
414CHECK_FAULT();
415SAVE_REGISTERS1();
416SAVE_ERRCODE();
417SAVE_REGISTERS2();
418asm ("pushl $14");
419CALL_HOOK();
420
421/*
422 * remcomHandler is a front end for handle_exception.  It moves the
423 * stack pointer into an area reserved for debugger use.
424 */
425asm("_remcomHandler:");
426asm("           popl %eax");        /* pop off return address     */
427asm("           popl %eax");      /* get the exception number   */
428asm("		movl _stackPtr, %esp"); /* move to remcom stack area  */
429asm("		pushl %eax");	/* push exception onto stack  */
430asm("		call  _handle_exception");    /* this never returns */
431
432void
433_returnFromException ()
434{
435  return_to_prog ();
436}
437
438int
439hex (ch)
440     char ch;
441{
442  if ((ch >= 'a') && (ch <= 'f'))
443    return (ch - 'a' + 10);
444  if ((ch >= '0') && (ch <= '9'))
445    return (ch - '0');
446  if ((ch >= 'A') && (ch <= 'F'))
447    return (ch - 'A' + 10);
448  return (-1);
449}
450
451static char remcomInBuffer[BUFMAX];
452static char remcomOutBuffer[BUFMAX];
453
454/* scan for the sequence $<data>#<checksum>     */
455
456unsigned char *
457getpacket (void)
458{
459  unsigned char *buffer = &remcomInBuffer[0];
460  unsigned char checksum;
461  unsigned char xmitcsum;
462  int count;
463  char ch;
464
465  while (1)
466    {
467      /* wait around for the start character, ignore all other characters */
468      while ((ch = getDebugChar ()) != '$')
469	;
470
471    retry:
472      checksum = 0;
473      xmitcsum = -1;
474      count = 0;
475
476      /* now, read until a # or end of buffer is found */
477      while (count < BUFMAX)
478	{
479	  ch = getDebugChar ();
480	  if (ch == '$')
481	    goto retry;
482	  if (ch == '#')
483	    break;
484	  checksum = checksum + ch;
485	  buffer[count] = ch;
486	  count = count + 1;
487	}
488      buffer[count] = 0;
489
490      if (ch == '#')
491	{
492	  ch = getDebugChar ();
493	  xmitcsum = hex (ch) << 4;
494	  ch = getDebugChar ();
495	  xmitcsum += hex (ch);
496
497	  if (checksum != xmitcsum)
498	    {
499	      if (remote_debug)
500		{
501		  fprintf (stderr,
502			   "bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
503			   checksum, xmitcsum, buffer);
504		}
505	      putDebugChar ('-');	/* failed checksum */
506	    }
507	  else
508	    {
509	      putDebugChar ('+');	/* successful transfer */
510
511	      /* if a sequence char is present, reply the sequence ID */
512	      if (buffer[2] == ':')
513		{
514		  putDebugChar (buffer[0]);
515		  putDebugChar (buffer[1]);
516
517		  return &buffer[3];
518		}
519
520	      return &buffer[0];
521	    }
522	}
523    }
524}
525
526/* send the packet in buffer.  */
527
528void
529putpacket (unsigned char *buffer)
530{
531  unsigned char checksum;
532  int count;
533  char ch;
534
535  /*  $<packet info>#<checksum>. */
536  do
537    {
538      putDebugChar ('$');
539      checksum = 0;
540      count = 0;
541
542      while (ch = buffer[count])
543	{
544	  putDebugChar (ch);
545	  checksum += ch;
546	  count += 1;
547	}
548
549      putDebugChar ('#');
550      putDebugChar (hexchars[checksum >> 4]);
551      putDebugChar (hexchars[checksum % 16]);
552
553    }
554  while (getDebugChar () != '+');
555}
556
557void
558debug_error (format, parm)
559     char *format;
560     char *parm;
561{
562  if (remote_debug)
563    fprintf (stderr, format, parm);
564}
565
566/* Address of a routine to RTE to if we get a memory fault.  */
567static void (*volatile mem_fault_routine) () = NULL;
568
569/* Indicate to caller of mem2hex or hex2mem that there has been an
570   error.  */
571static volatile int mem_err = 0;
572
573void
574set_mem_err (void)
575{
576  mem_err = 1;
577}
578
579/* These are separate functions so that they are so short and sweet
580   that the compiler won't save any registers (if there is a fault
581   to mem_fault, they won't get restored, so there better not be any
582   saved).  */
583int
584get_char (char *addr)
585{
586  return *addr;
587}
588
589void
590set_char (char *addr, int val)
591{
592  *addr = val;
593}
594
595/* convert the memory pointed to by mem into hex, placing result in buf */
596/* return a pointer to the last char put in buf (null) */
597/* If MAY_FAULT is non-zero, then we should set mem_err in response to
598   a fault; if zero treat a fault like any other fault in the stub.  */
599char *
600mem2hex (mem, buf, count, may_fault)
601     char *mem;
602     char *buf;
603     int count;
604     int may_fault;
605{
606  int i;
607  unsigned char ch;
608
609  if (may_fault)
610    mem_fault_routine = set_mem_err;
611  for (i = 0; i < count; i++)
612    {
613      ch = get_char (mem++);
614      if (may_fault && mem_err)
615	return (buf);
616      *buf++ = hexchars[ch >> 4];
617      *buf++ = hexchars[ch % 16];
618    }
619  *buf = 0;
620  if (may_fault)
621    mem_fault_routine = NULL;
622  return (buf);
623}
624
625/* convert the hex array pointed to by buf into binary to be placed in mem */
626/* return a pointer to the character AFTER the last byte written */
627char *
628hex2mem (buf, mem, count, may_fault)
629     char *buf;
630     char *mem;
631     int count;
632     int may_fault;
633{
634  int i;
635  unsigned char ch;
636
637  if (may_fault)
638    mem_fault_routine = set_mem_err;
639  for (i = 0; i < count; i++)
640    {
641      ch = hex (*buf++) << 4;
642      ch = ch + hex (*buf++);
643      set_char (mem++, ch);
644      if (may_fault && mem_err)
645	return (mem);
646    }
647  if (may_fault)
648    mem_fault_routine = NULL;
649  return (mem);
650}
651
652/* this function takes the 386 exception vector and attempts to
653   translate this number into a unix compatible signal value */
654int
655computeSignal (int exceptionVector)
656{
657  int sigval;
658  switch (exceptionVector)
659    {
660    case 0:
661      sigval = 8;
662      break;			/* divide by zero */
663    case 1:
664      sigval = 5;
665      break;			/* debug exception */
666    case 3:
667      sigval = 5;
668      break;			/* breakpoint */
669    case 4:
670      sigval = 16;
671      break;			/* into instruction (overflow) */
672    case 5:
673      sigval = 16;
674      break;			/* bound instruction */
675    case 6:
676      sigval = 4;
677      break;			/* Invalid opcode */
678    case 7:
679      sigval = 8;
680      break;			/* coprocessor not available */
681    case 8:
682      sigval = 7;
683      break;			/* double fault */
684    case 9:
685      sigval = 11;
686      break;			/* coprocessor segment overrun */
687    case 10:
688      sigval = 11;
689      break;			/* Invalid TSS */
690    case 11:
691      sigval = 11;
692      break;			/* Segment not present */
693    case 12:
694      sigval = 11;
695      break;			/* stack exception */
696    case 13:
697      sigval = 11;
698      break;			/* general protection */
699    case 14:
700      sigval = 11;
701      break;			/* page fault */
702    case 16:
703      sigval = 7;
704      break;			/* coprocessor error */
705    default:
706      sigval = 7;		/* "software generated" */
707    }
708  return (sigval);
709}
710
711/**********************************************/
712/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
713/* RETURN NUMBER OF CHARS PROCESSED           */
714/**********************************************/
715int
716hexToInt (char **ptr, int *intValue)
717{
718  int numChars = 0;
719  int hexValue;
720
721  *intValue = 0;
722
723  while (**ptr)
724    {
725      hexValue = hex (**ptr);
726      if (hexValue >= 0)
727	{
728	  *intValue = (*intValue << 4) | hexValue;
729	  numChars++;
730	}
731      else
732	break;
733
734      (*ptr)++;
735    }
736
737  return (numChars);
738}
739
740/*
741 * This function does all command procesing for interfacing to gdb.
742 */
743void
744handle_exception (int exceptionVector)
745{
746  int sigval, stepping;
747  int addr, length;
748  char *ptr;
749  int newPC;
750
751  gdb_i386vector = exceptionVector;
752
753  if (remote_debug)
754    {
755      printf ("vector=%d, sr=0x%x, pc=0x%x\n",
756	      exceptionVector, registers[PS], registers[PC]);
757    }
758
759  /* reply to host that an exception has occurred */
760  sigval = computeSignal (exceptionVector);
761
762  ptr = remcomOutBuffer;
763
764  *ptr++ = 'T';			/* notify gdb with signo, PC, FP and SP */
765  *ptr++ = hexchars[sigval >> 4];
766  *ptr++ = hexchars[sigval & 0xf];
767
768  *ptr++ = hexchars[ESP];
769  *ptr++ = ':';
770  ptr = mem2hex((char *)&registers[ESP], ptr, 4, 0);	/* SP */
771  *ptr++ = ';';
772
773  *ptr++ = hexchars[EBP];
774  *ptr++ = ':';
775  ptr = mem2hex((char *)&registers[EBP], ptr, 4, 0); 	/* FP */
776  *ptr++ = ';';
777
778  *ptr++ = hexchars[PC];
779  *ptr++ = ':';
780  ptr = mem2hex((char *)&registers[PC], ptr, 4, 0); 	/* PC */
781  *ptr++ = ';';
782
783  *ptr = '\0'
784
785  putpacket (remcomOutBuffer);
786
787  stepping = 0;
788
789  while (1 == 1)
790    {
791      remcomOutBuffer[0] = 0;
792      ptr = getpacket ();
793
794      switch (*ptr++)
795	{
796	case '?':
797	  remcomOutBuffer[0] = 'S';
798	  remcomOutBuffer[1] = hexchars[sigval >> 4];
799	  remcomOutBuffer[2] = hexchars[sigval % 16];
800	  remcomOutBuffer[3] = 0;
801	  break;
802	case 'd':
803	  remote_debug = !(remote_debug);	/* toggle debug flag */
804	  break;
805	case 'g':		/* return the value of the CPU registers */
806	  mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
807	  break;
808	case 'G':		/* set the value of the CPU registers - return OK */
809	  hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
810	  strcpy (remcomOutBuffer, "OK");
811	  break;
812	case 'P':		/* set the value of a single CPU register - return OK */
813	  {
814	    int regno;
815
816	    if (hexToInt (&ptr, &regno) && *ptr++ == '=')
817	      if (regno >= 0 && regno < NUMREGS)
818		{
819		  hex2mem (ptr, (char *) &registers[regno], 4, 0);
820		  strcpy (remcomOutBuffer, "OK");
821		  break;
822		}
823
824	    strcpy (remcomOutBuffer, "E01");
825	    break;
826	  }
827
828	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
829	case 'm':
830	  /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
831	  if (hexToInt (&ptr, &addr))
832	    if (*(ptr++) == ',')
833	      if (hexToInt (&ptr, &length))
834		{
835		  ptr = 0;
836		  mem_err = 0;
837		  mem2hex ((char *) addr, remcomOutBuffer, length, 1);
838		  if (mem_err)
839		    {
840		      strcpy (remcomOutBuffer, "E03");
841		      debug_error ("memory fault");
842		    }
843		}
844
845	  if (ptr)
846	    {
847	      strcpy (remcomOutBuffer, "E01");
848	    }
849	  break;
850
851	  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
852	case 'M':
853	  /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
854	  if (hexToInt (&ptr, &addr))
855	    if (*(ptr++) == ',')
856	      if (hexToInt (&ptr, &length))
857		if (*(ptr++) == ':')
858		  {
859		    mem_err = 0;
860		    hex2mem (ptr, (char *) addr, length, 1);
861
862		    if (mem_err)
863		      {
864			strcpy (remcomOutBuffer, "E03");
865			debug_error ("memory fault");
866		      }
867		    else
868		      {
869			strcpy (remcomOutBuffer, "OK");
870		      }
871
872		    ptr = 0;
873		  }
874	  if (ptr)
875	    {
876	      strcpy (remcomOutBuffer, "E02");
877	    }
878	  break;
879
880	  /* cAA..AA    Continue at address AA..AA(optional) */
881	  /* sAA..AA   Step one instruction from AA..AA(optional) */
882	case 's':
883	  stepping = 1;
884	case 'c':
885	  /* try to read optional parameter, pc unchanged if no parm */
886	  if (hexToInt (&ptr, &addr))
887	    registers[PC] = addr;
888
889	  newPC = registers[PC];
890
891	  /* clear the trace bit */
892	  registers[PS] &= 0xfffffeff;
893
894	  /* set the trace bit if we're stepping */
895	  if (stepping)
896	    registers[PS] |= 0x100;
897
898	  _returnFromException ();	/* this is a jump */
899	  break;
900
901	  /* kill the program */
902	case 'k':		/* do nothing */
903#if 0
904	  /* Huh? This doesn't look like "nothing".
905	     m68k-stub.c and sparc-stub.c don't have it.  */
906	  BREAKPOINT ();
907#endif
908	  break;
909	}			/* switch */
910
911      /* reply to the request */
912      putpacket (remcomOutBuffer);
913    }
914}
915
916/* this function is used to set up exception handlers for tracing and
917   breakpoints */
918void
919set_debug_traps (void)
920{
921  stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
922
923  exceptionHandler (0, _catchException0);
924  exceptionHandler (1, _catchException1);
925  exceptionHandler (3, _catchException3);
926  exceptionHandler (4, _catchException4);
927  exceptionHandler (5, _catchException5);
928  exceptionHandler (6, _catchException6);
929  exceptionHandler (7, _catchException7);
930  exceptionHandler (8, _catchException8);
931  exceptionHandler (9, _catchException9);
932  exceptionHandler (10, _catchException10);
933  exceptionHandler (11, _catchException11);
934  exceptionHandler (12, _catchException12);
935  exceptionHandler (13, _catchException13);
936  exceptionHandler (14, _catchException14);
937  exceptionHandler (16, _catchException16);
938
939  initialized = 1;
940}
941
942/* This function will generate a breakpoint exception.  It is used at the
943   beginning of a program to sync up with a debugger and can be used
944   otherwise as a quick means to stop program execution and "break" into
945   the debugger. */
946
947void
948breakpoint (void)
949{
950  if (initialized)
951    BREAKPOINT ();
952}
953