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 * Modified for 386 by Jim Kingdon, Cygnus Support.
33e93f7393Sniklas *
34e93f7393Sniklas * To enable debugger support, two things need to happen. One, a
35e93f7393Sniklas * call to set_debug_traps() is necessary in order to allow any breakpoints
36e93f7393Sniklas * or error conditions to be properly intercepted and reported to gdb.
37e93f7393Sniklas * Two, a breakpoint needs to be generated to begin communication. This
38e93f7393Sniklas * is most easily accomplished by a call to breakpoint(). Breakpoint()
39e93f7393Sniklas * simulates a breakpoint by executing a trap #1.
40e93f7393Sniklas *
41e93f7393Sniklas * The external function exceptionHandler() is
42e93f7393Sniklas * used to attach a specific handler to a specific 386 vector number.
43e93f7393Sniklas * It should use the same privilege level it runs at. It should
44e93f7393Sniklas * install it as an interrupt gate so that interrupts are masked
45e93f7393Sniklas * while the handler runs.
46e93f7393Sniklas *
47e93f7393Sniklas * Because gdb will sometimes write to the stack area to execute function
48e93f7393Sniklas * calls, this program cannot rely on using the supervisor stack so it
49e93f7393Sniklas * uses it's own stack area reserved in the int array remcomStack.
50e93f7393Sniklas *
51e93f7393Sniklas *************
52e93f7393Sniklas *
53e93f7393Sniklas * The following gdb commands are supported:
54e93f7393Sniklas *
55e93f7393Sniklas * command function Return value
56e93f7393Sniklas *
57e93f7393Sniklas * g return the value of the CPU registers hex data or ENN
58e93f7393Sniklas * G set the value of the CPU registers OK or ENN
59e93f7393Sniklas *
60e93f7393Sniklas * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
61e93f7393Sniklas * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
62e93f7393Sniklas *
63e93f7393Sniklas * c Resume at current address SNN ( signal NN)
64e93f7393Sniklas * cAA..AA Continue at address AA..AA SNN
65e93f7393Sniklas *
66e93f7393Sniklas * s Step one instruction SNN
67e93f7393Sniklas * sAA..AA Step one instruction from AA..AA SNN
68e93f7393Sniklas *
69e93f7393Sniklas * k kill
70e93f7393Sniklas *
71e93f7393Sniklas * ? What was the last sigval ? SNN (signal NN)
72e93f7393Sniklas *
73e93f7393Sniklas * All commands and responses are sent with a packet which includes a
74e93f7393Sniklas * checksum. A packet consists of
75e93f7393Sniklas *
76e93f7393Sniklas * $<packet info>#<checksum>.
77e93f7393Sniklas *
78e93f7393Sniklas * where
79e93f7393Sniklas * <packet info> :: <characters representing the command or response>
80e93f7393Sniklas * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
81e93f7393Sniklas *
82e93f7393Sniklas * When a packet is received, it is first acknowledged with either '+' or '-'.
83e93f7393Sniklas * '+' indicates a successful transfer. '-' indicates a failed transfer.
84e93f7393Sniklas *
85e93f7393Sniklas * Example:
86e93f7393Sniklas *
87e93f7393Sniklas * Host: Reply:
88e93f7393Sniklas * $m0,10#2a +$00010203040506070809101112131415#42
89e93f7393Sniklas *
90e93f7393Sniklas ****************************************************************************/
91e93f7393Sniklas
92e93f7393Sniklas #include <stdio.h>
93e93f7393Sniklas #include <string.h>
94e93f7393Sniklas
95e93f7393Sniklas /************************************************************************
96e93f7393Sniklas *
97e93f7393Sniklas * external low-level support routines
98e93f7393Sniklas */
99e93f7393Sniklas
100*b725ae77Skettenis extern void putDebugChar(); /* write a single character */
101*b725ae77Skettenis extern int getDebugChar(); /* read and return a single char */
102*b725ae77Skettenis extern void exceptionHandler(); /* assign an exception handler */
103e93f7393Sniklas
104e93f7393Sniklas /************************************************************************/
105e93f7393Sniklas /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
106e93f7393Sniklas /* at least NUMREGBYTES*2 are needed for register packets */
107e93f7393Sniklas #define BUFMAX 400
108e93f7393Sniklas
109e93f7393Sniklas static char initialized; /* boolean flag. != 0 means we've been initialized */
110e93f7393Sniklas
111e93f7393Sniklas int remote_debug;
112e93f7393Sniklas /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
113e93f7393Sniklas
114e93f7393Sniklas static const char hexchars[]="0123456789abcdef";
115e93f7393Sniklas
116*b725ae77Skettenis /* Number of registers. */
117*b725ae77Skettenis #define NUMREGS 16
118*b725ae77Skettenis
119e93f7393Sniklas /* Number of bytes of registers. */
120*b725ae77Skettenis #define NUMREGBYTES (NUMREGS * 4)
121*b725ae77Skettenis
122e93f7393Sniklas enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
123e93f7393Sniklas PC /* also known as eip */,
124e93f7393Sniklas PS /* also known as eflags */,
125e93f7393Sniklas CS, SS, DS, ES, FS, GS};
126e93f7393Sniklas
127e93f7393Sniklas /*
128e93f7393Sniklas * these should not be static cuz they can be used outside this module
129e93f7393Sniklas */
130*b725ae77Skettenis int registers[NUMREGS];
131e93f7393Sniklas
132e93f7393Sniklas #define STACKSIZE 10000
133e93f7393Sniklas int remcomStack[STACKSIZE/sizeof(int)];
134e93f7393Sniklas static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
135e93f7393Sniklas
136e93f7393Sniklas /*************************** ASSEMBLY CODE MACROS *************************/
137e93f7393Sniklas /* */
138e93f7393Sniklas
139e93f7393Sniklas extern void
140e93f7393Sniklas return_to_prog ();
141e93f7393Sniklas
142e93f7393Sniklas /* Restore the program's registers (including the stack pointer, which
143e93f7393Sniklas means we get the right stack and don't have to worry about popping our
144e93f7393Sniklas return address and any stack frames and so on) and return. */
145e93f7393Sniklas asm(".text");
146e93f7393Sniklas asm(".globl _return_to_prog");
147e93f7393Sniklas asm("_return_to_prog:");
148e93f7393Sniklas asm(" movw _registers+44, %ss");
149e93f7393Sniklas asm(" movl _registers+16, %esp");
150e93f7393Sniklas asm(" movl _registers+4, %ecx");
151e93f7393Sniklas asm(" movl _registers+8, %edx");
152e93f7393Sniklas asm(" movl _registers+12, %ebx");
153e93f7393Sniklas asm(" movl _registers+20, %ebp");
154e93f7393Sniklas asm(" movl _registers+24, %esi");
155e93f7393Sniklas asm(" movl _registers+28, %edi");
156e93f7393Sniklas asm(" movw _registers+48, %ds");
157e93f7393Sniklas asm(" movw _registers+52, %es");
158e93f7393Sniklas asm(" movw _registers+56, %fs");
159e93f7393Sniklas asm(" movw _registers+60, %gs");
160e93f7393Sniklas asm(" movl _registers+36, %eax");
161e93f7393Sniklas asm(" pushl %eax"); /* saved eflags */
162e93f7393Sniklas asm(" movl _registers+40, %eax");
163e93f7393Sniklas asm(" pushl %eax"); /* saved cs */
164e93f7393Sniklas asm(" movl _registers+32, %eax");
165e93f7393Sniklas asm(" pushl %eax"); /* saved eip */
166e93f7393Sniklas asm(" movl _registers, %eax");
167e93f7393Sniklas /* use iret to restore pc and flags together so
168e93f7393Sniklas that trace flag works right. */
169e93f7393Sniklas asm(" iret");
170e93f7393Sniklas
171e93f7393Sniklas #define BREAKPOINT() asm(" int $3");
172e93f7393Sniklas
173e93f7393Sniklas /* Put the error code here just in case the user cares. */
174e93f7393Sniklas int gdb_i386errcode;
175e93f7393Sniklas /* Likewise, the vector number here (since GDB only gets the signal
176e93f7393Sniklas number through the usual means, and that's not very specific). */
177e93f7393Sniklas int gdb_i386vector = -1;
178e93f7393Sniklas
179e93f7393Sniklas /* GDB stores segment registers in 32-bit words (that's just the way
180e93f7393Sniklas m-i386v.h is written). So zero the appropriate areas in registers. */
181e93f7393Sniklas #define SAVE_REGISTERS1() \
182e93f7393Sniklas asm ("movl %eax, _registers"); \
183e93f7393Sniklas asm ("movl %ecx, _registers+4"); \
184e93f7393Sniklas asm ("movl %edx, _registers+8"); \
185e93f7393Sniklas asm ("movl %ebx, _registers+12"); \
186e93f7393Sniklas asm ("movl %ebp, _registers+20"); \
187e93f7393Sniklas asm ("movl %esi, _registers+24"); \
188e93f7393Sniklas asm ("movl %edi, _registers+28"); \
189e93f7393Sniklas asm ("movw $0, %ax"); \
190e93f7393Sniklas asm ("movw %ds, _registers+48"); \
191e93f7393Sniklas asm ("movw %ax, _registers+50"); \
192e93f7393Sniklas asm ("movw %es, _registers+52"); \
193e93f7393Sniklas asm ("movw %ax, _registers+54"); \
194e93f7393Sniklas asm ("movw %fs, _registers+56"); \
195e93f7393Sniklas asm ("movw %ax, _registers+58"); \
196e93f7393Sniklas asm ("movw %gs, _registers+60"); \
197e93f7393Sniklas asm ("movw %ax, _registers+62");
198e93f7393Sniklas #define SAVE_ERRCODE() \
199e93f7393Sniklas asm ("popl %ebx"); \
200e93f7393Sniklas asm ("movl %ebx, _gdb_i386errcode");
201e93f7393Sniklas #define SAVE_REGISTERS2() \
202e93f7393Sniklas asm ("popl %ebx"); /* old eip */ \
203e93f7393Sniklas asm ("movl %ebx, _registers+32"); \
204e93f7393Sniklas asm ("popl %ebx"); /* old cs */ \
205e93f7393Sniklas asm ("movl %ebx, _registers+40"); \
206e93f7393Sniklas asm ("movw %ax, _registers+42"); \
207e93f7393Sniklas asm ("popl %ebx"); /* old eflags */ \
208e93f7393Sniklas asm ("movl %ebx, _registers+36"); \
209e93f7393Sniklas /* Now that we've done the pops, we can save the stack pointer."); */ \
210e93f7393Sniklas asm ("movw %ss, _registers+44"); \
211e93f7393Sniklas asm ("movw %ax, _registers+46"); \
212e93f7393Sniklas asm ("movl %esp, _registers+16");
213e93f7393Sniklas
214e93f7393Sniklas /* See if mem_fault_routine is set, if so just IRET to that address. */
215e93f7393Sniklas #define CHECK_FAULT() \
216e93f7393Sniklas asm ("cmpl $0, _mem_fault_routine"); \
217e93f7393Sniklas asm ("jne mem_fault");
218e93f7393Sniklas
219e93f7393Sniklas asm (".text");
220e93f7393Sniklas asm ("mem_fault:");
221e93f7393Sniklas /* OK to clobber temp registers; we're just going to end up in set_mem_err. */
222e93f7393Sniklas /* Pop error code from the stack and save it. */
223e93f7393Sniklas asm (" popl %eax");
224e93f7393Sniklas asm (" movl %eax, _gdb_i386errcode");
225e93f7393Sniklas
226e93f7393Sniklas asm (" popl %eax"); /* eip */
227e93f7393Sniklas /* We don't want to return there, we want to return to the function
228e93f7393Sniklas pointed to by mem_fault_routine instead. */
229e93f7393Sniklas asm (" movl _mem_fault_routine, %eax");
230e93f7393Sniklas asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
231e93f7393Sniklas asm (" popl %edx"); /* eflags */
232e93f7393Sniklas
233e93f7393Sniklas /* Remove this stack frame; when we do the iret, we will be going to
234e93f7393Sniklas the start of a function, so we want the stack to look just like it
235e93f7393Sniklas would after a "call" instruction. */
236e93f7393Sniklas asm (" leave");
237e93f7393Sniklas
238e93f7393Sniklas /* Push the stuff that iret wants. */
239e93f7393Sniklas asm (" pushl %edx"); /* eflags */
240e93f7393Sniklas asm (" pushl %ecx"); /* cs */
241e93f7393Sniklas asm (" pushl %eax"); /* eip */
242e93f7393Sniklas
243e93f7393Sniklas /* Zero mem_fault_routine. */
244e93f7393Sniklas asm (" movl $0, %eax");
245e93f7393Sniklas asm (" movl %eax, _mem_fault_routine");
246e93f7393Sniklas
247e93f7393Sniklas asm ("iret");
248e93f7393Sniklas
249e93f7393Sniklas #define CALL_HOOK() asm("call _remcomHandler");
250e93f7393Sniklas
251e93f7393Sniklas /* This function is called when a i386 exception occurs. It saves
252e93f7393Sniklas * all the cpu regs in the _registers array, munges the stack a bit,
253e93f7393Sniklas * and invokes an exception handler (remcom_handler).
254e93f7393Sniklas *
255e93f7393Sniklas * stack on entry: stack on exit:
256e93f7393Sniklas * old eflags vector number
257e93f7393Sniklas * old cs (zero-filled to 32 bits)
258e93f7393Sniklas * old eip
259e93f7393Sniklas *
260e93f7393Sniklas */
261e93f7393Sniklas extern void _catchException3();
262e93f7393Sniklas asm(".text");
263e93f7393Sniklas asm(".globl __catchException3");
264e93f7393Sniklas asm("__catchException3:");
265e93f7393Sniklas SAVE_REGISTERS1();
266e93f7393Sniklas SAVE_REGISTERS2();
267e93f7393Sniklas asm ("pushl $3");
268e93f7393Sniklas CALL_HOOK();
269e93f7393Sniklas
270e93f7393Sniklas /* Same thing for exception 1. */
271e93f7393Sniklas extern void _catchException1();
272e93f7393Sniklas asm(".text");
273e93f7393Sniklas asm(".globl __catchException1");
274e93f7393Sniklas asm("__catchException1:");
275e93f7393Sniklas SAVE_REGISTERS1();
276e93f7393Sniklas SAVE_REGISTERS2();
277e93f7393Sniklas asm ("pushl $1");
278e93f7393Sniklas CALL_HOOK();
279e93f7393Sniklas
280e93f7393Sniklas /* Same thing for exception 0. */
281e93f7393Sniklas extern void _catchException0();
282e93f7393Sniklas asm(".text");
283e93f7393Sniklas asm(".globl __catchException0");
284e93f7393Sniklas asm("__catchException0:");
285e93f7393Sniklas SAVE_REGISTERS1();
286e93f7393Sniklas SAVE_REGISTERS2();
287e93f7393Sniklas asm ("pushl $0");
288e93f7393Sniklas CALL_HOOK();
289e93f7393Sniklas
290e93f7393Sniklas /* Same thing for exception 4. */
291e93f7393Sniklas extern void _catchException4();
292e93f7393Sniklas asm(".text");
293e93f7393Sniklas asm(".globl __catchException4");
294e93f7393Sniklas asm("__catchException4:");
295e93f7393Sniklas SAVE_REGISTERS1();
296e93f7393Sniklas SAVE_REGISTERS2();
297e93f7393Sniklas asm ("pushl $4");
298e93f7393Sniklas CALL_HOOK();
299e93f7393Sniklas
300e93f7393Sniklas /* Same thing for exception 5. */
301e93f7393Sniklas extern void _catchException5();
302e93f7393Sniklas asm(".text");
303e93f7393Sniklas asm(".globl __catchException5");
304e93f7393Sniklas asm("__catchException5:");
305e93f7393Sniklas SAVE_REGISTERS1();
306e93f7393Sniklas SAVE_REGISTERS2();
307e93f7393Sniklas asm ("pushl $5");
308e93f7393Sniklas CALL_HOOK();
309e93f7393Sniklas
310e93f7393Sniklas /* Same thing for exception 6. */
311e93f7393Sniklas extern void _catchException6();
312e93f7393Sniklas asm(".text");
313e93f7393Sniklas asm(".globl __catchException6");
314e93f7393Sniklas asm("__catchException6:");
315e93f7393Sniklas SAVE_REGISTERS1();
316e93f7393Sniklas SAVE_REGISTERS2();
317e93f7393Sniklas asm ("pushl $6");
318e93f7393Sniklas CALL_HOOK();
319e93f7393Sniklas
320e93f7393Sniklas /* Same thing for exception 7. */
321e93f7393Sniklas extern void _catchException7();
322e93f7393Sniklas asm(".text");
323e93f7393Sniklas asm(".globl __catchException7");
324e93f7393Sniklas asm("__catchException7:");
325e93f7393Sniklas SAVE_REGISTERS1();
326e93f7393Sniklas SAVE_REGISTERS2();
327e93f7393Sniklas asm ("pushl $7");
328e93f7393Sniklas CALL_HOOK();
329e93f7393Sniklas
330e93f7393Sniklas /* Same thing for exception 8. */
331e93f7393Sniklas extern void _catchException8();
332e93f7393Sniklas asm(".text");
333e93f7393Sniklas asm(".globl __catchException8");
334e93f7393Sniklas asm("__catchException8:");
335e93f7393Sniklas SAVE_REGISTERS1();
336e93f7393Sniklas SAVE_ERRCODE();
337e93f7393Sniklas SAVE_REGISTERS2();
338e93f7393Sniklas asm ("pushl $8");
339e93f7393Sniklas CALL_HOOK();
340e93f7393Sniklas
341e93f7393Sniklas /* Same thing for exception 9. */
342e93f7393Sniklas extern void _catchException9();
343e93f7393Sniklas asm(".text");
344e93f7393Sniklas asm(".globl __catchException9");
345e93f7393Sniklas asm("__catchException9:");
346e93f7393Sniklas SAVE_REGISTERS1();
347e93f7393Sniklas SAVE_REGISTERS2();
348e93f7393Sniklas asm ("pushl $9");
349e93f7393Sniklas CALL_HOOK();
350e93f7393Sniklas
351e93f7393Sniklas /* Same thing for exception 10. */
352e93f7393Sniklas extern void _catchException10();
353e93f7393Sniklas asm(".text");
354e93f7393Sniklas asm(".globl __catchException10");
355e93f7393Sniklas asm("__catchException10:");
356e93f7393Sniklas SAVE_REGISTERS1();
357e93f7393Sniklas SAVE_ERRCODE();
358e93f7393Sniklas SAVE_REGISTERS2();
359e93f7393Sniklas asm ("pushl $10");
360e93f7393Sniklas CALL_HOOK();
361e93f7393Sniklas
362e93f7393Sniklas /* Same thing for exception 12. */
363e93f7393Sniklas extern void _catchException12();
364e93f7393Sniklas asm(".text");
365e93f7393Sniklas asm(".globl __catchException12");
366e93f7393Sniklas asm("__catchException12:");
367e93f7393Sniklas SAVE_REGISTERS1();
368e93f7393Sniklas SAVE_ERRCODE();
369e93f7393Sniklas SAVE_REGISTERS2();
370e93f7393Sniklas asm ("pushl $12");
371e93f7393Sniklas CALL_HOOK();
372e93f7393Sniklas
373e93f7393Sniklas /* Same thing for exception 16. */
374e93f7393Sniklas extern void _catchException16();
375e93f7393Sniklas asm(".text");
376e93f7393Sniklas asm(".globl __catchException16");
377e93f7393Sniklas asm("__catchException16:");
378e93f7393Sniklas SAVE_REGISTERS1();
379e93f7393Sniklas SAVE_REGISTERS2();
380e93f7393Sniklas asm ("pushl $16");
381e93f7393Sniklas CALL_HOOK();
382e93f7393Sniklas
383e93f7393Sniklas /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
384e93f7393Sniklas
385e93f7393Sniklas /* Same thing for exception 13. */
386e93f7393Sniklas extern void _catchException13 ();
387e93f7393Sniklas asm (".text");
388e93f7393Sniklas asm (".globl __catchException13");
389e93f7393Sniklas asm ("__catchException13:");
390e93f7393Sniklas CHECK_FAULT();
391e93f7393Sniklas SAVE_REGISTERS1();
392e93f7393Sniklas SAVE_ERRCODE();
393e93f7393Sniklas SAVE_REGISTERS2();
394e93f7393Sniklas asm ("pushl $13");
395e93f7393Sniklas CALL_HOOK();
396e93f7393Sniklas
397e93f7393Sniklas /* Same thing for exception 11. */
398e93f7393Sniklas extern void _catchException11 ();
399e93f7393Sniklas asm (".text");
400e93f7393Sniklas asm (".globl __catchException11");
401e93f7393Sniklas asm ("__catchException11:");
402e93f7393Sniklas CHECK_FAULT();
403e93f7393Sniklas SAVE_REGISTERS1();
404e93f7393Sniklas SAVE_ERRCODE();
405e93f7393Sniklas SAVE_REGISTERS2();
406e93f7393Sniklas asm ("pushl $11");
407e93f7393Sniklas CALL_HOOK();
408e93f7393Sniklas
409e93f7393Sniklas /* Same thing for exception 14. */
410e93f7393Sniklas extern void _catchException14 ();
411e93f7393Sniklas asm (".text");
412e93f7393Sniklas asm (".globl __catchException14");
413e93f7393Sniklas asm ("__catchException14:");
414e93f7393Sniklas CHECK_FAULT();
415e93f7393Sniklas SAVE_REGISTERS1();
416e93f7393Sniklas SAVE_ERRCODE();
417e93f7393Sniklas SAVE_REGISTERS2();
418e93f7393Sniklas asm ("pushl $14");
419e93f7393Sniklas CALL_HOOK();
420e93f7393Sniklas
421e93f7393Sniklas /*
422e93f7393Sniklas * remcomHandler is a front end for handle_exception. It moves the
423e93f7393Sniklas * stack pointer into an area reserved for debugger use.
424e93f7393Sniklas */
425e93f7393Sniklas asm("_remcomHandler:");
426e93f7393Sniklas asm(" popl %eax"); /* pop off return address */
427e93f7393Sniklas asm(" popl %eax"); /* get the exception number */
428e93f7393Sniklas asm(" movl _stackPtr, %esp"); /* move to remcom stack area */
429e93f7393Sniklas asm(" pushl %eax"); /* push exception onto stack */
430e93f7393Sniklas asm(" call _handle_exception"); /* this never returns */
431e93f7393Sniklas
432*b725ae77Skettenis void
_returnFromException()433*b725ae77Skettenis _returnFromException ()
434e93f7393Sniklas {
435e93f7393Sniklas return_to_prog ();
436e93f7393Sniklas }
437e93f7393Sniklas
438*b725ae77Skettenis int
hex(ch)439*b725ae77Skettenis hex (ch)
440e93f7393Sniklas char ch;
441e93f7393Sniklas {
442*b725ae77Skettenis if ((ch >= 'a') && (ch <= 'f'))
443*b725ae77Skettenis return (ch - 'a' + 10);
444*b725ae77Skettenis if ((ch >= '0') && (ch <= '9'))
445*b725ae77Skettenis return (ch - '0');
446*b725ae77Skettenis if ((ch >= 'A') && (ch <= 'F'))
447*b725ae77Skettenis return (ch - 'A' + 10);
448e93f7393Sniklas return (-1);
449e93f7393Sniklas }
450e93f7393Sniklas
451*b725ae77Skettenis static char remcomInBuffer[BUFMAX];
452*b725ae77Skettenis static char remcomOutBuffer[BUFMAX];
453e93f7393Sniklas
454e93f7393Sniklas /* scan for the sequence $<data>#<checksum> */
455*b725ae77Skettenis
456*b725ae77Skettenis unsigned char *
getpacket(void)457*b725ae77Skettenis getpacket (void)
458e93f7393Sniklas {
459*b725ae77Skettenis unsigned char *buffer = &remcomInBuffer[0];
460e93f7393Sniklas unsigned char checksum;
461e93f7393Sniklas unsigned char xmitcsum;
462e93f7393Sniklas int count;
463e93f7393Sniklas char ch;
464e93f7393Sniklas
465*b725ae77Skettenis while (1)
466*b725ae77Skettenis {
467e93f7393Sniklas /* wait around for the start character, ignore all other characters */
468*b725ae77Skettenis while ((ch = getDebugChar ()) != '$')
469*b725ae77Skettenis ;
470*b725ae77Skettenis
471*b725ae77Skettenis retry:
472e93f7393Sniklas checksum = 0;
473e93f7393Sniklas xmitcsum = -1;
474e93f7393Sniklas count = 0;
475e93f7393Sniklas
476e93f7393Sniklas /* now, read until a # or end of buffer is found */
477*b725ae77Skettenis while (count < BUFMAX)
478*b725ae77Skettenis {
479*b725ae77Skettenis ch = getDebugChar ();
480*b725ae77Skettenis if (ch == '$')
481*b725ae77Skettenis goto retry;
482*b725ae77Skettenis if (ch == '#')
483*b725ae77Skettenis break;
484e93f7393Sniklas checksum = checksum + ch;
485e93f7393Sniklas buffer[count] = ch;
486e93f7393Sniklas count = count + 1;
487e93f7393Sniklas }
488e93f7393Sniklas buffer[count] = 0;
489e93f7393Sniklas
490*b725ae77Skettenis if (ch == '#')
491*b725ae77Skettenis {
492*b725ae77Skettenis ch = getDebugChar ();
493*b725ae77Skettenis xmitcsum = hex (ch) << 4;
494*b725ae77Skettenis ch = getDebugChar ();
495*b725ae77Skettenis xmitcsum += hex (ch);
496*b725ae77Skettenis
497*b725ae77Skettenis if (checksum != xmitcsum)
498*b725ae77Skettenis {
499*b725ae77Skettenis if (remote_debug)
500*b725ae77Skettenis {
501*b725ae77Skettenis fprintf (stderr,
502*b725ae77Skettenis "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
503e93f7393Sniklas checksum, xmitcsum, buffer);
504e93f7393Sniklas }
505*b725ae77Skettenis putDebugChar ('-'); /* failed checksum */
506*b725ae77Skettenis }
507*b725ae77Skettenis else
508*b725ae77Skettenis {
509e93f7393Sniklas putDebugChar ('+'); /* successful transfer */
510*b725ae77Skettenis
511e93f7393Sniklas /* if a sequence char is present, reply the sequence ID */
512*b725ae77Skettenis if (buffer[2] == ':')
513*b725ae77Skettenis {
514e93f7393Sniklas putDebugChar (buffer[0]);
515e93f7393Sniklas putDebugChar (buffer[1]);
516e93f7393Sniklas
517*b725ae77Skettenis return &buffer[3];
518*b725ae77Skettenis }
519*b725ae77Skettenis
520*b725ae77Skettenis return &buffer[0];
521*b725ae77Skettenis }
522*b725ae77Skettenis }
523*b725ae77Skettenis }
524e93f7393Sniklas }
525e93f7393Sniklas
526e93f7393Sniklas /* send the packet in buffer. */
527e93f7393Sniklas
528*b725ae77Skettenis void
putpacket(unsigned char * buffer)529*b725ae77Skettenis putpacket (unsigned char *buffer)
530e93f7393Sniklas {
531e93f7393Sniklas unsigned char checksum;
532e93f7393Sniklas int count;
533e93f7393Sniklas char ch;
534e93f7393Sniklas
535e93f7393Sniklas /* $<packet info>#<checksum>. */
536*b725ae77Skettenis do
537*b725ae77Skettenis {
538e93f7393Sniklas putDebugChar ('$');
539e93f7393Sniklas checksum = 0;
540e93f7393Sniklas count = 0;
541e93f7393Sniklas
542*b725ae77Skettenis while (ch = buffer[count])
543*b725ae77Skettenis {
544*b725ae77Skettenis putDebugChar (ch);
545e93f7393Sniklas checksum += ch;
546e93f7393Sniklas count += 1;
547e93f7393Sniklas }
548e93f7393Sniklas
549e93f7393Sniklas putDebugChar ('#');
550e93f7393Sniklas putDebugChar (hexchars[checksum >> 4]);
551e93f7393Sniklas putDebugChar (hexchars[checksum % 16]);
552e93f7393Sniklas
553*b725ae77Skettenis }
554*b725ae77Skettenis while (getDebugChar () != '+');
555e93f7393Sniklas }
556e93f7393Sniklas
557*b725ae77Skettenis void
debug_error(format,parm)558*b725ae77Skettenis debug_error (format, parm)
559e93f7393Sniklas char *format;
560e93f7393Sniklas char *parm;
561e93f7393Sniklas {
562*b725ae77Skettenis if (remote_debug)
563*b725ae77Skettenis fprintf (stderr, format, parm);
564e93f7393Sniklas }
565e93f7393Sniklas
566e93f7393Sniklas /* Address of a routine to RTE to if we get a memory fault. */
567e93f7393Sniklas static void (*volatile mem_fault_routine) () = NULL;
568e93f7393Sniklas
569e93f7393Sniklas /* Indicate to caller of mem2hex or hex2mem that there has been an
570e93f7393Sniklas error. */
571e93f7393Sniklas static volatile int mem_err = 0;
572e93f7393Sniklas
573e93f7393Sniklas void
set_mem_err(void)574*b725ae77Skettenis set_mem_err (void)
575e93f7393Sniklas {
576e93f7393Sniklas mem_err = 1;
577e93f7393Sniklas }
578e93f7393Sniklas
579e93f7393Sniklas /* These are separate functions so that they are so short and sweet
580e93f7393Sniklas that the compiler won't save any registers (if there is a fault
581e93f7393Sniklas to mem_fault, they won't get restored, so there better not be any
582e93f7393Sniklas saved). */
583e93f7393Sniklas int
get_char(char * addr)584*b725ae77Skettenis get_char (char *addr)
585e93f7393Sniklas {
586e93f7393Sniklas return *addr;
587e93f7393Sniklas }
588e93f7393Sniklas
589e93f7393Sniklas void
set_char(char * addr,int val)590*b725ae77Skettenis set_char (char *addr, int val)
591e93f7393Sniklas {
592e93f7393Sniklas *addr = val;
593e93f7393Sniklas }
594e93f7393Sniklas
595e93f7393Sniklas /* convert the memory pointed to by mem into hex, placing result in buf */
596e93f7393Sniklas /* return a pointer to the last char put in buf (null) */
597e93f7393Sniklas /* If MAY_FAULT is non-zero, then we should set mem_err in response to
598e93f7393Sniklas a fault; if zero treat a fault like any other fault in the stub. */
599*b725ae77Skettenis char *
mem2hex(mem,buf,count,may_fault)600*b725ae77Skettenis mem2hex (mem, buf, count, may_fault)
601e93f7393Sniklas char *mem;
602e93f7393Sniklas char *buf;
603e93f7393Sniklas int count;
604e93f7393Sniklas int may_fault;
605e93f7393Sniklas {
606e93f7393Sniklas int i;
607e93f7393Sniklas unsigned char ch;
608e93f7393Sniklas
609e93f7393Sniklas if (may_fault)
610e93f7393Sniklas mem_fault_routine = set_mem_err;
611*b725ae77Skettenis for (i = 0; i < count; i++)
612*b725ae77Skettenis {
613e93f7393Sniklas ch = get_char (mem++);
614e93f7393Sniklas if (may_fault && mem_err)
615e93f7393Sniklas return (buf);
616e93f7393Sniklas *buf++ = hexchars[ch >> 4];
617e93f7393Sniklas *buf++ = hexchars[ch % 16];
618e93f7393Sniklas }
619e93f7393Sniklas *buf = 0;
620e93f7393Sniklas if (may_fault)
621e93f7393Sniklas mem_fault_routine = NULL;
622e93f7393Sniklas return (buf);
623e93f7393Sniklas }
624e93f7393Sniklas
625e93f7393Sniklas /* convert the hex array pointed to by buf into binary to be placed in mem */
626e93f7393Sniklas /* return a pointer to the character AFTER the last byte written */
627*b725ae77Skettenis char *
hex2mem(buf,mem,count,may_fault)628*b725ae77Skettenis hex2mem (buf, mem, count, may_fault)
629e93f7393Sniklas char *buf;
630e93f7393Sniklas char *mem;
631e93f7393Sniklas int count;
632e93f7393Sniklas int may_fault;
633e93f7393Sniklas {
634e93f7393Sniklas int i;
635e93f7393Sniklas unsigned char ch;
636e93f7393Sniklas
637e93f7393Sniklas if (may_fault)
638e93f7393Sniklas mem_fault_routine = set_mem_err;
639*b725ae77Skettenis for (i = 0; i < count; i++)
640*b725ae77Skettenis {
641e93f7393Sniklas ch = hex (*buf++) << 4;
642e93f7393Sniklas ch = ch + hex (*buf++);
643e93f7393Sniklas set_char (mem++, ch);
644e93f7393Sniklas if (may_fault && mem_err)
645e93f7393Sniklas return (mem);
646e93f7393Sniklas }
647e93f7393Sniklas if (may_fault)
648e93f7393Sniklas mem_fault_routine = NULL;
649e93f7393Sniklas return (mem);
650e93f7393Sniklas }
651e93f7393Sniklas
652e93f7393Sniklas /* this function takes the 386 exception vector and attempts to
653e93f7393Sniklas translate this number into a unix compatible signal value */
654*b725ae77Skettenis int
computeSignal(int exceptionVector)655*b725ae77Skettenis computeSignal (int exceptionVector)
656e93f7393Sniklas {
657e93f7393Sniklas int sigval;
658*b725ae77Skettenis switch (exceptionVector)
659*b725ae77Skettenis {
660*b725ae77Skettenis case 0:
661*b725ae77Skettenis sigval = 8;
662*b725ae77Skettenis break; /* divide by zero */
663*b725ae77Skettenis case 1:
664*b725ae77Skettenis sigval = 5;
665*b725ae77Skettenis break; /* debug exception */
666*b725ae77Skettenis case 3:
667*b725ae77Skettenis sigval = 5;
668*b725ae77Skettenis break; /* breakpoint */
669*b725ae77Skettenis case 4:
670*b725ae77Skettenis sigval = 16;
671*b725ae77Skettenis break; /* into instruction (overflow) */
672*b725ae77Skettenis case 5:
673*b725ae77Skettenis sigval = 16;
674*b725ae77Skettenis break; /* bound instruction */
675*b725ae77Skettenis case 6:
676*b725ae77Skettenis sigval = 4;
677*b725ae77Skettenis break; /* Invalid opcode */
678*b725ae77Skettenis case 7:
679*b725ae77Skettenis sigval = 8;
680*b725ae77Skettenis break; /* coprocessor not available */
681*b725ae77Skettenis case 8:
682*b725ae77Skettenis sigval = 7;
683*b725ae77Skettenis break; /* double fault */
684*b725ae77Skettenis case 9:
685*b725ae77Skettenis sigval = 11;
686*b725ae77Skettenis break; /* coprocessor segment overrun */
687*b725ae77Skettenis case 10:
688*b725ae77Skettenis sigval = 11;
689*b725ae77Skettenis break; /* Invalid TSS */
690*b725ae77Skettenis case 11:
691*b725ae77Skettenis sigval = 11;
692*b725ae77Skettenis break; /* Segment not present */
693*b725ae77Skettenis case 12:
694*b725ae77Skettenis sigval = 11;
695*b725ae77Skettenis break; /* stack exception */
696*b725ae77Skettenis case 13:
697*b725ae77Skettenis sigval = 11;
698*b725ae77Skettenis break; /* general protection */
699*b725ae77Skettenis case 14:
700*b725ae77Skettenis sigval = 11;
701*b725ae77Skettenis break; /* page fault */
702*b725ae77Skettenis case 16:
703*b725ae77Skettenis sigval = 7;
704*b725ae77Skettenis break; /* coprocessor error */
705e93f7393Sniklas default:
706e93f7393Sniklas sigval = 7; /* "software generated" */
707e93f7393Sniklas }
708e93f7393Sniklas return (sigval);
709e93f7393Sniklas }
710e93f7393Sniklas
711e93f7393Sniklas /**********************************************/
712e93f7393Sniklas /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
713e93f7393Sniklas /* RETURN NUMBER OF CHARS PROCESSED */
714e93f7393Sniklas /**********************************************/
715*b725ae77Skettenis int
hexToInt(char ** ptr,int * intValue)716*b725ae77Skettenis hexToInt (char **ptr, int *intValue)
717e93f7393Sniklas {
718e93f7393Sniklas int numChars = 0;
719e93f7393Sniklas int hexValue;
720e93f7393Sniklas
721e93f7393Sniklas *intValue = 0;
722e93f7393Sniklas
723e93f7393Sniklas while (**ptr)
724e93f7393Sniklas {
725e93f7393Sniklas hexValue = hex (**ptr);
726e93f7393Sniklas if (hexValue >= 0)
727e93f7393Sniklas {
728e93f7393Sniklas *intValue = (*intValue << 4) | hexValue;
729e93f7393Sniklas numChars++;
730e93f7393Sniklas }
731e93f7393Sniklas else
732e93f7393Sniklas break;
733e93f7393Sniklas
734e93f7393Sniklas (*ptr)++;
735e93f7393Sniklas }
736e93f7393Sniklas
737e93f7393Sniklas return (numChars);
738e93f7393Sniklas }
739e93f7393Sniklas
740e93f7393Sniklas /*
741e93f7393Sniklas * This function does all command procesing for interfacing to gdb.
742e93f7393Sniklas */
743*b725ae77Skettenis void
handle_exception(int exceptionVector)744*b725ae77Skettenis handle_exception (int exceptionVector)
745e93f7393Sniklas {
746*b725ae77Skettenis int sigval, stepping;
747e93f7393Sniklas int addr, length;
748e93f7393Sniklas char *ptr;
749e93f7393Sniklas int newPC;
750e93f7393Sniklas
751e93f7393Sniklas gdb_i386vector = exceptionVector;
752e93f7393Sniklas
753*b725ae77Skettenis if (remote_debug)
754*b725ae77Skettenis {
755*b725ae77Skettenis printf ("vector=%d, sr=0x%x, pc=0x%x\n",
756*b725ae77Skettenis exceptionVector, registers[PS], registers[PC]);
757*b725ae77Skettenis }
758e93f7393Sniklas
759e93f7393Sniklas /* reply to host that an exception has occurred */
760e93f7393Sniklas sigval = computeSignal (exceptionVector);
761*b725ae77Skettenis
762*b725ae77Skettenis ptr = remcomOutBuffer;
763*b725ae77Skettenis
764*b725ae77Skettenis *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
765*b725ae77Skettenis *ptr++ = hexchars[sigval >> 4];
766*b725ae77Skettenis *ptr++ = hexchars[sigval & 0xf];
767*b725ae77Skettenis
768*b725ae77Skettenis *ptr++ = hexchars[ESP];
769*b725ae77Skettenis *ptr++ = ':';
770*b725ae77Skettenis ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */
771*b725ae77Skettenis *ptr++ = ';';
772*b725ae77Skettenis
773*b725ae77Skettenis *ptr++ = hexchars[EBP];
774*b725ae77Skettenis *ptr++ = ':';
775*b725ae77Skettenis ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */
776*b725ae77Skettenis *ptr++ = ';';
777*b725ae77Skettenis
778*b725ae77Skettenis *ptr++ = hexchars[PC];
779*b725ae77Skettenis *ptr++ = ':';
780*b725ae77Skettenis ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */
781*b725ae77Skettenis *ptr++ = ';';
782*b725ae77Skettenis
783*b725ae77Skettenis *ptr = '\0'
784*b725ae77Skettenis
785*b725ae77Skettenis putpacket (remcomOutBuffer);
786*b725ae77Skettenis
787*b725ae77Skettenis stepping = 0;
788*b725ae77Skettenis
789*b725ae77Skettenis while (1 == 1)
790*b725ae77Skettenis {
791*b725ae77Skettenis remcomOutBuffer[0] = 0;
792*b725ae77Skettenis ptr = getpacket ();
793*b725ae77Skettenis
794*b725ae77Skettenis switch (*ptr++)
795*b725ae77Skettenis {
796*b725ae77Skettenis case '?':
797e93f7393Sniklas remcomOutBuffer[0] = 'S';
798e93f7393Sniklas remcomOutBuffer[1] = hexchars[sigval >> 4];
799e93f7393Sniklas remcomOutBuffer[2] = hexchars[sigval % 16];
800e93f7393Sniklas remcomOutBuffer[3] = 0;
801e93f7393Sniklas break;
802*b725ae77Skettenis case 'd':
803*b725ae77Skettenis remote_debug = !(remote_debug); /* toggle debug flag */
804e93f7393Sniklas break;
805e93f7393Sniklas case 'g': /* return the value of the CPU registers */
806e93f7393Sniklas mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
807e93f7393Sniklas break;
808e93f7393Sniklas case 'G': /* set the value of the CPU registers - return OK */
809*b725ae77Skettenis hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
810e93f7393Sniklas strcpy (remcomOutBuffer, "OK");
811e93f7393Sniklas break;
812*b725ae77Skettenis case 'P': /* set the value of a single CPU register - return OK */
813*b725ae77Skettenis {
814*b725ae77Skettenis int regno;
815*b725ae77Skettenis
816*b725ae77Skettenis if (hexToInt (&ptr, ®no) && *ptr++ == '=')
817*b725ae77Skettenis if (regno >= 0 && regno < NUMREGS)
818*b725ae77Skettenis {
819*b725ae77Skettenis hex2mem (ptr, (char *) ®isters[regno], 4, 0);
820*b725ae77Skettenis strcpy (remcomOutBuffer, "OK");
821*b725ae77Skettenis break;
822*b725ae77Skettenis }
823*b725ae77Skettenis
824*b725ae77Skettenis strcpy (remcomOutBuffer, "E01");
825*b725ae77Skettenis break;
826*b725ae77Skettenis }
827e93f7393Sniklas
828e93f7393Sniklas /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
829e93f7393Sniklas case 'm':
830e93f7393Sniklas /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
831e93f7393Sniklas if (hexToInt (&ptr, &addr))
832e93f7393Sniklas if (*(ptr++) == ',')
833e93f7393Sniklas if (hexToInt (&ptr, &length))
834e93f7393Sniklas {
835e93f7393Sniklas ptr = 0;
836e93f7393Sniklas mem_err = 0;
837e93f7393Sniklas mem2hex ((char *) addr, remcomOutBuffer, length, 1);
838*b725ae77Skettenis if (mem_err)
839*b725ae77Skettenis {
840e93f7393Sniklas strcpy (remcomOutBuffer, "E03");
841e93f7393Sniklas debug_error ("memory fault");
842e93f7393Sniklas }
843e93f7393Sniklas }
844e93f7393Sniklas
845e93f7393Sniklas if (ptr)
846e93f7393Sniklas {
847e93f7393Sniklas strcpy (remcomOutBuffer, "E01");
848e93f7393Sniklas }
849e93f7393Sniklas break;
850e93f7393Sniklas
851e93f7393Sniklas /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
852e93f7393Sniklas case 'M':
853e93f7393Sniklas /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
854e93f7393Sniklas if (hexToInt (&ptr, &addr))
855e93f7393Sniklas if (*(ptr++) == ',')
856e93f7393Sniklas if (hexToInt (&ptr, &length))
857e93f7393Sniklas if (*(ptr++) == ':')
858e93f7393Sniklas {
859e93f7393Sniklas mem_err = 0;
860e93f7393Sniklas hex2mem (ptr, (char *) addr, length, 1);
861e93f7393Sniklas
862*b725ae77Skettenis if (mem_err)
863*b725ae77Skettenis {
864e93f7393Sniklas strcpy (remcomOutBuffer, "E03");
865e93f7393Sniklas debug_error ("memory fault");
866*b725ae77Skettenis }
867*b725ae77Skettenis else
868*b725ae77Skettenis {
869e93f7393Sniklas strcpy (remcomOutBuffer, "OK");
870e93f7393Sniklas }
871e93f7393Sniklas
872e93f7393Sniklas ptr = 0;
873e93f7393Sniklas }
874e93f7393Sniklas if (ptr)
875e93f7393Sniklas {
876e93f7393Sniklas strcpy (remcomOutBuffer, "E02");
877e93f7393Sniklas }
878e93f7393Sniklas break;
879e93f7393Sniklas
880e93f7393Sniklas /* cAA..AA Continue at address AA..AA(optional) */
881e93f7393Sniklas /* sAA..AA Step one instruction from AA..AA(optional) */
882e93f7393Sniklas case 's':
883*b725ae77Skettenis stepping = 1;
884*b725ae77Skettenis case 'c':
885e93f7393Sniklas /* try to read optional parameter, pc unchanged if no parm */
886e93f7393Sniklas if (hexToInt (&ptr, &addr))
887e93f7393Sniklas registers[PC] = addr;
888e93f7393Sniklas
889e93f7393Sniklas newPC = registers[PC];
890e93f7393Sniklas
891e93f7393Sniklas /* clear the trace bit */
892e93f7393Sniklas registers[PS] &= 0xfffffeff;
893e93f7393Sniklas
894e93f7393Sniklas /* set the trace bit if we're stepping */
895*b725ae77Skettenis if (stepping)
896*b725ae77Skettenis registers[PS] |= 0x100;
897e93f7393Sniklas
898e93f7393Sniklas _returnFromException (); /* this is a jump */
899e93f7393Sniklas break;
900e93f7393Sniklas
901e93f7393Sniklas /* kill the program */
902e93f7393Sniklas case 'k': /* do nothing */
903e93f7393Sniklas #if 0
904e93f7393Sniklas /* Huh? This doesn't look like "nothing".
905e93f7393Sniklas m68k-stub.c and sparc-stub.c don't have it. */
906e93f7393Sniklas BREAKPOINT ();
907e93f7393Sniklas #endif
908e93f7393Sniklas break;
909e93f7393Sniklas } /* switch */
910e93f7393Sniklas
911e93f7393Sniklas /* reply to the request */
912e93f7393Sniklas putpacket (remcomOutBuffer);
913e93f7393Sniklas }
914e93f7393Sniklas }
915e93f7393Sniklas
916e93f7393Sniklas /* this function is used to set up exception handlers for tracing and
917e93f7393Sniklas breakpoints */
918*b725ae77Skettenis void
set_debug_traps(void)919*b725ae77Skettenis set_debug_traps (void)
920e93f7393Sniklas {
921e93f7393Sniklas stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
922e93f7393Sniklas
923e93f7393Sniklas exceptionHandler (0, _catchException0);
924e93f7393Sniklas exceptionHandler (1, _catchException1);
925e93f7393Sniklas exceptionHandler (3, _catchException3);
926e93f7393Sniklas exceptionHandler (4, _catchException4);
927e93f7393Sniklas exceptionHandler (5, _catchException5);
928e93f7393Sniklas exceptionHandler (6, _catchException6);
929e93f7393Sniklas exceptionHandler (7, _catchException7);
930e93f7393Sniklas exceptionHandler (8, _catchException8);
931e93f7393Sniklas exceptionHandler (9, _catchException9);
932e93f7393Sniklas exceptionHandler (10, _catchException10);
933e93f7393Sniklas exceptionHandler (11, _catchException11);
934e93f7393Sniklas exceptionHandler (12, _catchException12);
935e93f7393Sniklas exceptionHandler (13, _catchException13);
936e93f7393Sniklas exceptionHandler (14, _catchException14);
937e93f7393Sniklas exceptionHandler (16, _catchException16);
938e93f7393Sniklas
939e93f7393Sniklas initialized = 1;
940e93f7393Sniklas }
941e93f7393Sniklas
942e93f7393Sniklas /* This function will generate a breakpoint exception. It is used at the
943e93f7393Sniklas beginning of a program to sync up with a debugger and can be used
944e93f7393Sniklas otherwise as a quick means to stop program execution and "break" into
945e93f7393Sniklas the debugger. */
946e93f7393Sniklas
947*b725ae77Skettenis void
breakpoint(void)948*b725ae77Skettenis breakpoint (void)
949e93f7393Sniklas {
950e93f7393Sniklas if (initialized)
951e93f7393Sniklas BREAKPOINT ();
952e93f7393Sniklas }
953