4 #define UNWIND asm ("movel %/sp, %0" : "=g" (sp_ptr));\
5 printf ("\n\t\t== Starting at 0x%x ==\n", sp_ptr);\
6 for (cnt=4; cnt <=32; cnt+=4) {\
7 printf ("+%d(0x%x): 0x%x\t\t-%d(0x%x): 0x%x\n",\
8 cnt, (sp_ptr + cnt), *(unsigned long *)(sp_ptr + cnt),\
9 cnt, (sp_ptr - cnt), *(unsigned long *)(sp_ptr - cnt)\
10 ); }; fflush (stdout);
12 /****************************************************************************
14 THIS SOFTWARE IS NOT COPYRIGHTED
16 HP offers the following for use in the public domain. HP makes no
17 warranty with regard to the software or its performance and the
18 user accepts the software "AS IS" with all faults.
20 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
21 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 ****************************************************************************/
26 /****************************************************************************
27 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
29 * Module name: remcom.c $
31 * Date: 91/03/09 12:29:49 $
32 * Contributor: Lake Stevens Instrument Division$
34 * Description: low level support for gdb debugger. $
36 * Considerations: only works on target hardware $
38 * Written by: Glenn Engel $
39 * ModuleState: Experimental $
43 * To enable debugger support, two things need to happen. One, a
44 * call to set_debug_traps() is necessary in order to allow any breakpoints
45 * or error conditions to be properly intercepted and reported to gdb.
46 * Two, a breakpoint needs to be generated to begin communication. This
47 * is most easily accomplished by a call to breakpoint(). Breakpoint()
48 * simulates a breakpoint by executing a trap #1.
50 * Some explanation is probably necessary to explain how exceptions are
51 * handled. When an exception is encountered the 68000 pushes the current
52 * program counter and status register onto the supervisor stack and then
53 * transfers execution to a location specified in its vector table.
54 * The handlers for the exception vectors are hardwired to jmp to an address
55 * given by the relation: (exception - 256) * 6. These are decending
56 * addresses starting from -6, -12, -18, ... By allowing 6 bytes for
57 * each entry, a jsr, jmp, bsr, ... can be used to enter the exception
58 * handler. Using a jsr to handle an exception has an added benefit of
59 * allowing a single handler to service several exceptions and use the
60 * return address as the key differentiation. The vector number can be
61 * computed from the return address by [ exception = (addr + 1530) / 6 ].
62 * The sole purpose of the routine _catchException is to compute the
63 * exception number and push it on the stack in place of the return address.
64 * The external function exceptionHandler() is
65 * used to attach a specific handler to a specific 68k exception.
66 * For 68020 machines, the ability to have a return address around just
67 * so the vector can be determined is not necessary because the '020 pushes an
68 * extra word onto the stack containing the vector offset
70 * Because gdb will sometimes write to the stack area to execute function
71 * calls, this program cannot rely on using the supervisor stack so it
72 * uses its own stack area reserved in the int array remcomStack.
76 * The following gdb commands are supported:
78 * command function Return value
80 * g return the value of the CPU registers hex data or ENN
81 * G set the value of the CPU registers OK or ENN
83 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
84 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
86 * c Resume at current address SNN ( signal NN)
87 * cAA..AA Continue at address AA..AA SNN
89 * s Step one instruction SNN
90 * sAA..AA Step one instruction from AA..AA SNN
94 * ? What was the last sigval ? SNN (signal NN)
96 * All commands and responses are sent with a packet which includes a
97 * checksum. A packet consists of
99 * $<packet info>#<checksum>.
102 * <packet info> :: <characters representing the command or response>
103 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
105 * When a packet is received, it is first acknowledged with either '+' or '-'.
106 * '+' indicates a successful transfer. '-' indicates a failed transfer.
111 * $m0,10#2a +$00010203040506070809101112131415#42
113 ****************************************************************************/
120 /************************************************************************
122 * external low-level support routines
124 typedef void (*ExceptionHook
)(int); /* pointer to function with int parm */
125 typedef void (*Function
)(); /* pointer to a function */
127 extern int putDebugChar(); /* write a single character */
128 extern char getDebugChar(); /* read and return a single char */
130 ExceptionHook exceptionHook
; /* hook variable for errors/exceptions */
132 /************************/
133 /* FORWARD DECLARATIONS */
134 /************************/
135 /** static void initializeRemcomErrorFrame PARAMS ((void)); **/
136 static void initializeRemcomErrorFrame (void);
138 /************************************************************************/
139 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
140 /* at least NUMREGBYTES*2 are needed for register packets */
143 static char initialized
; /* boolean flag. != 0 means we've been initialized */
145 int remote_debug
= 0; /*** Robs Thu Sep 24 22:18:51 PDT 1992 ***/
146 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
148 static const char hexchars
[]="0123456789abcdef";
150 /* there are 180 bytes of registers on a 68020 w/68881 */
151 /* many of the fpa registers are 12 byte (96 bit) registers */
152 #define NUMREGBYTES 180
153 enum regnames
{D0
,D1
,D2
,D3
,D4
,D5
,D6
,D7
,
154 A0
,A1
,A2
,A3
,A4
,A5
,A6
,A7
,
156 FP0
,FP1
,FP2
,FP3
,FP4
,FP5
,FP6
,FP7
,
157 FPCONTROL
,FPSTATUS
,FPIADDR
160 typedef struct FrameStruct
162 struct FrameStruct
*previous
;
163 int exceptionPC
; /* pc value when this frame created */
164 int exceptionVector
; /* cpu vector causing exception */
165 short frameSize
; /* size of cpu frame in words */
166 short sr
; /* for 68000, this not always sr */
170 int morejunk
[0]; /* exception frame, fp save... */
173 #define FRAMESIZE 500
174 int gdbFrameStack
[FRAMESIZE
];
178 * these should not be static cuz they can be used outside this module
180 int registers
[NUMREGBYTES
/4];
183 #define STACKSIZE 10000
184 int remcomStack
[STACKSIZE
/sizeof(int)];
185 int* stackPtr
= &remcomStack
[STACKSIZE
/sizeof(int) - 1];
188 * In many cases, the system will want to continue exception processing
189 * when a continue command is given.
190 * oldExceptionHook is a function to invoke in this case.
193 static ExceptionHook oldExceptionHook
;
195 /* the size of the exception stack on the 68020 varies with the type of
196 * exception. The following table is the number of WORDS used
197 * for each exception format.
199 const short exceptionSize
[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
201 /************* jump buffer used for setjmp/longjmp **************************/
204 #define BREAKPOINT() asm(" trap #1");
206 extern void return_to_super (void);
207 extern void return_to_user (void);
208 extern void _catchException (void);
210 void _returnFromException( Frame
*frame
)
212 /* if no passed in frame, use the last one */
216 frame
->frameSize
= 4;
218 frame
->fsaveHeader
= -1; /* restore regs, but we dont have fsave info*/
222 /* a 68000 cannot use the internal info pushed onto a bus error
223 * or address error frame when doing an RTE so don't put this info
224 * onto the stack or the stack will creep every time this happens.
229 /* throw away any frames in the list after this frame */
232 frame
->sr
= registers
[(int) PS
];
233 frame
->pc
= registers
[(int) PC
];
235 if (registers
[(int) PS
] & 0x2000)
237 /* return to supervisor mode... */
241 { /* return to user mode */
249 if ((ch
>= 'a') && (ch
<= 'f')) return (ch
-'a'+10);
250 if ((ch
>= '0') && (ch
<= '9')) return (ch
-'0');
251 if ((ch
>= 'A') && (ch
<= 'F')) return (ch
-'A'+10);
256 /* scan for the sequence $<data>#<checksum> */
257 void getpacket(buffer
)
260 unsigned char checksum
;
261 unsigned char xmitcsum
;
267 printf("\nGETPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
276 /* wait around for the start character, ignore all other characters */
277 while ((ch
= getDebugChar()) != '$');
283 /* now, read until a # or end of buffer is found */
284 while (count
< BUFMAX
) {
286 if (ch
== '#') break;
287 checksum
= checksum
+ ch
;
294 xmitcsum
= hex(getDebugChar()) << 4;
295 xmitcsum
+= hex(getDebugChar());
296 if ((remote_debug
) && (checksum
!= xmitcsum
)) {
297 fprintf(stderr
,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
298 checksum
,xmitcsum
,buffer
);
301 if (checksum
!= xmitcsum
) putDebugChar('-'); /* failed checksum */
303 putDebugChar('+'); /* successful transfer */
304 /* if a sequence char is present, reply the sequence ID */
305 if (buffer
[2] == ':') {
306 putDebugChar( buffer
[0] );
307 putDebugChar( buffer
[1] );
308 /* remove sequence chars from buffer */
309 count
= strlen(buffer
);
310 for (i
=3; i
<= count
; i
++) buffer
[i
-3] = buffer
[i
];
314 } while (checksum
!= xmitcsum
);
318 /* send the packet in buffer. The host get's one chance to read it.
319 This routine does not wait for a positive acknowledge. */
321 void putpacket(buffer
)
324 unsigned char checksum
;
328 /* $<packet info>#<checksum>. */
334 while (ch
=buffer
[count
]) {
335 if (! putDebugChar(ch
)) return;
341 putDebugChar(hexchars
[checksum
>> 4]);
342 putDebugChar(hexchars
[checksum
% 16]);
345 printf("\nPUTPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n",
353 /*** } while (getDebugChar() != '+'); ***/
354 /** } while (1 == 0); (getDebugChar() != '+'); **/
358 char remcomInBuffer
[BUFMAX
];
359 char remcomOutBuffer
[BUFMAX
];
363 void debug_error(format
, parm
)
367 if (remote_debug
) fprintf(stderr
,format
,parm
);
370 /* convert the memory pointed to by mem into hex, placing result in buf */
371 /* return a pointer to the last char put in buf (null) */
372 char* mem2hex(mem
, buf
, count
)
379 for (i
=0;i
<count
;i
++) {
381 *buf
++ = hexchars
[ch
>> 4];
382 *buf
++ = hexchars
[ch
% 16];
388 /* convert the hex array pointed to by buf into binary to be placed in mem */
389 /* return a pointer to the character AFTER the last byte written */
390 char* hex2mem(buf
, mem
, count
)
397 for (i
=0;i
<count
;i
++) {
398 ch
= hex(*buf
++) << 4;
399 ch
= ch
+ hex(*buf
++);
405 /* a bus error has occurred, perform a longjmp
406 to return execution and allow handling of the error */
408 void handle_buserror()
410 longjmp(remcomEnv
,1);
413 /* this function takes the 68000 exception number and attempts to
414 translate this number into a unix compatible signal value */
415 int computeSignal( exceptionVector
)
419 switch (exceptionVector
) {
420 case 2 : sigval
= 10; break; /* bus error */
421 case 3 : sigval
= 10; break; /* address error */
422 case 4 : sigval
= 4; break; /* illegal instruction */
423 case 5 : sigval
= 8; break; /* zero divide */
424 case 6 : sigval
= 16; break; /* chk instruction */
425 case 7 : sigval
= 16; break; /* trapv instruction */
426 case 8 : sigval
= 11; break; /* privilege violation */
427 case 9 : sigval
= 5; break; /* trace trap */
428 case 10: sigval
= 4; break; /* line 1010 emulator */
429 case 11: sigval
= 4; break; /* line 1111 emulator */
430 case 13: sigval
= 8; break; /* floating point err */
431 case 31: sigval
= 2; break; /* interrupt */
432 case 33: sigval
= 5; break; /* breakpoint */
433 case 40: sigval
= 8; break; /* floating point err */
434 case 48: sigval
= 8; break; /* floating point err */
435 case 49: sigval
= 8; break; /* floating point err */
436 case 50: sigval
= 8; break; /* zero divide */
437 case 51: sigval
= 8; break; /* underflow */
438 case 52: sigval
= 8; break; /* operand error */
439 case 53: sigval
= 8; break; /* overflow */
440 case 54: sigval
= 8; break; /* NAN */
442 sigval
= 7; /* "software generated"*/
447 /**********************************************/
448 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
449 /* RETURN NUMBER OF CHARS PROCESSED */
450 /**********************************************/
451 int hexToInt(char **ptr
, int *intValue
)
460 hexValue
= hex(**ptr
);
463 *intValue
= (*intValue
<<4) | hexValue
;
476 * This function does all command procesing for interfacing to gdb.
478 void handle_exception(int exceptionVector
)
486 if (remote_debug
) printf("\nHANDLE_EXCEPTION: vector=%d, sr=0x%x, pc=0x%x, sp=0x%x\n",
493 /* reply to host that an exception has occurred */
494 sigval
= computeSignal( exceptionVector
);
495 remcomOutBuffer
[0] = 'S';
496 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
497 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
498 remcomOutBuffer
[3] = 0;
500 putpacket(remcomOutBuffer
);
504 remcomOutBuffer
[0] = 0;
505 getpacket(remcomInBuffer
);
506 switch (remcomInBuffer
[0]) {
507 case '?' : remcomOutBuffer
[0] = 'S';
508 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
509 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
510 remcomOutBuffer
[3] = 0;
512 case 'd' : remote_debug
= !(remote_debug
); /* toggle debug flag */
514 case 'g' : /* return the value of the CPU registers */
515 mem2hex((char*) registers
, remcomOutBuffer
, NUMREGBYTES
);
517 case 'G' : /* set the value of the CPU registers - return OK */
518 hex2mem(&remcomInBuffer
[1], (char*) registers
, NUMREGBYTES
);
519 strcpy(remcomOutBuffer
,"OK");
522 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
524 if (setjmp(remcomEnv
) == 0)
526 exceptionHandler(2,handle_buserror
);
528 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
529 ptr
= &remcomInBuffer
[1];
530 if (hexToInt(&ptr
,&addr
))
532 if (hexToInt(&ptr
,&length
))
535 mem2hex((char*) addr
, remcomOutBuffer
, length
);
540 strcpy(remcomOutBuffer
,"E01");
541 debug_error("malformed read memory command: %s",remcomInBuffer
);
545 exceptionHandler(2,_catchException
);
546 strcpy(remcomOutBuffer
,"E03");
547 debug_error("bus error");
550 /* restore handler for bus error */
551 exceptionHandler(2,_catchException
);
554 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
556 if (setjmp(remcomEnv
) == 0) {
557 exceptionHandler(2,handle_buserror
);
559 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
560 ptr
= &remcomInBuffer
[1];
561 if (hexToInt(&ptr
,&addr
))
563 if (hexToInt(&ptr
,&length
))
566 hex2mem(ptr
, (char*) addr
, length
);
568 strcpy(remcomOutBuffer
,"OK");
572 strcpy(remcomOutBuffer
,"E02");
573 debug_error("malformed write memory command: %s",remcomInBuffer
);
577 exceptionHandler(2,_catchException
);
578 strcpy(remcomOutBuffer
,"E03");
579 debug_error("bus error");
582 /* restore handler for bus error */
583 exceptionHandler(2,_catchException
);
586 /* cAA..AA Continue at address AA..AA(optional) */
587 /* sAA..AA Step one instruction from AA..AA(optional) */
590 /* try to read optional parameter, pc unchanged if no parm */
591 ptr
= &remcomInBuffer
[1];
592 if (hexToInt(&ptr
,&addr
))
593 registers
[ PC
] = addr
;
595 newPC
= registers
[ PC
];
597 /* clear the trace bit */
598 registers
[ PS
] &= 0x7fff;
600 /* set the trace bit if we're stepping */
601 if (remcomInBuffer
[0] == 's') registers
[ PS
] |= 0x8000;
604 * look for newPC in the linked list of exception frames.
605 * if it is found, use the old frame it. otherwise,
606 * fake up a dummy frame in returnFromException().
608 if (remote_debug
) printf("new pc = 0x%x\n",newPC
);
613 printf("frame at 0x%x has pc=0x%x, except#=%d\n",
614 frame
,frame
->exceptionPC
,
615 frame
->exceptionVector
);
616 if (frame
->exceptionPC
== newPC
) break; /* bingo! a match */
618 * for a breakpoint instruction, the saved pc may
619 * be off by two due to re-executing the instruction
620 * replaced by the trap instruction. Check for this.
622 if ((frame
->exceptionVector
== 33) &&
623 (frame
->exceptionPC
== (newPC
+2))) break;
624 if (frame
== frame
->previous
)
626 frame
= 0; /* no match found */
629 frame
= frame
->previous
;
633 * If we found a match for the PC AND we are not returning
634 * as a result of a breakpoint (33),
635 * trace exception (9), nmi (31), jmp to
636 * the old exception handler as if this code never ran.
640 if ((frame
->exceptionVector
!= 9) &&
641 (frame
->exceptionVector
!= 31) &&
642 (frame
->exceptionVector
!= 33))
645 * invoke the previous handler.
647 if (oldExceptionHook
)
648 (*oldExceptionHook
) (frame
->exceptionVector
);
649 newPC
= registers
[ PC
]; /* pc may have changed */
650 if (newPC
!= frame
->exceptionPC
)
653 printf("frame at 0x%x has pc=0x%x, except#=%d\n",
654 frame
,frame
->exceptionPC
,
655 frame
->exceptionVector
);
656 /* re-use the last frame, we're skipping it (longjump?)*/
658 _returnFromException( frame
); /* this is a jump */
663 /* if we couldn't find a frame, create one */
666 frame
= lastFrame
-1 ;
668 /* by using a bunch of print commands with breakpoints,
669 it's possible for the frame stack to creep down. If it creeps
670 too far, give up and reset it to the top. Normal use should
673 if ((unsigned int) (frame
-2) < (unsigned int) &gdbFrameStack
)
675 initializeRemcomErrorFrame();
678 frame
->previous
= lastFrame
;
680 frame
= 0; /* null so _return... will properly initialize it */
683 _returnFromException( frame
); /* this is a jump */
687 /* kill the program */
688 case 'k' : /* do nothing */
692 /* reply to the request */
693 putpacket(remcomOutBuffer
);
698 void initializeRemcomErrorFrame()
700 lastFrame
= ((Frame
*) &gdbFrameStack
[FRAMESIZE
-1]) - 1;
701 lastFrame
->previous
= lastFrame
;
704 /* this function is used to set up exception handlers for tracing and
706 void set_debug_traps()
708 extern void _debug_level7();
709 extern void remcomHandler();
712 initializeRemcomErrorFrame();
713 stackPtr
= &remcomStack
[STACKSIZE
/sizeof(int) - 1];
717 if (oldExceptionHook
!= remcomHandler
)
719 oldExceptionHook
= exceptionHook
;
720 exceptionHook
= remcomHandler
;
726 /* This function will generate a breakpoint exception. It is used at the
727 beginning of a program to sync up with a debugger and can be used
728 otherwise as a quick means to stop program execution and "break" into
733 if (initialized
) BREAKPOINT();