import gdb-1999-08-30 snapshot
[deliverable/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 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 }
This page took 0.066947 seconds and 4 git commands to generate.