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 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 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 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 * 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 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 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 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 654 get_char (char *addr) 655 { 656 return *addr; 657 } 658 659 void 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 * 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 * 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 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 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 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 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 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 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 1080 int getDebugChar() 1081 { 1082 return fgetc(ser_port); 1083 } 1084 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 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 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 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 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 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 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 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