xref: /openbsd-src/gnu/usr.bin/binutils/gdb/i386-stub.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
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 *)&registers[ESP], ptr, 4, 0);	/* SP */
771*b725ae77Skettenis   *ptr++ = ';';
772*b725ae77Skettenis 
773*b725ae77Skettenis   *ptr++ = hexchars[EBP];
774*b725ae77Skettenis   *ptr++ = ':';
775*b725ae77Skettenis   ptr = mem2hex((char *)&registers[EBP], ptr, 4, 0); 	/* FP */
776*b725ae77Skettenis   *ptr++ = ';';
777*b725ae77Skettenis 
778*b725ae77Skettenis   *ptr++ = hexchars[PC];
779*b725ae77Skettenis   *ptr++ = ':';
780*b725ae77Skettenis   ptr = mem2hex((char *)&registers[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, &regno) && *ptr++ == '=')
817*b725ae77Skettenis 	      if (regno >= 0 && regno < NUMREGS)
818*b725ae77Skettenis 		{
819*b725ae77Skettenis 		  hex2mem (ptr, (char *) &registers[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