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
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
)
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
;
842 gdb_i386vector
= exceptionVector
;
847 printf ("vector=%d, sr=0x%x, pc=0x%x\n",
848 exceptionVector
, registers
[PS
], registers
[PC
]);
851 /* reply to host that an exception has occurred */
852 sigval
= computeSignal (exceptionVector
);
854 ptr
= remcomOutBuffer
;
856 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
857 *ptr
++ = hexchars
[sigval
>> 4];
858 *ptr
++ = hexchars
[sigval
& 0xf];
860 *ptr
++ = hexchars
[ESP
];
862 ptr
= mem2hex((char *)®isters
[ESP
], ptr
, 4, 0); /* SP */
865 *ptr
++ = hexchars
[EBP
];
867 ptr
= mem2hex((char *)®isters
[EBP
], ptr
, 4, 0); /* FP */
870 *ptr
++ = hexchars
[PC
];
872 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0); /* PC */
877 putpacket (remcomOutBuffer
);
883 remcomOutBuffer
[0] = 0;
889 remcomOutBuffer
[0] = 'S';
890 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
891 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
892 remcomOutBuffer
[3] = 0;
895 remote_debug
= !(remote_debug
); /* toggle debug flag */
897 case 'g': /* return the value of the CPU registers */
898 mem2hex ((char *) registers
, remcomOutBuffer
, NUMREGBYTES
, 0);
900 case 'G': /* set the value of the CPU registers - return OK */
901 hex2mem (ptr
, (char *) registers
, NUMREGBYTES
, 0);
902 strcpy_s(remcomOutBuffer
, BUFMAX
, "OK");
904 case 'P': /* set the value of a single CPU register - return OK */
908 if (hexToInt (&ptr
, ®no
) && *ptr
++ == '=')
909 if (regno
>= 0 && regno
< NUMREGS
)
911 hex2mem (ptr
, (char *) ®isters
[regno
], 4, 0);
912 strcpy_s(remcomOutBuffer
, BUFMAX
, "OK");
916 strcpy_s(remcomOutBuffer
, BUFMAX
, "E01");
920 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
922 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
923 if (hexToInt (&ptr
, &addr
))
925 if (hexToInt (&ptr
, &length
))
929 mem2hex ((char *) addr
, remcomOutBuffer
, length
, 1);
932 strcpy_s(remcomOutBuffer
, BUFMAX
, "E03");
933 debug_error ("memory fault");
939 strcpy_s(remcomOutBuffer
, BUFMAX
, "E01");
943 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
945 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
946 if (hexToInt (&ptr
, &addr
))
948 if (hexToInt (&ptr
, &length
))
952 hex2mem (ptr
, (char *) addr
, length
, 1);
956 strcpy_s(remcomOutBuffer
, BUFMAX
, "E03");
957 debug_error ("memory fault");
961 strcpy_s(remcomOutBuffer
, BUFMAX
, "OK");
968 strcpy_s(remcomOutBuffer
, BUFMAX
, "E02");
972 /* cAA..AA Continue at address AA..AA(optional) */
973 /* sAA..AA Step one instruction from AA..AA(optional) */
977 /* try to read optional parameter, pc unchanged if no parm */
978 if (hexToInt (&ptr
, &addr
))
979 registers
[PC
] = addr
;
981 newPC
= registers
[PC
];
983 /* clear the trace bit */
984 registers
[PS
] &= 0xfffffeff;
986 /* set the trace bit if we're stepping */
988 registers
[PS
] |= 0x100;
993 _returnFromException (); /* this is a jump */
997 /* kill the program */
998 case 'k': /* do nothing */
1000 /* Huh? This doesn't look like "nothing".
1001 m68k-stub.c and sparc-stub.c don't have it. */
1007 /* reply to the request */
1008 putpacket (remcomOutBuffer
);
1012 /* this function is used to set up exception handlers for tracing and
1015 set_debug_traps (void)
1018 stackPtr
= &remcomStack
[STACKSIZE
/ sizeof (int) - 1];
1020 exceptionHandler (0, _catchException0
);
1021 exceptionHandler (1, _catchException1
);
1022 exceptionHandler (3, _catchException3
);
1023 exceptionHandler (4, _catchException4
);
1024 exceptionHandler (5, _catchException5
);
1025 exceptionHandler (6, _catchException6
);
1026 exceptionHandler (7, _catchException7
);
1027 exceptionHandler (8, _catchException8
);
1028 exceptionHandler (9, _catchException9
);
1029 exceptionHandler (10, _catchException10
);
1030 exceptionHandler (11, _catchException11
);
1031 exceptionHandler (12, _catchException12
);
1032 exceptionHandler (13, _catchException13
);
1033 exceptionHandler (14, _catchException14
);
1034 exceptionHandler (16, _catchException16
);
1040 /* This function will generate a breakpoint exception. It is used at the
1041 beginning of a program to sync up with a debugger and can be used
1042 otherwise as a quick means to stop program execution and "break" into
1055 // debugger stub implementation for WIN32 applications
1056 // M. Fuchs, 29.11.2003
1064 #include "utility/utility.h"
1067 int s_initial_breakpoint
= 0;
1072 FILE* ser_port
= NULL
;
1074 int init_gdb_connect()
1076 //TODO: set up connection using serial communication port
1078 ser_port
= fopen("COM1:", "rwb");
1085 return fgetc(ser_port
);
1088 void putDebugChar(int c
)
1094 #else // DEBUG_SERIAL
1097 static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler
= 0;
1100 #define I386_EXCEPTION_CNT 17
1102 LONG WINAPI
exc_protection_handler(EXCEPTION_POINTERS
* exc_info
)
1104 int exc_nr
= exc_info
->ExceptionRecord
->ExceptionCode
& 0xFFFF;
1106 if (exc_nr
< I386_EXCEPTION_CNT
) {
1107 //LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr));
1109 if (exc_nr
==11 || exc_nr
==13 || exc_nr
==14) {
1110 if (mem_fault_routine
)
1111 mem_fault_routine();
1114 ++exc_info
->ContextRecord
->Eip
;
1117 return EXCEPTION_CONTINUE_EXECUTION
;
1120 LONG WINAPI
exc_handler(EXCEPTION_POINTERS
* exc_info
)
1122 int exc_nr
= exc_info
->ExceptionRecord
->ExceptionCode
& 0xFFFF;
1124 if (exc_nr
< I386_EXCEPTION_CNT
) {
1125 //LOG(FmtString("Exception %x", exc_nr));
1126 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1128 // step over initial breakpoint
1129 if (s_initial_breakpoint
) {
1130 s_initial_breakpoint
= 0;
1131 ++exc_info
->ContextRecord
->Eip
;
1134 SetUnhandledExceptionFilter(exc_protection_handler
);
1136 win32_exception_handler(exc_info
);
1137 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1139 SetUnhandledExceptionFilter(exc_handler
);
1141 return EXCEPTION_CONTINUE_EXECUTION
;
1144 return EXCEPTION_CONTINUE_SEARCH
;
1147 /* not needed because we use win32_exception_handler() instead of catchExceptionX()
1148 void exceptionHandler(int exc_nr, void* exc_addr)
1150 if (exc_nr>=0 && exc_nr<I386_EXCEPTION_CNT)
1151 exc_handlers[exc_nr] = exc_addr;
1155 void disable_debugging()
1157 if (s_prev_exc_handler
) {
1158 SetUnhandledExceptionFilter(s_prev_exc_handler
);
1159 s_prev_exc_handler
= 0;
1164 #include <winsock.h>
1166 #pragma comment(lib, "wsock32")
1169 static int s_rem_fd
= -1;
1171 int init_gdb_connect()
1173 SOCKADDR_IN srv_addr
= {0};
1174 SOCKADDR_IN rem_addr
;
1176 int srv_socket
, rem_len
;
1178 s_prev_exc_handler
= SetUnhandledExceptionFilter(exc_handler
);
1180 if (WSAStartup(MAKEWORD(2,2), &wsa_data
)) {
1181 fprintf(stderr
, "WSAStartup() failed");
1185 srv_addr
.sin_family
= AF_INET
;
1186 srv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1187 srv_addr
.sin_port
= htons(9999);
1189 srv_socket
= socket(PF_INET
, SOCK_STREAM
, 0);
1190 if (srv_socket
== -1) {
1195 if (bind(srv_socket
, (struct sockaddr
*) &srv_addr
, sizeof(srv_addr
)) == -1) {
1200 if (listen(srv_socket
, 4) == -1) {
1205 rem_len
= sizeof(rem_addr
);
1208 s_rem_fd
= accept(srv_socket
, (struct sockaddr
*)&rem_addr
, &rem_len
);
1224 #endif // DEBUG_SERIAL
1235 r
= recv(s_rem_fd
, buffer
, 1, 0);
1238 LOG(TEXT("debugger connection broken"));
1249 void putDebugChar(int c
)
1251 if (s_rem_fd
!= -1) {
1252 const char buffer
[] = {c
};
1254 if (!send(s_rem_fd
, buffer
, 1, 0)) {
1256 LOG(TEXT("debugger connection broken"));
1263 // start up GDB stub interface
1265 int initialize_gdb_stub()
1267 if (!init_gdb_connect())
1272 s_initial_breakpoint
= 1;