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