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