Annotation of prex-old/sys/arch/i386/i386/gdb_stub.c, Revision 1.1
1.1 ! nbrk 1: /*-
! 2: * Copyright (c) 2005, Kohsuke Ohtani
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. Neither the name of the author nor the names of any co-contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /****************************************************************************
! 31:
! 32: THIS SOFTWARE IS NOT COPYRIGHTED
! 33:
! 34: HP offers the following for use in the public domain. HP makes no
! 35: warranty with regard to the software or it's performance and the
! 36: user accepts the software "AS IS" with all faults.
! 37:
! 38: HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
! 39: TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
! 40: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
! 41:
! 42: ****************************************************************************/
! 43:
! 44: /****************************************************************************
! 45: * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
! 46: *
! 47: * Module name: remcom.c $
! 48: * Revision: 1.34 $
! 49: * Date: 91/03/09 12:29:49 $
! 50: * Contributor: Lake Stevens Instrument Division$
! 51: *
! 52: * Description: low level support for gdb debugger. $
! 53: *
! 54: * Considerations: only works on target hardware $
! 55: *
! 56: * Written by: Glenn Engel $
! 57: * ModuleState: Experimental $
! 58: *
! 59: * NOTES: See Below $
! 60: *
! 61: * Modified for 386 by Jim Kingdon, Cygnus Support.
! 62: *
! 63: * To enable debugger support, two things need to happen. One, a
! 64: * call to set_debug_traps() is necessary in order to allow any breakpoints
! 65: * or error conditions to be properly intercepted and reported to gdb.
! 66: * Two, a breakpoint needs to be generated to begin communication. This
! 67: * is most easily accomplished by a call to breakpoint(). Breakpoint()
! 68: * simulates a breakpoint by executing a trap #1.
! 69: *
! 70: * The external function exceptionHandler() is
! 71: * used to attach a specific handler to a specific 386 vector number.
! 72: * It should use the same privilege level it runs at. It should
! 73: * install it as an interrupt gate so that interrupts are masked
! 74: * while the handler runs.
! 75: *
! 76: * Because gdb will sometimes write to the stack area to execute function
! 77: * calls, this program cannot rely on using the supervisor stack so it
! 78: * uses it's own stack area reserved in the int array remcomStack.
! 79: *
! 80: *************
! 81: *
! 82: * The following gdb commands are supported:
! 83: *
! 84: * command function Return value
! 85: *
! 86: * g return the value of the CPU registers hex data or ENN
! 87: * G set the value of the CPU registers OK or ENN
! 88: *
! 89: * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
! 90: * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
! 91: *
! 92: * c Resume at current address SNN ( signal NN)
! 93: * cAA..AA Continue at address AA..AA SNN
! 94: *
! 95: * s Step one instruction SNN
! 96: * sAA..AA Step one instruction from AA..AA SNN
! 97: *
! 98: * k kill
! 99: *
! 100: * ? What was the last sigval ? SNN (signal NN)
! 101: *
! 102: * All commands and responses are sent with a packet which includes a
! 103: * checksum. A packet consists of
! 104: *
! 105: * $<packet info>#<checksum>.
! 106: *
! 107: * where
! 108: * <packet info> :: <characters representing the command or response>
! 109: * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
! 110: *
! 111: * When a packet is received, it is first acknowledged with either '+' or '-'.
! 112: * '+' indicates a successful transfer. '-' indicates a failed transfer.
! 113: *
! 114: * Example:
! 115: *
! 116: * Host: Reply:
! 117: * $m0,10#2a +$00010203040506070809101112131415#42
! 118: *
! 119: ****************************************************************************/
! 120:
! 121: /* @PREX #include <stdio.h> */
! 122: /* @PREX #include <string.h> */
! 123:
! 124: /************************************************************************/
! 125: /* Prex modified */
! 126:
! 127: #include <kernel.h>
! 128:
! 129: #ifdef CONFIG_GDB
! 130:
! 131: #define printf(fmt, ...)
! 132: #define fprintf(fmt, ...)
! 133: #define strcpy(str1, str2) strlcpy(str1, str2, BUFMAX)
! 134: #undef BREAKPOINT
! 135: #undef breakpoint
! 136: /************************************************************************/
! 137:
! 138:
! 139: /************************************************************************
! 140: *
! 141: * external low-level support routines
! 142: */
! 143:
! 144: /* @PREX extern void putDebugChar(); */ /* write a single character */
! 145: /* @PREX extern int getDebugChar(); */ /* read and return a single char */
! 146: /* @PREX extern void exceptionHandler(); */ /* assign an exception handler */
! 147: extern int serial_getchar(void);
! 148: extern void serial_putchar(int);
! 149: extern int serial_init(void);
! 150: extern void trap_set(int, void *);
! 151: #define putDebugChar(ch) serial_set(ch)
! 152: #define getDebugChar() serial_get()
! 153: #define exceptionHandler(exec, func) trap_set(exec, func)
! 154:
! 155: /************************************************************************/
! 156: /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
! 157: /* at least NUMREGBYTES*2 are needed for register packets */
! 158: #define BUFMAX 400
! 159:
! 160: static char initialized; /* boolean flag. != 0 means we've been initialized */
! 161:
! 162: int remote_debug;
! 163: /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
! 164:
! 165: static const char hexchars[]="0123456789abcdef";
! 166:
! 167: /* Number of registers. */
! 168: #define NUMREGS 16
! 169:
! 170: /* Number of bytes of registers. */
! 171: #define NUMREGBYTES (NUMREGS * 4)
! 172:
! 173: enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
! 174: PC /* also known as eip */,
! 175: PS /* also known as eflags */,
! 176: CS, SS, DS, ES, FS, GS};
! 177:
! 178: /*
! 179: * these should not be static cuz they can be used outside this module
! 180: */
! 181: int registers[NUMREGS];
! 182:
! 183: #define STACKSIZE 10000
! 184: int remcomStack[STACKSIZE/sizeof(int)];
! 185: static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
! 186:
! 187: /*************************** ASSEMBLY CODE MACROS *************************/
! 188: /* */
! 189:
! 190: extern void
! 191: return_to_prog ();
! 192:
! 193: /* Restore the program's registers (including the stack pointer, which
! 194: means we get the right stack and don't have to worry about popping our
! 195: return address and any stack frames and so on) and return. */
! 196: asm(".text");
! 197: asm(".globl return_to_prog");
! 198: asm("return_to_prog:");
! 199: asm(" movw registers+44, %ss");
! 200: asm(" movl registers+16, %esp");
! 201: asm(" movl registers+4, %ecx");
! 202: asm(" movl registers+8, %edx");
! 203: asm(" movl registers+12, %ebx");
! 204: asm(" movl registers+20, %ebp");
! 205: asm(" movl registers+24, %esi");
! 206: asm(" movl registers+28, %edi");
! 207: asm(" movw registers+48, %ds");
! 208: asm(" movw registers+52, %es");
! 209: asm(" movw registers+56, %fs");
! 210: asm(" movw registers+60, %gs");
! 211: asm(" movl registers+36, %eax");
! 212: asm(" pushl %eax"); /* saved eflags */
! 213: asm(" movl registers+40, %eax");
! 214: asm(" pushl %eax"); /* saved cs */
! 215: asm(" movl registers+32, %eax");
! 216: asm(" pushl %eax"); /* saved eip */
! 217: asm(" movl registers, %eax");
! 218: /* use iret to restore pc and flags together so
! 219: that trace flag works right. */
! 220: asm(" iret");
! 221:
! 222: #define BREAKPOINT() asm(" int $3");
! 223:
! 224: /* Put the error code here just in case the user cares. */
! 225: int gdb_i386errcode;
! 226: /* Likewise, the vector number here (since GDB only gets the signal
! 227: number through the usual means, and that's not very specific). */
! 228: int gdb_i386vector = -1;
! 229:
! 230: /* GDB stores segment registers in 32-bit words (that's just the way
! 231: m-i386v.h is written). So zero the appropriate areas in registers. */
! 232: #define SAVE_REGISTERS1() \
! 233: asm ("movl %eax, registers"); \
! 234: asm ("movl %ecx, registers+4"); \
! 235: asm ("movl %edx, registers+8"); \
! 236: asm ("movl %ebx, registers+12"); \
! 237: asm ("movl %ebp, registers+20"); \
! 238: asm ("movl %esi, registers+24"); \
! 239: asm ("movl %edi, registers+28"); \
! 240: asm ("movw $0, %ax"); \
! 241: asm ("movw %ds, registers+48"); \
! 242: asm ("movw %ax, registers+50"); \
! 243: asm ("movw %es, registers+52"); \
! 244: asm ("movw %ax, registers+54"); \
! 245: asm ("movw %fs, registers+56"); \
! 246: asm ("movw %ax, registers+58"); \
! 247: asm ("movw %gs, registers+60"); \
! 248: asm ("movw %ax, registers+62");
! 249: #define SAVE_ERRCODE() \
! 250: asm ("popl %ebx"); \
! 251: asm ("movl %ebx, gdb_i386errcode");
! 252: #define SAVE_REGISTERS2() \
! 253: asm ("popl %ebx"); /* old eip */ \
! 254: asm ("movl %ebx, registers+32"); \
! 255: asm ("popl %ebx"); /* old cs */ \
! 256: asm ("movl %ebx, registers+40"); \
! 257: asm ("movw %ax, registers+42"); \
! 258: asm ("popl %ebx"); /* old eflags */ \
! 259: asm ("movl %ebx, registers+36"); \
! 260: /* Now that we've done the pops, we can save the stack pointer."); */ \
! 261: asm ("movw %ss, registers+44"); \
! 262: asm ("movw %ax, registers+46"); \
! 263: asm ("movl %esp, registers+16");
! 264:
! 265: /* See if mem_fault_routine is set, if so just IRET to that address. */
! 266: #define CHECK_FAULT() \
! 267: asm ("cmpl $0, mem_fault_routine"); \
! 268: asm ("jne mem_fault");
! 269:
! 270: asm (".text");
! 271: asm ("mem_fault:");
! 272: /* OK to clobber temp registers; we're just going to end up in set_mem_err. */
! 273: /* Pop error code from the stack and save it. */
! 274: asm (" popl %eax");
! 275: asm (" movl %eax, gdb_i386errcode");
! 276:
! 277: asm (" popl %eax"); /* eip */
! 278: /* We don't want to return there, we want to return to the function
! 279: pointed to by mem_fault_routine instead. */
! 280: asm (" movl mem_fault_routine, %eax");
! 281: asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
! 282: asm (" popl %edx"); /* eflags */
! 283:
! 284: /* Remove this stack frame; when we do the iret, we will be going to
! 285: the start of a function, so we want the stack to look just like it
! 286: would after a "call" instruction. */
! 287: asm (" leave");
! 288:
! 289: /* Push the stuff that iret wants. */
! 290: asm (" pushl %edx"); /* eflags */
! 291: asm (" pushl %ecx"); /* cs */
! 292: asm (" pushl %eax"); /* eip */
! 293:
! 294: /* Zero mem_fault_routine. */
! 295: asm (" movl $0, %eax");
! 296: asm (" movl %eax, mem_fault_routine");
! 297:
! 298: asm ("iret");
! 299:
! 300: #define CALL_HOOK() asm("call _remcomHandler");
! 301:
! 302: /* This function is called when a i386 exception occurs. It saves
! 303: * all the cpu regs in the _registers array, munges the stack a bit,
! 304: * and invokes an exception handler (remcom_handler).
! 305: *
! 306: * stack on entry: stack on exit:
! 307: * old eflags vector number
! 308: * old cs (zero-filled to 32 bits)
! 309: * old eip
! 310: *
! 311: */
! 312: extern void _catchException3();
! 313: asm(".text");
! 314: asm(".globl _catchException3");
! 315: asm("_catchException3:");
! 316: SAVE_REGISTERS1();
! 317: SAVE_REGISTERS2();
! 318: asm ("pushl $3");
! 319: CALL_HOOK();
! 320:
! 321: /* Same thing for exception 1. */
! 322: extern void _catchException1();
! 323: asm(".text");
! 324: asm(".globl _catchException1");
! 325: asm("_catchException1:");
! 326: SAVE_REGISTERS1();
! 327: SAVE_REGISTERS2();
! 328: asm ("pushl $1");
! 329: CALL_HOOK();
! 330:
! 331: /* Same thing for exception 0. */
! 332: extern void _catchException0();
! 333: asm(".text");
! 334: asm(".globl _catchException0");
! 335: asm("_catchException0:");
! 336: SAVE_REGISTERS1();
! 337: SAVE_REGISTERS2();
! 338: asm ("pushl $0");
! 339: CALL_HOOK();
! 340:
! 341: /* Same thing for exception 4. */
! 342: extern void _catchException4();
! 343: asm(".text");
! 344: asm(".globl _catchException4");
! 345: asm("_catchException4:");
! 346: SAVE_REGISTERS1();
! 347: SAVE_REGISTERS2();
! 348: asm ("pushl $4");
! 349: CALL_HOOK();
! 350:
! 351: /* Same thing for exception 5. */
! 352: extern void _catchException5();
! 353: asm(".text");
! 354: asm(".globl _catchException5");
! 355: asm("_catchException5:");
! 356: SAVE_REGISTERS1();
! 357: SAVE_REGISTERS2();
! 358: asm ("pushl $5");
! 359: CALL_HOOK();
! 360:
! 361: /* Same thing for exception 6. */
! 362: extern void _catchException6();
! 363: asm(".text");
! 364: asm(".globl _catchException6");
! 365: asm("_catchException6:");
! 366: SAVE_REGISTERS1();
! 367: SAVE_REGISTERS2();
! 368: asm ("pushl $6");
! 369: CALL_HOOK();
! 370:
! 371: /* Same thing for exception 7. */
! 372: extern void _catchException7();
! 373: asm(".text");
! 374: asm(".globl _catchException7");
! 375: asm("_catchException7:");
! 376: SAVE_REGISTERS1();
! 377: SAVE_REGISTERS2();
! 378: asm ("pushl $7");
! 379: CALL_HOOK();
! 380:
! 381: /* Same thing for exception 8. */
! 382: extern void _catchException8();
! 383: asm(".text");
! 384: asm(".globl _catchException8");
! 385: asm("_catchException8:");
! 386: SAVE_REGISTERS1();
! 387: SAVE_ERRCODE();
! 388: SAVE_REGISTERS2();
! 389: asm ("pushl $8");
! 390: CALL_HOOK();
! 391:
! 392: /* Same thing for exception 9. */
! 393: extern void _catchException9();
! 394: asm(".text");
! 395: asm(".globl _catchException9");
! 396: asm("_catchException9:");
! 397: SAVE_REGISTERS1();
! 398: SAVE_REGISTERS2();
! 399: asm ("pushl $9");
! 400: CALL_HOOK();
! 401:
! 402: /* Same thing for exception 10. */
! 403: extern void _catchException10();
! 404: asm(".text");
! 405: asm(".globl _catchException10");
! 406: asm("_catchException10:");
! 407: SAVE_REGISTERS1();
! 408: SAVE_ERRCODE();
! 409: SAVE_REGISTERS2();
! 410: asm ("pushl $10");
! 411: CALL_HOOK();
! 412:
! 413: /* Same thing for exception 12. */
! 414: extern void _catchException12();
! 415: asm(".text");
! 416: asm(".globl _catchException12");
! 417: asm("_catchException12:");
! 418: SAVE_REGISTERS1();
! 419: SAVE_ERRCODE();
! 420: SAVE_REGISTERS2();
! 421: asm ("pushl $12");
! 422: CALL_HOOK();
! 423:
! 424: /* Same thing for exception 16. */
! 425: extern void _catchException16();
! 426: asm(".text");
! 427: asm(".globl _catchException16");
! 428: asm("_catchException16:");
! 429: SAVE_REGISTERS1();
! 430: SAVE_REGISTERS2();
! 431: asm ("pushl $16");
! 432: CALL_HOOK();
! 433:
! 434: /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
! 435:
! 436: /* Same thing for exception 13. */
! 437: extern void _catchException13 ();
! 438: asm (".text");
! 439: asm (".globl _catchException13");
! 440: asm ("_catchException13:");
! 441: CHECK_FAULT();
! 442: SAVE_REGISTERS1();
! 443: SAVE_ERRCODE();
! 444: SAVE_REGISTERS2();
! 445: asm ("pushl $13");
! 446: CALL_HOOK();
! 447:
! 448: /* Same thing for exception 11. */
! 449: extern void _catchException11 ();
! 450: asm (".text");
! 451: asm (".globl _catchException11");
! 452: asm ("_catchException11:");
! 453: CHECK_FAULT();
! 454: SAVE_REGISTERS1();
! 455: SAVE_ERRCODE();
! 456: SAVE_REGISTERS2();
! 457: asm ("pushl $11");
! 458: CALL_HOOK();
! 459:
! 460: /* Same thing for exception 14. */
! 461: extern void _catchException14 ();
! 462: asm (".text");
! 463: asm (".globl _catchException14");
! 464: asm ("_catchException14:");
! 465: CHECK_FAULT();
! 466: SAVE_REGISTERS1();
! 467: SAVE_ERRCODE();
! 468: SAVE_REGISTERS2();
! 469: asm ("pushl $14");
! 470: CALL_HOOK();
! 471:
! 472: /*
! 473: * remcomHandler is a front end for handle_exception. It moves the
! 474: * stack pointer into an area reserved for debugger use.
! 475: */
! 476: asm("_remcomHandler:");
! 477: asm(" popl %eax"); /* pop off return address */
! 478: asm(" popl %eax"); /* get the exception number */
! 479: asm(" movl stackPtr, %esp"); /* move to remcom stack area */
! 480: asm(" pushl %eax"); /* push exception onto stack */
! 481: asm(" call handle_exception"); /* this never returns */
! 482:
! 483: void
! 484: _returnFromException ()
! 485: {
! 486: return_to_prog ();
! 487: }
! 488:
! 489: int
! 490: hex (ch)
! 491: char ch;
! 492: {
! 493: if ((ch >= 'a') && (ch <= 'f'))
! 494: return (ch - 'a' + 10);
! 495: if ((ch >= '0') && (ch <= '9'))
! 496: return (ch - '0');
! 497: if ((ch >= 'A') && (ch <= 'F'))
! 498: return (ch - 'A' + 10);
! 499: return (-1);
! 500: }
! 501:
! 502: static char remcomInBuffer[BUFMAX];
! 503: static char remcomOutBuffer[BUFMAX];
! 504:
! 505: /* scan for the sequence $<data>#<checksum> */
! 506:
! 507: unsigned char *
! 508: getpacket (void)
! 509: {
! 510: unsigned char *buffer = &remcomInBuffer[0];
! 511: unsigned char checksum;
! 512: unsigned char xmitcsum;
! 513: int count;
! 514: char ch;
! 515:
! 516: while (1)
! 517: {
! 518: /* wait around for the start character, ignore all other characters */
! 519: while ((ch = getDebugChar ()) != '$')
! 520: ;
! 521:
! 522: retry:
! 523: checksum = 0;
! 524: xmitcsum = -1;
! 525: count = 0;
! 526:
! 527: /* now, read until a # or end of buffer is found */
! 528: while (count < BUFMAX)
! 529: {
! 530: ch = getDebugChar ();
! 531: if (ch == '$')
! 532: goto retry;
! 533: if (ch == '#')
! 534: break;
! 535: checksum = checksum + ch;
! 536: buffer[count] = ch;
! 537: count = count + 1;
! 538: }
! 539: buffer[count] = 0;
! 540:
! 541: if (ch == '#')
! 542: {
! 543: ch = getDebugChar ();
! 544: xmitcsum = hex (ch) << 4;
! 545: ch = getDebugChar ();
! 546: xmitcsum += hex (ch);
! 547:
! 548: if (checksum != xmitcsum)
! 549: {
! 550: if (remote_debug)
! 551: {
! 552: fprintf (stderr,
! 553: "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
! 554: checksum, xmitcsum, buffer);
! 555: }
! 556: putDebugChar ('-'); /* failed checksum */
! 557: }
! 558: else
! 559: {
! 560: putDebugChar ('+'); /* successful transfer */
! 561:
! 562: /* if a sequence char is present, reply the sequence ID */
! 563: if (buffer[2] == ':')
! 564: {
! 565: putDebugChar (buffer[0]);
! 566: putDebugChar (buffer[1]);
! 567:
! 568: return &buffer[3];
! 569: }
! 570:
! 571: return &buffer[0];
! 572: }
! 573: }
! 574: }
! 575: }
! 576:
! 577: /* send the packet in buffer. */
! 578:
! 579: void
! 580: putpacket (unsigned char *buffer)
! 581: {
! 582: unsigned char checksum;
! 583: int count;
! 584: char ch;
! 585:
! 586: /* $<packet info>#<checksum>. */
! 587: do
! 588: {
! 589: putDebugChar ('$');
! 590: checksum = 0;
! 591: count = 0;
! 592:
! 593: while ((ch = buffer[count]) != 0)
! 594: {
! 595: putDebugChar (ch);
! 596: checksum += ch;
! 597: count += 1;
! 598: }
! 599:
! 600: putDebugChar ('#');
! 601: putDebugChar (hexchars[checksum >> 4]);
! 602: putDebugChar (hexchars[checksum % 16]);
! 603:
! 604: }
! 605: while (getDebugChar () != '+');
! 606: }
! 607:
! 608: void
! 609: debug_error (format, parm)
! 610: char *format;
! 611: char *parm;
! 612: {
! 613: if (remote_debug)
! 614: fprintf (stderr, format, parm);
! 615: }
! 616:
! 617: /* Address of a routine to RTE to if we get a memory fault. */
! 618: static void (*volatile mem_fault_routine) () = NULL;
! 619:
! 620: /* Indicate to caller of mem2hex or hex2mem that there has been an
! 621: error. */
! 622: static volatile int mem_err = 0;
! 623:
! 624: void
! 625: set_mem_err (void)
! 626: {
! 627: mem_err = 1;
! 628: }
! 629:
! 630: /* These are separate functions so that they are so short and sweet
! 631: that the compiler won't save any registers (if there is a fault
! 632: to mem_fault, they won't get restored, so there better not be any
! 633: saved). */
! 634: int
! 635: get_char (char *addr)
! 636: {
! 637: return *addr;
! 638: }
! 639:
! 640: void
! 641: set_char (char *addr, int val)
! 642: {
! 643: *addr = val;
! 644: }
! 645:
! 646: /* convert the memory pointed to by mem into hex, placing result in buf */
! 647: /* return a pointer to the last char put in buf (null) */
! 648: /* If MAY_FAULT is non-zero, then we should set mem_err in response to
! 649: a fault; if zero treat a fault like any other fault in the stub. */
! 650: char *
! 651: mem2hex (mem, buf, count, may_fault)
! 652: char *mem;
! 653: char *buf;
! 654: int count;
! 655: int may_fault;
! 656: {
! 657: int i;
! 658: unsigned char ch;
! 659:
! 660: if (may_fault)
! 661: mem_fault_routine = set_mem_err;
! 662: for (i = 0; i < count; i++)
! 663: {
! 664: ch = get_char (mem++);
! 665: if (may_fault && mem_err)
! 666: return (buf);
! 667: *buf++ = hexchars[ch >> 4];
! 668: *buf++ = hexchars[ch % 16];
! 669: }
! 670: *buf = 0;
! 671: if (may_fault)
! 672: mem_fault_routine = NULL;
! 673: return (buf);
! 674: }
! 675:
! 676: /* convert the hex array pointed to by buf into binary to be placed in mem */
! 677: /* return a pointer to the character AFTER the last byte written */
! 678: char *
! 679: hex2mem (buf, mem, count, may_fault)
! 680: char *buf;
! 681: char *mem;
! 682: int count;
! 683: int may_fault;
! 684: {
! 685: int i;
! 686: unsigned char ch;
! 687:
! 688: if (may_fault)
! 689: mem_fault_routine = set_mem_err;
! 690: for (i = 0; i < count; i++)
! 691: {
! 692: ch = hex (*buf++) << 4;
! 693: ch = ch + hex (*buf++);
! 694: set_char (mem++, ch);
! 695: if (may_fault && mem_err)
! 696: return (mem);
! 697: }
! 698: if (may_fault)
! 699: mem_fault_routine = NULL;
! 700: return (mem);
! 701: }
! 702:
! 703: /* this function takes the 386 exception vector and attempts to
! 704: translate this number into a unix compatible signal value */
! 705: int
! 706: computeSignal (int exceptionVector)
! 707: {
! 708: int sigval;
! 709: switch (exceptionVector)
! 710: {
! 711: case 0:
! 712: sigval = 8;
! 713: break; /* divide by zero */
! 714: case 1:
! 715: sigval = 5;
! 716: break; /* debug exception */
! 717: case 3:
! 718: sigval = 5;
! 719: break; /* breakpoint */
! 720: case 4:
! 721: sigval = 16;
! 722: break; /* into instruction (overflow) */
! 723: case 5:
! 724: sigval = 16;
! 725: break; /* bound instruction */
! 726: case 6:
! 727: sigval = 4;
! 728: break; /* Invalid opcode */
! 729: case 7:
! 730: sigval = 8;
! 731: break; /* coprocessor not available */
! 732: case 8:
! 733: sigval = 7;
! 734: break; /* double fault */
! 735: case 9:
! 736: sigval = 11;
! 737: break; /* coprocessor segment overrun */
! 738: case 10:
! 739: sigval = 11;
! 740: break; /* Invalid TSS */
! 741: case 11:
! 742: sigval = 11;
! 743: break; /* Segment not present */
! 744: case 12:
! 745: sigval = 11;
! 746: break; /* stack exception */
! 747: case 13:
! 748: sigval = 11;
! 749: break; /* general protection */
! 750: case 14:
! 751: sigval = 11;
! 752: break; /* page fault */
! 753: case 16:
! 754: sigval = 7;
! 755: break; /* coprocessor error */
! 756: default:
! 757: sigval = 7; /* "software generated" */
! 758: }
! 759: return (sigval);
! 760: }
! 761:
! 762: /**********************************************/
! 763: /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
! 764: /* RETURN NUMBER OF CHARS PROCESSED */
! 765: /**********************************************/
! 766: int
! 767: hexToInt (char **ptr, int *intValue)
! 768: {
! 769: int numChars = 0;
! 770: int hexValue;
! 771:
! 772: *intValue = 0;
! 773:
! 774: while (**ptr)
! 775: {
! 776: hexValue = hex (**ptr);
! 777: if (hexValue >= 0)
! 778: {
! 779: *intValue = (*intValue << 4) | hexValue;
! 780: numChars++;
! 781: }
! 782: else
! 783: break;
! 784:
! 785: (*ptr)++;
! 786: }
! 787:
! 788: return (numChars);
! 789: }
! 790:
! 791: /*
! 792: * This function does all command procesing for interfacing to gdb.
! 793: */
! 794: void
! 795: handle_exception (int exceptionVector)
! 796: {
! 797: int sigval, stepping;
! 798: int addr, length;
! 799: char *ptr;
! 800: int newPC;
! 801:
! 802: gdb_i386vector = exceptionVector;
! 803:
! 804: if (remote_debug)
! 805: {
! 806: printf ("vector=%d, sr=0x%x, pc=0x%x\n",
! 807: exceptionVector, registers[PS], registers[PC]);
! 808: }
! 809:
! 810: /* reply to host that an exception has occurred */
! 811: sigval = computeSignal (exceptionVector);
! 812:
! 813: ptr = remcomOutBuffer;
! 814:
! 815: *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
! 816: *ptr++ = hexchars[sigval >> 4];
! 817: *ptr++ = hexchars[sigval & 0xf];
! 818:
! 819: *ptr++ = hexchars[ESP];
! 820: *ptr++ = ':';
! 821: ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */
! 822: *ptr++ = ';';
! 823:
! 824: *ptr++ = hexchars[EBP];
! 825: *ptr++ = ':';
! 826: ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */
! 827: *ptr++ = ';';
! 828:
! 829: *ptr++ = hexchars[PC];
! 830: *ptr++ = ':';
! 831: ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */
! 832: *ptr++ = ';';
! 833:
! 834: *ptr = '\0';
! 835:
! 836: putpacket (remcomOutBuffer);
! 837:
! 838: stepping = 0;
! 839:
! 840: while (1 == 1)
! 841: {
! 842: remcomOutBuffer[0] = 0;
! 843: ptr = getpacket ();
! 844:
! 845: switch (*ptr++)
! 846: {
! 847: case '?':
! 848: remcomOutBuffer[0] = 'S';
! 849: remcomOutBuffer[1] = hexchars[sigval >> 4];
! 850: remcomOutBuffer[2] = hexchars[sigval % 16];
! 851: remcomOutBuffer[3] = 0;
! 852: break;
! 853: case 'd':
! 854: remote_debug = !(remote_debug); /* toggle debug flag */
! 855: break;
! 856: case 'g': /* return the value of the CPU registers */
! 857: mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
! 858: break;
! 859: case 'G': /* set the value of the CPU registers - return OK */
! 860: hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
! 861: strcpy (remcomOutBuffer, "OK");
! 862: break;
! 863: case 'P': /* set the value of a single CPU register - return OK */
! 864: {
! 865: int regno;
! 866:
! 867: if (hexToInt (&ptr, ®no) && *ptr++ == '=')
! 868: if (regno >= 0 && regno < NUMREGS)
! 869: {
! 870: hex2mem (ptr, (char *) ®isters[regno], 4, 0);
! 871: strcpy (remcomOutBuffer, "OK");
! 872: break;
! 873: }
! 874:
! 875: strcpy (remcomOutBuffer, "E01");
! 876: break;
! 877: }
! 878:
! 879: /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
! 880: case 'm':
! 881: /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
! 882: if (hexToInt (&ptr, &addr))
! 883: if (*(ptr++) == ',')
! 884: if (hexToInt (&ptr, &length))
! 885: {
! 886: ptr = 0;
! 887: mem_err = 0;
! 888: mem2hex ((char *) addr, remcomOutBuffer, length, 1);
! 889: if (mem_err)
! 890: {
! 891: strcpy (remcomOutBuffer, "E03");
! 892: debug_error ("memory fault");
! 893: }
! 894: }
! 895:
! 896: if (ptr)
! 897: {
! 898: strcpy (remcomOutBuffer, "E01");
! 899: }
! 900: break;
! 901:
! 902: /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
! 903: case 'M':
! 904: /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
! 905: if (hexToInt (&ptr, &addr))
! 906: if (*(ptr++) == ',')
! 907: if (hexToInt (&ptr, &length))
! 908: if (*(ptr++) == ':')
! 909: {
! 910: mem_err = 0;
! 911: hex2mem (ptr, (char *) addr, length, 1);
! 912:
! 913: if (mem_err)
! 914: {
! 915: strcpy (remcomOutBuffer, "E03");
! 916: debug_error ("memory fault");
! 917: }
! 918: else
! 919: {
! 920: strcpy (remcomOutBuffer, "OK");
! 921: }
! 922:
! 923: ptr = 0;
! 924: }
! 925: if (ptr)
! 926: {
! 927: strcpy (remcomOutBuffer, "E02");
! 928: }
! 929: break;
! 930:
! 931: /* cAA..AA Continue at address AA..AA(optional) */
! 932: /* sAA..AA Step one instruction from AA..AA(optional) */
! 933: case 's':
! 934: stepping = 1;
! 935: case 'c':
! 936: /* try to read optional parameter, pc unchanged if no parm */
! 937: if (hexToInt (&ptr, &addr))
! 938: registers[PC] = addr;
! 939:
! 940: newPC = registers[PC];
! 941:
! 942: /* clear the trace bit */
! 943: registers[PS] &= 0xfffffeff;
! 944:
! 945: /* set the trace bit if we're stepping */
! 946: if (stepping)
! 947: registers[PS] |= 0x100;
! 948:
! 949: _returnFromException (); /* this is a jump */
! 950: break;
! 951:
! 952: /* kill the program */
! 953: case 'k': /* do nothing */
! 954: #if 0
! 955: /* Huh? This doesn't look like "nothing".
! 956: m68k-stub.c and sparc-stub.c don't have it. */
! 957: BREAKPOINT ();
! 958: #endif
! 959: break;
! 960: } /* switch */
! 961:
! 962: /* reply to the request */
! 963: putpacket (remcomOutBuffer);
! 964: }
! 965: }
! 966:
! 967: /* this function is used to set up exception handlers for tracing and
! 968: breakpoints */
! 969: void
! 970: set_debug_traps (void)
! 971: {
! 972: stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
! 973:
! 974: exceptionHandler (0, _catchException0);
! 975: exceptionHandler (1, _catchException1);
! 976: exceptionHandler (3, _catchException3);
! 977: exceptionHandler (4, _catchException4);
! 978: exceptionHandler (5, _catchException5);
! 979: exceptionHandler (6, _catchException6);
! 980: exceptionHandler (7, _catchException7);
! 981: exceptionHandler (8, _catchException8);
! 982: exceptionHandler (9, _catchException9);
! 983: exceptionHandler (10, _catchException10);
! 984: exceptionHandler (11, _catchException11);
! 985: exceptionHandler (12, _catchException12);
! 986: exceptionHandler (13, _catchException13);
! 987: exceptionHandler (14, _catchException14);
! 988: exceptionHandler (16, _catchException16);
! 989:
! 990: initialized = 1;
! 991: }
! 992:
! 993: /* This function will generate a breakpoint exception. It is used at the
! 994: beginning of a program to sync up with a debugger and can be used
! 995: otherwise as a quick means to stop program execution and "break" into
! 996: the debugger. */
! 997:
! 998: /*
! 999: void
! 1000: breakpoint (void)
! 1001: {
! 1002: if (initialized)
! 1003: BREAKPOINT ();
! 1004: }
! 1005: */
! 1006:
! 1007: void
! 1008: gdb_init(void)
! 1009: {
! 1010: if (serial_init())
! 1011: return;
! 1012: set_debug_traps();
! 1013:
! 1014: printk("Waiting to connect remote gdb...\n");
! 1015: BREAKPOINT();
! 1016: }
! 1017:
! 1018: #endif /* CONFIG_GDB */
CVSweb