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 *)®isters[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 *)®isters[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 *)®isters[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, ®no) && *ptr++ == '=') 817 1.1 christos if (regno >= 0 && regno < NUMREGS) 818 1.1 christos { 819 1.1 christos hex2mem (ptr, (char *) ®isters[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