]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/i386-stub.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.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 }