1 /****************************************************************************
2
3 THIS SOFTWARE IS NOT COPYRIGHTED
4
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
8
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
22 *
23 * Description: low level support for gdb debugger. $
24 *
25 * Considerations: only works on target hardware $
26 *
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
29 *
30 * NOTES: See Below $
31 *
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
33 *
34 * To enable debugger support, two things need to happen. One, a
35 * call to set_debug_traps() is necessary in order to allow any breakpoints
36 * or error conditions to be properly intercepted and reported to gdb.
37 * Two, a breakpoint needs to be generated to begin communication. This
38 * is most easily accomplished by a call to breakpoint(). Breakpoint()
39 * simulates a breakpoint by executing a trap #1.
40 *
41 * The external function exceptionHandler() is
42 * used to attach a specific handler to a specific 386 vector number.
43 * It should use the same privilege level it runs at. It should
44 * install it as an interrupt gate so that interrupts are masked
45 * while the handler runs.
46 *
47 * Because gdb will sometimes write to the stack area to execute function
48 * calls, this program cannot rely on using the supervisor stack so it
49 * uses it's own stack area reserved in the int array remcomStack.
50 *
51 *************
52 *
53 * The following gdb commands are supported:
54 *
55 * command function Return value
56 *
57 * g return the value of the CPU registers hex data or ENN
58 * G set the value of the CPU registers OK or ENN
59 *
60 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
61 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
62 *
63 * c Resume at current address SNN ( signal NN)
64 * cAA..AA Continue at address AA..AA SNN
65 *
66 * s Step one instruction SNN
67 * sAA..AA Step one instruction from AA..AA SNN
68 *
69 * k kill
70 *
71 * ? What was the last sigval ? SNN (signal NN)
72 *
73 * All commands and responses are sent with a packet which includes a
74 * checksum. A packet consists of
75 *
76 * $<packet info>#<checksum>.
77 *
78 * where
79 * <packet info> :: <characters representing the command or response>
80 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
81 *
82 * When a packet is received, it is first acknowledged with either '+' or '-'.
83 * '+' indicates a successful transfer. '-' indicates a failed transfer.
84 *
85 * Example:
86 *
87 * Host: Reply:
88 * $m0,10#2a +$00010203040506070809101112131415#42
89 *
90 ****************************************************************************/
91
92 #include <stdio.h>
93 #include <string.h>
94
95 #include "utility/utility.h" // for strcpy_s()
96
97 /************************************************************************
98 *
99 * external low-level support routines
100 */
101
102 extern void putDebugChar(); /* write a single character */
103 extern int getDebugChar(); /* read and return a single char */
104 extern void exceptionHandler(); /* assign an exception handler */
105
106 /************************************************************************/
107 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
108 /* at least NUMREGBYTES*2 are needed for register packets */
109 #define BUFMAX 400
110
111 static char initialized; /* boolean flag. != 0 means we've been initialized */
112
113 int remote_debug;
114 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
115
116 static const char hexchars[]="0123456789abcdef";
117
118 /* Number of registers. */
119 #define NUMREGS 16
120
121 /* Number of bytes of registers. */
122 #define NUMREGBYTES (NUMREGS * 4)
123
124 enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
125 PC /* also known as eip */,
126 PS /* also known as eflags */,
127 CS, SS, DS, ES, FS, GS};
128
129 /*
130 * these should not be static cuz they can be used outside this module
131 */
132 int registers[NUMREGS];
133
134 #ifndef WIN32 //MF
135
136 #define STACKSIZE 10000
137 int remcomStack[STACKSIZE/sizeof(int)];
138 static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
139
140 /*************************** ASSEMBLY CODE MACROS *************************/
141 /* */
142
143 extern void
144 return_to_prog ();
145
146 /* Restore the program's registers (including the stack pointer, which
147 means we get the right stack and don't have to worry about popping our
148 return address and any stack frames and so on) and return. */
149 asm(".text");
150 asm(".globl _return_to_prog");
151 asm("_return_to_prog:");
152 asm(" movw _registers+44, %ss");
153 asm(" movl _registers+16, %esp");
154 asm(" movl _registers+4, %ecx");
155 asm(" movl _registers+8, %edx");
156 asm(" movl _registers+12, %ebx");
157 asm(" movl _registers+20, %ebp");
158 asm(" movl _registers+24, %esi");
159 asm(" movl _registers+28, %edi");
160 asm(" movw _registers+48, %ds");
161 asm(" movw _registers+52, %es");
162 asm(" movw _registers+56, %fs");
163 asm(" movw _registers+60, %gs");
164 asm(" movl _registers+36, %eax");
165 asm(" pushl %eax"); /* saved eflags */
166 asm(" movl _registers+40, %eax");
167 asm(" pushl %eax"); /* saved cs */
168 asm(" movl _registers+32, %eax");
169 asm(" pushl %eax"); /* saved eip */
170 asm(" movl _registers, %eax");
171
172 asm("ret"); //MF
173
174 /* use iret to restore pc and flags together so
175 that trace flag works right. */
176 asm(" iret");
177
178
179 #ifdef WIN32 //MF
180 asm(".data"); //MF
181 #endif
182
183 /* Put the error code here just in case the user cares. */
184 int gdb_i386errcode;
185 /* Likewise, the vector number here (since GDB only gets the signal
186 number through the usual means, and that's not very specific). */
187 int gdb_i386vector = -1;
188
189 /* GDB stores segment registers in 32-bit words (that's just the way
190 m-i386v.h is written). So zero the appropriate areas in registers. */
191 #define SAVE_REGISTERS1() \
192 asm ("movl %eax, _registers"); \
193 asm ("movl %ecx, _registers+4"); \
194 asm ("movl %edx, _registers+8"); \
195 asm ("movl %ebx, _registers+12"); \
196 asm ("movl %ebp, _registers+20"); \
197 asm ("movl %esi, _registers+24"); \
198 asm ("movl %edi, _registers+28"); \
199 asm ("movw $0, %ax"); \
200 asm ("movw %ds, _registers+48"); \
201 asm ("movw %ax, _registers+50"); \
202 asm ("movw %es, _registers+52"); \
203 asm ("movw %ax, _registers+54"); \
204 asm ("movw %fs, _registers+56"); \
205 asm ("movw %ax, _registers+58"); \
206 asm ("movw %gs, _registers+60"); \
207 asm ("movw %ax, _registers+62");
208 #define SAVE_ERRCODE() \
209 asm ("popl %ebx"); \
210 asm ("movl %ebx, _gdb_i386errcode");
211 #define SAVE_REGISTERS2() \
212 asm ("popl %ebx"); /* old eip */ \
213 asm ("movl %ebx, _registers+32"); \
214 asm ("popl %ebx"); /* old cs */ \
215 asm ("movl %ebx, _registers+40"); \
216 asm ("movw %ax, _registers+42"); \
217 asm ("popl %ebx"); /* old eflags */ \
218 asm ("movl %ebx, _registers+36"); \
219 /* Now that we've done the pops, we can save the stack pointer."); */ \
220 asm ("movw %ss, _registers+44"); \
221 asm ("movw %ax, _registers+46"); \
222 asm ("movl %esp, _registers+16");
223
224 /* See if mem_fault_routine is set, if so just IRET to that address. */
225 #define CHECK_FAULT() \
226 asm ("cmpl $0, _mem_fault_routine"); \
227 asm ("jne mem_fault");
228
229 asm (".text");
230 asm ("mem_fault:");
231 /* OK to clobber temp registers; we're just going to end up in set_mem_err. */
232 /* Pop error code from the stack and save it. */
233 asm (" popl %eax");
234 asm (" movl %eax, _gdb_i386errcode");
235
236 asm (" popl %eax"); /* eip */
237 /* We don't want to return there, we want to return to the function
238 pointed to by mem_fault_routine instead. */
239 asm (" movl _mem_fault_routine, %eax");
240 asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
241 asm (" popl %edx"); /* eflags */
242
243 /* Remove this stack frame; when we do the iret, we will be going to
244 the start of a function, so we want the stack to look just like it
245 would after a "call" instruction. */
246 asm (" leave");
247
248 /* Push the stuff that iret wants. */
249 asm (" pushl %edx"); /* eflags */
250 asm (" pushl %ecx"); /* cs */
251 asm (" pushl %eax"); /* eip */
252
253 /* Zero mem_fault_routine. */
254 asm (" movl $0, %eax");
255 asm (" movl %eax, _mem_fault_routine");
256
257 asm ("iret");
258
259
260 #define CALL_HOOK() asm("call _remcomHandler");
261
262 /* This function is called when a i386 exception occurs. It saves
263 * all the cpu regs in the _registers array, munges the stack a bit,
264 * and invokes an exception handler (remcom_handler).
265 *
266 * stack on entry: stack on exit:
267 * old eflags vector number
268 * old cs (zero-filled to 32 bits)
269 * old eip
270 *
271 */
272 extern void _catchException3();
273 asm(".text");
274 asm(".globl __catchException3");
275 asm("__catchException3:");
276 SAVE_REGISTERS1();
277 SAVE_REGISTERS2();
278 asm ("pushl $3");
279 CALL_HOOK();
280
281 /* Same thing for exception 1. */
282 extern void _catchException1();
283 asm(".text");
284 asm(".globl __catchException1");
285 asm("__catchException1:");
286 SAVE_REGISTERS1();
287 SAVE_REGISTERS2();
288 asm ("pushl $1");
289 CALL_HOOK();
290
291 /* Same thing for exception 0. */
292 extern void _catchException0();
293 asm(".text");
294 asm(".globl __catchException0");
295 asm("__catchException0:");
296 SAVE_REGISTERS1();
297 SAVE_REGISTERS2();
298 asm ("pushl $0");
299 CALL_HOOK();
300
301 /* Same thing for exception 4. */
302 extern void _catchException4();
303 asm(".text");
304 asm(".globl __catchException4");
305 asm("__catchException4:");
306 SAVE_REGISTERS1();
307 SAVE_REGISTERS2();
308 asm ("pushl $4");
309 CALL_HOOK();
310
311 /* Same thing for exception 5. */
312 extern void _catchException5();
313 asm(".text");
314 asm(".globl __catchException5");
315 asm("__catchException5:");
316 SAVE_REGISTERS1();
317 SAVE_REGISTERS2();
318 asm ("pushl $5");
319 CALL_HOOK();
320
321 /* Same thing for exception 6. */
322 extern void _catchException6();
323 asm(".text");
324 asm(".globl __catchException6");
325 asm("__catchException6:");
326 SAVE_REGISTERS1();
327 SAVE_REGISTERS2();
328 asm ("pushl $6");
329 CALL_HOOK();
330
331 /* Same thing for exception 7. */
332 extern void _catchException7();
333 asm(".text");
334 asm(".globl __catchException7");
335 asm("__catchException7:");
336 SAVE_REGISTERS1();
337 SAVE_REGISTERS2();
338 asm ("pushl $7");
339 CALL_HOOK();
340
341 /* Same thing for exception 8. */
342 extern void _catchException8();
343 asm(".text");
344 asm(".globl __catchException8");
345 asm("__catchException8:");
346 SAVE_REGISTERS1();
347 SAVE_ERRCODE();
348 SAVE_REGISTERS2();
349 asm ("pushl $8");
350 CALL_HOOK();
351
352 /* Same thing for exception 9. */
353 extern void _catchException9();
354 asm(".text");
355 asm(".globl __catchException9");
356 asm("__catchException9:");
357 SAVE_REGISTERS1();
358 SAVE_REGISTERS2();
359 asm ("pushl $9");
360 CALL_HOOK();
361
362 /* Same thing for exception 10. */
363 extern void _catchException10();
364 asm(".text");
365 asm(".globl __catchException10");
366 asm("__catchException10:");
367 SAVE_REGISTERS1();
368 SAVE_ERRCODE();
369 SAVE_REGISTERS2();
370 asm ("pushl $10");
371 CALL_HOOK();
372
373 /* Same thing for exception 12. */
374 extern void _catchException12();
375 asm(".text");
376 asm(".globl __catchException12");
377 asm("__catchException12:");
378 SAVE_REGISTERS1();
379 SAVE_ERRCODE();
380 SAVE_REGISTERS2();
381 asm ("pushl $12");
382 CALL_HOOK();
383
384 /* Same thing for exception 16. */
385 extern void _catchException16();
386 asm(".text");
387 asm(".globl __catchException16");
388 asm("__catchException16:");
389 SAVE_REGISTERS1();
390 SAVE_REGISTERS2();
391 asm ("pushl $16");
392 CALL_HOOK();
393
394 /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
395
396 /* Same thing for exception 13. */
397 extern void _catchException13 ();
398 asm (".text");
399 asm (".globl __catchException13");
400 asm ("__catchException13:");
401 CHECK_FAULT();
402 SAVE_REGISTERS1();
403 SAVE_ERRCODE();
404 SAVE_REGISTERS2();
405 asm ("pushl $13");
406 CALL_HOOK();
407
408 /* Same thing for exception 11. */
409 extern void _catchException11 ();
410 asm (".text");
411 asm (".globl __catchException11");
412 asm ("__catchException11:");
413 CHECK_FAULT();
414 SAVE_REGISTERS1();
415 SAVE_ERRCODE();
416 SAVE_REGISTERS2();
417 asm ("pushl $11");
418 CALL_HOOK();
419
420 /* Same thing for exception 14. */
421 extern void _catchException14 ();
422 asm (".text");
423 asm (".globl __catchException14");
424 asm ("__catchException14:");
425 CHECK_FAULT();
426 SAVE_REGISTERS1();
427 SAVE_ERRCODE();
428 SAVE_REGISTERS2();
429 asm ("pushl $14");
430 CALL_HOOK();
431
432 /*
433 * remcomHandler is a front end for handle_exception. It moves the
434 * stack pointer into an area reserved for debugger use.
435 */
436 asm("_remcomHandler:");
437 asm(" popl %eax"); /* pop off return address */
438 asm(" popl %eax"); /* get the exception number */
439 asm(" movl _stackPtr, %esp"); /* move to remcom stack area */
440 asm(" pushl %eax"); /* push exception onto stack */
441 asm(" call _handle_exception"); /* this never returns */
442
443
444 void
_returnFromException()445 _returnFromException ()
446 {
447 return_to_prog ();
448 }
449
450 #endif // !WIN32
451
452
453 #ifdef _MSC_VER //MF
454 #define BREAKPOINT() __asm int 3;
455 #else
456 #define BREAKPOINT() asm(" int $3");
457 #endif
458
459
460 #ifdef WIN32 //MF
461
462 #define WIN32_LEAN_AND_MEAN
463 //#include <windows.h>
464
465 void handle_exception(int exceptionVector);
466
win32_exception_handler(EXCEPTION_POINTERS * exc_info)467 void win32_exception_handler(EXCEPTION_POINTERS* exc_info)
468 {
469 PCONTEXT ctx = exc_info->ContextRecord;
470
471 registers[EAX] = ctx->Eax;
472 registers[ECX] = ctx->Ecx;
473 registers[EDX] = ctx->Edx;
474 registers[EBX] = ctx->Ebx;
475 registers[ESP] = ctx->Esp;
476 registers[EBP] = ctx->Ebp;
477 registers[ESI] = ctx->Esi;
478 registers[EDI] = ctx->Edi;
479 registers[PC] = ctx->Eip;
480 registers[PS] = ctx->EFlags;
481 registers[CS] = ctx->SegCs;
482 registers[SS] = ctx->SegSs;
483 registers[DS] = ctx->SegDs;
484 registers[ES] = ctx->SegEs;
485 registers[FS] = ctx->SegFs;
486 registers[GS] = ctx->SegGs;
487
488 handle_exception(exc_info->ExceptionRecord->ExceptionCode & 0xFFFF);
489
490 ctx->Eax = registers[EAX];
491 ctx->Ecx = registers[ECX];
492 ctx->Edx = registers[EDX];
493 ctx->Ebx = registers[EBX];
494 ctx->Esp = registers[ESP];
495 ctx->Ebp = registers[EBP];
496 ctx->Esi = registers[ESI];
497 ctx->Edi = registers[EDI];
498 ctx->Eip = registers[PC];
499 ctx->EFlags = registers[PS];
500 ctx->SegCs = registers[CS];
501 ctx->SegSs = registers[SS];
502 ctx->SegDs = registers[DS];
503 ctx->SegEs = registers[ES];
504 ctx->SegFs = registers[FS];
505 ctx->SegGs = registers[GS];
506 }
507
508 #endif // WIN32
509
510
511 int
hex(ch)512 hex (ch)
513 char ch;
514 {
515 if ((ch >= 'a') && (ch <= 'f'))
516 return (ch - 'a' + 10);
517 if ((ch >= '0') && (ch <= '9'))
518 return (ch - '0');
519 if ((ch >= 'A') && (ch <= 'F'))
520 return (ch - 'A' + 10);
521 return (-1);
522 }
523
524 static char remcomInBuffer[BUFMAX];
525 static char remcomOutBuffer[BUFMAX];
526
527 /* scan for the sequence $<data>#<checksum> */
528
529 char *
getpacket(void)530 getpacket (void)
531 {
532 char *buffer = &remcomInBuffer[0];
533 unsigned char checksum;
534 unsigned char xmitcsum;
535 int count;
536 char ch;
537
538 while (1)
539 {
540 /* wait around for the start character, ignore all other characters */
541 while ((ch = getDebugChar ()) != '$')
542 ;
543
544 retry:
545 checksum = 0;
546 xmitcsum = -1;
547 count = 0;
548
549 /* now, read until a # or end of buffer is found */
550 while (count < BUFMAX - 1)
551 {
552 ch = getDebugChar ();
553 if (ch == '$')
554 goto retry;
555 if (ch == '#')
556 break;
557 checksum = checksum + ch;
558 buffer[count] = ch;
559 count = count + 1;
560 }
561 buffer[count] = 0;
562
563 if (ch == '#')
564 {
565 ch = getDebugChar ();
566 xmitcsum = hex (ch) << 4;
567 ch = getDebugChar ();
568 xmitcsum += hex (ch);
569
570 if (checksum != xmitcsum)
571 {
572 if (remote_debug)
573 {
574 fprintf (stderr,
575 "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
576 checksum, xmitcsum, buffer);
577 }
578 putDebugChar ('-'); /* failed checksum */
579 }
580 else
581 {
582 putDebugChar ('+'); /* successful transfer */
583
584 /* if a sequence char is present, reply the sequence ID */
585 if (buffer[2] == ':')
586 {
587 putDebugChar (buffer[0]);
588 putDebugChar (buffer[1]);
589
590 return &buffer[3];
591 }
592
593 return &buffer[0];
594 }
595 }
596 }
597 }
598
599 /* send the packet in buffer. */
600
601 void
putpacket(char * buffer)602 putpacket (char *buffer)
603 {
604 unsigned char checksum;
605 int count;
606 char ch;
607
608 /* $<packet info>#<checksum>. */
609 do
610 {
611 putDebugChar ('$');
612 checksum = 0;
613 count = 0;
614
615 while ((ch = buffer[count]) != 0)
616 {
617 putDebugChar (ch);
618 checksum += ch;
619 count += 1;
620 }
621
622 putDebugChar ('#');
623 putDebugChar (hexchars[checksum >> 4]);
624 putDebugChar (hexchars[checksum % 16]);
625
626 }
627 while (getDebugChar () != '+');
628 }
629
debug_error(char * format)630 void debug_error (char* format/*, char* parm*/)
631 {
632 if (remote_debug)
633 fprintf (stderr, format/*, parm*/);
634 }
635
636 /* Address of a routine to RTE to if we get a memory fault. */
637 static void (*volatile mem_fault_routine) () = NULL;
638
639 /* Indicate to caller of mem2hex or hex2mem that there has been an
640 error. */
641 static volatile int mem_err = 0;
642
643 void
set_mem_err(void)644 set_mem_err (void)
645 {
646 mem_err = 1;
647 }
648
649 /* These are separate functions so that they are so short and sweet
650 that the compiler won't save any registers (if there is a fault
651 to mem_fault, they won't get restored, so there better not be any
652 saved). */
653 int
get_char(char * addr)654 get_char (char *addr)
655 {
656 return *addr;
657 }
658
659 void
set_char(char * addr,int val)660 set_char (char *addr, int val)
661 {
662 *addr = val;
663 }
664
665 /* convert the memory pointed to by mem into hex, placing result in buf */
666 /* return a pointer to the last char put in buf (null) */
667 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
668 a fault; if zero treat a fault like any other fault in the stub. */
669 char *
mem2hex(mem,buf,count,may_fault)670 mem2hex (mem, buf, count, may_fault)
671 char *mem;
672 char *buf;
673 int count;
674 int may_fault;
675 {
676 int i;
677 unsigned char ch;
678
679 #ifdef WIN32 //MF
680 if (IsBadReadPtr(mem, count))
681 return mem;
682 #else
683 if (may_fault)
684 mem_fault_routine = set_mem_err;
685 #endif
686 for (i = 0; i < count; i++)
687 {
688 ch = get_char (mem++);
689 if (may_fault && mem_err)
690 return (buf);
691 *buf++ = hexchars[ch >> 4];
692 *buf++ = hexchars[ch % 16];
693 }
694 *buf = 0;
695 #ifndef WIN32 //MF
696 if (may_fault)
697 mem_fault_routine = NULL;
698 #endif
699 return (buf);
700 }
701
702 /* convert the hex array pointed to by buf into binary to be placed in mem */
703 /* return a pointer to the character AFTER the last byte written */
704 char *
hex2mem(buf,mem,count,may_fault)705 hex2mem (buf, mem, count, may_fault)
706 char *buf;
707 char *mem;
708 int count;
709 int may_fault;
710 {
711 int i;
712 unsigned char ch;
713
714 #ifdef WIN32 //MF
715 // MinGW does not support structured exception handling, so let's
716 // go safe and make memory writable by default
717 DWORD old_protect;
718
719 VirtualProtect(mem, count, PAGE_EXECUTE_READWRITE, &old_protect);
720 #else
721 if (may_fault)
722 mem_fault_routine = set_mem_err;
723 #endif
724
725 for (i = 0; i < count; i++)
726 {
727 ch = hex (*buf++) << 4;
728 ch = ch + hex (*buf++);
729 set_char (mem++, ch);
730 if (may_fault && mem_err)
731 return (mem);
732 }
733
734 #ifndef WIN32 //MF
735 if (may_fault)
736 mem_fault_routine = NULL;
737 #endif
738
739 return (mem);
740 }
741
742 /* this function takes the 386 exception vector and attempts to
743 translate this number into a unix compatible signal value */
744 int
computeSignal(int exceptionVector)745 computeSignal (int exceptionVector)
746 {
747 int sigval;
748 switch (exceptionVector)
749 {
750 case 0:
751 sigval = 8;
752 break; /* divide by zero */
753 case 1:
754 sigval = 5;
755 break; /* debug exception */
756 case 3:
757 sigval = 5;
758 break; /* breakpoint */
759 case 4:
760 sigval = 16;
761 break; /* into instruction (overflow) */
762 case 5:
763 sigval = 16;
764 break; /* bound instruction */
765 case 6:
766 sigval = 4;
767 break; /* Invalid opcode */
768 case 7:
769 sigval = 8;
770 break; /* coprocessor not available */
771 case 8:
772 sigval = 7;
773 break; /* double fault */
774 case 9:
775 sigval = 11;
776 break; /* coprocessor segment overrun */
777 case 10:
778 sigval = 11;
779 break; /* Invalid TSS */
780 case 11:
781 sigval = 11;
782 break; /* Segment not present */
783 case 12:
784 sigval = 11;
785 break; /* stack exception */
786 case 13:
787 sigval = 11;
788 break; /* general protection */
789 case 14:
790 sigval = 11;
791 break; /* page fault */
792 case 16:
793 sigval = 7;
794 break; /* coprocessor error */
795 default:
796 sigval = 7; /* "software generated" */
797 }
798 return (sigval);
799 }
800
801 /**********************************************/
802 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
803 /* RETURN NUMBER OF CHARS PROCESSED */
804 /**********************************************/
805 int
hexToInt(char ** ptr,int * intValue)806 hexToInt (char **ptr, int *intValue)
807 {
808 int numChars = 0;
809 int hexValue;
810
811 *intValue = 0;
812
813 while (**ptr)
814 {
815 hexValue = hex (**ptr);
816 if (hexValue >= 0)
817 {
818 *intValue = (*intValue << 4) | hexValue;
819 numChars++;
820 }
821 else
822 break;
823
824 (*ptr)++;
825 }
826
827 return (numChars);
828 }
829
830 /*
831 * This function does all command procesing for interfacing to gdb.
832 */
833 void
handle_exception(int exceptionVector)834 handle_exception (int exceptionVector)
835 {
836 int sigval, stepping;
837 int addr, length;
838 char *ptr;
839
840 #ifndef WIN32 //MF
841 gdb_i386vector = exceptionVector;
842 #endif
843
844 if (remote_debug)
845 {
846 printf ("vector=%d, sr=0x%x, pc=0x%x\n",
847 exceptionVector, registers[PS], registers[PC]);
848 }
849
850 /* reply to host that an exception has occurred */
851 sigval = computeSignal (exceptionVector);
852
853 ptr = remcomOutBuffer;
854
855 *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
856 *ptr++ = hexchars[sigval >> 4];
857 *ptr++ = hexchars[sigval & 0xf];
858
859 *ptr++ = hexchars[ESP];
860 *ptr++ = ':';
861 ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */
862 *ptr++ = ';';
863
864 *ptr++ = hexchars[EBP];
865 *ptr++ = ':';
866 ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */
867 *ptr++ = ';';
868
869 *ptr++ = hexchars[PC];
870 *ptr++ = ':';
871 ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */
872 *ptr++ = ';';
873
874 *ptr = '\0';
875
876 putpacket (remcomOutBuffer);
877
878 stepping = 0;
879
880 while (1 == 1)
881 {
882 remcomOutBuffer[0] = 0;
883 ptr = getpacket ();
884
885 switch (*ptr++)
886 {
887 case '?':
888 remcomOutBuffer[0] = 'S';
889 remcomOutBuffer[1] = hexchars[sigval >> 4];
890 remcomOutBuffer[2] = hexchars[sigval % 16];
891 remcomOutBuffer[3] = 0;
892 break;
893 case 'd':
894 remote_debug = !(remote_debug); /* toggle debug flag */
895 break;
896 case 'g': /* return the value of the CPU registers */
897 mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
898 break;
899 case 'G': /* set the value of the CPU registers - return OK */
900 hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
901 strcpy_s(remcomOutBuffer, BUFMAX, "OK");
902 break;
903 case 'P': /* set the value of a single CPU register - return OK */
904 {
905 int regno;
906
907 if (hexToInt (&ptr, ®no) && *ptr++ == '=')
908 if (regno >= 0 && regno < NUMREGS)
909 {
910 hex2mem (ptr, (char *) ®isters[regno], 4, 0);
911 strcpy_s(remcomOutBuffer, BUFMAX, "OK");
912 break;
913 }
914
915 strcpy_s(remcomOutBuffer, BUFMAX, "E01");
916 break;
917 }
918
919 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
920 case 'm':
921 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
922 if (hexToInt (&ptr, &addr))
923 if (*(ptr++) == ',')
924 if (hexToInt (&ptr, &length))
925 {
926 ptr = 0;
927 mem_err = 0;
928 mem2hex ((char *) addr, remcomOutBuffer, length, 1);
929 if (mem_err)
930 {
931 strcpy_s(remcomOutBuffer, BUFMAX, "E03");
932 debug_error ("memory fault");
933 }
934 }
935
936 if (ptr)
937 {
938 strcpy_s(remcomOutBuffer, BUFMAX, "E01");
939 }
940 break;
941
942 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
943 case 'M':
944 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
945 if (hexToInt (&ptr, &addr))
946 if (*(ptr++) == ',')
947 if (hexToInt (&ptr, &length))
948 if (*(ptr++) == ':')
949 {
950 mem_err = 0;
951 hex2mem (ptr, (char *) addr, length, 1);
952
953 if (mem_err)
954 {
955 strcpy_s(remcomOutBuffer, BUFMAX, "E03");
956 debug_error ("memory fault");
957 }
958 else
959 {
960 strcpy_s(remcomOutBuffer, BUFMAX, "OK");
961 }
962
963 ptr = 0;
964 }
965 if (ptr)
966 {
967 strcpy_s(remcomOutBuffer, BUFMAX, "E02");
968 }
969 break;
970
971 /* cAA..AA Continue at address AA..AA(optional) */
972 /* sAA..AA Step one instruction from AA..AA(optional) */
973 case 's':
974 stepping = 1;
975 case 'c':
976 /* try to read optional parameter, pc unchanged if no parm */
977 if (hexToInt (&ptr, &addr))
978 registers[PC] = addr;
979
980 /* clear the trace bit */
981 registers[PS] &= 0xfffffeff;
982
983 /* set the trace bit if we're stepping */
984 if (stepping)
985 registers[PS] |= 0x100;
986
987 #ifdef WIN32 //MF
988 return;
989 #else
990 _returnFromException (); /* this is a jump */
991 #endif
992 break;
993
994 /* kill the program */
995 case 'k': /* do nothing */
996 #if 0
997 /* Huh? This doesn't look like "nothing".
998 m68k-stub.c and sparc-stub.c don't have it. */
999 BREAKPOINT ();
1000 #endif
1001 break;
1002 } /* switch */
1003
1004 /* reply to the request */
1005 putpacket (remcomOutBuffer);
1006 }
1007 }
1008
1009 /* this function is used to set up exception handlers for tracing and
1010 breakpoints */
1011 void
set_debug_traps(void)1012 set_debug_traps (void)
1013 {
1014 #ifndef WIN32 //MF
1015 stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
1016
1017 exceptionHandler (0, _catchException0);
1018 exceptionHandler (1, _catchException1);
1019 exceptionHandler (3, _catchException3);
1020 exceptionHandler (4, _catchException4);
1021 exceptionHandler (5, _catchException5);
1022 exceptionHandler (6, _catchException6);
1023 exceptionHandler (7, _catchException7);
1024 exceptionHandler (8, _catchException8);
1025 exceptionHandler (9, _catchException9);
1026 exceptionHandler (10, _catchException10);
1027 exceptionHandler (11, _catchException11);
1028 exceptionHandler (12, _catchException12);
1029 exceptionHandler (13, _catchException13);
1030 exceptionHandler (14, _catchException14);
1031 exceptionHandler (16, _catchException16);
1032 #endif // WIN32
1033
1034 initialized = 1;
1035 }
1036
1037 /* This function will generate a breakpoint exception. It is used at the
1038 beginning of a program to sync up with a debugger and can be used
1039 otherwise as a quick means to stop program execution and "break" into
1040 the debugger. */
1041
1042 void
breakpoint(void)1043 breakpoint (void)
1044 {
1045 if (initialized)
1046 BREAKPOINT ();
1047 }
1048
1049
1050
1051 //
1052 // debugger stub implementation for WIN32 applications
1053 // M. Fuchs, 29.11.2003
1054 //
1055
1056 #ifdef WIN32
1057
1058 #include <stdlib.h>
1059 #include <errno.h>
1060
1061 #include "utility/utility.h"
1062
1063
1064 int s_initial_breakpoint = 0;
1065
1066
1067 #ifdef DEBUG_SERIAL
1068
1069 FILE* ser_port = NULL;
1070
init_gdb_connect()1071 int init_gdb_connect()
1072 {
1073 //TODO: set up connection using serial communication port
1074
1075 ser_port = fopen("COM1:", "rwb");
1076
1077 return 1;
1078 }
1079
getDebugChar()1080 int getDebugChar()
1081 {
1082 return fgetc(ser_port);
1083 }
1084
putDebugChar(int c)1085 void putDebugChar(int c)
1086 {
1087 fputc(c, ser_port);
1088 }
1089
1090
1091 #else // DEBUG_SERIAL
1092
1093
1094 static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler = 0;
1095
1096
1097 #define I386_EXCEPTION_CNT 17
1098
exc_protection_handler(EXCEPTION_POINTERS * exc_info)1099 LONG WINAPI exc_protection_handler(EXCEPTION_POINTERS* exc_info)
1100 {
1101 int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF;
1102
1103 if (exc_nr < I386_EXCEPTION_CNT) {
1104 //LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr));
1105
1106 if (exc_nr==11 || exc_nr==13 || exc_nr==14) {
1107 if (mem_fault_routine)
1108 mem_fault_routine();
1109 }
1110
1111 ++exc_info->ContextRecord->Eip;
1112 }
1113
1114 return EXCEPTION_CONTINUE_EXECUTION;
1115 }
1116
exc_handler(EXCEPTION_POINTERS * exc_info)1117 LONG WINAPI exc_handler(EXCEPTION_POINTERS* exc_info)
1118 {
1119 int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF;
1120
1121 if (exc_nr < I386_EXCEPTION_CNT) {
1122 //LOG(FmtString("Exception %x", exc_nr));
1123 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1124
1125 // step over initial breakpoint
1126 if (s_initial_breakpoint) {
1127 s_initial_breakpoint = 0;
1128 ++exc_info->ContextRecord->Eip;
1129 }
1130
1131 SetUnhandledExceptionFilter(exc_protection_handler);
1132
1133 win32_exception_handler(exc_info);
1134 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1135
1136 SetUnhandledExceptionFilter(exc_handler);
1137
1138 return EXCEPTION_CONTINUE_EXECUTION;
1139 }
1140
1141 return EXCEPTION_CONTINUE_SEARCH;
1142 }
1143
1144 /* not needed because we use win32_exception_handler() instead of catchExceptionX()
1145 void exceptionHandler(int exc_nr, void* exc_addr)
1146 {
1147 if (exc_nr>=0 && exc_nr<I386_EXCEPTION_CNT)
1148 exc_handlers[exc_nr] = exc_addr;
1149 }
1150 */
1151
disable_debugging()1152 void disable_debugging()
1153 {
1154 if (s_prev_exc_handler) {
1155 SetUnhandledExceptionFilter(s_prev_exc_handler);
1156 s_prev_exc_handler = 0;
1157 }
1158 }
1159
1160 #define _INC_WINDOWS
1161 #include <winsock.h>
1162 #ifdef _MSC_VER
1163 #pragma comment(lib, "wsock32")
1164 #endif
1165
1166 static int s_rem_fd = -1;
1167
init_gdb_connect()1168 int init_gdb_connect()
1169 {
1170 SOCKADDR_IN srv_addr = {0};
1171 SOCKADDR_IN rem_addr;
1172 WSADATA wsa_data;
1173 int srv_socket, rem_len;
1174
1175 s_prev_exc_handler = SetUnhandledExceptionFilter(exc_handler);
1176
1177 if (WSAStartup(MAKEWORD(2,2), &wsa_data)) {
1178 fprintf(stderr, "WSAStartup() failed");
1179 return 0;
1180 }
1181
1182 srv_addr.sin_family = AF_INET;
1183 srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1184 srv_addr.sin_port = htons(9999);
1185
1186 srv_socket = socket(PF_INET, SOCK_STREAM, 0);
1187 if (srv_socket == -1) {
1188 perror("socket()");
1189 return 0;
1190 }
1191
1192 if (bind(srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) {
1193 perror("bind()");
1194 return 0;
1195 }
1196
1197 if (listen(srv_socket, 4) == -1) {
1198 perror("listen()");
1199 return 0;
1200 }
1201
1202 rem_len = sizeof(rem_addr);
1203
1204 for(;;) {
1205 s_rem_fd = accept(srv_socket, (struct sockaddr*)&rem_addr, &rem_len);
1206
1207 if (s_rem_fd < 0) {
1208 if (errno == EINTR)
1209 continue;
1210
1211 perror("accept()");
1212 return 0;
1213 }
1214
1215 break;
1216 }
1217
1218 return 1;
1219 }
1220
1221 #endif // DEBUG_SERIAL
1222
1223
getDebugChar()1224 int getDebugChar()
1225 {
1226 char buffer[1024];
1227 int r;
1228
1229 if (s_rem_fd == -1)
1230 return EOF;
1231
1232 r = recv(s_rem_fd, buffer, 1, 0);
1233 if (r == -1) {
1234 perror("recv()");
1235 LOG(TEXT("debugger connection broken"));
1236 s_rem_fd = -1;
1237 return EOF;
1238 }
1239
1240 if (!r)
1241 return EOF;
1242
1243 return buffer[0];
1244 }
1245
putDebugChar(int c)1246 void putDebugChar(int c)
1247 {
1248 if (s_rem_fd != -1) {
1249 const char buffer[] = {c};
1250
1251 if (!send(s_rem_fd, buffer, 1, 0)) {
1252 perror("send()");
1253 LOG(TEXT("debugger connection broken"));
1254 exit(-1);
1255 }
1256 }
1257 }
1258
1259
1260 // start up GDB stub interface
1261
initialize_gdb_stub()1262 int initialize_gdb_stub()
1263 {
1264 if (!init_gdb_connect())
1265 return 0;
1266
1267 set_debug_traps();
1268
1269 s_initial_breakpoint = 1;
1270 breakpoint();
1271
1272 return 1;
1273 }
1274
1275 #endif // WIN32
1276