import gdb-1999-06-14 snapshot
[deliverable/binutils-gdb.git] / gdb / i386-stub.c
CommitLineData
c906108c
SS
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 */
100typedef void (*ExceptionHook)(int); /* pointer to function with int parm */
101typedef void (*Function)(); /* pointer to a function */
102
103extern void putDebugChar(); /* write a single character */
104extern int getDebugChar(); /* read and return a single char */
105
106extern Function exceptionHandler(); /* assign an exception handler */
107extern 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
114static char initialized; /* boolean flag. != 0 means we've been initialized */
115
116int remote_debug;
117/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
118
119void waitabit();
120
121static 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
129enum 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 */
137int registers[NUMREGS];
138
139#define STACKSIZE 10000
140int remcomStack[STACKSIZE/sizeof(int)];
141static 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
149static ExceptionHook oldExceptionHook;
150
151/*************************** ASSEMBLY CODE MACROS *************************/
152/* */
153
154extern void
155return_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. */
160asm(".text");
161asm(".globl _return_to_prog");
162asm("_return_to_prog:");
163asm(" movw _registers+44, %ss");
164asm(" movl _registers+16, %esp");
165asm(" movl _registers+4, %ecx");
166asm(" movl _registers+8, %edx");
167asm(" movl _registers+12, %ebx");
168asm(" movl _registers+20, %ebp");
169asm(" movl _registers+24, %esi");
170asm(" movl _registers+28, %edi");
171asm(" movw _registers+48, %ds");
172asm(" movw _registers+52, %es");
173asm(" movw _registers+56, %fs");
174asm(" movw _registers+60, %gs");
175asm(" movl _registers+36, %eax");
176asm(" pushl %eax"); /* saved eflags */
177asm(" movl _registers+40, %eax");
178asm(" pushl %eax"); /* saved cs */
179asm(" movl _registers+32, %eax");
180asm(" pushl %eax"); /* saved eip */
181asm(" movl _registers, %eax");
182/* use iret to restore pc and flags together so
183 that trace flag works right. */
184asm(" iret");
185
186#define BREAKPOINT() asm(" int $3");
187
188/* Put the error code here just in case the user cares. */
189int 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). */
192int 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
234asm (".text");
235asm ("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. */
238asm (" popl %eax");
239asm (" movl %eax, _gdb_i386errcode");
240
241asm (" 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. */
244asm (" movl _mem_fault_routine, %eax");
245asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
246asm (" 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. */
251asm (" leave");
252
253/* Push the stuff that iret wants. */
254asm (" pushl %edx"); /* eflags */
255asm (" pushl %ecx"); /* cs */
256asm (" pushl %eax"); /* eip */
257
258/* Zero mem_fault_routine. */
259asm (" movl $0, %eax");
260asm (" movl %eax, _mem_fault_routine");
261
262asm ("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 */
276extern void _catchException3();
277asm(".text");
278asm(".globl __catchException3");
279asm("__catchException3:");
280SAVE_REGISTERS1();
281SAVE_REGISTERS2();
282asm ("pushl $3");
283CALL_HOOK();
284
285/* Same thing for exception 1. */
286extern void _catchException1();
287asm(".text");
288asm(".globl __catchException1");
289asm("__catchException1:");
290SAVE_REGISTERS1();
291SAVE_REGISTERS2();
292asm ("pushl $1");
293CALL_HOOK();
294
295/* Same thing for exception 0. */
296extern void _catchException0();
297asm(".text");
298asm(".globl __catchException0");
299asm("__catchException0:");
300SAVE_REGISTERS1();
301SAVE_REGISTERS2();
302asm ("pushl $0");
303CALL_HOOK();
304
305/* Same thing for exception 4. */
306extern void _catchException4();
307asm(".text");
308asm(".globl __catchException4");
309asm("__catchException4:");
310SAVE_REGISTERS1();
311SAVE_REGISTERS2();
312asm ("pushl $4");
313CALL_HOOK();
314
315/* Same thing for exception 5. */
316extern void _catchException5();
317asm(".text");
318asm(".globl __catchException5");
319asm("__catchException5:");
320SAVE_REGISTERS1();
321SAVE_REGISTERS2();
322asm ("pushl $5");
323CALL_HOOK();
324
325/* Same thing for exception 6. */
326extern void _catchException6();
327asm(".text");
328asm(".globl __catchException6");
329asm("__catchException6:");
330SAVE_REGISTERS1();
331SAVE_REGISTERS2();
332asm ("pushl $6");
333CALL_HOOK();
334
335/* Same thing for exception 7. */
336extern void _catchException7();
337asm(".text");
338asm(".globl __catchException7");
339asm("__catchException7:");
340SAVE_REGISTERS1();
341SAVE_REGISTERS2();
342asm ("pushl $7");
343CALL_HOOK();
344
345/* Same thing for exception 8. */
346extern void _catchException8();
347asm(".text");
348asm(".globl __catchException8");
349asm("__catchException8:");
350SAVE_REGISTERS1();
351SAVE_ERRCODE();
352SAVE_REGISTERS2();
353asm ("pushl $8");
354CALL_HOOK();
355
356/* Same thing for exception 9. */
357extern void _catchException9();
358asm(".text");
359asm(".globl __catchException9");
360asm("__catchException9:");
361SAVE_REGISTERS1();
362SAVE_REGISTERS2();
363asm ("pushl $9");
364CALL_HOOK();
365
366/* Same thing for exception 10. */
367extern void _catchException10();
368asm(".text");
369asm(".globl __catchException10");
370asm("__catchException10:");
371SAVE_REGISTERS1();
372SAVE_ERRCODE();
373SAVE_REGISTERS2();
374asm ("pushl $10");
375CALL_HOOK();
376
377/* Same thing for exception 12. */
378extern void _catchException12();
379asm(".text");
380asm(".globl __catchException12");
381asm("__catchException12:");
382SAVE_REGISTERS1();
383SAVE_ERRCODE();
384SAVE_REGISTERS2();
385asm ("pushl $12");
386CALL_HOOK();
387
388/* Same thing for exception 16. */
389extern void _catchException16();
390asm(".text");
391asm(".globl __catchException16");
392asm("__catchException16:");
393SAVE_REGISTERS1();
394SAVE_REGISTERS2();
395asm ("pushl $16");
396CALL_HOOK();
397
398/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
399
400/* Same thing for exception 13. */
401extern void _catchException13 ();
402asm (".text");
403asm (".globl __catchException13");
404asm ("__catchException13:");
405CHECK_FAULT();
406SAVE_REGISTERS1();
407SAVE_ERRCODE();
408SAVE_REGISTERS2();
409asm ("pushl $13");
410CALL_HOOK();
411
412/* Same thing for exception 11. */
413extern void _catchException11 ();
414asm (".text");
415asm (".globl __catchException11");
416asm ("__catchException11:");
417CHECK_FAULT();
418SAVE_REGISTERS1();
419SAVE_ERRCODE();
420SAVE_REGISTERS2();
421asm ("pushl $11");
422CALL_HOOK();
423
424/* Same thing for exception 14. */
425extern void _catchException14 ();
426asm (".text");
427asm (".globl __catchException14");
428asm ("__catchException14:");
429CHECK_FAULT();
430SAVE_REGISTERS1();
431SAVE_ERRCODE();
432SAVE_REGISTERS2();
433asm ("pushl $14");
434CALL_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 */
440asm("_remcomHandler:");
441asm(" popl %eax"); /* pop off return address */
442asm(" popl %eax"); /* get the exception number */
443asm(" movl _stackPtr, %esp"); /* move to remcom stack area */
444asm(" pushl %eax"); /* push exception onto stack */
445asm(" call _handle_exception"); /* this never returns */
446
447void _returnFromException()
448{
449 return_to_prog ();
450}
451
452int hex(ch)
453char 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> */
463void getpacket(buffer)
464char * 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
518void putpacket(buffer)
519char * 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
545char remcomInBuffer[BUFMAX];
546char remcomOutBuffer[BUFMAX];
547static short error;
548
549
550void debug_error(format, parm)
551char * format;
552char * 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. */
558static void (*volatile mem_fault_routine)() = NULL;
559
560/* Indicate to caller of mem2hex or hex2mem that there has been an
561 error. */
562static volatile int mem_err = 0;
563
564void
565set_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). */
574int
575get_char (addr)
576 char *addr;
577{
578 return *addr;
579}
580
581void
582set_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. */
593char* mem2hex(mem, buf, count, may_fault)
594char* mem;
595char* buf;
596int count;
597int 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 */
619char* hex2mem(buf, mem, count, may_fault)
620char* buf;
621char* mem;
622int count;
623int 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 */
644int computeSignal( exceptionVector )
645int 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/**********************************************/
674int 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 */
701void 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 */
867void set_debug_traps()
868{
869extern void remcomHandler();
870int 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
909void breakpoint()
910{
911 if (initialized)
912#if 0
913 handle_exception(3);
914#else
915 BREAKPOINT();
916#endif
917 waitabit();
918}
919
920int waitlimit = 1000000;
921
922void
923waitabit()
924{
925 int i;
926 for (i = 0; i < waitlimit; i++) ;
927}
This page took 0.226661 seconds and 4 git commands to generate.