1130812Smarcel/**************************************************************************** 2130812Smarcel 3130812Smarcel THIS SOFTWARE IS NOT COPYRIGHTED 4130812Smarcel 5130812Smarcel HP offers the following for use in the public domain. HP makes no 6130812Smarcel warranty with regard to the software or it's performance and the 7130812Smarcel user accepts the software "AS IS" with all faults. 8130812Smarcel 9130812Smarcel HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD 10130812Smarcel TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES 11130812Smarcel OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12130812Smarcel 13130812Smarcel****************************************************************************/ 14130812Smarcel 15130812Smarcel/**************************************************************************** 16130812Smarcel * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ 17130812Smarcel * 18130812Smarcel * Module name: remcom.c $ 19130812Smarcel * Revision: 1.34 $ 20130812Smarcel * Date: 91/03/09 12:29:49 $ 21130812Smarcel * Contributor: Lake Stevens Instrument Division$ 22130812Smarcel * 23130812Smarcel * Description: low level support for gdb debugger. $ 24130812Smarcel * 25130812Smarcel * Considerations: only works on target hardware $ 26130812Smarcel * 27130812Smarcel * Written by: Glenn Engel $ 28130812Smarcel * ModuleState: Experimental $ 29130812Smarcel * 30130812Smarcel * NOTES: See Below $ 31130812Smarcel * 32130812Smarcel * Modified for 386 by Jim Kingdon, Cygnus Support. 33130812Smarcel * 34130812Smarcel * To enable debugger support, two things need to happen. One, a 35130812Smarcel * call to set_debug_traps() is necessary in order to allow any breakpoints 36130812Smarcel * or error conditions to be properly intercepted and reported to gdb. 37130812Smarcel * Two, a breakpoint needs to be generated to begin communication. This 38130812Smarcel * is most easily accomplished by a call to breakpoint(). Breakpoint() 39130812Smarcel * simulates a breakpoint by executing a trap #1. 40130812Smarcel * 41130812Smarcel * The external function exceptionHandler() is 42130812Smarcel * used to attach a specific handler to a specific 386 vector number. 43130812Smarcel * It should use the same privilege level it runs at. It should 44130812Smarcel * install it as an interrupt gate so that interrupts are masked 45130812Smarcel * while the handler runs. 46130812Smarcel * 47130812Smarcel * Because gdb will sometimes write to the stack area to execute function 48130812Smarcel * calls, this program cannot rely on using the supervisor stack so it 49130812Smarcel * uses it's own stack area reserved in the int array remcomStack. 50130812Smarcel * 51130812Smarcel ************* 52130812Smarcel * 53130812Smarcel * The following gdb commands are supported: 54130812Smarcel * 55130812Smarcel * command function Return value 56130812Smarcel * 57130812Smarcel * g return the value of the CPU registers hex data or ENN 58130812Smarcel * G set the value of the CPU registers OK or ENN 59130812Smarcel * 60130812Smarcel * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN 61130812Smarcel * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN 62130812Smarcel * 63130812Smarcel * c Resume at current address SNN ( signal NN) 64130812Smarcel * cAA..AA Continue at address AA..AA SNN 65130812Smarcel * 66130812Smarcel * s Step one instruction SNN 67130812Smarcel * sAA..AA Step one instruction from AA..AA SNN 68130812Smarcel * 69130812Smarcel * k kill 70130812Smarcel * 71130812Smarcel * ? What was the last sigval ? SNN (signal NN) 72130812Smarcel * 73130812Smarcel * All commands and responses are sent with a packet which includes a 74130812Smarcel * checksum. A packet consists of 75130812Smarcel * 76130812Smarcel * $<packet info>#<checksum>. 77130812Smarcel * 78130812Smarcel * where 79130812Smarcel * <packet info> :: <characters representing the command or response> 80130812Smarcel * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> 81130812Smarcel * 82130812Smarcel * When a packet is received, it is first acknowledged with either '+' or '-'. 83130812Smarcel * '+' indicates a successful transfer. '-' indicates a failed transfer. 84130812Smarcel * 85130812Smarcel * Example: 86130812Smarcel * 87130812Smarcel * Host: Reply: 88130812Smarcel * $m0,10#2a +$00010203040506070809101112131415#42 89130812Smarcel * 90130812Smarcel ****************************************************************************/ 91130812Smarcel 92130812Smarcel#include <stdio.h> 93130812Smarcel#include <string.h> 94130812Smarcel 95130812Smarcel/************************************************************************ 96130812Smarcel * 97130812Smarcel * external low-level support routines 98130812Smarcel */ 99130812Smarcel 100130812Smarcelextern void putDebugChar(); /* write a single character */ 101130812Smarcelextern int getDebugChar(); /* read and return a single char */ 102130812Smarcelextern void exceptionHandler(); /* assign an exception handler */ 103130812Smarcel 104130812Smarcel/************************************************************************/ 105130812Smarcel/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ 106130812Smarcel/* at least NUMREGBYTES*2 are needed for register packets */ 107130812Smarcel#define BUFMAX 400 108130812Smarcel 109130812Smarcelstatic char initialized; /* boolean flag. != 0 means we've been initialized */ 110130812Smarcel 111130812Smarcelint remote_debug; 112130812Smarcel/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ 113130812Smarcel 114130812Smarcelstatic const char hexchars[]="0123456789abcdef"; 115130812Smarcel 116130812Smarcel/* Number of registers. */ 117130812Smarcel#define NUMREGS 16 118130812Smarcel 119130812Smarcel/* Number of bytes of registers. */ 120130812Smarcel#define NUMREGBYTES (NUMREGS * 4) 121130812Smarcel 122130812Smarcelenum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, 123130812Smarcel PC /* also known as eip */, 124130812Smarcel PS /* also known as eflags */, 125130812Smarcel CS, SS, DS, ES, FS, GS}; 126130812Smarcel 127130812Smarcel/* 128130812Smarcel * these should not be static cuz they can be used outside this module 129130812Smarcel */ 130130812Smarcelint registers[NUMREGS]; 131130812Smarcel 132130812Smarcel#define STACKSIZE 10000 133130812Smarcelint remcomStack[STACKSIZE/sizeof(int)]; 134130812Smarcelstatic int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; 135130812Smarcel 136130812Smarcel/*************************** ASSEMBLY CODE MACROS *************************/ 137130812Smarcel/* */ 138130812Smarcel 139130812Smarcelextern void 140130812Smarcelreturn_to_prog (); 141130812Smarcel 142130812Smarcel/* Restore the program's registers (including the stack pointer, which 143130812Smarcel means we get the right stack and don't have to worry about popping our 144130812Smarcel return address and any stack frames and so on) and return. */ 145130812Smarcelasm(".text"); 146130812Smarcelasm(".globl _return_to_prog"); 147130812Smarcelasm("_return_to_prog:"); 148130812Smarcelasm(" movw _registers+44, %ss"); 149130812Smarcelasm(" movl _registers+16, %esp"); 150130812Smarcelasm(" movl _registers+4, %ecx"); 151130812Smarcelasm(" movl _registers+8, %edx"); 152130812Smarcelasm(" movl _registers+12, %ebx"); 153130812Smarcelasm(" movl _registers+20, %ebp"); 154130812Smarcelasm(" movl _registers+24, %esi"); 155130812Smarcelasm(" movl _registers+28, %edi"); 156130812Smarcelasm(" movw _registers+48, %ds"); 157130812Smarcelasm(" movw _registers+52, %es"); 158130812Smarcelasm(" movw _registers+56, %fs"); 159130812Smarcelasm(" movw _registers+60, %gs"); 160130812Smarcelasm(" movl _registers+36, %eax"); 161130812Smarcelasm(" pushl %eax"); /* saved eflags */ 162130812Smarcelasm(" movl _registers+40, %eax"); 163130812Smarcelasm(" pushl %eax"); /* saved cs */ 164130812Smarcelasm(" movl _registers+32, %eax"); 165130812Smarcelasm(" pushl %eax"); /* saved eip */ 166130812Smarcelasm(" movl _registers, %eax"); 167130812Smarcel/* use iret to restore pc and flags together so 168130812Smarcel that trace flag works right. */ 169130812Smarcelasm(" iret"); 170130812Smarcel 171130812Smarcel#define BREAKPOINT() asm(" int $3"); 172130812Smarcel 173130812Smarcel/* Put the error code here just in case the user cares. */ 174130812Smarcelint gdb_i386errcode; 175130812Smarcel/* Likewise, the vector number here (since GDB only gets the signal 176130812Smarcel number through the usual means, and that's not very specific). */ 177130812Smarcelint gdb_i386vector = -1; 178130812Smarcel 179130812Smarcel/* GDB stores segment registers in 32-bit words (that's just the way 180130812Smarcel m-i386v.h is written). So zero the appropriate areas in registers. */ 181130812Smarcel#define SAVE_REGISTERS1() \ 182130812Smarcel asm ("movl %eax, _registers"); \ 183130812Smarcel asm ("movl %ecx, _registers+4"); \ 184130812Smarcel asm ("movl %edx, _registers+8"); \ 185130812Smarcel asm ("movl %ebx, _registers+12"); \ 186130812Smarcel asm ("movl %ebp, _registers+20"); \ 187130812Smarcel asm ("movl %esi, _registers+24"); \ 188130812Smarcel asm ("movl %edi, _registers+28"); \ 189130812Smarcel asm ("movw $0, %ax"); \ 190130812Smarcel asm ("movw %ds, _registers+48"); \ 191130812Smarcel asm ("movw %ax, _registers+50"); \ 192130812Smarcel asm ("movw %es, _registers+52"); \ 193130812Smarcel asm ("movw %ax, _registers+54"); \ 194130812Smarcel asm ("movw %fs, _registers+56"); \ 195130812Smarcel asm ("movw %ax, _registers+58"); \ 196130812Smarcel asm ("movw %gs, _registers+60"); \ 197130812Smarcel asm ("movw %ax, _registers+62"); 198130812Smarcel#define SAVE_ERRCODE() \ 199130812Smarcel asm ("popl %ebx"); \ 200130812Smarcel asm ("movl %ebx, _gdb_i386errcode"); 201130812Smarcel#define SAVE_REGISTERS2() \ 202130812Smarcel asm ("popl %ebx"); /* old eip */ \ 203130812Smarcel asm ("movl %ebx, _registers+32"); \ 204130812Smarcel asm ("popl %ebx"); /* old cs */ \ 205130812Smarcel asm ("movl %ebx, _registers+40"); \ 206130812Smarcel asm ("movw %ax, _registers+42"); \ 207130812Smarcel asm ("popl %ebx"); /* old eflags */ \ 208130812Smarcel asm ("movl %ebx, _registers+36"); \ 209130812Smarcel /* Now that we've done the pops, we can save the stack pointer."); */ \ 210130812Smarcel asm ("movw %ss, _registers+44"); \ 211130812Smarcel asm ("movw %ax, _registers+46"); \ 212130812Smarcel asm ("movl %esp, _registers+16"); 213130812Smarcel 214130812Smarcel/* See if mem_fault_routine is set, if so just IRET to that address. */ 215130812Smarcel#define CHECK_FAULT() \ 216130812Smarcel asm ("cmpl $0, _mem_fault_routine"); \ 217130812Smarcel asm ("jne mem_fault"); 218130812Smarcel 219130812Smarcelasm (".text"); 220130812Smarcelasm ("mem_fault:"); 221130812Smarcel/* OK to clobber temp registers; we're just going to end up in set_mem_err. */ 222130812Smarcel/* Pop error code from the stack and save it. */ 223130812Smarcelasm (" popl %eax"); 224130812Smarcelasm (" movl %eax, _gdb_i386errcode"); 225130812Smarcel 226130812Smarcelasm (" popl %eax"); /* eip */ 227130812Smarcel/* We don't want to return there, we want to return to the function 228130812Smarcel pointed to by mem_fault_routine instead. */ 229130812Smarcelasm (" movl _mem_fault_routine, %eax"); 230130812Smarcelasm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */ 231130812Smarcelasm (" popl %edx"); /* eflags */ 232130812Smarcel 233130812Smarcel/* Remove this stack frame; when we do the iret, we will be going to 234130812Smarcel the start of a function, so we want the stack to look just like it 235130812Smarcel would after a "call" instruction. */ 236130812Smarcelasm (" leave"); 237130812Smarcel 238130812Smarcel/* Push the stuff that iret wants. */ 239130812Smarcelasm (" pushl %edx"); /* eflags */ 240130812Smarcelasm (" pushl %ecx"); /* cs */ 241130812Smarcelasm (" pushl %eax"); /* eip */ 242130812Smarcel 243130812Smarcel/* Zero mem_fault_routine. */ 244130812Smarcelasm (" movl $0, %eax"); 245130812Smarcelasm (" movl %eax, _mem_fault_routine"); 246130812Smarcel 247130812Smarcelasm ("iret"); 248130812Smarcel 249130812Smarcel#define CALL_HOOK() asm("call _remcomHandler"); 250130812Smarcel 251130812Smarcel/* This function is called when a i386 exception occurs. It saves 252130812Smarcel * all the cpu regs in the _registers array, munges the stack a bit, 253130812Smarcel * and invokes an exception handler (remcom_handler). 254130812Smarcel * 255130812Smarcel * stack on entry: stack on exit: 256130812Smarcel * old eflags vector number 257130812Smarcel * old cs (zero-filled to 32 bits) 258130812Smarcel * old eip 259130812Smarcel * 260130812Smarcel */ 261130812Smarcelextern void _catchException3(); 262130812Smarcelasm(".text"); 263130812Smarcelasm(".globl __catchException3"); 264130812Smarcelasm("__catchException3:"); 265130812SmarcelSAVE_REGISTERS1(); 266130812SmarcelSAVE_REGISTERS2(); 267130812Smarcelasm ("pushl $3"); 268130812SmarcelCALL_HOOK(); 269130812Smarcel 270130812Smarcel/* Same thing for exception 1. */ 271130812Smarcelextern void _catchException1(); 272130812Smarcelasm(".text"); 273130812Smarcelasm(".globl __catchException1"); 274130812Smarcelasm("__catchException1:"); 275130812SmarcelSAVE_REGISTERS1(); 276130812SmarcelSAVE_REGISTERS2(); 277130812Smarcelasm ("pushl $1"); 278130812SmarcelCALL_HOOK(); 279130812Smarcel 280130812Smarcel/* Same thing for exception 0. */ 281130812Smarcelextern void _catchException0(); 282130812Smarcelasm(".text"); 283130812Smarcelasm(".globl __catchException0"); 284130812Smarcelasm("__catchException0:"); 285130812SmarcelSAVE_REGISTERS1(); 286130812SmarcelSAVE_REGISTERS2(); 287130812Smarcelasm ("pushl $0"); 288130812SmarcelCALL_HOOK(); 289130812Smarcel 290130812Smarcel/* Same thing for exception 4. */ 291130812Smarcelextern void _catchException4(); 292130812Smarcelasm(".text"); 293130812Smarcelasm(".globl __catchException4"); 294130812Smarcelasm("__catchException4:"); 295130812SmarcelSAVE_REGISTERS1(); 296130812SmarcelSAVE_REGISTERS2(); 297130812Smarcelasm ("pushl $4"); 298130812SmarcelCALL_HOOK(); 299130812Smarcel 300130812Smarcel/* Same thing for exception 5. */ 301130812Smarcelextern void _catchException5(); 302130812Smarcelasm(".text"); 303130812Smarcelasm(".globl __catchException5"); 304130812Smarcelasm("__catchException5:"); 305130812SmarcelSAVE_REGISTERS1(); 306130812SmarcelSAVE_REGISTERS2(); 307130812Smarcelasm ("pushl $5"); 308130812SmarcelCALL_HOOK(); 309130812Smarcel 310130812Smarcel/* Same thing for exception 6. */ 311130812Smarcelextern void _catchException6(); 312130812Smarcelasm(".text"); 313130812Smarcelasm(".globl __catchException6"); 314130812Smarcelasm("__catchException6:"); 315130812SmarcelSAVE_REGISTERS1(); 316130812SmarcelSAVE_REGISTERS2(); 317130812Smarcelasm ("pushl $6"); 318130812SmarcelCALL_HOOK(); 319130812Smarcel 320130812Smarcel/* Same thing for exception 7. */ 321130812Smarcelextern void _catchException7(); 322130812Smarcelasm(".text"); 323130812Smarcelasm(".globl __catchException7"); 324130812Smarcelasm("__catchException7:"); 325130812SmarcelSAVE_REGISTERS1(); 326130812SmarcelSAVE_REGISTERS2(); 327130812Smarcelasm ("pushl $7"); 328130812SmarcelCALL_HOOK(); 329130812Smarcel 330130812Smarcel/* Same thing for exception 8. */ 331130812Smarcelextern void _catchException8(); 332130812Smarcelasm(".text"); 333130812Smarcelasm(".globl __catchException8"); 334130812Smarcelasm("__catchException8:"); 335130812SmarcelSAVE_REGISTERS1(); 336130812SmarcelSAVE_ERRCODE(); 337130812SmarcelSAVE_REGISTERS2(); 338130812Smarcelasm ("pushl $8"); 339130812SmarcelCALL_HOOK(); 340130812Smarcel 341130812Smarcel/* Same thing for exception 9. */ 342130812Smarcelextern void _catchException9(); 343130812Smarcelasm(".text"); 344130812Smarcelasm(".globl __catchException9"); 345130812Smarcelasm("__catchException9:"); 346130812SmarcelSAVE_REGISTERS1(); 347130812SmarcelSAVE_REGISTERS2(); 348130812Smarcelasm ("pushl $9"); 349130812SmarcelCALL_HOOK(); 350130812Smarcel 351130812Smarcel/* Same thing for exception 10. */ 352130812Smarcelextern void _catchException10(); 353130812Smarcelasm(".text"); 354130812Smarcelasm(".globl __catchException10"); 355130812Smarcelasm("__catchException10:"); 356130812SmarcelSAVE_REGISTERS1(); 357130812SmarcelSAVE_ERRCODE(); 358130812SmarcelSAVE_REGISTERS2(); 359130812Smarcelasm ("pushl $10"); 360130812SmarcelCALL_HOOK(); 361130812Smarcel 362130812Smarcel/* Same thing for exception 12. */ 363130812Smarcelextern void _catchException12(); 364130812Smarcelasm(".text"); 365130812Smarcelasm(".globl __catchException12"); 366130812Smarcelasm("__catchException12:"); 367130812SmarcelSAVE_REGISTERS1(); 368130812SmarcelSAVE_ERRCODE(); 369130812SmarcelSAVE_REGISTERS2(); 370130812Smarcelasm ("pushl $12"); 371130812SmarcelCALL_HOOK(); 372130812Smarcel 373130812Smarcel/* Same thing for exception 16. */ 374130812Smarcelextern void _catchException16(); 375130812Smarcelasm(".text"); 376130812Smarcelasm(".globl __catchException16"); 377130812Smarcelasm("__catchException16:"); 378130812SmarcelSAVE_REGISTERS1(); 379130812SmarcelSAVE_REGISTERS2(); 380130812Smarcelasm ("pushl $16"); 381130812SmarcelCALL_HOOK(); 382130812Smarcel 383130812Smarcel/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */ 384130812Smarcel 385130812Smarcel/* Same thing for exception 13. */ 386130812Smarcelextern void _catchException13 (); 387130812Smarcelasm (".text"); 388130812Smarcelasm (".globl __catchException13"); 389130812Smarcelasm ("__catchException13:"); 390130812SmarcelCHECK_FAULT(); 391130812SmarcelSAVE_REGISTERS1(); 392130812SmarcelSAVE_ERRCODE(); 393130812SmarcelSAVE_REGISTERS2(); 394130812Smarcelasm ("pushl $13"); 395130812SmarcelCALL_HOOK(); 396130812Smarcel 397130812Smarcel/* Same thing for exception 11. */ 398130812Smarcelextern void _catchException11 (); 399130812Smarcelasm (".text"); 400130812Smarcelasm (".globl __catchException11"); 401130812Smarcelasm ("__catchException11:"); 402130812SmarcelCHECK_FAULT(); 403130812SmarcelSAVE_REGISTERS1(); 404130812SmarcelSAVE_ERRCODE(); 405130812SmarcelSAVE_REGISTERS2(); 406130812Smarcelasm ("pushl $11"); 407130812SmarcelCALL_HOOK(); 408130812Smarcel 409130812Smarcel/* Same thing for exception 14. */ 410130812Smarcelextern void _catchException14 (); 411130812Smarcelasm (".text"); 412130812Smarcelasm (".globl __catchException14"); 413130812Smarcelasm ("__catchException14:"); 414130812SmarcelCHECK_FAULT(); 415130812SmarcelSAVE_REGISTERS1(); 416130812SmarcelSAVE_ERRCODE(); 417130812SmarcelSAVE_REGISTERS2(); 418130812Smarcelasm ("pushl $14"); 419130812SmarcelCALL_HOOK(); 420130812Smarcel 421130812Smarcel/* 422130812Smarcel * remcomHandler is a front end for handle_exception. It moves the 423130812Smarcel * stack pointer into an area reserved for debugger use. 424130812Smarcel */ 425130812Smarcelasm("_remcomHandler:"); 426130812Smarcelasm(" popl %eax"); /* pop off return address */ 427130812Smarcelasm(" popl %eax"); /* get the exception number */ 428130812Smarcelasm(" movl _stackPtr, %esp"); /* move to remcom stack area */ 429130812Smarcelasm(" pushl %eax"); /* push exception onto stack */ 430130812Smarcelasm(" call _handle_exception"); /* this never returns */ 431130812Smarcel 432130812Smarcelvoid 433130812Smarcel_returnFromException () 434130812Smarcel{ 435130812Smarcel return_to_prog (); 436130812Smarcel} 437130812Smarcel 438130812Smarcelint 439130812Smarcelhex (ch) 440130812Smarcel char ch; 441130812Smarcel{ 442130812Smarcel if ((ch >= 'a') && (ch <= 'f')) 443130812Smarcel return (ch - 'a' + 10); 444130812Smarcel if ((ch >= '0') && (ch <= '9')) 445130812Smarcel return (ch - '0'); 446130812Smarcel if ((ch >= 'A') && (ch <= 'F')) 447130812Smarcel return (ch - 'A' + 10); 448130812Smarcel return (-1); 449130812Smarcel} 450130812Smarcel 451130812Smarcelstatic char remcomInBuffer[BUFMAX]; 452130812Smarcelstatic char remcomOutBuffer[BUFMAX]; 453130812Smarcel 454130812Smarcel/* scan for the sequence $<data>#<checksum> */ 455130812Smarcel 456130812Smarcelunsigned char * 457130812Smarcelgetpacket (void) 458130812Smarcel{ 459130812Smarcel unsigned char *buffer = &remcomInBuffer[0]; 460130812Smarcel unsigned char checksum; 461130812Smarcel unsigned char xmitcsum; 462130812Smarcel int count; 463130812Smarcel char ch; 464130812Smarcel 465130812Smarcel while (1) 466130812Smarcel { 467130812Smarcel /* wait around for the start character, ignore all other characters */ 468130812Smarcel while ((ch = getDebugChar ()) != '$') 469130812Smarcel ; 470130812Smarcel 471130812Smarcel retry: 472130812Smarcel checksum = 0; 473130812Smarcel xmitcsum = -1; 474130812Smarcel count = 0; 475130812Smarcel 476130812Smarcel /* now, read until a # or end of buffer is found */ 477130812Smarcel while (count < BUFMAX) 478130812Smarcel { 479130812Smarcel ch = getDebugChar (); 480130812Smarcel if (ch == '$') 481130812Smarcel goto retry; 482130812Smarcel if (ch == '#') 483130812Smarcel break; 484130812Smarcel checksum = checksum + ch; 485130812Smarcel buffer[count] = ch; 486130812Smarcel count = count + 1; 487130812Smarcel } 488130812Smarcel buffer[count] = 0; 489130812Smarcel 490130812Smarcel if (ch == '#') 491130812Smarcel { 492130812Smarcel ch = getDebugChar (); 493130812Smarcel xmitcsum = hex (ch) << 4; 494130812Smarcel ch = getDebugChar (); 495130812Smarcel xmitcsum += hex (ch); 496130812Smarcel 497130812Smarcel if (checksum != xmitcsum) 498130812Smarcel { 499130812Smarcel if (remote_debug) 500130812Smarcel { 501130812Smarcel fprintf (stderr, 502130812Smarcel "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", 503130812Smarcel checksum, xmitcsum, buffer); 504130812Smarcel } 505130812Smarcel putDebugChar ('-'); /* failed checksum */ 506130812Smarcel } 507130812Smarcel else 508130812Smarcel { 509130812Smarcel putDebugChar ('+'); /* successful transfer */ 510130812Smarcel 511130812Smarcel /* if a sequence char is present, reply the sequence ID */ 512130812Smarcel if (buffer[2] == ':') 513130812Smarcel { 514130812Smarcel putDebugChar (buffer[0]); 515130812Smarcel putDebugChar (buffer[1]); 516130812Smarcel 517130812Smarcel return &buffer[3]; 518130812Smarcel } 519130812Smarcel 520130812Smarcel return &buffer[0]; 521130812Smarcel } 522130812Smarcel } 523130812Smarcel } 524130812Smarcel} 525130812Smarcel 526130812Smarcel/* send the packet in buffer. */ 527130812Smarcel 528130812Smarcelvoid 529130812Smarcelputpacket (unsigned char *buffer) 530130812Smarcel{ 531130812Smarcel unsigned char checksum; 532130812Smarcel int count; 533130812Smarcel char ch; 534130812Smarcel 535130812Smarcel /* $<packet info>#<checksum>. */ 536130812Smarcel do 537130812Smarcel { 538130812Smarcel putDebugChar ('$'); 539130812Smarcel checksum = 0; 540130812Smarcel count = 0; 541130812Smarcel 542130812Smarcel while (ch = buffer[count]) 543130812Smarcel { 544130812Smarcel putDebugChar (ch); 545130812Smarcel checksum += ch; 546130812Smarcel count += 1; 547130812Smarcel } 548130812Smarcel 549130812Smarcel putDebugChar ('#'); 550130812Smarcel putDebugChar (hexchars[checksum >> 4]); 551130812Smarcel putDebugChar (hexchars[checksum % 16]); 552130812Smarcel 553130812Smarcel } 554130812Smarcel while (getDebugChar () != '+'); 555130812Smarcel} 556130812Smarcel 557130812Smarcelvoid 558130812Smarceldebug_error (format, parm) 559130812Smarcel char *format; 560130812Smarcel char *parm; 561130812Smarcel{ 562130812Smarcel if (remote_debug) 563130812Smarcel fprintf (stderr, format, parm); 564130812Smarcel} 565130812Smarcel 566130812Smarcel/* Address of a routine to RTE to if we get a memory fault. */ 567130812Smarcelstatic void (*volatile mem_fault_routine) () = NULL; 568130812Smarcel 569130812Smarcel/* Indicate to caller of mem2hex or hex2mem that there has been an 570130812Smarcel error. */ 571130812Smarcelstatic volatile int mem_err = 0; 572130812Smarcel 573130812Smarcelvoid 574130812Smarcelset_mem_err (void) 575130812Smarcel{ 576130812Smarcel mem_err = 1; 577130812Smarcel} 578130812Smarcel 579130812Smarcel/* These are separate functions so that they are so short and sweet 580130812Smarcel that the compiler won't save any registers (if there is a fault 581130812Smarcel to mem_fault, they won't get restored, so there better not be any 582130812Smarcel saved). */ 583130812Smarcelint 584130812Smarcelget_char (char *addr) 585130812Smarcel{ 586130812Smarcel return *addr; 587130812Smarcel} 588130812Smarcel 589130812Smarcelvoid 590130812Smarcelset_char (char *addr, int val) 591130812Smarcel{ 592130812Smarcel *addr = val; 593130812Smarcel} 594130812Smarcel 595130812Smarcel/* convert the memory pointed to by mem into hex, placing result in buf */ 596130812Smarcel/* return a pointer to the last char put in buf (null) */ 597130812Smarcel/* If MAY_FAULT is non-zero, then we should set mem_err in response to 598130812Smarcel a fault; if zero treat a fault like any other fault in the stub. */ 599130812Smarcelchar * 600130812Smarcelmem2hex (mem, buf, count, may_fault) 601130812Smarcel char *mem; 602130812Smarcel char *buf; 603130812Smarcel int count; 604130812Smarcel int may_fault; 605130812Smarcel{ 606130812Smarcel int i; 607130812Smarcel unsigned char ch; 608130812Smarcel 609130812Smarcel if (may_fault) 610130812Smarcel mem_fault_routine = set_mem_err; 611130812Smarcel for (i = 0; i < count; i++) 612130812Smarcel { 613130812Smarcel ch = get_char (mem++); 614130812Smarcel if (may_fault && mem_err) 615130812Smarcel return (buf); 616130812Smarcel *buf++ = hexchars[ch >> 4]; 617130812Smarcel *buf++ = hexchars[ch % 16]; 618130812Smarcel } 619130812Smarcel *buf = 0; 620130812Smarcel if (may_fault) 621130812Smarcel mem_fault_routine = NULL; 622130812Smarcel return (buf); 623130812Smarcel} 624130812Smarcel 625130812Smarcel/* convert the hex array pointed to by buf into binary to be placed in mem */ 626130812Smarcel/* return a pointer to the character AFTER the last byte written */ 627130812Smarcelchar * 628130812Smarcelhex2mem (buf, mem, count, may_fault) 629130812Smarcel char *buf; 630130812Smarcel char *mem; 631130812Smarcel int count; 632130812Smarcel int may_fault; 633130812Smarcel{ 634130812Smarcel int i; 635130812Smarcel unsigned char ch; 636130812Smarcel 637130812Smarcel if (may_fault) 638130812Smarcel mem_fault_routine = set_mem_err; 639130812Smarcel for (i = 0; i < count; i++) 640130812Smarcel { 641130812Smarcel ch = hex (*buf++) << 4; 642130812Smarcel ch = ch + hex (*buf++); 643130812Smarcel set_char (mem++, ch); 644130812Smarcel if (may_fault && mem_err) 645130812Smarcel return (mem); 646130812Smarcel } 647130812Smarcel if (may_fault) 648130812Smarcel mem_fault_routine = NULL; 649130812Smarcel return (mem); 650130812Smarcel} 651130812Smarcel 652130812Smarcel/* this function takes the 386 exception vector and attempts to 653130812Smarcel translate this number into a unix compatible signal value */ 654130812Smarcelint 655130812SmarcelcomputeSignal (int exceptionVector) 656130812Smarcel{ 657130812Smarcel int sigval; 658130812Smarcel switch (exceptionVector) 659130812Smarcel { 660130812Smarcel case 0: 661130812Smarcel sigval = 8; 662130812Smarcel break; /* divide by zero */ 663130812Smarcel case 1: 664130812Smarcel sigval = 5; 665130812Smarcel break; /* debug exception */ 666130812Smarcel case 3: 667130812Smarcel sigval = 5; 668130812Smarcel break; /* breakpoint */ 669130812Smarcel case 4: 670130812Smarcel sigval = 16; 671130812Smarcel break; /* into instruction (overflow) */ 672130812Smarcel case 5: 673130812Smarcel sigval = 16; 674130812Smarcel break; /* bound instruction */ 675130812Smarcel case 6: 676130812Smarcel sigval = 4; 677130812Smarcel break; /* Invalid opcode */ 678130812Smarcel case 7: 679130812Smarcel sigval = 8; 680130812Smarcel break; /* coprocessor not available */ 681130812Smarcel case 8: 682130812Smarcel sigval = 7; 683130812Smarcel break; /* double fault */ 684130812Smarcel case 9: 685130812Smarcel sigval = 11; 686130812Smarcel break; /* coprocessor segment overrun */ 687130812Smarcel case 10: 688130812Smarcel sigval = 11; 689130812Smarcel break; /* Invalid TSS */ 690130812Smarcel case 11: 691130812Smarcel sigval = 11; 692130812Smarcel break; /* Segment not present */ 693130812Smarcel case 12: 694130812Smarcel sigval = 11; 695130812Smarcel break; /* stack exception */ 696130812Smarcel case 13: 697130812Smarcel sigval = 11; 698130812Smarcel break; /* general protection */ 699130812Smarcel case 14: 700130812Smarcel sigval = 11; 701130812Smarcel break; /* page fault */ 702130812Smarcel case 16: 703130812Smarcel sigval = 7; 704130812Smarcel break; /* coprocessor error */ 705130812Smarcel default: 706130812Smarcel sigval = 7; /* "software generated" */ 707130812Smarcel } 708130812Smarcel return (sigval); 709130812Smarcel} 710130812Smarcel 711130812Smarcel/**********************************************/ 712130812Smarcel/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ 713130812Smarcel/* RETURN NUMBER OF CHARS PROCESSED */ 714130812Smarcel/**********************************************/ 715130812Smarcelint 716130812SmarcelhexToInt (char **ptr, int *intValue) 717130812Smarcel{ 718130812Smarcel int numChars = 0; 719130812Smarcel int hexValue; 720130812Smarcel 721130812Smarcel *intValue = 0; 722130812Smarcel 723130812Smarcel while (**ptr) 724130812Smarcel { 725130812Smarcel hexValue = hex (**ptr); 726130812Smarcel if (hexValue >= 0) 727130812Smarcel { 728130812Smarcel *intValue = (*intValue << 4) | hexValue; 729130812Smarcel numChars++; 730130812Smarcel } 731130812Smarcel else 732130812Smarcel break; 733130812Smarcel 734130812Smarcel (*ptr)++; 735130812Smarcel } 736130812Smarcel 737130812Smarcel return (numChars); 738130812Smarcel} 739130812Smarcel 740130812Smarcel/* 741130812Smarcel * This function does all command procesing for interfacing to gdb. 742130812Smarcel */ 743130812Smarcelvoid 744130812Smarcelhandle_exception (int exceptionVector) 745130812Smarcel{ 746130812Smarcel int sigval, stepping; 747130812Smarcel int addr, length; 748130812Smarcel char *ptr; 749130812Smarcel int newPC; 750130812Smarcel 751130812Smarcel gdb_i386vector = exceptionVector; 752130812Smarcel 753130812Smarcel if (remote_debug) 754130812Smarcel { 755130812Smarcel printf ("vector=%d, sr=0x%x, pc=0x%x\n", 756130812Smarcel exceptionVector, registers[PS], registers[PC]); 757130812Smarcel } 758130812Smarcel 759130812Smarcel /* reply to host that an exception has occurred */ 760130812Smarcel sigval = computeSignal (exceptionVector); 761130812Smarcel 762130812Smarcel ptr = remcomOutBuffer; 763130812Smarcel 764130812Smarcel *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ 765130812Smarcel *ptr++ = hexchars[sigval >> 4]; 766130812Smarcel *ptr++ = hexchars[sigval & 0xf]; 767130812Smarcel 768130812Smarcel *ptr++ = hexchars[ESP]; 769130812Smarcel *ptr++ = ':'; 770130812Smarcel ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */ 771130812Smarcel *ptr++ = ';'; 772130812Smarcel 773130812Smarcel *ptr++ = hexchars[EBP]; 774130812Smarcel *ptr++ = ':'; 775130812Smarcel ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */ 776130812Smarcel *ptr++ = ';'; 777130812Smarcel 778130812Smarcel *ptr++ = hexchars[PC]; 779130812Smarcel *ptr++ = ':'; 780130812Smarcel ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */ 781130812Smarcel *ptr++ = ';'; 782130812Smarcel 783130812Smarcel *ptr = '\0' 784130812Smarcel 785130812Smarcel putpacket (remcomOutBuffer); 786130812Smarcel 787130812Smarcel stepping = 0; 788130812Smarcel 789130812Smarcel while (1 == 1) 790130812Smarcel { 791130812Smarcel remcomOutBuffer[0] = 0; 792130812Smarcel ptr = getpacket (); 793130812Smarcel 794130812Smarcel switch (*ptr++) 795130812Smarcel { 796130812Smarcel case '?': 797130812Smarcel remcomOutBuffer[0] = 'S'; 798130812Smarcel remcomOutBuffer[1] = hexchars[sigval >> 4]; 799130812Smarcel remcomOutBuffer[2] = hexchars[sigval % 16]; 800130812Smarcel remcomOutBuffer[3] = 0; 801130812Smarcel break; 802130812Smarcel case 'd': 803130812Smarcel remote_debug = !(remote_debug); /* toggle debug flag */ 804130812Smarcel break; 805130812Smarcel case 'g': /* return the value of the CPU registers */ 806130812Smarcel mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); 807130812Smarcel break; 808130812Smarcel case 'G': /* set the value of the CPU registers - return OK */ 809130812Smarcel hex2mem (ptr, (char *) registers, NUMREGBYTES, 0); 810130812Smarcel strcpy (remcomOutBuffer, "OK"); 811130812Smarcel break; 812130812Smarcel case 'P': /* set the value of a single CPU register - return OK */ 813130812Smarcel { 814130812Smarcel int regno; 815130812Smarcel 816130812Smarcel if (hexToInt (&ptr, ®no) && *ptr++ == '=') 817130812Smarcel if (regno >= 0 && regno < NUMREGS) 818130812Smarcel { 819130812Smarcel hex2mem (ptr, (char *) ®isters[regno], 4, 0); 820130812Smarcel strcpy (remcomOutBuffer, "OK"); 821130812Smarcel break; 822130812Smarcel } 823130812Smarcel 824130812Smarcel strcpy (remcomOutBuffer, "E01"); 825130812Smarcel break; 826130812Smarcel } 827130812Smarcel 828130812Smarcel /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 829130812Smarcel case 'm': 830130812Smarcel /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ 831130812Smarcel if (hexToInt (&ptr, &addr)) 832130812Smarcel if (*(ptr++) == ',') 833130812Smarcel if (hexToInt (&ptr, &length)) 834130812Smarcel { 835130812Smarcel ptr = 0; 836130812Smarcel mem_err = 0; 837130812Smarcel mem2hex ((char *) addr, remcomOutBuffer, length, 1); 838130812Smarcel if (mem_err) 839130812Smarcel { 840130812Smarcel strcpy (remcomOutBuffer, "E03"); 841130812Smarcel debug_error ("memory fault"); 842130812Smarcel } 843130812Smarcel } 844130812Smarcel 845130812Smarcel if (ptr) 846130812Smarcel { 847130812Smarcel strcpy (remcomOutBuffer, "E01"); 848130812Smarcel } 849130812Smarcel break; 850130812Smarcel 851130812Smarcel /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 852130812Smarcel case 'M': 853130812Smarcel /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ 854130812Smarcel if (hexToInt (&ptr, &addr)) 855130812Smarcel if (*(ptr++) == ',') 856130812Smarcel if (hexToInt (&ptr, &length)) 857130812Smarcel if (*(ptr++) == ':') 858130812Smarcel { 859130812Smarcel mem_err = 0; 860130812Smarcel hex2mem (ptr, (char *) addr, length, 1); 861130812Smarcel 862130812Smarcel if (mem_err) 863130812Smarcel { 864130812Smarcel strcpy (remcomOutBuffer, "E03"); 865130812Smarcel debug_error ("memory fault"); 866130812Smarcel } 867130812Smarcel else 868130812Smarcel { 869130812Smarcel strcpy (remcomOutBuffer, "OK"); 870130812Smarcel } 871130812Smarcel 872130812Smarcel ptr = 0; 873130812Smarcel } 874130812Smarcel if (ptr) 875130812Smarcel { 876130812Smarcel strcpy (remcomOutBuffer, "E02"); 877130812Smarcel } 878130812Smarcel break; 879130812Smarcel 880130812Smarcel /* cAA..AA Continue at address AA..AA(optional) */ 881130812Smarcel /* sAA..AA Step one instruction from AA..AA(optional) */ 882130812Smarcel case 's': 883130812Smarcel stepping = 1; 884130812Smarcel case 'c': 885130812Smarcel /* try to read optional parameter, pc unchanged if no parm */ 886130812Smarcel if (hexToInt (&ptr, &addr)) 887130812Smarcel registers[PC] = addr; 888130812Smarcel 889130812Smarcel newPC = registers[PC]; 890130812Smarcel 891130812Smarcel /* clear the trace bit */ 892130812Smarcel registers[PS] &= 0xfffffeff; 893130812Smarcel 894130812Smarcel /* set the trace bit if we're stepping */ 895130812Smarcel if (stepping) 896130812Smarcel registers[PS] |= 0x100; 897130812Smarcel 898130812Smarcel _returnFromException (); /* this is a jump */ 899130812Smarcel break; 900130812Smarcel 901130812Smarcel /* kill the program */ 902130812Smarcel case 'k': /* do nothing */ 903130812Smarcel#if 0 904130812Smarcel /* Huh? This doesn't look like "nothing". 905130812Smarcel m68k-stub.c and sparc-stub.c don't have it. */ 906130812Smarcel BREAKPOINT (); 907130812Smarcel#endif 908130812Smarcel break; 909130812Smarcel } /* switch */ 910130812Smarcel 911130812Smarcel /* reply to the request */ 912130812Smarcel putpacket (remcomOutBuffer); 913130812Smarcel } 914130812Smarcel} 915130812Smarcel 916130812Smarcel/* this function is used to set up exception handlers for tracing and 917130812Smarcel breakpoints */ 918130812Smarcelvoid 919130812Smarcelset_debug_traps (void) 920130812Smarcel{ 921130812Smarcel stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; 922130812Smarcel 923130812Smarcel exceptionHandler (0, _catchException0); 924130812Smarcel exceptionHandler (1, _catchException1); 925130812Smarcel exceptionHandler (3, _catchException3); 926130812Smarcel exceptionHandler (4, _catchException4); 927130812Smarcel exceptionHandler (5, _catchException5); 928130812Smarcel exceptionHandler (6, _catchException6); 929130812Smarcel exceptionHandler (7, _catchException7); 930130812Smarcel exceptionHandler (8, _catchException8); 931130812Smarcel exceptionHandler (9, _catchException9); 932130812Smarcel exceptionHandler (10, _catchException10); 933130812Smarcel exceptionHandler (11, _catchException11); 934130812Smarcel exceptionHandler (12, _catchException12); 935130812Smarcel exceptionHandler (13, _catchException13); 936130812Smarcel exceptionHandler (14, _catchException14); 937130812Smarcel exceptionHandler (16, _catchException16); 938130812Smarcel 939130812Smarcel initialized = 1; 940130812Smarcel} 941130812Smarcel 942130812Smarcel/* This function will generate a breakpoint exception. It is used at the 943130812Smarcel beginning of a program to sync up with a debugger and can be used 944130812Smarcel otherwise as a quick means to stop program execution and "break" into 945130812Smarcel the debugger. */ 946130812Smarcel 947130812Smarcelvoid 948130812Smarcelbreakpoint (void) 949130812Smarcel{ 950130812Smarcel if (initialized) 951130812Smarcel BREAKPOINT (); 952130812Smarcel} 953