1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
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.
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.
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.
54 * The following gdb commands are supported:
56 * command function Return value
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
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
64 * c Resume at current address SNN ( signal NN)
65 * cAA..AA Continue at address AA..AA SNN
67 * s Step one instruction SNN
68 * sAA..AA Step one instruction from AA..AA SNN
72 * ? What was the last sigval ? SNN (signal NN)
74 * All commands and responses are sent with a packet which includes a
75 * checksum. A packet consists of
77 * $<packet info>#<checksum>.
80 * <packet info> :: <characters representing the command or response>
81 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
83 * When a packet is received, it is first acknowledged with either '+' or '-'.
84 * '+' indicates a successful transfer. '-' indicates a failed transfer.
89 * $m0,10#2a +$00010203040506070809101112131415#42
91 ****************************************************************************/
96 /************************************************************************
98 * external low-level support routines
100 typedef void (*ExceptionHook)(int); /* pointer to function with int parm */
101 typedef void (*Function)(); /* pointer to a function */
103 extern void putDebugChar(); /* write a single character */
104 extern int getDebugChar(); /* read and return a single char */
106 extern Function exceptionHandler(); /* assign an exception handler */
107 extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */
109 /************************************************************************/
110 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
111 /* at least NUMREGBYTES*2 are needed for register packets */
114 static char initialized; /* boolean flag. != 0 means we've been initialized */
117 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
121 static const char hexchars[]="0123456789abcdef";
123 /* Number of registers. */
126 /* Number of bytes of registers. */
127 #define NUMREGBYTES (NUMREGS * 4)
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};
135 * these should not be static cuz they can be used outside this module
137 int registers[NUMREGS];
139 #define STACKSIZE 10000
140 int remcomStack[STACKSIZE/sizeof(int)];
141 static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
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.
149 static ExceptionHook oldExceptionHook;
151 /*************************** ASSEMBLY CODE MACROS *************************/
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. */
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. */
186 #define BREAKPOINT() asm(" int $3");
188 /* Put the error code here just in case the user cares. */
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;
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() \
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");
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");
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. */
239 asm (" movl %eax, _gdb_i386errcode");
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 */
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. */
253 /* Push the stuff that iret wants. */
254 asm (" pushl %edx"); /* eflags */
255 asm (" pushl %ecx"); /* cs */
256 asm (" pushl %eax"); /* eip */
258 /* Zero mem_fault_routine. */
259 asm (" movl $0, %eax");
260 asm (" movl %eax, _mem_fault_routine");
264 #define CALL_HOOK() asm("call _remcomHandler");
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).
270 * stack on entry: stack on exit:
271 * old eflags vector number
272 * old cs (zero-filled to 32 bits)
276 extern void _catchException3();
278 asm(".globl __catchException3");
279 asm("__catchException3:");
285 /* Same thing for exception 1. */
286 extern void _catchException1();
288 asm(".globl __catchException1");
289 asm("__catchException1:");
295 /* Same thing for exception 0. */
296 extern void _catchException0();
298 asm(".globl __catchException0");
299 asm("__catchException0:");
305 /* Same thing for exception 4. */
306 extern void _catchException4();
308 asm(".globl __catchException4");
309 asm("__catchException4:");
315 /* Same thing for exception 5. */
316 extern void _catchException5();
318 asm(".globl __catchException5");
319 asm("__catchException5:");
325 /* Same thing for exception 6. */
326 extern void _catchException6();
328 asm(".globl __catchException6");
329 asm("__catchException6:");
335 /* Same thing for exception 7. */
336 extern void _catchException7();
338 asm(".globl __catchException7");
339 asm("__catchException7:");
345 /* Same thing for exception 8. */
346 extern void _catchException8();
348 asm(".globl __catchException8");
349 asm("__catchException8:");
356 /* Same thing for exception 9. */
357 extern void _catchException9();
359 asm(".globl __catchException9");
360 asm("__catchException9:");
366 /* Same thing for exception 10. */
367 extern void _catchException10();
369 asm(".globl __catchException10");
370 asm("__catchException10:");
377 /* Same thing for exception 12. */
378 extern void _catchException12();
380 asm(".globl __catchException12");
381 asm("__catchException12:");
388 /* Same thing for exception 16. */
389 extern void _catchException16();
391 asm(".globl __catchException16");
392 asm("__catchException16:");
398 /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
400 /* Same thing for exception 13. */
401 extern void _catchException13 ();
403 asm (".globl __catchException13");
404 asm ("__catchException13:");
412 /* Same thing for exception 11. */
413 extern void _catchException11 ();
415 asm (".globl __catchException11");
416 asm ("__catchException11:");
424 /* Same thing for exception 14. */
425 extern void _catchException14 ();
427 asm (".globl __catchException14");
428 asm ("__catchException14:");
437 * remcomHandler is a front end for handle_exception. It moves the
438 * stack pointer into an area reserved for debugger use.
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 */
447 void _returnFromException()
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);
462 /* scan for the sequence $<data>#<checksum> */
463 void getpacket(buffer)
466 unsigned char checksum;
467 unsigned char xmitcsum;
473 /* wait around for the start character, ignore all other characters */
474 while ((ch = (getDebugChar() & 0x7f)) != '$');
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;
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);
498 if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */
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];
511 } while (checksum != xmitcsum);
515 /* send the packet in buffer. */
518 void putpacket(buffer)
521 unsigned char checksum;
525 /* $<packet info>#<checksum>. */
531 while (ch=buffer[count]) {
538 putDebugChar(hexchars[checksum >> 4]);
539 putDebugChar(hexchars[checksum % 16]);
541 } while ((getDebugChar() & 0x7f) != '+');
545 char remcomInBuffer[BUFMAX];
546 char remcomOutBuffer[BUFMAX];
550 void debug_error(format, parm)
554 if (remote_debug) fprintf (stderr,format,parm);
557 /* Address of a routine to RTE to if we get a memory fault. */
558 static void (*volatile mem_fault_routine)() = NULL;
560 /* Indicate to caller of mem2hex or hex2mem that there has been an
562 static volatile int mem_err = 0;
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
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)
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)
608 *buf++ = hexchars[ch >> 4];
609 *buf++ = hexchars[ch % 16];
613 mem_fault_routine = NULL;
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)
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)
638 mem_fault_routine = NULL;
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 )
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 */
665 sigval = 7; /* "software generated"*/
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)
683 hexValue = hex(**ptr);
686 *intValue = (*intValue <<4) | hexValue;
699 * This function does all command procesing for interfacing to gdb.
701 void handle_exception(int exceptionVector)
708 gdb_i386vector = exceptionVector;
710 if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n",
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;
722 putpacket(remcomOutBuffer);
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;
734 case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */
736 case 'g' : /* return the value of the CPU registers */
737 mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES, 0);
739 case 'G' : /* set the value of the CPU registers - return OK */
740 hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0);
741 strcpy(remcomOutBuffer,"OK");
743 case 'P' : /* set the value of a single CPU register - return OK */
747 ptr = &remcomInBuffer[1];
748 if (hexToInt (&ptr, ®no) && *ptr++ == '=')
749 if (regno >= 0 && regno < NUMREGS)
751 hex2mem (ptr, (char *)®isters[regno], 4, 0);
752 strcpy(remcomOutBuffer,"OK");
756 strcpy (remcomOutBuffer, "E01");
760 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
762 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
763 ptr = &remcomInBuffer[1];
764 if (hexToInt(&ptr,&addr))
766 if (hexToInt(&ptr,&length))
770 mem2hex((char*) addr, remcomOutBuffer, length, 1);
772 strcpy (remcomOutBuffer, "E03");
773 debug_error ("memory fault");
779 strcpy(remcomOutBuffer,"E01");
780 debug_error("malformed read memory command: %s",remcomInBuffer);
784 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
786 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
787 ptr = &remcomInBuffer[1];
788 if (hexToInt(&ptr,&addr))
790 if (hexToInt(&ptr,&length))
794 hex2mem(ptr, (char*) addr, length, 1);
797 strcpy (remcomOutBuffer, "E03");
798 debug_error ("memory fault");
800 strcpy(remcomOutBuffer,"OK");
807 strcpy(remcomOutBuffer,"E02");
808 debug_error("malformed write memory command: %s",remcomInBuffer);
812 /* cAA..AA Continue at address AA..AA(optional) */
813 /* sAA..AA Step one instruction from AA..AA(optional) */
816 /* try to read optional parameter, pc unchanged if no parm */
817 ptr = &remcomInBuffer[1];
818 if (hexToInt(&ptr,&addr))
819 registers[ PC ] = addr;
821 newPC = registers[ PC];
823 /* clear the trace bit */
824 registers[ PS ] &= 0xfffffeff;
826 /* set the trace bit if we're stepping */
827 if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100;
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.
836 /* Don't really think we need this, except maybe for protection
839 * invoke the previous handler.
841 if (oldExceptionHook)
842 (*oldExceptionHook) (frame->exceptionVector);
843 newPC = registers[ PC ]; /* pc may have changed */
846 _returnFromException(); /* this is a jump */
850 /* kill the program */
851 case 'k' : /* do nothing */
853 /* Huh? This doesn't look like "nothing".
854 m68k-stub.c and sparc-stub.c don't have it. */
860 /* reply to the request */
861 putpacket(remcomOutBuffer);
865 /* this function is used to set up exception handlers for tracing and
867 void set_debug_traps()
869 extern void remcomHandler();
872 stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
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);
890 if (exceptionHook != remcomHandler)
892 oldExceptionHook = exceptionHook;
893 exceptionHook = remcomHandler;
896 /* In case GDB is started before us, ack any packets (presumably
897 "$?#xx") sitting there. */
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
920 int waitlimit = 1000000;
926 for (i = 0; i < waitlimit; i++) ;