00001 /**************************************************************************** 00002 00003 THIS SOFTWARE IS NOT COPYRIGHTED 00004 00005 HP offers the following for use in the public domain. HP makes no 00006 warranty with regard to the software or it's performance and the 00007 user accepts the software "AS IS" with all faults. 00008 00009 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD 00010 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES 00011 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00012 00013 ****************************************************************************/ 00014 00015 /**************************************************************************** 00016 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ 00017 * 00018 * Module name: remcom.c $ 00019 * Revision: 1.34 $ 00020 * Date: 91/03/09 12:29:49 $ 00021 * Contributor: Lake Stevens Instrument Division$ 00022 * 00023 * Description: low level support for gdb debugger. $ 00024 * 00025 * Considerations: only works on target hardware $ 00026 * 00027 * Written by: Glenn Engel $ 00028 * ModuleState: Experimental $ 00029 * 00030 * NOTES: See Below $ 00031 * 00032 * Modified for 386 by Jim Kingdon, Cygnus Support. 00033 * 00034 * To enable debugger support, two things need to happen. One, a 00035 * call to set_debug_traps() is necessary in order to allow any breakpoints 00036 * or error conditions to be properly intercepted and reported to gdb. 00037 * Two, a breakpoint needs to be generated to begin communication. This 00038 * is most easily accomplished by a call to breakpoint(). Breakpoint() 00039 * simulates a breakpoint by executing a trap #1. 00040 * 00041 * The external function exceptionHandler() is 00042 * used to attach a specific handler to a specific 386 vector number. 00043 * It should use the same privilege level it runs at. It should 00044 * install it as an interrupt gate so that interrupts are masked 00045 * while the handler runs. 00046 * 00047 * Because gdb will sometimes write to the stack area to execute function 00048 * calls, this program cannot rely on using the supervisor stack so it 00049 * uses it's own stack area reserved in the int array remcomStack. 00050 * 00051 ************* 00052 * 00053 * The following gdb commands are supported: 00054 * 00055 * command function Return value 00056 * 00057 * g return the value of the CPU registers hex data or ENN 00058 * G set the value of the CPU registers OK or ENN 00059 * 00060 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN 00061 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN 00062 * 00063 * c Resume at current address SNN ( signal NN) 00064 * cAA..AA Continue at address AA..AA SNN 00065 * 00066 * s Step one instruction SNN 00067 * sAA..AA Step one instruction from AA..AA SNN 00068 * 00069 * k kill 00070 * 00071 * ? What was the last sigval ? SNN (signal NN) 00072 * 00073 * All commands and responses are sent with a packet which includes a 00074 * checksum. A packet consists of 00075 * 00076 * $<packet info>#<checksum>. 00077 * 00078 * where 00079 * <packet info> :: <characters representing the command or response> 00080 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> 00081 * 00082 * When a packet is received, it is first acknowledged with either '+' or '-'. 00083 * '+' indicates a successful transfer. '-' indicates a failed transfer. 00084 * 00085 * Example: 00086 * 00087 * Host: Reply: 00088 * $m0,10#2a +$00010203040506070809101112131415#42 00089 * 00090 ****************************************************************************/ 00091 00092 #include <stdio.h> 00093 #include <string.h> 00094 00095 #include "utility/utility.h" // for strcpy_s() 00096 00097 /************************************************************************ 00098 * 00099 * external low-level support routines 00100 */ 00101 00102 extern void putDebugChar(); /* write a single character */ 00103 extern int getDebugChar(); /* read and return a single char */ 00104 extern void exceptionHandler(); /* assign an exception handler */ 00105 00106 /************************************************************************/ 00107 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ 00108 /* at least NUMREGBYTES*2 are needed for register packets */ 00109 #define BUFMAX 400 00110 00111 static char initialized; /* boolean flag. != 0 means we've been initialized */ 00112 00113 int remote_debug; 00114 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */ 00115 00116 static const char hexchars[]="0123456789abcdef"; 00117 00118 /* Number of registers. */ 00119 #define NUMREGS 16 00120 00121 /* Number of bytes of registers. */ 00122 #define NUMREGBYTES (NUMREGS * 4) 00123 00124 enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, 00125 PC /* also known as eip */, 00126 PS /* also known as eflags */, 00127 CS, SS, DS, ES, FS, GS}; 00128 00129 /* 00130 * these should not be static cuz they can be used outside this module 00131 */ 00132 int registers[NUMREGS]; 00133 00134 #ifndef WIN32 //MF 00135 00136 #define STACKSIZE 10000 00137 int remcomStack[STACKSIZE/sizeof(int)]; 00138 static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; 00139 00140 /*************************** ASSEMBLY CODE MACROS *************************/ 00141 /* */ 00142 00143 extern void 00144 return_to_prog (); 00145 00146 /* Restore the program's registers (including the stack pointer, which 00147 means we get the right stack and don't have to worry about popping our 00148 return address and any stack frames and so on) and return. */ 00149 asm(".text"); 00150 asm(".globl _return_to_prog"); 00151 asm("_return_to_prog:"); 00152 asm(" movw _registers+44, %ss"); 00153 asm(" movl _registers+16, %esp"); 00154 asm(" movl _registers+4, %ecx"); 00155 asm(" movl _registers+8, %edx"); 00156 asm(" movl _registers+12, %ebx"); 00157 asm(" movl _registers+20, %ebp"); 00158 asm(" movl _registers+24, %esi"); 00159 asm(" movl _registers+28, %edi"); 00160 asm(" movw _registers+48, %ds"); 00161 asm(" movw _registers+52, %es"); 00162 asm(" movw _registers+56, %fs"); 00163 asm(" movw _registers+60, %gs"); 00164 asm(" movl _registers+36, %eax"); 00165 asm(" pushl %eax"); /* saved eflags */ 00166 asm(" movl _registers+40, %eax"); 00167 asm(" pushl %eax"); /* saved cs */ 00168 asm(" movl _registers+32, %eax"); 00169 asm(" pushl %eax"); /* saved eip */ 00170 asm(" movl _registers, %eax"); 00171 00172 asm("ret"); //MF 00173 00174 /* use iret to restore pc and flags together so 00175 that trace flag works right. */ 00176 asm(" iret"); 00177 00178 00179 #ifdef WIN32 //MF 00180 asm(".data"); //MF 00181 #endif 00182 00183 /* Put the error code here just in case the user cares. */ 00184 int gdb_i386errcode; 00185 /* Likewise, the vector number here (since GDB only gets the signal 00186 number through the usual means, and that's not very specific). */ 00187 int gdb_i386vector = -1; 00188 00189 /* GDB stores segment registers in 32-bit words (that's just the way 00190 m-i386v.h is written). So zero the appropriate areas in registers. */ 00191 #define SAVE_REGISTERS1() \ 00192 asm ("movl %eax, _registers"); \ 00193 asm ("movl %ecx, _registers+4"); \ 00194 asm ("movl %edx, _registers+8"); \ 00195 asm ("movl %ebx, _registers+12"); \ 00196 asm ("movl %ebp, _registers+20"); \ 00197 asm ("movl %esi, _registers+24"); \ 00198 asm ("movl %edi, _registers+28"); \ 00199 asm ("movw $0, %ax"); \ 00200 asm ("movw %ds, _registers+48"); \ 00201 asm ("movw %ax, _registers+50"); \ 00202 asm ("movw %es, _registers+52"); \ 00203 asm ("movw %ax, _registers+54"); \ 00204 asm ("movw %fs, _registers+56"); \ 00205 asm ("movw %ax, _registers+58"); \ 00206 asm ("movw %gs, _registers+60"); \ 00207 asm ("movw %ax, _registers+62"); 00208 #define SAVE_ERRCODE() \ 00209 asm ("popl %ebx"); \ 00210 asm ("movl %ebx, _gdb_i386errcode"); 00211 #define SAVE_REGISTERS2() \ 00212 asm ("popl %ebx"); /* old eip */ \ 00213 asm ("movl %ebx, _registers+32"); \ 00214 asm ("popl %ebx"); /* old cs */ \ 00215 asm ("movl %ebx, _registers+40"); \ 00216 asm ("movw %ax, _registers+42"); \ 00217 asm ("popl %ebx"); /* old eflags */ \ 00218 asm ("movl %ebx, _registers+36"); \ 00219 /* Now that we've done the pops, we can save the stack pointer."); */ \ 00220 asm ("movw %ss, _registers+44"); \ 00221 asm ("movw %ax, _registers+46"); \ 00222 asm ("movl %esp, _registers+16"); 00223 00224 /* See if mem_fault_routine is set, if so just IRET to that address. */ 00225 #define CHECK_FAULT() \ 00226 asm ("cmpl $0, _mem_fault_routine"); \ 00227 asm ("jne mem_fault"); 00228 00229 asm (".text"); 00230 asm ("mem_fault:"); 00231 /* OK to clobber temp registers; we're just going to end up in set_mem_err. */ 00232 /* Pop error code from the stack and save it. */ 00233 asm (" popl %eax"); 00234 asm (" movl %eax, _gdb_i386errcode"); 00235 00236 asm (" popl %eax"); /* eip */ 00237 /* We don't want to return there, we want to return to the function 00238 pointed to by mem_fault_routine instead. */ 00239 asm (" movl _mem_fault_routine, %eax"); 00240 asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */ 00241 asm (" popl %edx"); /* eflags */ 00242 00243 /* Remove this stack frame; when we do the iret, we will be going to 00244 the start of a function, so we want the stack to look just like it 00245 would after a "call" instruction. */ 00246 asm (" leave"); 00247 00248 /* Push the stuff that iret wants. */ 00249 asm (" pushl %edx"); /* eflags */ 00250 asm (" pushl %ecx"); /* cs */ 00251 asm (" pushl %eax"); /* eip */ 00252 00253 /* Zero mem_fault_routine. */ 00254 asm (" movl $0, %eax"); 00255 asm (" movl %eax, _mem_fault_routine"); 00256 00257 asm ("iret"); 00258 00259 00260 #define CALL_HOOK() asm("call _remcomHandler"); 00261 00262 /* This function is called when a i386 exception occurs. It saves 00263 * all the cpu regs in the _registers array, munges the stack a bit, 00264 * and invokes an exception handler (remcom_handler). 00265 * 00266 * stack on entry: stack on exit: 00267 * old eflags vector number 00268 * old cs (zero-filled to 32 bits) 00269 * old eip 00270 * 00271 */ 00272 extern void _catchException3(); 00273 asm(".text"); 00274 asm(".globl __catchException3"); 00275 asm("__catchException3:"); 00276 SAVE_REGISTERS1(); 00277 SAVE_REGISTERS2(); 00278 asm ("pushl $3"); 00279 CALL_HOOK(); 00280 00281 /* Same thing for exception 1. */ 00282 extern void _catchException1(); 00283 asm(".text"); 00284 asm(".globl __catchException1"); 00285 asm("__catchException1:"); 00286 SAVE_REGISTERS1(); 00287 SAVE_REGISTERS2(); 00288 asm ("pushl $1"); 00289 CALL_HOOK(); 00290 00291 /* Same thing for exception 0. */ 00292 extern void _catchException0(); 00293 asm(".text"); 00294 asm(".globl __catchException0"); 00295 asm("__catchException0:"); 00296 SAVE_REGISTERS1(); 00297 SAVE_REGISTERS2(); 00298 asm ("pushl $0"); 00299 CALL_HOOK(); 00300 00301 /* Same thing for exception 4. */ 00302 extern void _catchException4(); 00303 asm(".text"); 00304 asm(".globl __catchException4"); 00305 asm("__catchException4:"); 00306 SAVE_REGISTERS1(); 00307 SAVE_REGISTERS2(); 00308 asm ("pushl $4"); 00309 CALL_HOOK(); 00310 00311 /* Same thing for exception 5. */ 00312 extern void _catchException5(); 00313 asm(".text"); 00314 asm(".globl __catchException5"); 00315 asm("__catchException5:"); 00316 SAVE_REGISTERS1(); 00317 SAVE_REGISTERS2(); 00318 asm ("pushl $5"); 00319 CALL_HOOK(); 00320 00321 /* Same thing for exception 6. */ 00322 extern void _catchException6(); 00323 asm(".text"); 00324 asm(".globl __catchException6"); 00325 asm("__catchException6:"); 00326 SAVE_REGISTERS1(); 00327 SAVE_REGISTERS2(); 00328 asm ("pushl $6"); 00329 CALL_HOOK(); 00330 00331 /* Same thing for exception 7. */ 00332 extern void _catchException7(); 00333 asm(".text"); 00334 asm(".globl __catchException7"); 00335 asm("__catchException7:"); 00336 SAVE_REGISTERS1(); 00337 SAVE_REGISTERS2(); 00338 asm ("pushl $7"); 00339 CALL_HOOK(); 00340 00341 /* Same thing for exception 8. */ 00342 extern void _catchException8(); 00343 asm(".text"); 00344 asm(".globl __catchException8"); 00345 asm("__catchException8:"); 00346 SAVE_REGISTERS1(); 00347 SAVE_ERRCODE(); 00348 SAVE_REGISTERS2(); 00349 asm ("pushl $8"); 00350 CALL_HOOK(); 00351 00352 /* Same thing for exception 9. */ 00353 extern void _catchException9(); 00354 asm(".text"); 00355 asm(".globl __catchException9"); 00356 asm("__catchException9:"); 00357 SAVE_REGISTERS1(); 00358 SAVE_REGISTERS2(); 00359 asm ("pushl $9"); 00360 CALL_HOOK(); 00361 00362 /* Same thing for exception 10. */ 00363 extern void _catchException10(); 00364 asm(".text"); 00365 asm(".globl __catchException10"); 00366 asm("__catchException10:"); 00367 SAVE_REGISTERS1(); 00368 SAVE_ERRCODE(); 00369 SAVE_REGISTERS2(); 00370 asm ("pushl $10"); 00371 CALL_HOOK(); 00372 00373 /* Same thing for exception 12. */ 00374 extern void _catchException12(); 00375 asm(".text"); 00376 asm(".globl __catchException12"); 00377 asm("__catchException12:"); 00378 SAVE_REGISTERS1(); 00379 SAVE_ERRCODE(); 00380 SAVE_REGISTERS2(); 00381 asm ("pushl $12"); 00382 CALL_HOOK(); 00383 00384 /* Same thing for exception 16. */ 00385 extern void _catchException16(); 00386 asm(".text"); 00387 asm(".globl __catchException16"); 00388 asm("__catchException16:"); 00389 SAVE_REGISTERS1(); 00390 SAVE_REGISTERS2(); 00391 asm ("pushl $16"); 00392 CALL_HOOK(); 00393 00394 /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */ 00395 00396 /* Same thing for exception 13. */ 00397 extern void _catchException13 (); 00398 asm (".text"); 00399 asm (".globl __catchException13"); 00400 asm ("__catchException13:"); 00401 CHECK_FAULT(); 00402 SAVE_REGISTERS1(); 00403 SAVE_ERRCODE(); 00404 SAVE_REGISTERS2(); 00405 asm ("pushl $13"); 00406 CALL_HOOK(); 00407 00408 /* Same thing for exception 11. */ 00409 extern void _catchException11 (); 00410 asm (".text"); 00411 asm (".globl __catchException11"); 00412 asm ("__catchException11:"); 00413 CHECK_FAULT(); 00414 SAVE_REGISTERS1(); 00415 SAVE_ERRCODE(); 00416 SAVE_REGISTERS2(); 00417 asm ("pushl $11"); 00418 CALL_HOOK(); 00419 00420 /* Same thing for exception 14. */ 00421 extern void _catchException14 (); 00422 asm (".text"); 00423 asm (".globl __catchException14"); 00424 asm ("__catchException14:"); 00425 CHECK_FAULT(); 00426 SAVE_REGISTERS1(); 00427 SAVE_ERRCODE(); 00428 SAVE_REGISTERS2(); 00429 asm ("pushl $14"); 00430 CALL_HOOK(); 00431 00432 /* 00433 * remcomHandler is a front end for handle_exception. It moves the 00434 * stack pointer into an area reserved for debugger use. 00435 */ 00436 asm("_remcomHandler:"); 00437 asm(" popl %eax"); /* pop off return address */ 00438 asm(" popl %eax"); /* get the exception number */ 00439 asm(" movl _stackPtr, %esp"); /* move to remcom stack area */ 00440 asm(" pushl %eax"); /* push exception onto stack */ 00441 asm(" call _handle_exception"); /* this never returns */ 00442 00443 00444 void 00445 _returnFromException () 00446 { 00447 return_to_prog (); 00448 } 00449 00450 #endif // !WIN32 00451 00452 00453 #ifdef _MSC_VER //MF 00454 #define BREAKPOINT() __asm int 3; 00455 #else 00456 #define BREAKPOINT() asm(" int $3"); 00457 #endif 00458 00459 00460 #ifdef WIN32 //MF 00461 00462 #define WIN32_LEAN_AND_MEAN 00463 #include <windows.h> 00464 00465 void handle_exception(int exceptionVector); 00466 00467 void win32_exception_handler(EXCEPTION_POINTERS* exc_info) 00468 { 00469 PCONTEXT ctx = exc_info->ContextRecord; 00470 00471 registers[EAX] = ctx->Eax; 00472 registers[ECX] = ctx->Ecx; 00473 registers[EDX] = ctx->Edx; 00474 registers[EBX] = ctx->Ebx; 00475 registers[ESP] = ctx->Esp; 00476 registers[EBP] = ctx->Ebp; 00477 registers[ESI] = ctx->Esi; 00478 registers[EDI] = ctx->Edi; 00479 registers[PC] = ctx->Eip; 00480 registers[PS] = ctx->EFlags; 00481 registers[CS] = ctx->SegCs; 00482 registers[SS] = ctx->SegSs; 00483 registers[DS] = ctx->SegDs; 00484 registers[ES] = ctx->SegEs; 00485 registers[FS] = ctx->SegFs; 00486 registers[GS] = ctx->SegGs; 00487 00488 handle_exception(exc_info->ExceptionRecord->ExceptionCode & 0xFFFF); 00489 00490 ctx->Eax = registers[EAX]; 00491 ctx->Ecx = registers[ECX]; 00492 ctx->Edx = registers[EDX]; 00493 ctx->Ebx = registers[EBX]; 00494 ctx->Esp = registers[ESP]; 00495 ctx->Ebp = registers[EBP]; 00496 ctx->Esi = registers[ESI]; 00497 ctx->Edi = registers[EDI]; 00498 ctx->Eip = registers[PC]; 00499 ctx->EFlags = registers[PS]; 00500 ctx->SegCs = registers[CS]; 00501 ctx->SegSs = registers[SS]; 00502 ctx->SegDs = registers[DS]; 00503 ctx->SegEs = registers[ES]; 00504 ctx->SegFs = registers[FS]; 00505 ctx->SegGs = registers[GS]; 00506 } 00507 00508 #endif // WIN32 00509 00510 00511 int 00512 hex (ch) 00513 char ch; 00514 { 00515 if ((ch >= 'a') && (ch <= 'f')) 00516 return (ch - 'a' + 10); 00517 if ((ch >= '0') && (ch <= '9')) 00518 return (ch - '0'); 00519 if ((ch >= 'A') && (ch <= 'F')) 00520 return (ch - 'A' + 10); 00521 return (-1); 00522 } 00523 00524 static char remcomInBuffer[BUFMAX]; 00525 static char remcomOutBuffer[BUFMAX]; 00526 00527 /* scan for the sequence $<data>#<checksum> */ 00528 00529 char * 00530 getpacket (void) 00531 { 00532 char *buffer = &remcomInBuffer[0]; 00533 unsigned char checksum; 00534 unsigned char xmitcsum; 00535 int count; 00536 char ch; 00537 00538 while (1) 00539 { 00540 /* wait around for the start character, ignore all other characters */ 00541 while ((ch = getDebugChar ()) != '$') 00542 ; 00543 00544 retry: 00545 checksum = 0; 00546 xmitcsum = -1; 00547 count = 0; 00548 00549 /* now, read until a # or end of buffer is found */ 00550 while (count < BUFMAX) 00551 { 00552 ch = getDebugChar (); 00553 if (ch == '$') 00554 goto retry; 00555 if (ch == '#') 00556 break; 00557 checksum = checksum + ch; 00558 buffer[count] = ch; 00559 count = count + 1; 00560 } 00561 buffer[count] = 0; 00562 00563 if (ch == '#') 00564 { 00565 ch = getDebugChar (); 00566 xmitcsum = hex (ch) << 4; 00567 ch = getDebugChar (); 00568 xmitcsum += hex (ch); 00569 00570 if (checksum != xmitcsum) 00571 { 00572 if (remote_debug) 00573 { 00574 fprintf (stderr, 00575 "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", 00576 checksum, xmitcsum, buffer); 00577 } 00578 putDebugChar ('-'); /* failed checksum */ 00579 } 00580 else 00581 { 00582 putDebugChar ('+'); /* successful transfer */ 00583 00584 /* if a sequence char is present, reply the sequence ID */ 00585 if (buffer[2] == ':') 00586 { 00587 putDebugChar (buffer[0]); 00588 putDebugChar (buffer[1]); 00589 00590 return &buffer[3]; 00591 } 00592 00593 return &buffer[0]; 00594 } 00595 } 00596 } 00597 } 00598 00599 /* send the packet in buffer. */ 00600 00601 void 00602 putpacket (char *buffer) 00603 { 00604 unsigned char checksum; 00605 int count; 00606 char ch; 00607 00608 /* $<packet info>#<checksum>. */ 00609 do 00610 { 00611 putDebugChar ('$'); 00612 checksum = 0; 00613 count = 0; 00614 00615 while ((ch = buffer[count]) != 0) 00616 { 00617 putDebugChar (ch); 00618 checksum += ch; 00619 count += 1; 00620 } 00621 00622 putDebugChar ('#'); 00623 putDebugChar (hexchars[checksum >> 4]); 00624 putDebugChar (hexchars[checksum % 16]); 00625 00626 } 00627 while (getDebugChar () != '+'); 00628 } 00629 00630 void debug_error (char* format/*, char* parm*/) 00631 { 00632 if (remote_debug) 00633 fprintf (stderr, format/*, parm*/); 00634 } 00635 00636 /* Address of a routine to RTE to if we get a memory fault. */ 00637 static void (*volatile mem_fault_routine) () = NULL; 00638 00639 /* Indicate to caller of mem2hex or hex2mem that there has been an 00640 error. */ 00641 static volatile int mem_err = 0; 00642 00643 void 00644 set_mem_err (void) 00645 { 00646 mem_err = 1; 00647 } 00648 00649 /* These are separate functions so that they are so short and sweet 00650 that the compiler won't save any registers (if there is a fault 00651 to mem_fault, they won't get restored, so there better not be any 00652 saved). */ 00653 int 00654 get_char (char *addr) 00655 { 00656 return *addr; 00657 } 00658 00659 void 00660 set_char (char *addr, int val) 00661 { 00662 *addr = val; 00663 } 00664 00665 /* convert the memory pointed to by mem into hex, placing result in buf */ 00666 /* return a pointer to the last char put in buf (null) */ 00667 /* If MAY_FAULT is non-zero, then we should set mem_err in response to 00668 a fault; if zero treat a fault like any other fault in the stub. */ 00669 char * 00670 mem2hex (mem, buf, count, may_fault) 00671 char *mem; 00672 char *buf; 00673 int count; 00674 int may_fault; 00675 { 00676 int i; 00677 unsigned char ch; 00678 00679 #ifdef WIN32 //MF 00680 if (IsBadReadPtr(mem, count)) 00681 return mem; 00682 #else 00683 if (may_fault) 00684 mem_fault_routine = set_mem_err; 00685 #endif 00686 for (i = 0; i < count; i++) 00687 { 00688 ch = get_char (mem++); 00689 if (may_fault && mem_err) 00690 return (buf); 00691 *buf++ = hexchars[ch >> 4]; 00692 *buf++ = hexchars[ch % 16]; 00693 } 00694 *buf = 0; 00695 #ifndef WIN32 //MF 00696 if (may_fault) 00697 mem_fault_routine = NULL; 00698 #endif 00699 return (buf); 00700 } 00701 00702 /* convert the hex array pointed to by buf into binary to be placed in mem */ 00703 /* return a pointer to the character AFTER the last byte written */ 00704 char * 00705 hex2mem (buf, mem, count, may_fault) 00706 char *buf; 00707 char *mem; 00708 int count; 00709 int may_fault; 00710 { 00711 int i; 00712 unsigned char ch; 00713 00714 #ifdef WIN32 //MF 00715 // MinGW does not support structured exception handling, so let's 00716 // go safe and make memory writable by default 00717 DWORD old_protect; 00718 00719 VirtualProtect(mem, count, PAGE_EXECUTE_READWRITE, &old_protect); 00720 #else 00721 if (may_fault) 00722 mem_fault_routine = set_mem_err; 00723 #endif 00724 00725 for (i = 0; i < count; i++) 00726 { 00727 ch = hex (*buf++) << 4; 00728 ch = ch + hex (*buf++); 00729 set_char (mem++, ch); 00730 if (may_fault && mem_err) 00731 return (mem); 00732 } 00733 00734 #ifndef WIN32 //MF 00735 if (may_fault) 00736 mem_fault_routine = NULL; 00737 #endif 00738 00739 return (mem); 00740 } 00741 00742 /* this function takes the 386 exception vector and attempts to 00743 translate this number into a unix compatible signal value */ 00744 int 00745 computeSignal (int exceptionVector) 00746 { 00747 int sigval; 00748 switch (exceptionVector) 00749 { 00750 case 0: 00751 sigval = 8; 00752 break; /* divide by zero */ 00753 case 1: 00754 sigval = 5; 00755 break; /* debug exception */ 00756 case 3: 00757 sigval = 5; 00758 break; /* breakpoint */ 00759 case 4: 00760 sigval = 16; 00761 break; /* into instruction (overflow) */ 00762 case 5: 00763 sigval = 16; 00764 break; /* bound instruction */ 00765 case 6: 00766 sigval = 4; 00767 break; /* Invalid opcode */ 00768 case 7: 00769 sigval = 8; 00770 break; /* coprocessor not available */ 00771 case 8: 00772 sigval = 7; 00773 break; /* double fault */ 00774 case 9: 00775 sigval = 11; 00776 break; /* coprocessor segment overrun */ 00777 case 10: 00778 sigval = 11; 00779 break; /* Invalid TSS */ 00780 case 11: 00781 sigval = 11; 00782 break; /* Segment not present */ 00783 case 12: 00784 sigval = 11; 00785 break; /* stack exception */ 00786 case 13: 00787 sigval = 11; 00788 break; /* general protection */ 00789 case 14: 00790 sigval = 11; 00791 break; /* page fault */ 00792 case 16: 00793 sigval = 7; 00794 break; /* coprocessor error */ 00795 default: 00796 sigval = 7; /* "software generated" */ 00797 } 00798 return (sigval); 00799 } 00800 00801 /**********************************************/ 00802 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ 00803 /* RETURN NUMBER OF CHARS PROCESSED */ 00804 /**********************************************/ 00805 int 00806 hexToInt (char **ptr, int *intValue) 00807 { 00808 int numChars = 0; 00809 int hexValue; 00810 00811 *intValue = 0; 00812 00813 while (**ptr) 00814 { 00815 hexValue = hex (**ptr); 00816 if (hexValue >= 0) 00817 { 00818 *intValue = (*intValue << 4) | hexValue; 00819 numChars++; 00820 } 00821 else 00822 break; 00823 00824 (*ptr)++; 00825 } 00826 00827 return (numChars); 00828 } 00829 00830 /* 00831 * This function does all command procesing for interfacing to gdb. 00832 */ 00833 void 00834 handle_exception (int exceptionVector) 00835 { 00836 int sigval, stepping; 00837 int addr, length; 00838 char *ptr; 00839 int newPC; 00840 00841 #ifndef WIN32 //MF 00842 gdb_i386vector = exceptionVector; 00843 #endif 00844 00845 if (remote_debug) 00846 { 00847 printf ("vector=%d, sr=0x%x, pc=0x%x\n", 00848 exceptionVector, registers[PS], registers[PC]); 00849 } 00850 00851 /* reply to host that an exception has occurred */ 00852 sigval = computeSignal (exceptionVector); 00853 00854 ptr = remcomOutBuffer; 00855 00856 *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ 00857 *ptr++ = hexchars[sigval >> 4]; 00858 *ptr++ = hexchars[sigval & 0xf]; 00859 00860 *ptr++ = hexchars[ESP]; 00861 *ptr++ = ':'; 00862 ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */ 00863 *ptr++ = ';'; 00864 00865 *ptr++ = hexchars[EBP]; 00866 *ptr++ = ':'; 00867 ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */ 00868 *ptr++ = ';'; 00869 00870 *ptr++ = hexchars[PC]; 00871 *ptr++ = ':'; 00872 ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */ 00873 *ptr++ = ';'; 00874 00875 *ptr = '\0'; 00876 00877 putpacket (remcomOutBuffer); 00878 00879 stepping = 0; 00880 00881 while (1 == 1) 00882 { 00883 remcomOutBuffer[0] = 0; 00884 ptr = getpacket (); 00885 00886 switch (*ptr++) 00887 { 00888 case '?': 00889 remcomOutBuffer[0] = 'S'; 00890 remcomOutBuffer[1] = hexchars[sigval >> 4]; 00891 remcomOutBuffer[2] = hexchars[sigval % 16]; 00892 remcomOutBuffer[3] = 0; 00893 break; 00894 case 'd': 00895 remote_debug = !(remote_debug); /* toggle debug flag */ 00896 break; 00897 case 'g': /* return the value of the CPU registers */ 00898 mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); 00899 break; 00900 case 'G': /* set the value of the CPU registers - return OK */ 00901 hex2mem (ptr, (char *) registers, NUMREGBYTES, 0); 00902 strcpy_s(remcomOutBuffer, BUFMAX, "OK"); 00903 break; 00904 case 'P': /* set the value of a single CPU register - return OK */ 00905 { 00906 int regno; 00907 00908 if (hexToInt (&ptr, ®no) && *ptr++ == '=') 00909 if (regno >= 0 && regno < NUMREGS) 00910 { 00911 hex2mem (ptr, (char *) ®isters[regno], 4, 0); 00912 strcpy_s(remcomOutBuffer, BUFMAX, "OK"); 00913 break; 00914 } 00915 00916 strcpy_s(remcomOutBuffer, BUFMAX, "E01"); 00917 break; 00918 } 00919 00920 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 00921 case 'm': 00922 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ 00923 if (hexToInt (&ptr, &addr)) 00924 if (*(ptr++) == ',') 00925 if (hexToInt (&ptr, &length)) 00926 { 00927 ptr = 0; 00928 mem_err = 0; 00929 mem2hex ((char *) addr, remcomOutBuffer, length, 1); 00930 if (mem_err) 00931 { 00932 strcpy_s(remcomOutBuffer, BUFMAX, "E03"); 00933 debug_error ("memory fault"); 00934 } 00935 } 00936 00937 if (ptr) 00938 { 00939 strcpy_s(remcomOutBuffer, BUFMAX, "E01"); 00940 } 00941 break; 00942 00943 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 00944 case 'M': 00945 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ 00946 if (hexToInt (&ptr, &addr)) 00947 if (*(ptr++) == ',') 00948 if (hexToInt (&ptr, &length)) 00949 if (*(ptr++) == ':') 00950 { 00951 mem_err = 0; 00952 hex2mem (ptr, (char *) addr, length, 1); 00953 00954 if (mem_err) 00955 { 00956 strcpy_s(remcomOutBuffer, BUFMAX, "E03"); 00957 debug_error ("memory fault"); 00958 } 00959 else 00960 { 00961 strcpy_s(remcomOutBuffer, BUFMAX, "OK"); 00962 } 00963 00964 ptr = 0; 00965 } 00966 if (ptr) 00967 { 00968 strcpy_s(remcomOutBuffer, BUFMAX, "E02"); 00969 } 00970 break; 00971 00972 /* cAA..AA Continue at address AA..AA(optional) */ 00973 /* sAA..AA Step one instruction from AA..AA(optional) */ 00974 case 's': 00975 stepping = 1; 00976 case 'c': 00977 /* try to read optional parameter, pc unchanged if no parm */ 00978 if (hexToInt (&ptr, &addr)) 00979 registers[PC] = addr; 00980 00981 newPC = registers[PC]; 00982 00983 /* clear the trace bit */ 00984 registers[PS] &= 0xfffffeff; 00985 00986 /* set the trace bit if we're stepping */ 00987 if (stepping) 00988 registers[PS] |= 0x100; 00989 00990 #ifdef WIN32 //MF 00991 return; 00992 #else 00993 _returnFromException (); /* this is a jump */ 00994 #endif 00995 break; 00996 00997 /* kill the program */ 00998 case 'k': /* do nothing */ 00999 #if 0 01000 /* Huh? This doesn't look like "nothing". 01001 m68k-stub.c and sparc-stub.c don't have it. */ 01002 BREAKPOINT (); 01003 #endif 01004 break; 01005 } /* switch */ 01006 01007 /* reply to the request */ 01008 putpacket (remcomOutBuffer); 01009 } 01010 } 01011 01012 /* this function is used to set up exception handlers for tracing and 01013 breakpoints */ 01014 void 01015 set_debug_traps (void) 01016 { 01017 #ifndef WIN32 //MF 01018 stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; 01019 01020 exceptionHandler (0, _catchException0); 01021 exceptionHandler (1, _catchException1); 01022 exceptionHandler (3, _catchException3); 01023 exceptionHandler (4, _catchException4); 01024 exceptionHandler (5, _catchException5); 01025 exceptionHandler (6, _catchException6); 01026 exceptionHandler (7, _catchException7); 01027 exceptionHandler (8, _catchException8); 01028 exceptionHandler (9, _catchException9); 01029 exceptionHandler (10, _catchException10); 01030 exceptionHandler (11, _catchException11); 01031 exceptionHandler (12, _catchException12); 01032 exceptionHandler (13, _catchException13); 01033 exceptionHandler (14, _catchException14); 01034 exceptionHandler (16, _catchException16); 01035 #endif // WIN32 01036 01037 initialized = 1; 01038 } 01039 01040 /* This function will generate a breakpoint exception. It is used at the 01041 beginning of a program to sync up with a debugger and can be used 01042 otherwise as a quick means to stop program execution and "break" into 01043 the debugger. */ 01044 01045 void 01046 breakpoint (void) 01047 { 01048 if (initialized) 01049 BREAKPOINT (); 01050 } 01051 01052 01053 01054 // 01055 // debugger stub implementation for WIN32 applications 01056 // M. Fuchs, 29.11.2003 01057 // 01058 01059 #ifdef WIN32 01060 01061 #include <stdlib.h> 01062 #include <errno.h> 01063 01064 #include "utility/utility.h" 01065 01066 01067 int s_initial_breakpoint = 0; 01068 01069 01070 #ifdef DEBUG_SERIAL 01071 01072 FILE* ser_port = NULL; 01073 01074 int init_gdb_connect() 01075 { 01076 //TODO: set up connection using serial communication port 01077 01078 ser_port = fopen("COM1:", "rwb"); 01079 01080 return 1; 01081 } 01082 01083 int getDebugChar() 01084 { 01085 return fgetc(ser_port); 01086 } 01087 01088 void putDebugChar(int c) 01089 { 01090 fputc(c, ser_port); 01091 } 01092 01093 01094 #else // DEBUG_SERIAL 01095 01096 01097 static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler = 0; 01098 01099 01100 #define I386_EXCEPTION_CNT 17 01101 01102 LONG WINAPI exc_protection_handler(EXCEPTION_POINTERS* exc_info) 01103 { 01104 int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF; 01105 01106 if (exc_nr < I386_EXCEPTION_CNT) { 01107 //LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr)); 01108 01109 if (exc_nr==11 || exc_nr==13 || exc_nr==14) { 01110 if (mem_fault_routine) 01111 mem_fault_routine(); 01112 } 01113 01114 ++exc_info->ContextRecord->Eip; 01115 } 01116 01117 return EXCEPTION_CONTINUE_EXECUTION; 01118 } 01119 01120 LONG WINAPI exc_handler(EXCEPTION_POINTERS* exc_info) 01121 { 01122 int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF; 01123 01124 if (exc_nr < I386_EXCEPTION_CNT) { 01125 //LOG(FmtString("Exception %x", exc_nr)); 01126 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags)); 01127 01128 // step over initial breakpoint 01129 if (s_initial_breakpoint) { 01130 s_initial_breakpoint = 0; 01131 ++exc_info->ContextRecord->Eip; 01132 } 01133 01134 SetUnhandledExceptionFilter(exc_protection_handler); 01135 01136 win32_exception_handler(exc_info); 01137 //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags)); 01138 01139 SetUnhandledExceptionFilter(exc_handler); 01140 01141 return EXCEPTION_CONTINUE_EXECUTION; 01142 } 01143 01144 return EXCEPTION_CONTINUE_SEARCH; 01145 } 01146 01147 /* not needed because we use win32_exception_handler() instead of catchExceptionX() 01148 void exceptionHandler(int exc_nr, void* exc_addr) 01149 { 01150 if (exc_nr>=0 && exc_nr<I386_EXCEPTION_CNT) 01151 exc_handlers[exc_nr] = exc_addr; 01152 } 01153 */ 01154 01155 void disable_debugging() 01156 { 01157 if (s_prev_exc_handler) { 01158 SetUnhandledExceptionFilter(s_prev_exc_handler); 01159 s_prev_exc_handler = 0; 01160 } 01161 } 01162 01163 01164 #include <winsock.h> 01165 #ifdef _MSC_VER 01166 #pragma comment(lib, "wsock32") 01167 #endif 01168 01169 static int s_rem_fd = -1; 01170 01171 int init_gdb_connect() 01172 { 01173 SOCKADDR_IN srv_addr = {0}; 01174 SOCKADDR_IN rem_addr; 01175 WSADATA wsa_data; 01176 int srv_socket, rem_len; 01177 01178 s_prev_exc_handler = SetUnhandledExceptionFilter(exc_handler); 01179 01180 if (WSAStartup(MAKEWORD(2,2), &wsa_data)) { 01181 fprintf(stderr, "WSAStartup() failed"); 01182 return 0; 01183 } 01184 01185 srv_addr.sin_family = AF_INET; 01186 srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 01187 srv_addr.sin_port = htons(9999); 01188 01189 srv_socket = socket(PF_INET, SOCK_STREAM, 0); 01190 if (srv_socket == -1) { 01191 perror("socket()"); 01192 return 0; 01193 } 01194 01195 if (bind(srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) { 01196 perror("bind()"); 01197 return 0; 01198 } 01199 01200 if (listen(srv_socket, 4) == -1) { 01201 perror("listen()"); 01202 return 0; 01203 } 01204 01205 rem_len = sizeof(rem_addr); 01206 01207 for(;;) { 01208 s_rem_fd = accept(srv_socket, (struct sockaddr*)&rem_addr, &rem_len); 01209 01210 if (s_rem_fd < 0) { 01211 if (errno == EINTR) 01212 continue; 01213 01214 perror("accept()"); 01215 return 0; 01216 } 01217 01218 break; 01219 } 01220 01221 return 1; 01222 } 01223 01224 #endif // DEBUG_SERIAL 01225 01226 01227 int getDebugChar() 01228 { 01229 char buffer[1024]; 01230 int r; 01231 01232 if (s_rem_fd == -1) 01233 return EOF; 01234 01235 r = recv(s_rem_fd, buffer, 1, 0); 01236 if (r == -1) { 01237 perror("recv()"); 01238 LOG(TEXT("debugger connection broken")); 01239 s_rem_fd = -1; 01240 return EOF; 01241 } 01242 01243 if (!r) 01244 return EOF; 01245 01246 return buffer[0]; 01247 } 01248 01249 void putDebugChar(int c) 01250 { 01251 if (s_rem_fd != -1) { 01252 const char buffer[] = {c}; 01253 01254 if (!send(s_rem_fd, buffer, 1, 0)) { 01255 perror("send()"); 01256 LOG(TEXT("debugger connection broken")); 01257 exit(-1); 01258 } 01259 } 01260 } 01261 01262 01263 // start up GDB stub interface 01264 01265 int initialize_gdb_stub() 01266 { 01267 if (!init_gdb_connect()) 01268 return 0; 01269 01270 set_debug_traps(); 01271 01272 s_initial_breakpoint = 1; 01273 breakpoint(); 01274 01275 return 1; 01276 } 01277 01278 #endif // WIN32
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |