1e93f7393Sniklas /****************************************************************************
2e93f7393Sniklas
3e93f7393Sniklas THIS SOFTWARE IS NOT COPYRIGHTED
4e93f7393Sniklas
5e93f7393Sniklas HP offers the following for use in the public domain. HP makes no
6e93f7393Sniklas warranty with regard to the software or it's performance and the
7e93f7393Sniklas user accepts the software "AS IS" with all faults.
8e93f7393Sniklas
9e93f7393Sniklas HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10e93f7393Sniklas TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11e93f7393Sniklas OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12e93f7393Sniklas
13e93f7393Sniklas ****************************************************************************/
14e93f7393Sniklas
15e93f7393Sniklas /****************************************************************************
16e93f7393Sniklas * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17e93f7393Sniklas *
18e93f7393Sniklas * Module name: remcom.c $
19e93f7393Sniklas * Revision: 1.34 $
20e93f7393Sniklas * Date: 91/03/09 12:29:49 $
21e93f7393Sniklas * Contributor: Lake Stevens Instrument Division$
22e93f7393Sniklas *
23e93f7393Sniklas * Description: low level support for gdb debugger. $
24e93f7393Sniklas *
25e93f7393Sniklas * Considerations: only works on target hardware $
26e93f7393Sniklas *
27e93f7393Sniklas * Written by: Glenn Engel $
28e93f7393Sniklas * ModuleState: Experimental $
29e93f7393Sniklas *
30e93f7393Sniklas * NOTES: See Below $
31e93f7393Sniklas *
32e93f7393Sniklas * To enable debugger support, two things need to happen. One, a
33e93f7393Sniklas * call to set_debug_traps() is necessary in order to allow any breakpoints
34e93f7393Sniklas * or error conditions to be properly intercepted and reported to gdb.
35e93f7393Sniklas * Two, a breakpoint needs to be generated to begin communication. This
36e93f7393Sniklas * is most easily accomplished by a call to breakpoint(). Breakpoint()
37e93f7393Sniklas * simulates a breakpoint by executing a trap #1. The breakpoint instruction
38e93f7393Sniklas * is hardwired to trap #1 because not to do so is a compatibility problem--
39e93f7393Sniklas * there either should be a standard breakpoint instruction, or the protocol
40e93f7393Sniklas * should be extended to provide some means to communicate which breakpoint
41e93f7393Sniklas * instruction is in use (or have the stub insert the breakpoint).
42e93f7393Sniklas *
43e93f7393Sniklas * Some explanation is probably necessary to explain how exceptions are
44e93f7393Sniklas * handled. When an exception is encountered the 68000 pushes the current
45e93f7393Sniklas * program counter and status register onto the supervisor stack and then
46e93f7393Sniklas * transfers execution to a location specified in it's vector table.
47e93f7393Sniklas * The handlers for the exception vectors are hardwired to jmp to an address
48e93f7393Sniklas * given by the relation: (exception - 256) * 6. These are decending
49e93f7393Sniklas * addresses starting from -6, -12, -18, ... By allowing 6 bytes for
50e93f7393Sniklas * each entry, a jsr, jmp, bsr, ... can be used to enter the exception
51e93f7393Sniklas * handler. Using a jsr to handle an exception has an added benefit of
52e93f7393Sniklas * allowing a single handler to service several exceptions and use the
53e93f7393Sniklas * return address as the key differentiation. The vector number can be
54e93f7393Sniklas * computed from the return address by [ exception = (addr + 1530) / 6 ].
55e93f7393Sniklas * The sole purpose of the routine _catchException is to compute the
56e93f7393Sniklas * exception number and push it on the stack in place of the return address.
57e93f7393Sniklas * The external function exceptionHandler() is
58e93f7393Sniklas * used to attach a specific handler to a specific m68k exception.
59e93f7393Sniklas * For 68020 machines, the ability to have a return address around just
60e93f7393Sniklas * so the vector can be determined is not necessary because the '020 pushes an
61e93f7393Sniklas * extra word onto the stack containing the vector offset
62e93f7393Sniklas *
63e93f7393Sniklas * Because gdb will sometimes write to the stack area to execute function
64e93f7393Sniklas * calls, this program cannot rely on using the supervisor stack so it
65e93f7393Sniklas * uses it's own stack area reserved in the int array remcomStack.
66e93f7393Sniklas *
67e93f7393Sniklas *************
68e93f7393Sniklas *
69e93f7393Sniklas * The following gdb commands are supported:
70e93f7393Sniklas *
71e93f7393Sniklas * command function Return value
72e93f7393Sniklas *
73e93f7393Sniklas * g return the value of the CPU registers hex data or ENN
74e93f7393Sniklas * G set the value of the CPU registers OK or ENN
75e93f7393Sniklas *
76e93f7393Sniklas * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
77e93f7393Sniklas * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
78e93f7393Sniklas *
79e93f7393Sniklas * c Resume at current address SNN ( signal NN)
80e93f7393Sniklas * cAA..AA Continue at address AA..AA SNN
81e93f7393Sniklas *
82e93f7393Sniklas * s Step one instruction SNN
83e93f7393Sniklas * sAA..AA Step one instruction from AA..AA SNN
84e93f7393Sniklas *
85e93f7393Sniklas * k kill
86e93f7393Sniklas *
87e93f7393Sniklas * ? What was the last sigval ? SNN (signal NN)
88e93f7393Sniklas *
89e93f7393Sniklas * All commands and responses are sent with a packet which includes a
90e93f7393Sniklas * checksum. A packet consists of
91e93f7393Sniklas *
92e93f7393Sniklas * $<packet info>#<checksum>.
93e93f7393Sniklas *
94e93f7393Sniklas * where
95e93f7393Sniklas * <packet info> :: <characters representing the command or response>
96e93f7393Sniklas * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
97e93f7393Sniklas *
98e93f7393Sniklas * When a packet is received, it is first acknowledged with either '+' or '-'.
99e93f7393Sniklas * '+' indicates a successful transfer. '-' indicates a failed transfer.
100e93f7393Sniklas *
101e93f7393Sniklas * Example:
102e93f7393Sniklas *
103e93f7393Sniklas * Host: Reply:
104e93f7393Sniklas * $m0,10#2a +$00010203040506070809101112131415#42
105e93f7393Sniklas *
106e93f7393Sniklas ****************************************************************************/
107e93f7393Sniklas
108e93f7393Sniklas #include <stdio.h>
109e93f7393Sniklas #include <string.h>
110e93f7393Sniklas #include <setjmp.h>
111e93f7393Sniklas
112e93f7393Sniklas /************************************************************************
113e93f7393Sniklas *
114e93f7393Sniklas * external low-level support routines
115e93f7393Sniklas */
116e93f7393Sniklas typedef void (*ExceptionHook)(int); /* pointer to function with int parm */
117e93f7393Sniklas typedef void (*Function)(); /* pointer to a function */
118e93f7393Sniklas
119*b725ae77Skettenis extern void putDebugChar(); /* write a single character */
120*b725ae77Skettenis extern int getDebugChar(); /* read and return a single char */
121e93f7393Sniklas
122e93f7393Sniklas extern Function exceptionHandler(); /* assign an exception handler */
123e93f7393Sniklas extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */
124e93f7393Sniklas
125e93f7393Sniklas /************************/
126e93f7393Sniklas /* FORWARD DECLARATIONS */
127e93f7393Sniklas /************************/
128e93f7393Sniklas static void
129e93f7393Sniklas initializeRemcomErrorFrame ();
130e93f7393Sniklas
131e93f7393Sniklas /************************************************************************/
132e93f7393Sniklas /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
133e93f7393Sniklas /* at least NUMREGBYTES*2 are needed for register packets */
134e93f7393Sniklas #define BUFMAX 400
135e93f7393Sniklas
136e93f7393Sniklas static char initialized; /* boolean flag. != 0 means we've been initialized */
137e93f7393Sniklas
138e93f7393Sniklas int remote_debug;
139e93f7393Sniklas /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
140e93f7393Sniklas
141e93f7393Sniklas static const char hexchars[]="0123456789abcdef";
142e93f7393Sniklas
143e93f7393Sniklas /* there are 180 bytes of registers on a 68020 w/68881 */
144e93f7393Sniklas /* many of the fpa registers are 12 byte (96 bit) registers */
145e93f7393Sniklas #define NUMREGBYTES 180
146e93f7393Sniklas enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
147e93f7393Sniklas A0,A1,A2,A3,A4,A5,A6,A7,
148e93f7393Sniklas PS,PC,
149e93f7393Sniklas FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
150e93f7393Sniklas FPCONTROL,FPSTATUS,FPIADDR
151e93f7393Sniklas };
152e93f7393Sniklas
153e93f7393Sniklas
154e93f7393Sniklas /* We keep a whole frame cache here. "Why?", I hear you cry, "doesn't
155e93f7393Sniklas GDB handle that sort of thing?" Well, yes, I believe the only
156e93f7393Sniklas reason for this cache is to save and restore floating point state
157e93f7393Sniklas (fsave/frestore). A cleaner way to do this would be to make the
158e93f7393Sniklas fsave data part of the registers which GDB deals with like any
159e93f7393Sniklas other registers. This should not be a performance problem if the
160e93f7393Sniklas ability to read individual registers is added to the protocol. */
161e93f7393Sniklas
162e93f7393Sniklas typedef struct FrameStruct
163e93f7393Sniklas {
164e93f7393Sniklas struct FrameStruct *previous;
165e93f7393Sniklas int exceptionPC; /* pc value when this frame created */
166e93f7393Sniklas int exceptionVector; /* cpu vector causing exception */
167e93f7393Sniklas short frameSize; /* size of cpu frame in words */
168e93f7393Sniklas short sr; /* for 68000, this not always sr */
169e93f7393Sniklas int pc;
170e93f7393Sniklas short format;
171e93f7393Sniklas int fsaveHeader;
172e93f7393Sniklas int morejunk[0]; /* exception frame, fp save... */
173e93f7393Sniklas } Frame;
174e93f7393Sniklas
175e93f7393Sniklas #define FRAMESIZE 500
176e93f7393Sniklas int gdbFrameStack[FRAMESIZE];
177e93f7393Sniklas static Frame *lastFrame;
178e93f7393Sniklas
179e93f7393Sniklas /*
180e93f7393Sniklas * these should not be static cuz they can be used outside this module
181e93f7393Sniklas */
182e93f7393Sniklas int registers[NUMREGBYTES/4];
183e93f7393Sniklas int superStack;
184e93f7393Sniklas
185e93f7393Sniklas #define STACKSIZE 10000
186e93f7393Sniklas int remcomStack[STACKSIZE/sizeof(int)];
187e93f7393Sniklas static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
188e93f7393Sniklas
189e93f7393Sniklas /*
190e93f7393Sniklas * In many cases, the system will want to continue exception processing
191e93f7393Sniklas * when a continue command is given.
192e93f7393Sniklas * oldExceptionHook is a function to invoke in this case.
193e93f7393Sniklas */
194e93f7393Sniklas
195e93f7393Sniklas static ExceptionHook oldExceptionHook;
196e93f7393Sniklas
197e93f7393Sniklas #ifdef mc68020
198e93f7393Sniklas /* the size of the exception stack on the 68020 varies with the type of
199e93f7393Sniklas * exception. The following table is the number of WORDS used
200e93f7393Sniklas * for each exception format.
201e93f7393Sniklas */
202e93f7393Sniklas const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
203e93f7393Sniklas #endif
204e93f7393Sniklas
205e93f7393Sniklas #ifdef mc68332
206e93f7393Sniklas static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 };
207e93f7393Sniklas #endif
208e93f7393Sniklas
209e93f7393Sniklas /************* jump buffer used for setjmp/longjmp **************************/
210e93f7393Sniklas jmp_buf remcomEnv;
211e93f7393Sniklas
212e93f7393Sniklas /*************************** ASSEMBLY CODE MACROS *************************/
213e93f7393Sniklas /* */
214e93f7393Sniklas
215e93f7393Sniklas #ifdef __HAVE_68881__
216e93f7393Sniklas /* do an fsave, then remember the address to begin a restore from */
217e93f7393Sniklas #define SAVE_FP_REGS() asm(" fsave a0@-"); \
218e93f7393Sniklas asm(" fmovemx fp0-fp7,_registers+72"); \
219e93f7393Sniklas asm(" fmoveml fpcr/fpsr/fpi,_registers+168");
220e93f7393Sniklas #define RESTORE_FP_REGS() \
221e93f7393Sniklas asm(" \n\
222e93f7393Sniklas fmoveml _registers+168,fpcr/fpsr/fpi \n\
223e93f7393Sniklas fmovemx _registers+72,fp0-fp7 \n\
224e93f7393Sniklas cmpl #-1,a0@ | skip frestore flag set ? \n\
225e93f7393Sniklas beq skip_frestore \n\
226e93f7393Sniklas frestore a0@+ \n\
227e93f7393Sniklas skip_frestore: \n\
228e93f7393Sniklas ");
229e93f7393Sniklas
230e93f7393Sniklas #else
231e93f7393Sniklas #define SAVE_FP_REGS()
232e93f7393Sniklas #define RESTORE_FP_REGS()
233e93f7393Sniklas #endif /* __HAVE_68881__ */
234e93f7393Sniklas
235e93f7393Sniklas void return_to_super();
236e93f7393Sniklas void return_to_user();
237e93f7393Sniklas
238e93f7393Sniklas asm("
239e93f7393Sniklas .text
240e93f7393Sniklas .globl _return_to_super
241e93f7393Sniklas _return_to_super:
242e93f7393Sniklas movel _registers+60,sp /* get new stack pointer */
243e93f7393Sniklas movel _lastFrame,a0 /* get last frame info */
244e93f7393Sniklas bra return_to_any
245e93f7393Sniklas
246e93f7393Sniklas .globl _return_to_user
247e93f7393Sniklas _return_to_user:
248e93f7393Sniklas movel _registers+60,a0 /* get usp */
249e93f7393Sniklas movel a0,usp /* set usp */
250e93f7393Sniklas movel _superStack,sp /* get original stack pointer */
251e93f7393Sniklas
252e93f7393Sniklas return_to_any:
253e93f7393Sniklas movel _lastFrame,a0 /* get last frame info */
254e93f7393Sniklas movel a0@+,_lastFrame /* link in previous frame */
255e93f7393Sniklas addql #8,a0 /* skip over pc, vector#*/
256e93f7393Sniklas movew a0@+,d0 /* get # of words in cpu frame */
257e93f7393Sniklas addw d0,a0 /* point to end of data */
258e93f7393Sniklas addw d0,a0 /* point to end of data */
259e93f7393Sniklas movel a0,a1
260e93f7393Sniklas #
261e93f7393Sniklas # copy the stack frame
262e93f7393Sniklas subql #1,d0
263e93f7393Sniklas copyUserLoop:
264e93f7393Sniklas movew a1@-,sp@-
265e93f7393Sniklas dbf d0,copyUserLoop
266e93f7393Sniklas ");
267e93f7393Sniklas RESTORE_FP_REGS()
268e93f7393Sniklas asm(" moveml _registers,d0-d7/a0-a6");
269e93f7393Sniklas asm(" rte"); /* pop and go! */
270e93f7393Sniklas
271e93f7393Sniklas #define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr");
272e93f7393Sniklas #define BREAKPOINT() asm(" trap #1");
273e93f7393Sniklas
274e93f7393Sniklas /* this function is called immediately when a level 7 interrupt occurs */
275e93f7393Sniklas /* if the previous interrupt level was 7 then we're already servicing */
276e93f7393Sniklas /* this interrupt and an rte is in order to return to the debugger. */
277e93f7393Sniklas /* For the 68000, the offset for sr is 6 due to the jsr return address */
278e93f7393Sniklas asm("
279e93f7393Sniklas .text
280e93f7393Sniklas .globl __debug_level7
281e93f7393Sniklas __debug_level7:
282e93f7393Sniklas movew d0,sp@-");
283e93f7393Sniklas #if defined (mc68020) || defined (mc68332)
284e93f7393Sniklas asm(" movew sp@(2),d0");
285e93f7393Sniklas #else
286e93f7393Sniklas asm(" movew sp@(6),d0");
287e93f7393Sniklas #endif
288e93f7393Sniklas asm(" andiw #0x700,d0
289e93f7393Sniklas cmpiw #0x700,d0
290e93f7393Sniklas beq _already7
291e93f7393Sniklas movew sp@+,d0
292e93f7393Sniklas bra __catchException
293e93f7393Sniklas _already7:
294e93f7393Sniklas movew sp@+,d0");
295e93f7393Sniklas #if !defined (mc68020) && !defined (mc68332)
296e93f7393Sniklas asm(" lea sp@(4),sp"); /* pull off 68000 return address */
297e93f7393Sniklas #endif
298e93f7393Sniklas asm(" rte");
299e93f7393Sniklas
300e93f7393Sniklas extern void _catchException ();
301e93f7393Sniklas
302e93f7393Sniklas #if defined (mc68020) || defined (mc68332)
303e93f7393Sniklas /* This function is called when a 68020 exception occurs. It saves
304e93f7393Sniklas * all the cpu and fpcp regs in the _registers array, creates a frame on a
305e93f7393Sniklas * linked list of frames which has the cpu and fpcp stack frames needed
306e93f7393Sniklas * to properly restore the context of these processors, and invokes
307e93f7393Sniklas * an exception handler (remcom_handler).
308e93f7393Sniklas *
309e93f7393Sniklas * stack on entry: stack on exit:
310e93f7393Sniklas * N bytes of junk exception # MSWord
311e93f7393Sniklas * Exception Format Word exception # MSWord
312e93f7393Sniklas * Program counter LSWord
313e93f7393Sniklas * Program counter MSWord
314e93f7393Sniklas * Status Register
315e93f7393Sniklas *
316e93f7393Sniklas *
317e93f7393Sniklas */
318e93f7393Sniklas asm("
319e93f7393Sniklas .text
320e93f7393Sniklas .globl __catchException
321e93f7393Sniklas __catchException:");
322e93f7393Sniklas DISABLE_INTERRUPTS();
323e93f7393Sniklas asm("
324e93f7393Sniklas moveml d0-d7/a0-a6,_registers /* save registers */
325e93f7393Sniklas movel _lastFrame,a0 /* last frame pointer */
326e93f7393Sniklas ");
327e93f7393Sniklas SAVE_FP_REGS();
328e93f7393Sniklas asm("
329e93f7393Sniklas lea _registers,a5 /* get address of registers */
330e93f7393Sniklas movew sp@,d1 /* get status register */
331e93f7393Sniklas movew d1,a5@(66) /* save sr */
332e93f7393Sniklas movel sp@(2),a4 /* save pc in a4 for later use */
333e93f7393Sniklas movel a4,a5@(68) /* save pc in _regisers[] */
334e93f7393Sniklas
335e93f7393Sniklas #
336e93f7393Sniklas # figure out how many bytes in the stack frame
337e93f7393Sniklas movew sp@(6),d0 /* get '020 exception format */
338e93f7393Sniklas movew d0,d2 /* make a copy of format word */
339e93f7393Sniklas andiw #0xf000,d0 /* mask off format type */
340e93f7393Sniklas rolw #5,d0 /* rotate into the low byte *2 */
341e93f7393Sniklas lea _exceptionSize,a1
342e93f7393Sniklas addw d0,a1 /* index into the table */
343e93f7393Sniklas movew a1@,d0 /* get number of words in frame */
344e93f7393Sniklas movew d0,d3 /* save it */
345e93f7393Sniklas subw d0,a0 /* adjust save pointer */
346e93f7393Sniklas subw d0,a0 /* adjust save pointer(bytes) */
347e93f7393Sniklas movel a0,a1 /* copy save pointer */
348e93f7393Sniklas subql #1,d0 /* predecrement loop counter */
349e93f7393Sniklas #
350e93f7393Sniklas # copy the frame
351e93f7393Sniklas saveFrameLoop:
352e93f7393Sniklas movew sp@+,a1@+
353e93f7393Sniklas dbf d0,saveFrameLoop
354e93f7393Sniklas #
355e93f7393Sniklas # now that the stack has been clenaed,
356e93f7393Sniklas # save the a7 in use at time of exception
357e93f7393Sniklas movel sp,_superStack /* save supervisor sp */
358e93f7393Sniklas andiw #0x2000,d1 /* were we in supervisor mode ? */
359e93f7393Sniklas beq userMode
360e93f7393Sniklas movel a7,a5@(60) /* save a7 */
361e93f7393Sniklas bra a7saveDone
362e93f7393Sniklas userMode:
363e93f7393Sniklas movel usp,a1
364e93f7393Sniklas movel a1,a5@(60) /* save user stack pointer */
365e93f7393Sniklas a7saveDone:
366e93f7393Sniklas
367e93f7393Sniklas #
368e93f7393Sniklas # save size of frame
369e93f7393Sniklas movew d3,a0@-
370e93f7393Sniklas
371e93f7393Sniklas #
372e93f7393Sniklas # compute exception number
373e93f7393Sniklas andl #0xfff,d2 /* mask off vector offset */
374e93f7393Sniklas lsrw #2,d2 /* divide by 4 to get vect num */
375e93f7393Sniklas movel d2,a0@- /* save it */
376e93f7393Sniklas #
377e93f7393Sniklas # save pc causing exception
378e93f7393Sniklas movel a4,a0@-
379e93f7393Sniklas #
380e93f7393Sniklas # save old frame link and set the new value
381e93f7393Sniklas movel _lastFrame,a1 /* last frame pointer */
382e93f7393Sniklas movel a1,a0@- /* save pointer to prev frame */
383e93f7393Sniklas movel a0,_lastFrame
384e93f7393Sniklas
385e93f7393Sniklas movel d2,sp@- /* push exception num */
386e93f7393Sniklas movel _exceptionHook,a0 /* get address of handler */
387e93f7393Sniklas jbsr a0@ /* and call it */
388e93f7393Sniklas clrl sp@ /* replace exception num parm with frame ptr */
389e93f7393Sniklas jbsr __returnFromException /* jbsr, but never returns */
390e93f7393Sniklas ");
391e93f7393Sniklas #else /* mc68000 */
392e93f7393Sniklas /* This function is called when an exception occurs. It translates the
393e93f7393Sniklas * return address found on the stack into an exception vector # which
394e93f7393Sniklas * is then handled by either handle_exception or a system handler.
395e93f7393Sniklas * _catchException provides a front end for both.
396e93f7393Sniklas *
397e93f7393Sniklas * stack on entry: stack on exit:
398e93f7393Sniklas * Program counter MSWord exception # MSWord
399e93f7393Sniklas * Program counter LSWord exception # MSWord
400e93f7393Sniklas * Status Register
401e93f7393Sniklas * Return Address MSWord
402e93f7393Sniklas * Return Address LSWord
403e93f7393Sniklas */
404e93f7393Sniklas asm("
405e93f7393Sniklas .text
406e93f7393Sniklas .globl __catchException
407e93f7393Sniklas __catchException:");
408e93f7393Sniklas DISABLE_INTERRUPTS();
409e93f7393Sniklas asm("
410e93f7393Sniklas moveml d0-d7/a0-a6,_registers /* save registers */
411e93f7393Sniklas movel _lastFrame,a0 /* last frame pointer */
412e93f7393Sniklas ");
413e93f7393Sniklas SAVE_FP_REGS();
414e93f7393Sniklas asm("
415e93f7393Sniklas lea _registers,a5 /* get address of registers */
416e93f7393Sniklas movel sp@+,d2 /* pop return address */
417e93f7393Sniklas addl #1530,d2 /* convert return addr to */
418e93f7393Sniklas divs #6,d2 /* exception number */
419e93f7393Sniklas extl d2
420e93f7393Sniklas
421e93f7393Sniklas moveql #3,d3 /* assume a three word frame */
422e93f7393Sniklas
423e93f7393Sniklas cmpiw #3,d2 /* bus error or address error ? */
424e93f7393Sniklas bgt normal /* if >3 then normal error */
425e93f7393Sniklas movel sp@+,a0@- /* copy error info to frame buff*/
426e93f7393Sniklas movel sp@+,a0@- /* these are never used */
427e93f7393Sniklas moveql #7,d3 /* this is a 7 word frame */
428e93f7393Sniklas
429e93f7393Sniklas normal:
430e93f7393Sniklas movew sp@+,d1 /* pop status register */
431e93f7393Sniklas movel sp@+,a4 /* pop program counter */
432e93f7393Sniklas movew d1,a5@(66) /* save sr */
433e93f7393Sniklas movel a4,a5@(68) /* save pc in _regisers[] */
434e93f7393Sniklas movel a4,a0@- /* copy pc to frame buffer */
435e93f7393Sniklas movew d1,a0@- /* copy sr to frame buffer */
436e93f7393Sniklas
437e93f7393Sniklas movel sp,_superStack /* save supervisor sp */
438e93f7393Sniklas
439e93f7393Sniklas andiw #0x2000,d1 /* were we in supervisor mode ? */
440e93f7393Sniklas beq userMode
441e93f7393Sniklas movel a7,a5@(60) /* save a7 */
442e93f7393Sniklas bra saveDone
443e93f7393Sniklas userMode:
444e93f7393Sniklas movel usp,a1 /* save user stack pointer */
445e93f7393Sniklas movel a1,a5@(60) /* save user stack pointer */
446e93f7393Sniklas saveDone:
447e93f7393Sniklas
448e93f7393Sniklas movew d3,a0@- /* push frame size in words */
449e93f7393Sniklas movel d2,a0@- /* push vector number */
450e93f7393Sniklas movel a4,a0@- /* push exception pc */
451e93f7393Sniklas
452e93f7393Sniklas #
453e93f7393Sniklas # save old frame link and set the new value
454e93f7393Sniklas movel _lastFrame,a1 /* last frame pointer */
455e93f7393Sniklas movel a1,a0@- /* save pointer to prev frame */
456e93f7393Sniklas movel a0,_lastFrame
457e93f7393Sniklas
458e93f7393Sniklas movel d2,sp@- /* push exception num */
459e93f7393Sniklas movel _exceptionHook,a0 /* get address of handler */
460e93f7393Sniklas jbsr a0@ /* and call it */
461e93f7393Sniklas clrl sp@ /* replace exception num parm with frame ptr */
462e93f7393Sniklas jbsr __returnFromException /* jbsr, but never returns */
463e93f7393Sniklas ");
464e93f7393Sniklas #endif
465e93f7393Sniklas
466e93f7393Sniklas
467e93f7393Sniklas /*
468e93f7393Sniklas * remcomHandler is a front end for handle_exception. It moves the
469e93f7393Sniklas * stack pointer into an area reserved for debugger use in case the
470e93f7393Sniklas * breakpoint happened in supervisor mode.
471e93f7393Sniklas */
472e93f7393Sniklas asm("_remcomHandler:");
473e93f7393Sniklas asm(" addl #4,sp"); /* pop off return address */
474e93f7393Sniklas asm(" movel sp@+,d0"); /* get the exception number */
475e93f7393Sniklas asm(" movel _stackPtr,sp"); /* move to remcom stack area */
476e93f7393Sniklas asm(" movel d0,sp@-"); /* push exception onto stack */
477e93f7393Sniklas asm(" jbsr _handle_exception"); /* this never returns */
478e93f7393Sniklas asm(" rts"); /* return */
479e93f7393Sniklas
480*b725ae77Skettenis void
_returnFromException(Frame * frame)481*b725ae77Skettenis _returnFromException (Frame * frame)
482e93f7393Sniklas {
483e93f7393Sniklas /* if no passed in frame, use the last one */
484e93f7393Sniklas if (!frame)
485e93f7393Sniklas {
486e93f7393Sniklas frame = lastFrame;
487e93f7393Sniklas frame->frameSize = 4;
488e93f7393Sniklas frame->format = 0;
489e93f7393Sniklas frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info */
490e93f7393Sniklas }
491e93f7393Sniklas
492e93f7393Sniklas #if !defined (mc68020) && !defined (mc68332)
493e93f7393Sniklas /* a 68000 cannot use the internal info pushed onto a bus error
494e93f7393Sniklas * or address error frame when doing an RTE so don't put this info
495e93f7393Sniklas * onto the stack or the stack will creep every time this happens.
496e93f7393Sniklas */
497e93f7393Sniklas frame->frameSize = 3;
498e93f7393Sniklas #endif
499e93f7393Sniklas
500e93f7393Sniklas /* throw away any frames in the list after this frame */
501e93f7393Sniklas lastFrame = frame;
502e93f7393Sniklas
503e93f7393Sniklas frame->sr = registers[(int) PS];
504e93f7393Sniklas frame->pc = registers[(int) PC];
505e93f7393Sniklas
506e93f7393Sniklas if (registers[(int) PS] & 0x2000)
507e93f7393Sniklas {
508e93f7393Sniklas /* return to supervisor mode... */
509e93f7393Sniklas return_to_super ();
510e93f7393Sniklas }
511e93f7393Sniklas else
512e93f7393Sniklas { /* return to user mode */
513e93f7393Sniklas return_to_user ();
514e93f7393Sniklas }
515e93f7393Sniklas }
516e93f7393Sniklas
517*b725ae77Skettenis int
hex(ch)518*b725ae77Skettenis hex (ch)
519e93f7393Sniklas char ch;
520e93f7393Sniklas {
521*b725ae77Skettenis if ((ch >= 'a') && (ch <= 'f'))
522*b725ae77Skettenis return (ch - 'a' + 10);
523*b725ae77Skettenis if ((ch >= '0') && (ch <= '9'))
524*b725ae77Skettenis return (ch - '0');
525*b725ae77Skettenis if ((ch >= 'A') && (ch <= 'F'))
526*b725ae77Skettenis return (ch - 'A' + 10);
527e93f7393Sniklas return (-1);
528e93f7393Sniklas }
529e93f7393Sniklas
530*b725ae77Skettenis static char remcomInBuffer[BUFMAX];
531*b725ae77Skettenis static char remcomOutBuffer[BUFMAX];
532e93f7393Sniklas
533e93f7393Sniklas /* scan for the sequence $<data>#<checksum> */
534*b725ae77Skettenis
535*b725ae77Skettenis unsigned char *
getpacket(void)536*b725ae77Skettenis getpacket (void)
537e93f7393Sniklas {
538*b725ae77Skettenis unsigned char *buffer = &remcomInBuffer[0];
539e93f7393Sniklas unsigned char checksum;
540e93f7393Sniklas unsigned char xmitcsum;
541e93f7393Sniklas int count;
542e93f7393Sniklas char ch;
543e93f7393Sniklas
544*b725ae77Skettenis while (1)
545*b725ae77Skettenis {
546e93f7393Sniklas /* wait around for the start character, ignore all other characters */
547*b725ae77Skettenis while ((ch = getDebugChar ()) != '$')
548*b725ae77Skettenis ;
549*b725ae77Skettenis
550*b725ae77Skettenis retry:
551e93f7393Sniklas checksum = 0;
552e93f7393Sniklas xmitcsum = -1;
553e93f7393Sniklas count = 0;
554e93f7393Sniklas
555e93f7393Sniklas /* now, read until a # or end of buffer is found */
556*b725ae77Skettenis while (count < BUFMAX)
557*b725ae77Skettenis {
558*b725ae77Skettenis ch = getDebugChar ();
559*b725ae77Skettenis if (ch == '$')
560*b725ae77Skettenis goto retry;
561*b725ae77Skettenis if (ch == '#')
562*b725ae77Skettenis break;
563e93f7393Sniklas checksum = checksum + ch;
564e93f7393Sniklas buffer[count] = ch;
565e93f7393Sniklas count = count + 1;
566e93f7393Sniklas }
567e93f7393Sniklas buffer[count] = 0;
568e93f7393Sniklas
569*b725ae77Skettenis if (ch == '#')
570*b725ae77Skettenis {
571*b725ae77Skettenis ch = getDebugChar ();
572*b725ae77Skettenis xmitcsum = hex (ch) << 4;
573*b725ae77Skettenis ch = getDebugChar ();
574*b725ae77Skettenis xmitcsum += hex (ch);
575*b725ae77Skettenis
576*b725ae77Skettenis if (checksum != xmitcsum)
577*b725ae77Skettenis {
578*b725ae77Skettenis if (remote_debug)
579*b725ae77Skettenis {
580*b725ae77Skettenis fprintf (stderr,
581*b725ae77Skettenis "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
582e93f7393Sniklas checksum, xmitcsum, buffer);
583e93f7393Sniklas }
584*b725ae77Skettenis putDebugChar ('-'); /* failed checksum */
585*b725ae77Skettenis }
586*b725ae77Skettenis else
587*b725ae77Skettenis {
588e93f7393Sniklas putDebugChar ('+'); /* successful transfer */
589*b725ae77Skettenis
590e93f7393Sniklas /* if a sequence char is present, reply the sequence ID */
591*b725ae77Skettenis if (buffer[2] == ':')
592*b725ae77Skettenis {
593e93f7393Sniklas putDebugChar (buffer[0]);
594e93f7393Sniklas putDebugChar (buffer[1]);
595*b725ae77Skettenis
596*b725ae77Skettenis return &buffer[3];
597*b725ae77Skettenis }
598*b725ae77Skettenis
599*b725ae77Skettenis return &buffer[0];
600e93f7393Sniklas }
601e93f7393Sniklas }
602e93f7393Sniklas }
603e93f7393Sniklas }
604e93f7393Sniklas
605*b725ae77Skettenis /* send the packet in buffer. */
606e93f7393Sniklas
607*b725ae77Skettenis void
putpacket(buffer)608*b725ae77Skettenis putpacket (buffer)
609e93f7393Sniklas char *buffer;
610e93f7393Sniklas {
611e93f7393Sniklas unsigned char checksum;
612e93f7393Sniklas int count;
613e93f7393Sniklas char ch;
614e93f7393Sniklas
615e93f7393Sniklas /* $<packet info>#<checksum>. */
616*b725ae77Skettenis do
617*b725ae77Skettenis {
618e93f7393Sniklas putDebugChar ('$');
619e93f7393Sniklas checksum = 0;
620e93f7393Sniklas count = 0;
621e93f7393Sniklas
622*b725ae77Skettenis while (ch = buffer[count])
623*b725ae77Skettenis {
624*b725ae77Skettenis putDebugChar (ch);
625e93f7393Sniklas checksum += ch;
626e93f7393Sniklas count += 1;
627e93f7393Sniklas }
628e93f7393Sniklas
629e93f7393Sniklas putDebugChar ('#');
630e93f7393Sniklas putDebugChar (hexchars[checksum >> 4]);
631e93f7393Sniklas putDebugChar (hexchars[checksum % 16]);
632e93f7393Sniklas
633*b725ae77Skettenis }
634*b725ae77Skettenis while (getDebugChar () != '+');
635e93f7393Sniklas
636e93f7393Sniklas }
637e93f7393Sniklas
638*b725ae77Skettenis void
debug_error(format,parm)639*b725ae77Skettenis debug_error (format, parm)
640e93f7393Sniklas char *format;
641e93f7393Sniklas char *parm;
642e93f7393Sniklas {
643*b725ae77Skettenis if (remote_debug)
644*b725ae77Skettenis fprintf (stderr, format, parm);
645e93f7393Sniklas }
646e93f7393Sniklas
647e93f7393Sniklas /* convert the memory pointed to by mem into hex, placing result in buf */
648e93f7393Sniklas /* return a pointer to the last char put in buf (null) */
649*b725ae77Skettenis char *
mem2hex(mem,buf,count)650*b725ae77Skettenis mem2hex (mem, buf, count)
651e93f7393Sniklas char *mem;
652e93f7393Sniklas char *buf;
653e93f7393Sniklas int count;
654e93f7393Sniklas {
655e93f7393Sniklas int i;
656e93f7393Sniklas unsigned char ch;
657*b725ae77Skettenis for (i = 0; i < count; i++)
658*b725ae77Skettenis {
659e93f7393Sniklas ch = *mem++;
660e93f7393Sniklas *buf++ = hexchars[ch >> 4];
661e93f7393Sniklas *buf++ = hexchars[ch % 16];
662e93f7393Sniklas }
663e93f7393Sniklas *buf = 0;
664e93f7393Sniklas return (buf);
665e93f7393Sniklas }
666e93f7393Sniklas
667e93f7393Sniklas /* convert the hex array pointed to by buf into binary to be placed in mem */
668e93f7393Sniklas /* return a pointer to the character AFTER the last byte written */
669*b725ae77Skettenis char *
hex2mem(buf,mem,count)670*b725ae77Skettenis hex2mem (buf, mem, count)
671e93f7393Sniklas char *buf;
672e93f7393Sniklas char *mem;
673e93f7393Sniklas int count;
674e93f7393Sniklas {
675e93f7393Sniklas int i;
676e93f7393Sniklas unsigned char ch;
677*b725ae77Skettenis for (i = 0; i < count; i++)
678*b725ae77Skettenis {
679e93f7393Sniklas ch = hex (*buf++) << 4;
680e93f7393Sniklas ch = ch + hex (*buf++);
681e93f7393Sniklas *mem++ = ch;
682e93f7393Sniklas }
683e93f7393Sniklas return (mem);
684e93f7393Sniklas }
685e93f7393Sniklas
686e93f7393Sniklas /* a bus error has occurred, perform a longjmp
687e93f7393Sniklas to return execution and allow handling of the error */
688e93f7393Sniklas
689*b725ae77Skettenis void
handle_buserror()690*b725ae77Skettenis handle_buserror ()
691e93f7393Sniklas {
692e93f7393Sniklas longjmp (remcomEnv, 1);
693e93f7393Sniklas }
694e93f7393Sniklas
695e93f7393Sniklas /* this function takes the 68000 exception number and attempts to
696e93f7393Sniklas translate this number into a unix compatible signal value */
697*b725ae77Skettenis int
computeSignal(exceptionVector)698*b725ae77Skettenis computeSignal (exceptionVector)
699e93f7393Sniklas int exceptionVector;
700e93f7393Sniklas {
701e93f7393Sniklas int sigval;
702*b725ae77Skettenis switch (exceptionVector)
703*b725ae77Skettenis {
704*b725ae77Skettenis case 2:
705*b725ae77Skettenis sigval = 10;
706*b725ae77Skettenis break; /* bus error */
707*b725ae77Skettenis case 3:
708*b725ae77Skettenis sigval = 10;
709*b725ae77Skettenis break; /* address error */
710*b725ae77Skettenis case 4:
711*b725ae77Skettenis sigval = 4;
712*b725ae77Skettenis break; /* illegal instruction */
713*b725ae77Skettenis case 5:
714*b725ae77Skettenis sigval = 8;
715*b725ae77Skettenis break; /* zero divide */
716*b725ae77Skettenis case 6:
717*b725ae77Skettenis sigval = 8;
718*b725ae77Skettenis break; /* chk instruction */
719*b725ae77Skettenis case 7:
720*b725ae77Skettenis sigval = 8;
721*b725ae77Skettenis break; /* trapv instruction */
722*b725ae77Skettenis case 8:
723*b725ae77Skettenis sigval = 11;
724*b725ae77Skettenis break; /* privilege violation */
725*b725ae77Skettenis case 9:
726*b725ae77Skettenis sigval = 5;
727*b725ae77Skettenis break; /* trace trap */
728*b725ae77Skettenis case 10:
729*b725ae77Skettenis sigval = 4;
730*b725ae77Skettenis break; /* line 1010 emulator */
731*b725ae77Skettenis case 11:
732*b725ae77Skettenis sigval = 4;
733*b725ae77Skettenis break; /* line 1111 emulator */
734e93f7393Sniklas
735e93f7393Sniklas /* Coprocessor protocol violation. Using a standard MMU or FPU
736e93f7393Sniklas this cannot be triggered by software. Call it a SIGBUS. */
737*b725ae77Skettenis case 13:
738*b725ae77Skettenis sigval = 10;
739*b725ae77Skettenis break;
740e93f7393Sniklas
741*b725ae77Skettenis case 31:
742*b725ae77Skettenis sigval = 2;
743*b725ae77Skettenis break; /* interrupt */
744*b725ae77Skettenis case 33:
745*b725ae77Skettenis sigval = 5;
746*b725ae77Skettenis break; /* breakpoint */
747e93f7393Sniklas
748e93f7393Sniklas /* This is a trap #8 instruction. Apparently it is someone's software
749e93f7393Sniklas convention for some sort of SIGFPE condition. Whose? How many
750e93f7393Sniklas people are being screwed by having this code the way it is?
751e93f7393Sniklas Is there a clean solution? */
752*b725ae77Skettenis case 40:
753*b725ae77Skettenis sigval = 8;
754*b725ae77Skettenis break; /* floating point err */
755e93f7393Sniklas
756*b725ae77Skettenis case 48:
757*b725ae77Skettenis sigval = 8;
758*b725ae77Skettenis break; /* floating point err */
759*b725ae77Skettenis case 49:
760*b725ae77Skettenis sigval = 8;
761*b725ae77Skettenis break; /* floating point err */
762*b725ae77Skettenis case 50:
763*b725ae77Skettenis sigval = 8;
764*b725ae77Skettenis break; /* zero divide */
765*b725ae77Skettenis case 51:
766*b725ae77Skettenis sigval = 8;
767*b725ae77Skettenis break; /* underflow */
768*b725ae77Skettenis case 52:
769*b725ae77Skettenis sigval = 8;
770*b725ae77Skettenis break; /* operand error */
771*b725ae77Skettenis case 53:
772*b725ae77Skettenis sigval = 8;
773*b725ae77Skettenis break; /* overflow */
774*b725ae77Skettenis case 54:
775*b725ae77Skettenis sigval = 8;
776*b725ae77Skettenis break; /* NAN */
777e93f7393Sniklas default:
778e93f7393Sniklas sigval = 7; /* "software generated" */
779e93f7393Sniklas }
780e93f7393Sniklas return (sigval);
781e93f7393Sniklas }
782e93f7393Sniklas
783e93f7393Sniklas /**********************************************/
784e93f7393Sniklas /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
785e93f7393Sniklas /* RETURN NUMBER OF CHARS PROCESSED */
786e93f7393Sniklas /**********************************************/
787*b725ae77Skettenis int
hexToInt(char ** ptr,int * intValue)788*b725ae77Skettenis hexToInt (char **ptr, int *intValue)
789e93f7393Sniklas {
790e93f7393Sniklas int numChars = 0;
791e93f7393Sniklas int hexValue;
792e93f7393Sniklas
793e93f7393Sniklas *intValue = 0;
794e93f7393Sniklas
795e93f7393Sniklas while (**ptr)
796e93f7393Sniklas {
797e93f7393Sniklas hexValue = hex (**ptr);
798e93f7393Sniklas if (hexValue >= 0)
799e93f7393Sniklas {
800e93f7393Sniklas *intValue = (*intValue << 4) | hexValue;
801e93f7393Sniklas numChars++;
802e93f7393Sniklas }
803e93f7393Sniklas else
804e93f7393Sniklas break;
805e93f7393Sniklas
806e93f7393Sniklas (*ptr)++;
807e93f7393Sniklas }
808e93f7393Sniklas
809e93f7393Sniklas return (numChars);
810e93f7393Sniklas }
811e93f7393Sniklas
812e93f7393Sniklas /*
813e93f7393Sniklas * This function does all command procesing for interfacing to gdb.
814e93f7393Sniklas */
815*b725ae77Skettenis void
handle_exception(int exceptionVector)816*b725ae77Skettenis handle_exception (int exceptionVector)
817e93f7393Sniklas {
818*b725ae77Skettenis int sigval, stepping;
819e93f7393Sniklas int addr, length;
820e93f7393Sniklas char *ptr;
821e93f7393Sniklas int newPC;
822e93f7393Sniklas Frame *frame;
823e93f7393Sniklas
824*b725ae77Skettenis if (remote_debug)
825*b725ae77Skettenis printf ("vector=%d, sr=0x%x, pc=0x%x\n",
826*b725ae77Skettenis exceptionVector, registers[PS], registers[PC]);
827e93f7393Sniklas
828e93f7393Sniklas /* reply to host that an exception has occurred */
829e93f7393Sniklas sigval = computeSignal (exceptionVector);
830e93f7393Sniklas remcomOutBuffer[0] = 'S';
831e93f7393Sniklas remcomOutBuffer[1] = hexchars[sigval >> 4];
832e93f7393Sniklas remcomOutBuffer[2] = hexchars[sigval % 16];
833e93f7393Sniklas remcomOutBuffer[3] = 0;
834e93f7393Sniklas
835e93f7393Sniklas putpacket (remcomOutBuffer);
836e93f7393Sniklas
837*b725ae77Skettenis stepping = 0;
838*b725ae77Skettenis
839*b725ae77Skettenis while (1 == 1)
840*b725ae77Skettenis {
841e93f7393Sniklas remcomOutBuffer[0] = 0;
842*b725ae77Skettenis ptr = getpacket ();
843*b725ae77Skettenis switch (*ptr++)
844*b725ae77Skettenis {
845*b725ae77Skettenis case '?':
846*b725ae77Skettenis remcomOutBuffer[0] = 'S';
847e93f7393Sniklas remcomOutBuffer[1] = hexchars[sigval >> 4];
848e93f7393Sniklas remcomOutBuffer[2] = hexchars[sigval % 16];
849e93f7393Sniklas remcomOutBuffer[3] = 0;
850e93f7393Sniklas break;
851*b725ae77Skettenis case 'd':
852*b725ae77Skettenis remote_debug = !(remote_debug); /* toggle debug flag */
853e93f7393Sniklas break;
854e93f7393Sniklas case 'g': /* return the value of the CPU registers */
855e93f7393Sniklas mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES);
856e93f7393Sniklas break;
857e93f7393Sniklas case 'G': /* set the value of the CPU registers - return OK */
858*b725ae77Skettenis hex2mem (ptr, (char *) registers, NUMREGBYTES);
859e93f7393Sniklas strcpy (remcomOutBuffer, "OK");
860e93f7393Sniklas break;
861e93f7393Sniklas
862e93f7393Sniklas /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
863e93f7393Sniklas case 'm':
864e93f7393Sniklas if (setjmp (remcomEnv) == 0)
865e93f7393Sniklas {
866e93f7393Sniklas exceptionHandler (2, handle_buserror);
867e93f7393Sniklas
868e93f7393Sniklas /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
869e93f7393Sniklas if (hexToInt (&ptr, &addr))
870e93f7393Sniklas if (*(ptr++) == ',')
871e93f7393Sniklas if (hexToInt (&ptr, &length))
872e93f7393Sniklas {
873e93f7393Sniklas ptr = 0;
874e93f7393Sniklas mem2hex ((char *) addr, remcomOutBuffer, length);
875e93f7393Sniklas }
876e93f7393Sniklas
877e93f7393Sniklas if (ptr)
878e93f7393Sniklas {
879e93f7393Sniklas strcpy (remcomOutBuffer, "E01");
880e93f7393Sniklas }
881e93f7393Sniklas }
882*b725ae77Skettenis else
883*b725ae77Skettenis {
884e93f7393Sniklas exceptionHandler (2, _catchException);
885e93f7393Sniklas strcpy (remcomOutBuffer, "E03");
886e93f7393Sniklas debug_error ("bus error");
887e93f7393Sniklas }
888e93f7393Sniklas
889e93f7393Sniklas /* restore handler for bus error */
890e93f7393Sniklas exceptionHandler (2, _catchException);
891e93f7393Sniklas break;
892e93f7393Sniklas
893e93f7393Sniklas /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
894e93f7393Sniklas case 'M':
895*b725ae77Skettenis if (setjmp (remcomEnv) == 0)
896*b725ae77Skettenis {
897e93f7393Sniklas exceptionHandler (2, handle_buserror);
898e93f7393Sniklas
899e93f7393Sniklas /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
900e93f7393Sniklas if (hexToInt (&ptr, &addr))
901e93f7393Sniklas if (*(ptr++) == ',')
902e93f7393Sniklas if (hexToInt (&ptr, &length))
903e93f7393Sniklas if (*(ptr++) == ':')
904e93f7393Sniklas {
905e93f7393Sniklas hex2mem (ptr, (char *) addr, length);
906e93f7393Sniklas ptr = 0;
907e93f7393Sniklas strcpy (remcomOutBuffer, "OK");
908e93f7393Sniklas }
909e93f7393Sniklas if (ptr)
910e93f7393Sniklas {
911e93f7393Sniklas strcpy (remcomOutBuffer, "E02");
912e93f7393Sniklas }
913e93f7393Sniklas }
914*b725ae77Skettenis else
915*b725ae77Skettenis {
916e93f7393Sniklas exceptionHandler (2, _catchException);
917e93f7393Sniklas strcpy (remcomOutBuffer, "E03");
918e93f7393Sniklas debug_error ("bus error");
919e93f7393Sniklas }
920e93f7393Sniklas
921e93f7393Sniklas /* restore handler for bus error */
922e93f7393Sniklas exceptionHandler (2, _catchException);
923e93f7393Sniklas break;
924e93f7393Sniklas
925e93f7393Sniklas /* cAA..AA Continue at address AA..AA(optional) */
926e93f7393Sniklas /* sAA..AA Step one instruction from AA..AA(optional) */
927e93f7393Sniklas case 's':
928*b725ae77Skettenis stepping = 1;
929*b725ae77Skettenis case 'c':
930e93f7393Sniklas /* try to read optional parameter, pc unchanged if no parm */
931e93f7393Sniklas if (hexToInt (&ptr, &addr))
932e93f7393Sniklas registers[PC] = addr;
933e93f7393Sniklas
934e93f7393Sniklas newPC = registers[PC];
935e93f7393Sniklas
936e93f7393Sniklas /* clear the trace bit */
937e93f7393Sniklas registers[PS] &= 0x7fff;
938e93f7393Sniklas
939e93f7393Sniklas /* set the trace bit if we're stepping */
940*b725ae77Skettenis if (stepping)
941*b725ae77Skettenis registers[PS] |= 0x8000;
942e93f7393Sniklas
943e93f7393Sniklas /*
944e93f7393Sniklas * look for newPC in the linked list of exception frames.
945e93f7393Sniklas * if it is found, use the old frame it. otherwise,
946e93f7393Sniklas * fake up a dummy frame in returnFromException().
947e93f7393Sniklas */
948*b725ae77Skettenis if (remote_debug)
949*b725ae77Skettenis printf ("new pc = 0x%x\n", newPC);
950e93f7393Sniklas frame = lastFrame;
951e93f7393Sniklas while (frame)
952e93f7393Sniklas {
953e93f7393Sniklas if (remote_debug)
954e93f7393Sniklas printf ("frame at 0x%x has pc=0x%x, except#=%d\n",
955*b725ae77Skettenis frame, frame->exceptionPC, frame->exceptionVector);
956*b725ae77Skettenis if (frame->exceptionPC == newPC)
957*b725ae77Skettenis break; /* bingo! a match */
958e93f7393Sniklas /*
959e93f7393Sniklas * for a breakpoint instruction, the saved pc may
960e93f7393Sniklas * be off by two due to re-executing the instruction
961e93f7393Sniklas * replaced by the trap instruction. Check for this.
962e93f7393Sniklas */
963e93f7393Sniklas if ((frame->exceptionVector == 33) &&
964*b725ae77Skettenis (frame->exceptionPC == (newPC + 2)))
965*b725ae77Skettenis break;
966e93f7393Sniklas if (frame == frame->previous)
967e93f7393Sniklas {
968e93f7393Sniklas frame = 0; /* no match found */
969e93f7393Sniklas break;
970e93f7393Sniklas }
971e93f7393Sniklas frame = frame->previous;
972e93f7393Sniklas }
973e93f7393Sniklas
974e93f7393Sniklas /*
975e93f7393Sniklas * If we found a match for the PC AND we are not returning
976e93f7393Sniklas * as a result of a breakpoint (33),
977e93f7393Sniklas * trace exception (9), nmi (31), jmp to
978e93f7393Sniklas * the old exception handler as if this code never ran.
979e93f7393Sniklas */
980e93f7393Sniklas if (frame)
981e93f7393Sniklas {
982e93f7393Sniklas if ((frame->exceptionVector != 9) &&
983e93f7393Sniklas (frame->exceptionVector != 31) &&
984e93f7393Sniklas (frame->exceptionVector != 33))
985e93f7393Sniklas {
986e93f7393Sniklas /*
987e93f7393Sniklas * invoke the previous handler.
988e93f7393Sniklas */
989e93f7393Sniklas if (oldExceptionHook)
990e93f7393Sniklas (*oldExceptionHook) (frame->exceptionVector);
991e93f7393Sniklas newPC = registers[PC]; /* pc may have changed */
992e93f7393Sniklas if (newPC != frame->exceptionPC)
993e93f7393Sniklas {
994e93f7393Sniklas if (remote_debug)
995e93f7393Sniklas printf ("frame at 0x%x has pc=0x%x, except#=%d\n",
996e93f7393Sniklas frame, frame->exceptionPC,
997e93f7393Sniklas frame->exceptionVector);
998e93f7393Sniklas /* re-use the last frame, we're skipping it (longjump?) */
999e93f7393Sniklas frame = (Frame *) 0;
1000e93f7393Sniklas _returnFromException (frame); /* this is a jump */
1001e93f7393Sniklas }
1002e93f7393Sniklas }
1003e93f7393Sniklas }
1004e93f7393Sniklas
1005e93f7393Sniklas /* if we couldn't find a frame, create one */
1006e93f7393Sniklas if (frame == 0)
1007e93f7393Sniklas {
1008e93f7393Sniklas frame = lastFrame - 1;
1009e93f7393Sniklas
1010e93f7393Sniklas /* by using a bunch of print commands with breakpoints,
1011e93f7393Sniklas it's possible for the frame stack to creep down. If it creeps
1012e93f7393Sniklas too far, give up and reset it to the top. Normal use should
1013e93f7393Sniklas not see this happen.
1014e93f7393Sniklas */
1015e93f7393Sniklas if ((unsigned int) (frame - 2) < (unsigned int) &gdbFrameStack)
1016e93f7393Sniklas {
1017e93f7393Sniklas initializeRemcomErrorFrame ();
1018e93f7393Sniklas frame = lastFrame;
1019e93f7393Sniklas }
1020e93f7393Sniklas frame->previous = lastFrame;
1021e93f7393Sniklas lastFrame = frame;
1022e93f7393Sniklas frame = 0; /* null so _return... will properly initialize it */
1023e93f7393Sniklas }
1024e93f7393Sniklas
1025e93f7393Sniklas _returnFromException (frame); /* this is a jump */
1026e93f7393Sniklas
1027e93f7393Sniklas break;
1028e93f7393Sniklas
1029e93f7393Sniklas /* kill the program */
1030e93f7393Sniklas case 'k': /* do nothing */
1031e93f7393Sniklas break;
1032e93f7393Sniklas } /* switch */
1033e93f7393Sniklas
1034e93f7393Sniklas /* reply to the request */
1035e93f7393Sniklas putpacket (remcomOutBuffer);
1036e93f7393Sniklas }
1037e93f7393Sniklas }
1038e93f7393Sniklas
1039e93f7393Sniklas
1040e93f7393Sniklas void
initializeRemcomErrorFrame(void)1041*b725ae77Skettenis initializeRemcomErrorFrame (void)
1042e93f7393Sniklas {
1043e93f7393Sniklas lastFrame = ((Frame *) & gdbFrameStack[FRAMESIZE - 1]) - 1;
1044e93f7393Sniklas lastFrame->previous = lastFrame;
1045e93f7393Sniklas }
1046e93f7393Sniklas
1047e93f7393Sniklas /* this function is used to set up exception handlers for tracing and
1048e93f7393Sniklas breakpoints */
1049*b725ae77Skettenis void
set_debug_traps()1050*b725ae77Skettenis set_debug_traps ()
1051e93f7393Sniklas {
1052e93f7393Sniklas extern void _debug_level7 ();
1053e93f7393Sniklas extern void remcomHandler ();
1054e93f7393Sniklas int exception;
1055e93f7393Sniklas
1056e93f7393Sniklas initializeRemcomErrorFrame ();
1057e93f7393Sniklas stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
1058e93f7393Sniklas
1059e93f7393Sniklas for (exception = 2; exception <= 23; exception++)
1060e93f7393Sniklas exceptionHandler (exception, _catchException);
1061e93f7393Sniklas
1062e93f7393Sniklas /* level 7 interrupt */
1063e93f7393Sniklas exceptionHandler (31, _debug_level7);
1064e93f7393Sniklas
1065e93f7393Sniklas /* breakpoint exception (trap #1) */
1066e93f7393Sniklas exceptionHandler (33, _catchException);
1067e93f7393Sniklas
1068e93f7393Sniklas /* This is a trap #8 instruction. Apparently it is someone's software
1069e93f7393Sniklas convention for some sort of SIGFPE condition. Whose? How many
1070e93f7393Sniklas people are being screwed by having this code the way it is?
1071e93f7393Sniklas Is there a clean solution? */
1072e93f7393Sniklas exceptionHandler (40, _catchException);
1073e93f7393Sniklas
1074e93f7393Sniklas /* 48 to 54 are floating point coprocessor errors */
1075e93f7393Sniklas for (exception = 48; exception <= 54; exception++)
1076e93f7393Sniklas exceptionHandler (exception, _catchException);
1077e93f7393Sniklas
1078e93f7393Sniklas if (oldExceptionHook != remcomHandler)
1079e93f7393Sniklas {
1080e93f7393Sniklas oldExceptionHook = exceptionHook;
1081e93f7393Sniklas exceptionHook = remcomHandler;
1082e93f7393Sniklas }
1083e93f7393Sniklas
1084e93f7393Sniklas initialized = 1;
1085e93f7393Sniklas
1086e93f7393Sniklas }
1087e93f7393Sniklas
1088e93f7393Sniklas /* This function will generate a breakpoint exception. It is used at the
1089e93f7393Sniklas beginning of a program to sync up with a debugger and can be used
1090e93f7393Sniklas otherwise as a quick means to stop program execution and "break" into
1091e93f7393Sniklas the debugger. */
1092e93f7393Sniklas
1093*b725ae77Skettenis void
breakpoint()1094*b725ae77Skettenis breakpoint ()
1095e93f7393Sniklas {
1096*b725ae77Skettenis if (initialized)
1097*b725ae77Skettenis BREAKPOINT ();
1098e93f7393Sniklas }
1099