1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
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.
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.
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.
53 * The following gdb commands are supported:
55 * command function Return value
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
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
63 * c Resume at current address SNN ( signal NN)
64 * cAA..AA Continue at address AA..AA SNN
66 * s Step one instruction SNN
67 * sAA..AA Step one instruction from AA..AA SNN
71 * ? What was the last sigval ? SNN (signal NN)
73 * All commands and responses are sent with a packet which includes a
74 * checksum. A packet consists of
76 * $<packet info>#<checksum>.
79 * <packet info> :: <characters representing the command or response>
80 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
82 * When a packet is received, it is first acknowledged with either '+' or '-'.
83 * '+' indicates a successful transfer. '-' indicates a failed transfer.
88 * $m0,10#2a +$00010203040506070809101112131415#42
90 ****************************************************************************/
95 #include "utility/utility.h" // for strcpy_s()
97 /************************************************************************
99 * external low-level support routines
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 */
106 /************************************************************************/
107 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
108 /* at least NUMREGBYTES*2 are needed for register packets */
111 static char initialized
; /* boolean flag. != 0 means we've been initialized */
114 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
116 static const char hexchars
[]="0123456789abcdef";
118 /* Number of registers. */
121 /* Number of bytes of registers. */
122 #define NUMREGBYTES (NUMREGS * 4)
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
};
130 * these should not be static cuz they can be used outside this module
132 int registers
[NUMREGS
];
136 #define STACKSIZE 10000
137 int remcomStack
[STACKSIZE
/sizeof(int)];
138 static int* stackPtr
= &remcomStack
[STACKSIZE
/sizeof(int) - 1];
140 /*************************** ASSEMBLY CODE MACROS *************************/
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. */
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");
174 /* use iret to restore pc and flags together so
175 that trace flag works right. */
183 /* Put the error code here just in case the user cares. */
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;
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() \
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");
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");
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. */
234 asm (" movl %eax, _gdb_i386errcode");
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 */
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. */
248 /* Push the stuff that iret wants. */
249 asm (" pushl %edx"); /* eflags */
250 asm (" pushl %ecx"); /* cs */
251 asm (" pushl %eax"); /* eip */
253 /* Zero mem_fault_routine. */
254 asm (" movl $0, %eax");
255 asm (" movl %eax, _mem_fault_routine");
260 #define CALL_HOOK() asm("call _remcomHandler");
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).
266 * stack on entry: stack on exit:
267 * old eflags vector number
268 * old cs (zero-filled to 32 bits)
272 extern void _catchException3();
274 asm(".globl __catchException3");
275 asm("__catchException3:");
281 /* Same thing for exception 1. */
282 extern void _catchException1();
284 asm(".globl __catchException1");
285 asm("__catchException1:");
291 /* Same thing for exception 0. */
292 extern void _catchException0();
294 asm(".globl __catchException0");
295 asm("__catchException0:");
301 /* Same thing for exception 4. */
302 extern void _catchException4();
304 asm(".globl __catchException4");
305 asm("__catchException4:");
311 /* Same thing for exception 5. */
312 extern void _catchException5();
314 asm(".globl __catchException5");
315 asm("__catchException5:");
321 /* Same thing for exception 6. */
322 extern void _catchException6();
324 asm(".globl __catchException6");
325 asm("__catchException6:");
331 /* Same thing for exception 7. */
332 extern void _catchException7();
334 asm(".globl __catchException7");
335 asm("__catchException7:");
341 /* Same thing for exception 8. */
342 extern void _catchException8();
344 asm(".globl __catchException8");
345 asm("__catchException8:");
352 /* Same thing for exception 9. */
353 extern void _catchException9();
355 asm(".globl __catchException9");
356 asm("__catchException9:");
362 /* Same thing for exception 10. */
363 extern void _catchException10();
365 asm(".globl __catchException10");
366 asm("__catchException10:");
373 /* Same thing for exception 12. */
374 extern void _catchException12();
376 asm(".globl __catchException12");
377 asm("__catchException12:");
384 /* Same thing for exception 16. */
385 extern void _catchException16();
387 asm(".globl __catchException16");
388 asm("__catchException16:");
394 /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
396 /* Same thing for exception 13. */
397 extern void _catchException13 ();
399 asm (".globl __catchException13");
400 asm ("__catchException13:");
408 /* Same thing for exception 11. */
409 extern void _catchException11 ();
411 asm (".globl __catchException11");
412 asm ("__catchException11:");
420 /* Same thing for exception 14. */
421 extern void _catchException14 ();
423 asm (".globl __catchException14");
424 asm ("__catchException14:");
433 * remcomHandler is a front end for handle_exception. It moves the
434 * stack pointer into an area reserved for debugger use.
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 */
445 _returnFromException ()
454 #define BREAKPOINT() __asm int 3;
456 #define BREAKPOINT() asm(" int $3");
462 #define WIN32_LEAN_AND_MEAN
463 //#include <windows.h>
465 void handle_exception(int exceptionVector
);
467 void win32_exception_handler(EXCEPTION_POINTERS
* exc_info
)
469 PCONTEXT ctx
= exc_info
->ContextRecord
;
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
;
488 handle_exception(exc_info
->ExceptionRecord
->ExceptionCode
& 0xFFFF);
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
];
515 if ((ch
>= 'a') && (ch
<= 'f'))
516 return (ch
- 'a' + 10);
517 if ((ch
>= '0') && (ch
<= '9'))
519 if ((ch
>= 'A') && (ch
<= 'F'))
520 return (ch
- 'A' + 10);
524 static char remcomInBuffer
[BUFMAX
];
525 static char remcomOutBuffer
[BUFMAX
];
527 /* scan for the sequence $<data>#<checksum> */
532 char *buffer
= &remcomInBuffer
[0];
533 unsigned char checksum
;
534 unsigned char xmitcsum
;
540 /* wait around for the start character, ignore all other characters */
541 while ((ch
= getDebugChar ()) != '$')
549 /* now, read until a # or end of buffer is found */
550 while (count
< BUFMAX
- 1)
552 ch
= getDebugChar ();
557 checksum
= checksum
+ ch
;
565 ch
= getDebugChar ();
566 xmitcsum
= hex (ch
) << 4;
567 ch
= getDebugChar ();
568 xmitcsum
+= hex (ch
);
570 if (checksum
!= xmitcsum
)
575 "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
576 checksum
, xmitcsum
, buffer
);
578 putDebugChar ('-'); /* failed checksum */
582 putDebugChar ('+'); /* successful transfer */
584 /* if a sequence char is present, reply the sequence ID */
585 if (buffer
[2] == ':')
587 putDebugChar (buffer
[0]);
588 putDebugChar (buffer
[1]);
599 /* send the packet in buffer. */
602 putpacket (char *buffer
)
604 unsigned char checksum
;
608 /* $<packet info>#<checksum>. */
615 while ((ch
= buffer
[count
]) != 0)
623 putDebugChar (hexchars
[checksum
>> 4]);
624 putDebugChar (hexchars
[checksum
% 16]);
627 while (getDebugChar () != '+');
630 void debug_error (char* format
/*, char* parm*/)
633 fprintf (stderr
, format
/*, parm*/);
636 /* Address of a routine to RTE to if we get a memory fault. */
637 static void (*volatile mem_fault_routine
) () = NULL
;
639 /* Indicate to caller of mem2hex or hex2mem that there has been an
641 static volatile int mem_err
= 0;
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
654 get_char (char *addr
)
660 set_char (char *addr
, int val
)
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. */
670 mem2hex (mem
, buf
, count
, may_fault
)
680 if (IsBadReadPtr(mem
, count
))
684 mem_fault_routine
= set_mem_err
;
686 for (i
= 0; i
< count
; i
++)
688 ch
= get_char (mem
++);
689 if (may_fault
&& mem_err
)
691 *buf
++ = hexchars
[ch
>> 4];
692 *buf
++ = hexchars
[ch
% 16];
697 mem_fault_routine
= NULL
;
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 */
705 hex2mem (buf
, mem
, count
, may_fault
)
715 // MinGW does not support structured exception handling, so let's
716 // go safe and make memory writable by default
719 VirtualProtect(mem
, count
, PAGE_EXECUTE_READWRITE
, &old_protect
);
722 mem_fault_routine
= set_mem_err
;
725 for (i
= 0; i
< count
; i
++)
727 ch
= hex (*buf
++) << 4;
728 ch
= ch
+ hex (*buf
++);
729 set_char (mem
++, ch
);
730 if (may_fault
&& mem_err
)
736 mem_fault_routine
= NULL
;
742 /* this function takes the 386 exception vector and attempts to
743 translate this number into a unix compatible signal value */
745 computeSignal (int exceptionVector
)
748 switch (exceptionVector
)
752 break; /* divide by zero */
755 break; /* debug exception */
758 break; /* breakpoint */
761 break; /* into instruction (overflow) */
764 break; /* bound instruction */
767 break; /* Invalid opcode */
770 break; /* coprocessor not available */
773 break; /* double fault */
776 break; /* coprocessor segment overrun */
779 break; /* Invalid TSS */
782 break; /* Segment not present */
785 break; /* stack exception */
788 break; /* general protection */
791 break; /* page fault */
794 break; /* coprocessor error */
796 sigval
= 7; /* "software generated" */
801 /**********************************************/
802 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
803 /* RETURN NUMBER OF CHARS PROCESSED */
804 /**********************************************/
806 hexToInt (char **ptr
, int *intValue
)
815 hexValue
= hex (**ptr
);
818 *intValue
= (*intValue
<< 4) | hexValue
;
831 * This function does all command procesing for interfacing to gdb.
834 handle_exception (int exceptionVector
)
836 int sigval
, stepping
;
841 gdb_i386vector
= exceptionVector
;
846 printf ("vector=%d, sr=0x%x, pc=0x%x\n",
847 exceptionVector
, registers
[PS
], registers
[PC
]);
850 /* reply to host that an exception has occurred */
851 sigval
= computeSignal (exceptionVector
);
853 ptr
= remcomOutBuffer
;
855 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
856 *ptr
++ = hexchars
[sigval
>> 4];
857 *ptr
++ = hexchars
[sigval
& 0xf];
859 *ptr
++ = hexchars
[ESP
];
861 ptr
= mem2hex((char *)®isters
[ESP
], ptr
, 4, 0); /* SP */
864 *ptr
++ = hexchars
[EBP
];
866 ptr
= mem2hex((char *)®isters
[EBP
], ptr
, 4, 0); /* FP */
869 *ptr
++ = hexchars
[PC
];
871 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0); /* PC */
876 putpacket (remcomOutBuffer
);
882 remcomOutBuffer
[0] = 0;
888 remcomOutBuffer
[0] = 'S';
889 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
890 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
891 remcomOutBuffer
[3] = 0;
894 remote_debug
= !(remote_debug
); /* toggle debug flag */
896 case 'g': /* return the value of the CPU registers */
897 mem2hex ((char *) registers
, remcomOutBuffer
, NUMREGBYTES
, 0);
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");
903 case 'P': /* set the value of a single CPU register - return OK */
907 if (hexToInt (&ptr
, ®no
) && *ptr
++ == '=')
908 if (regno
>= 0 && regno
< NUMREGS
)
910 hex2mem (ptr
, (char *) ®isters
[regno
], 4, 0);
911 strcpy_s(remcomOutBuffer
, BUFMAX
, "OK");
915 strcpy_s(remcomOutBuffer
, BUFMAX
, "E01");
919 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
921 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
922 if (hexToInt (&ptr
, &addr
))
924 if (hexToInt (&ptr
, &length
))
928 mem2hex ((char *) addr
, remcomOutBuffer
, length
, 1);
931 strcpy_s(remcomOutBuffer
, BUFMAX
, "E03");
932 debug_error ("memory fault");
938 strcpy_s(remcomOutBuffer
, BUFMAX
, "E01");
942 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
944 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
945 if (hexToInt (&ptr
, &addr
))
947 if (hexToInt (&ptr
, &length
))
951 hex2mem (ptr
, (char *) addr
, length
, 1);
955 strcpy_s(remcomOutBuffer
, BUFMAX
, "E03");
956 debug_error ("memory fault");
960 strcpy_s(remcomOutBuffer
, BUFMAX
, "OK");
967 strcpy_s(remcomOutBuffer
, BUFMAX
, "E02");
971 /* cAA..AA Continue at address AA..AA(optional) */
972 /* sAA..AA Step one instruction from AA..AA(optional) */
976 /* try to read optional parameter, pc unchanged if no parm */
977 if (hexToInt (&ptr
, &addr
))
978 registers
[PC
] = addr
;
980 /* clear the trace bit */
981 registers
[PS
] &= 0xfffffeff;
983 /* set the trace bit if we're stepping */
985 registers
[PS
] |= 0x100;
990 _returnFromException (); /* this is a jump */
994 /* kill the program */
995 case 'k': /* do nothing */
997 /* Huh? This doesn't look like "nothing".
998 m68k-stub.c and sparc-stub.c don't have it. */
1004 /* reply to the request */
1005 putpacket (remcomOutBuffer
);
1009 /* this function is used to set up exception handlers for tracing and
1012 set_debug_traps (void)
1015 stackPtr
= &remcomStack
[STACKSIZE
/ sizeof (int) - 1];
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
);
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
1052 // debugger stub implementation for WIN32 applications
1053 // M. Fuchs, 29.11.2003
1061 #include "utility/utility.h"
1064 int s_initial_breakpoint
= 0;
1069 FILE* ser_port
= NULL
;
1071 int init_gdb_connect()
1073 //TODO: set up connection using serial communication port
1075 ser_port
= fopen("COM1:", "rwb");
1082 return fgetc(ser_port
);
1085 void putDebugChar(int c
)
1091 #else // DEBUG_SERIAL
1094 static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler
= 0;
1097 #define I386_EXCEPTION_CNT 17
1099 LONG WINAPI
exc_protection_handler(EXCEPTION_POINTERS
* exc_info
)
1101 int exc_nr
= exc_info
->ExceptionRecord
->ExceptionCode
& 0xFFFF;
1103 if (exc_nr
< I386_EXCEPTION_CNT
) {
1104 //LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr));
1106 if (exc_nr
==11 || exc_nr
==13 || exc_nr
==14) {
1107 if (mem_fault_routine
)
1108 mem_fault_routine();
1111 ++exc_info
->ContextRecord
->Eip
;
1114 return EXCEPTION_CONTINUE_EXECUTION
;
1117 LONG WINAPI
exc_handler(EXCEPTION_POINTERS
* exc_info
)
1119 int exc_nr
= exc_info
->ExceptionRecord
->ExceptionCode
& 0xFFFF;
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));
1125 // step over initial breakpoint
1126 if (s_initial_breakpoint
) {
1127 s_initial_breakpoint
= 0;
1128 ++exc_info
->ContextRecord
->Eip
;
1131 SetUnhandledExceptionFilter(exc_protection_handler
);
1133 win32_exception_handler(exc_info
);
1134 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1136 SetUnhandledExceptionFilter(exc_handler
);
1138 return EXCEPTION_CONTINUE_EXECUTION
;
1141 return EXCEPTION_CONTINUE_SEARCH
;
1144 /* not needed because we use win32_exception_handler() instead of catchExceptionX()
1145 void exceptionHandler(int exc_nr, void* exc_addr)
1147 if (exc_nr>=0 && exc_nr<I386_EXCEPTION_CNT)
1148 exc_handlers[exc_nr] = exc_addr;
1152 void disable_debugging()
1154 if (s_prev_exc_handler
) {
1155 SetUnhandledExceptionFilter(s_prev_exc_handler
);
1156 s_prev_exc_handler
= 0;
1160 #define _INC_WINDOWS
1161 #include <winsock.h>
1163 #pragma comment(lib, "wsock32")
1166 static int s_rem_fd
= -1;
1168 int init_gdb_connect()
1170 SOCKADDR_IN srv_addr
= {0};
1171 SOCKADDR_IN rem_addr
;
1173 int srv_socket
, rem_len
;
1175 s_prev_exc_handler
= SetUnhandledExceptionFilter(exc_handler
);
1177 if (WSAStartup(MAKEWORD(2,2), &wsa_data
)) {
1178 fprintf(stderr
, "WSAStartup() failed");
1182 srv_addr
.sin_family
= AF_INET
;
1183 srv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1184 srv_addr
.sin_port
= htons(9999);
1186 srv_socket
= socket(PF_INET
, SOCK_STREAM
, 0);
1187 if (srv_socket
== -1) {
1192 if (bind(srv_socket
, (struct sockaddr
*) &srv_addr
, sizeof(srv_addr
)) == -1) {
1197 if (listen(srv_socket
, 4) == -1) {
1202 rem_len
= sizeof(rem_addr
);
1205 s_rem_fd
= accept(srv_socket
, (struct sockaddr
*)&rem_addr
, &rem_len
);
1221 #endif // DEBUG_SERIAL
1232 r
= recv(s_rem_fd
, buffer
, 1, 0);
1235 LOG(TEXT("debugger connection broken"));
1246 void putDebugChar(int c
)
1248 if (s_rem_fd
!= -1) {
1249 const char buffer
[] = {c
};
1251 if (!send(s_rem_fd
, buffer
, 1, 0)) {
1253 LOG(TEXT("debugger connection broken"));
1260 // start up GDB stub interface
1262 int initialize_gdb_stub()
1264 if (!init_gdb_connect())
1269 s_initial_breakpoint
= 1;