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