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