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 * To enable debugger support, two things need to happen. One, a 33 1.1 christos * call to set_debug_traps() is necessary in order to allow any breakpoints 34 1.1 christos * or error conditions to be properly intercepted and reported to gdb. 35 1.1 christos * Two, a breakpoint needs to be generated to begin communication. This 36 1.1 christos * is most easily accomplished by a call to breakpoint(). Breakpoint() 37 1.1 christos * simulates a breakpoint by executing a trap #1. The breakpoint instruction 38 1.1 christos * is hardwired to trap #1 because not to do so is a compatibility problem-- 39 1.1 christos * there either should be a standard breakpoint instruction, or the protocol 40 1.1 christos * should be extended to provide some means to communicate which breakpoint 41 1.1 christos * instruction is in use (or have the stub insert the breakpoint). 42 1.1 christos * 43 1.1 christos * Some explanation is probably necessary to explain how exceptions are 44 1.1 christos * handled. When an exception is encountered the 68000 pushes the current 45 1.1 christos * program counter and status register onto the supervisor stack and then 46 1.1 christos * transfers execution to a location specified in it's vector table. 47 1.1 christos * The handlers for the exception vectors are hardwired to jmp to an address 48 1.6 christos * given by the relation: (exception - 256) * 6. These are descending 49 1.1 christos * addresses starting from -6, -12, -18, ... By allowing 6 bytes for 50 1.1 christos * each entry, a jsr, jmp, bsr, ... can be used to enter the exception 51 1.1 christos * handler. Using a jsr to handle an exception has an added benefit of 52 1.1 christos * allowing a single handler to service several exceptions and use the 53 1.1 christos * return address as the key differentiation. The vector number can be 54 1.1 christos * computed from the return address by [ exception = (addr + 1530) / 6 ]. 55 1.1 christos * The sole purpose of the routine _catchException is to compute the 56 1.1 christos * exception number and push it on the stack in place of the return address. 57 1.1 christos * The external function exceptionHandler() is 58 1.1 christos * used to attach a specific handler to a specific m68k exception. 59 1.1 christos * For 68020 machines, the ability to have a return address around just 60 1.1 christos * so the vector can be determined is not necessary because the '020 pushes an 61 1.1 christos * extra word onto the stack containing the vector offset 62 1.1 christos * 63 1.1 christos * Because gdb will sometimes write to the stack area to execute function 64 1.1 christos * calls, this program cannot rely on using the supervisor stack so it 65 1.8 christos * uses its own stack area reserved in the int array remcomStack. 66 1.1 christos * 67 1.1 christos ************* 68 1.1 christos * 69 1.1 christos * The following gdb commands are supported: 70 1.1 christos * 71 1.1 christos * command function Return value 72 1.1 christos * 73 1.1 christos * g return the value of the CPU registers hex data or ENN 74 1.1 christos * G set the value of the CPU registers OK or ENN 75 1.1 christos * 76 1.1 christos * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN 77 1.1 christos * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN 78 1.1 christos * 79 1.1 christos * c Resume at current address SNN ( signal NN) 80 1.1 christos * cAA..AA Continue at address AA..AA SNN 81 1.1 christos * 82 1.1 christos * s Step one instruction SNN 83 1.1 christos * sAA..AA Step one instruction from AA..AA SNN 84 1.1 christos * 85 1.1 christos * k kill 86 1.1 christos * 87 1.1 christos * ? What was the last sigval ? SNN (signal NN) 88 1.1 christos * 89 1.1 christos * All commands and responses are sent with a packet which includes a 90 1.1 christos * checksum. A packet consists of 91 1.1 christos * 92 1.1 christos * $<packet info>#<checksum>. 93 1.1 christos * 94 1.1 christos * where 95 1.1 christos * <packet info> :: <characters representing the command or response> 96 1.1 christos * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> 97 1.1 christos * 98 1.1 christos * When a packet is received, it is first acknowledged with either '+' or '-'. 99 1.1 christos * '+' indicates a successful transfer. '-' indicates a failed transfer. 100 1.1 christos * 101 1.1 christos * Example: 102 1.1 christos * 103 1.1 christos * Host: Reply: 104 1.1 christos * $m0,10#2a +$00010203040506070809101112131415#42 105 1.1 christos * 106 1.1 christos ****************************************************************************/ 107 1.1 christos 108 1.1 christos #include <stdio.h> 109 1.1 christos #include <string.h> 110 1.1 christos #include <setjmp.h> 111 1.1 christos 112 1.1 christos /************************************************************************ 113 1.1 christos * 114 1.1 christos * external low-level support routines 115 1.1 christos */ 116 1.1 christos typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ 117 1.1 christos typedef void (*Function)(); /* pointer to a function */ 118 1.1 christos 119 1.1 christos extern void putDebugChar(); /* write a single character */ 120 1.1 christos extern int getDebugChar(); /* read and return a single char */ 121 1.1 christos 122 1.1 christos extern Function exceptionHandler(); /* assign an exception handler */ 123 1.1 christos extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ 124 1.1 christos 125 1.1 christos /************************/ 126 1.1 christos /* FORWARD DECLARATIONS */ 127 1.1 christos /************************/ 128 1.1 christos static void 129 1.1 christos initializeRemcomErrorFrame (); 130 1.1 christos 131 1.1 christos /************************************************************************/ 132 1.1 christos /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ 133 1.1 christos /* at least NUMREGBYTES*2 are needed for register packets */ 134 1.1 christos #define BUFMAX 400 135 1.1 christos 136 1.1 christos static char initialized; /* boolean flag. != 0 means we've been initialized */ 137 1.1 christos 138 1.1 christos int remote_debug; 139 1.1 christos /* debug > 0 prints ill-formed commands in valid packets & checksum errors */ 140 1.1 christos 141 1.1 christos static const char hexchars[]="0123456789abcdef"; 142 1.1 christos 143 1.1 christos /* there are 180 bytes of registers on a 68020 w/68881 */ 144 1.1 christos /* many of the fpa registers are 12 byte (96 bit) registers */ 145 1.1 christos #define NUMREGBYTES 180 146 1.1 christos enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, 147 1.7 christos A0,A1,A2,A3,A4,A5,A6,A7, 148 1.7 christos PS,PC, 149 1.7 christos FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, 150 1.7 christos FPCONTROL,FPSTATUS,FPIADDR 151 1.7 christos }; 152 1.1 christos 153 1.1 christos 154 1.1 christos /* We keep a whole frame cache here. "Why?", I hear you cry, "doesn't 156 1.1 christos GDB handle that sort of thing?" Well, yes, I believe the only 157 1.1 christos reason for this cache is to save and restore floating point state 158 1.1 christos (fsave/frestore). A cleaner way to do this would be to make the 159 1.1 christos fsave data part of the registers which GDB deals with like any 160 1.1 christos other registers. This should not be a performance problem if the 161 1.1 christos ability to read individual registers is added to the protocol. */ 162 1.1 christos 163 1.1 christos typedef struct FrameStruct 164 1.1 christos { 165 1.1 christos struct FrameStruct *previous; 166 1.1 christos int exceptionPC; /* pc value when this frame created */ 167 1.1 christos int exceptionVector; /* cpu vector causing exception */ 168 1.1 christos short frameSize; /* size of cpu frame in words */ 169 1.1 christos short sr; /* for 68000, this not always sr */ 170 1.1 christos int pc; 171 1.1 christos short format; 172 1.1 christos int fsaveHeader; 173 1.1 christos int morejunk[0]; /* exception frame, fp save... */ 174 1.1 christos } Frame; 175 1.1 christos 176 1.1 christos #define FRAMESIZE 500 177 1.1 christos int gdbFrameStack[FRAMESIZE]; 178 1.1 christos static Frame *lastFrame; 179 1.1 christos 180 1.1 christos /* 181 1.1 christos * these should not be static cuz they can be used outside this module 182 1.1 christos */ 183 1.1 christos int registers[NUMREGBYTES/4]; 184 1.1 christos int superStack; 185 1.1 christos 186 1.1 christos #define STACKSIZE 10000 187 1.1 christos int remcomStack[STACKSIZE/sizeof(int)]; 188 1.1 christos static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; 189 1.1 christos 190 1.1 christos /* 191 1.1 christos * In many cases, the system will want to continue exception processing 192 1.1 christos * when a continue command is given. 193 1.1 christos * oldExceptionHook is a function to invoke in this case. 194 1.1 christos */ 195 1.1 christos 196 1.1 christos static ExceptionHook oldExceptionHook; 197 1.1 christos 198 1.1 christos #ifdef mc68020 199 1.1 christos /* the size of the exception stack on the 68020 varies with the type of 200 1.1 christos * exception. The following table is the number of WORDS used 201 1.1 christos * for each exception format. 202 1.1 christos */ 203 1.1 christos const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 }; 204 1.1 christos #endif 205 1.1 christos 206 1.1 christos #ifdef mc68332 207 1.1 christos static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 }; 208 1.1 christos #endif 209 1.1 christos 210 1.1 christos /************* jump buffer used for setjmp/longjmp **************************/ 211 1.1 christos jmp_buf remcomEnv; 212 1.1 christos 213 1.1 christos /*************************** ASSEMBLY CODE MACROS *************************/ 214 1.1 christos /* */ 215 1.1 christos 216 1.1 christos #ifdef __HAVE_68881__ 217 1.1 christos /* do an fsave, then remember the address to begin a restore from */ 218 1.1 christos #define SAVE_FP_REGS() asm(" fsave a0@-"); \ 219 1.1 christos asm(" fmovemx fp0-fp7,_registers+72"); \ 220 1.1 christos asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); 221 1.1 christos #define RESTORE_FP_REGS() \ 222 1.1 christos asm(" \n\ 223 1.1 christos fmoveml _registers+168,fpcr/fpsr/fpi \n\ 224 1.1 christos fmovemx _registers+72,fp0-fp7 \n\ 225 1.1 christos cmpl #-1,a0@ | skip frestore flag set ? \n\ 226 1.1 christos beq skip_frestore \n\ 227 1.1 christos frestore a0@+ \n\ 228 1.1 christos skip_frestore: \n\ 229 1.1 christos "); 230 1.1 christos 231 1.1 christos #else 232 1.1 christos #define SAVE_FP_REGS() 233 1.1 christos #define RESTORE_FP_REGS() 234 1.1 christos #endif /* __HAVE_68881__ */ 235 1.1 christos 236 1.1 christos void return_to_super(); 237 1.1 christos void return_to_user(); 238 1.1 christos 239 1.1 christos asm(" 240 1.1 christos .text 241 1.1 christos .globl _return_to_super 242 1.7 christos _return_to_super: 243 1.7 christos movel _registers+60,sp /* get new stack pointer */ 244 1.7 christos movel _lastFrame,a0 /* get last frame info */ 245 1.1 christos bra return_to_any 246 1.1 christos 247 1.1 christos .globl _return_to_user 248 1.7 christos _return_to_user: 249 1.7 christos movel _registers+60,a0 /* get usp */ 250 1.7 christos movel a0,usp /* set usp */ 251 1.1 christos movel _superStack,sp /* get original stack pointer */ 252 1.1 christos 253 1.7 christos return_to_any: 254 1.7 christos movel _lastFrame,a0 /* get last frame info */ 255 1.7 christos movel a0@+,_lastFrame /* link in previous frame */ 256 1.7 christos addql #8,a0 /* skip over pc, vector#*/ 257 1.7 christos movew a0@+,d0 /* get # of words in cpu frame */ 258 1.7 christos addw d0,a0 /* point to end of data */ 259 1.7 christos addw d0,a0 /* point to end of data */ 260 1.1 christos movel a0,a1 261 1.1 christos # 262 1.7 christos # copy the stack frame 263 1.1 christos subql #1,d0 264 1.7 christos copyUserLoop: 265 1.7 christos movew a1@-,sp@- 266 1.1 christos dbf d0,copyUserLoop 267 1.7 christos "); 268 1.1 christos RESTORE_FP_REGS() 269 1.1 christos asm(" moveml _registers,d0-d7/a0-a6"); 270 1.1 christos asm(" rte"); /* pop and go! */ 271 1.1 christos 272 1.1 christos #define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr"); 273 1.1 christos #define BREAKPOINT() asm(" trap #1"); 274 1.1 christos 275 1.1 christos /* this function is called immediately when a level 7 interrupt occurs */ 276 1.1 christos /* if the previous interrupt level was 7 then we're already servicing */ 277 1.1 christos /* this interrupt and an rte is in order to return to the debugger. */ 278 1.1 christos /* For the 68000, the offset for sr is 6 due to the jsr return address */ 279 1.1 christos asm(" 280 1.1 christos .text 281 1.1 christos .globl __debug_level7 282 1.1 christos __debug_level7: 283 1.1 christos movew d0,sp@-"); 284 1.1 christos #if defined (mc68020) || defined (mc68332) 285 1.1 christos asm(" movew sp@(2),d0"); 286 1.1 christos #else 287 1.1 christos asm(" movew sp@(6),d0"); 288 1.1 christos #endif 289 1.1 christos asm(" andiw #0x700,d0 290 1.1 christos cmpiw #0x700,d0 291 1.7 christos beq _already7 292 1.7 christos movew sp@+,d0 293 1.1 christos bra __catchException 294 1.1 christos _already7: 295 1.1 christos movew sp@+,d0"); 296 1.1 christos #if !defined (mc68020) && !defined (mc68332) 297 1.1 christos asm(" lea sp@(4),sp"); /* pull off 68000 return address */ 298 1.1 christos #endif 299 1.1 christos asm(" rte"); 300 1.1 christos 301 1.1 christos extern void _catchException (); 302 1.1 christos 303 1.1 christos #if defined (mc68020) || defined (mc68332) 304 1.1 christos /* This function is called when a 68020 exception occurs. It saves 305 1.1 christos * all the cpu and fpcp regs in the _registers array, creates a frame on a 306 1.1 christos * linked list of frames which has the cpu and fpcp stack frames needed 307 1.1 christos * to properly restore the context of these processors, and invokes 308 1.1 christos * an exception handler (remcom_handler). 309 1.1 christos * 310 1.1 christos * stack on entry: stack on exit: 311 1.1 christos * N bytes of junk exception # MSWord 312 1.1 christos * Exception Format Word exception # MSWord 313 1.1 christos * Program counter LSWord 314 1.1 christos * Program counter MSWord 315 1.1 christos * Status Register 316 1.1 christos * 317 1.1 christos * 318 1.1 christos */ 319 1.1 christos asm(" 320 1.1 christos .text 321 1.1 christos .globl __catchException 322 1.1 christos __catchException:"); 323 1.1 christos DISABLE_INTERRUPTS(); 324 1.7 christos asm(" 325 1.1 christos moveml d0-d7/a0-a6,_registers /* save registers */ 326 1.1 christos movel _lastFrame,a0 /* last frame pointer */ 327 1.1 christos "); 328 1.1 christos SAVE_FP_REGS(); 329 1.1 christos asm(" 330 1.7 christos lea _registers,a5 /* get address of registers */ 331 1.7 christos movew sp@,d1 /* get status register */ 332 1.1 christos movew d1,a5@(66) /* save sr */ 333 1.7 christos movel sp@(2),a4 /* save pc in a4 for later use */ 334 1.1 christos movel a4,a5@(68) /* save pc in _regisers[] */ 335 1.1 christos 336 1.1 christos # 337 1.1 christos # figure out how many bytes in the stack frame 338 1.7 christos movew sp@(6),d0 /* get '020 exception format */ 339 1.7 christos movew d0,d2 /* make a copy of format word */ 340 1.7 christos andiw #0xf000,d0 /* mask off format type */ 341 1.7 christos rolw #5,d0 /* rotate into the low byte *2 */ 342 1.7 christos lea _exceptionSize,a1 343 1.1 christos addw d0,a1 /* index into the table */ 344 1.7 christos movew a1@,d0 /* get number of words in frame */ 345 1.7 christos movew d0,d3 /* save it */ 346 1.7 christos subw d0,a0 /* adjust save pointer */ 347 1.1 christos subw d0,a0 /* adjust save pointer(bytes) */ 348 1.1 christos movel a0,a1 /* copy save pointer */ 349 1.1 christos subql #1,d0 /* predecrement loop counter */ 350 1.1 christos # 351 1.1 christos # copy the frame 352 1.1 christos saveFrameLoop: 353 1.1 christos movew sp@+,a1@+ 354 1.1 christos dbf d0,saveFrameLoop 355 1.8 christos # 356 1.1 christos # now that the stack has been cleaned, 357 1.7 christos # save the a7 in use at time of exception 358 1.7 christos movel sp,_superStack /* save supervisor sp */ 359 1.7 christos andiw #0x2000,d1 /* were we in supervisor mode ? */ 360 1.7 christos beq userMode 361 1.7 christos movel a7,a5@(60) /* save a7 */ 362 1.1 christos bra a7saveDone 363 1.1 christos userMode: 364 1.7 christos movel usp,a1 365 1.1 christos movel a1,a5@(60) /* save user stack pointer */ 366 1.1 christos a7saveDone: 367 1.1 christos 368 1.1 christos # 369 1.7 christos # save size of frame 370 1.1 christos movew d3,a0@- 371 1.1 christos 372 1.1 christos # 373 1.1 christos # compute exception number 374 1.1 christos andl #0xfff,d2 /* mask off vector offset */ 375 1.7 christos lsrw #2,d2 /* divide by 4 to get vect num */ 376 1.1 christos movel d2,a0@- /* save it */ 377 1.1 christos # 378 1.7 christos # save pc causing exception 379 1.1 christos movel a4,a0@- 380 1.1 christos # 381 1.1 christos # save old frame link and set the new value 382 1.1 christos movel _lastFrame,a1 /* last frame pointer */ 383 1.7 christos movel a1,a0@- /* save pointer to prev frame */ 384 1.1 christos movel a0,_lastFrame 385 1.7 christos 386 1.1 christos movel d2,sp@- /* push exception num */ 387 1.7 christos movel _exceptionHook,a0 /* get address of handler */ 388 1.7 christos jbsr a0@ /* and call it */ 389 1.7 christos clrl sp@ /* replace exception num parm with frame ptr */ 390 1.1 christos jbsr __returnFromException /* jbsr, but never returns */ 391 1.1 christos "); 392 1.1 christos #else /* mc68000 */ 393 1.1 christos /* This function is called when an exception occurs. It translates the 394 1.1 christos * return address found on the stack into an exception vector # which 395 1.1 christos * is then handled by either handle_exception or a system handler. 396 1.1 christos * _catchException provides a front end for both. 397 1.1 christos * 398 1.1 christos * stack on entry: stack on exit: 399 1.1 christos * Program counter MSWord exception # MSWord 400 1.1 christos * Program counter LSWord exception # MSWord 401 1.1 christos * Status Register 402 1.1 christos * Return Address MSWord 403 1.1 christos * Return Address LSWord 404 1.1 christos */ 405 1.1 christos asm(" 406 1.1 christos .text 407 1.1 christos .globl __catchException 408 1.1 christos __catchException:"); 409 1.1 christos DISABLE_INTERRUPTS(); 410 1.7 christos asm(" 411 1.1 christos moveml d0-d7/a0-a6,_registers /* save registers */ 412 1.1 christos movel _lastFrame,a0 /* last frame pointer */ 413 1.1 christos "); 414 1.1 christos SAVE_FP_REGS(); 415 1.7 christos asm(" 416 1.7 christos lea _registers,a5 /* get address of registers */ 417 1.1 christos movel sp@+,d2 /* pop return address */ 418 1.1 christos addl #1530,d2 /* convert return addr to */ 419 1.1 christos divs #6,d2 /* exception number */ 420 1.1 christos extl d2 421 1.7 christos 422 1.1 christos moveql #3,d3 /* assume a three word frame */ 423 1.7 christos 424 1.7 christos cmpiw #3,d2 /* bus error or address error ? */ 425 1.7 christos bgt normal /* if >3 then normal error */ 426 1.7 christos movel sp@+,a0@- /* copy error info to frame buff*/ 427 1.7 christos movel sp@+,a0@- /* these are never used */ 428 1.1 christos moveql #7,d3 /* this is a 7 word frame */ 429 1.1 christos 430 1.1 christos normal: 431 1.7 christos movew sp@+,d1 /* pop status register */ 432 1.7 christos movel sp@+,a4 /* pop program counter */ 433 1.7 christos movew d1,a5@(66) /* save sr */ 434 1.7 christos movel a4,a5@(68) /* save pc in _regisers[] */ 435 1.1 christos movel a4,a0@- /* copy pc to frame buffer */ 436 1.1 christos movew d1,a0@- /* copy sr to frame buffer */ 437 1.7 christos 438 1.1 christos movel sp,_superStack /* save supervisor sp */ 439 1.7 christos 440 1.7 christos andiw #0x2000,d1 /* were we in supervisor mode ? */ 441 1.7 christos beq userMode 442 1.7 christos movel a7,a5@(60) /* save a7 */ 443 1.1 christos bra saveDone 444 1.7 christos userMode: 445 1.7 christos movel usp,a1 /* save user stack pointer */ 446 1.1 christos movel a1,a5@(60) /* save user stack pointer */ 447 1.1 christos saveDone: 448 1.7 christos 449 1.7 christos movew d3,a0@- /* push frame size in words */ 450 1.7 christos movel d2,a0@- /* push vector number */ 451 1.1 christos movel a4,a0@- /* push exception pc */ 452 1.1 christos 453 1.1 christos # 454 1.1 christos # save old frame link and set the new value 455 1.1 christos movel _lastFrame,a1 /* last frame pointer */ 456 1.7 christos movel a1,a0@- /* save pointer to prev frame */ 457 1.1 christos movel a0,_lastFrame 458 1.7 christos 459 1.1 christos movel d2,sp@- /* push exception num */ 460 1.7 christos movel _exceptionHook,a0 /* get address of handler */ 461 1.7 christos jbsr a0@ /* and call it */ 462 1.7 christos clrl sp@ /* replace exception num parm with frame ptr */ 463 1.1 christos jbsr __returnFromException /* jbsr, but never returns */ 464 1.1 christos "); 465 1.1 christos #endif 466 1.1 christos 467 1.1 christos 468 1.1 christos /* 469 1.1 christos * remcomHandler is a front end for handle_exception. It moves the 470 1.1 christos * stack pointer into an area reserved for debugger use in case the 471 1.1 christos * breakpoint happened in supervisor mode. 472 1.1 christos */ 473 1.1 christos asm("_remcomHandler:"); 474 1.1 christos asm(" addl #4,sp"); /* pop off return address */ 475 1.1 christos asm(" movel sp@+,d0"); /* get the exception number */ 476 1.1 christos asm(" movel _stackPtr,sp"); /* move to remcom stack area */ 477 1.1 christos asm(" movel d0,sp@-"); /* push exception onto stack */ 478 1.1 christos asm(" jbsr _handle_exception"); /* this never returns */ 479 1.1 christos asm(" rts"); /* return */ 480 1.1 christos 481 1.1 christos void 482 1.1 christos _returnFromException (Frame * frame) 483 1.1 christos { 484 1.1 christos /* if no passed in frame, use the last one */ 485 1.1 christos if (!frame) 486 1.1 christos { 487 1.1 christos frame = lastFrame; 488 1.1 christos frame->frameSize = 4; 489 1.1 christos frame->format = 0; 490 1.1 christos frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info */ 491 1.1 christos } 492 1.1 christos 493 1.1 christos #if !defined (mc68020) && !defined (mc68332) 494 1.1 christos /* a 68000 cannot use the internal info pushed onto a bus error 495 1.1 christos * or address error frame when doing an RTE so don't put this info 496 1.1 christos * onto the stack or the stack will creep every time this happens. 497 1.1 christos */ 498 1.1 christos frame->frameSize = 3; 499 1.1 christos #endif 500 1.1 christos 501 1.1 christos /* throw away any frames in the list after this frame */ 502 1.1 christos lastFrame = frame; 503 1.1 christos 504 1.1 christos frame->sr = registers[(int) PS]; 505 1.1 christos frame->pc = registers[(int) PC]; 506 1.1 christos 507 1.1 christos if (registers[(int) PS] & 0x2000) 508 1.1 christos { 509 1.1 christos /* return to supervisor mode... */ 510 1.1 christos return_to_super (); 511 1.1 christos } 512 1.1 christos else 513 1.1 christos { /* return to user mode */ 514 1.1 christos return_to_user (); 515 1.1 christos } 516 1.1 christos } 517 1.1 christos 518 1.1 christos int 519 1.1 christos hex (ch) 520 1.1 christos char ch; 521 1.1 christos { 522 1.1 christos if ((ch >= 'a') && (ch <= 'f')) 523 1.1 christos return (ch - 'a' + 10); 524 1.1 christos if ((ch >= '0') && (ch <= '9')) 525 1.1 christos return (ch - '0'); 526 1.1 christos if ((ch >= 'A') && (ch <= 'F')) 527 1.1 christos return (ch - 'A' + 10); 528 1.1 christos return (-1); 529 1.1 christos } 530 1.1 christos 531 1.1 christos static char remcomInBuffer[BUFMAX]; 532 1.1 christos static char remcomOutBuffer[BUFMAX]; 533 1.1 christos 534 1.1 christos /* scan for the sequence $<data>#<checksum> */ 535 1.1 christos 536 1.1 christos unsigned char * 537 1.1 christos getpacket (void) 538 1.1 christos { 539 1.1 christos unsigned char *buffer = &remcomInBuffer[0]; 540 1.1 christos unsigned char checksum; 541 1.1 christos unsigned char xmitcsum; 542 1.1 christos int count; 543 1.1 christos char ch; 544 1.1 christos 545 1.1 christos while (1) 546 1.1 christos { 547 1.1 christos /* wait around for the start character, ignore all other characters */ 548 1.1 christos while ((ch = getDebugChar ()) != '$') 549 1.1 christos ; 550 1.1 christos 551 1.1 christos retry: 552 1.1 christos checksum = 0; 553 1.1 christos xmitcsum = -1; 554 1.1 christos count = 0; 555 1.1 christos 556 1.1 christos /* now, read until a # or end of buffer is found */ 557 1.1 christos while (count < BUFMAX - 1) 558 1.1 christos { 559 1.1 christos ch = getDebugChar (); 560 1.1 christos if (ch == '$') 561 1.1 christos goto retry; 562 1.1 christos if (ch == '#') 563 1.1 christos break; 564 1.1 christos checksum = checksum + ch; 565 1.1 christos buffer[count] = ch; 566 1.1 christos count = count + 1; 567 1.1 christos } 568 1.1 christos buffer[count] = 0; 569 1.1 christos 570 1.1 christos if (ch == '#') 571 1.1 christos { 572 1.1 christos ch = getDebugChar (); 573 1.1 christos xmitcsum = hex (ch) << 4; 574 1.1 christos ch = getDebugChar (); 575 1.1 christos xmitcsum += hex (ch); 576 1.1 christos 577 1.1 christos if (checksum != xmitcsum) 578 1.1 christos { 579 1.1 christos if (remote_debug) 580 1.1 christos { 581 1.1 christos fprintf (stderr, 582 1.1 christos "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", 583 1.1 christos checksum, xmitcsum, buffer); 584 1.1 christos } 585 1.1 christos putDebugChar ('-'); /* failed checksum */ 586 1.1 christos } 587 1.1 christos else 588 1.1 christos { 589 1.1 christos putDebugChar ('+'); /* successful transfer */ 590 1.1 christos 591 1.1 christos /* if a sequence char is present, reply the sequence ID */ 592 1.1 christos if (buffer[2] == ':') 593 1.1 christos { 594 1.1 christos putDebugChar (buffer[0]); 595 1.1 christos putDebugChar (buffer[1]); 596 1.1 christos 597 1.1 christos return &buffer[3]; 598 1.1 christos } 599 1.1 christos 600 1.1 christos return &buffer[0]; 601 1.1 christos } 602 1.1 christos } 603 1.1 christos } 604 1.1 christos } 605 1.1 christos 606 1.1 christos /* send the packet in buffer. */ 607 1.1 christos 608 1.1 christos void 609 1.1 christos putpacket (buffer) 610 1.1 christos char *buffer; 611 1.1 christos { 612 1.1 christos unsigned char checksum; 613 1.1 christos int count; 614 1.1 christos char ch; 615 1.1 christos 616 1.1 christos /* $<packet info>#<checksum>. */ 617 1.1 christos do 618 1.1 christos { 619 1.1 christos putDebugChar ('$'); 620 1.1 christos checksum = 0; 621 1.1 christos count = 0; 622 1.1 christos 623 1.1 christos while (ch = buffer[count]) 624 1.1 christos { 625 1.1 christos putDebugChar (ch); 626 1.1 christos checksum += ch; 627 1.1 christos count += 1; 628 1.1 christos } 629 1.1 christos 630 1.1 christos putDebugChar ('#'); 631 1.1 christos putDebugChar (hexchars[checksum >> 4]); 632 1.1 christos putDebugChar (hexchars[checksum % 16]); 633 1.1 christos 634 1.1 christos } 635 1.1 christos while (getDebugChar () != '+'); 636 1.1 christos 637 1.1 christos } 638 1.1 christos 639 1.1 christos void 640 1.1 christos debug_error (format, parm) 641 1.1 christos char *format; 642 1.1 christos char *parm; 643 1.1 christos { 644 1.1 christos if (remote_debug) 645 1.1 christos fprintf (stderr, format, parm); 646 1.1 christos } 647 1.1 christos 648 1.1 christos /* convert the memory pointed to by mem into hex, placing result in buf */ 649 1.1 christos /* return a pointer to the last char put in buf (null) */ 650 1.1 christos char * 651 1.1 christos mem2hex (mem, buf, count) 652 1.1 christos char *mem; 653 1.1 christos char *buf; 654 1.1 christos int count; 655 1.1 christos { 656 1.1 christos int i; 657 1.1 christos unsigned char ch; 658 1.1 christos for (i = 0; i < count; i++) 659 1.1 christos { 660 1.1 christos ch = *mem++; 661 1.1 christos *buf++ = hexchars[ch >> 4]; 662 1.1 christos *buf++ = hexchars[ch % 16]; 663 1.1 christos } 664 1.1 christos *buf = 0; 665 1.1 christos return (buf); 666 1.1 christos } 667 1.1 christos 668 1.1 christos /* convert the hex array pointed to by buf into binary to be placed in mem */ 669 1.1 christos /* return a pointer to the character AFTER the last byte written */ 670 1.1 christos char * 671 1.1 christos hex2mem (buf, mem, count) 672 1.1 christos char *buf; 673 1.1 christos char *mem; 674 1.1 christos int count; 675 1.1 christos { 676 1.1 christos int i; 677 1.1 christos unsigned char ch; 678 1.1 christos for (i = 0; i < count; i++) 679 1.1 christos { 680 1.1 christos ch = hex (*buf++) << 4; 681 1.1 christos ch = ch + hex (*buf++); 682 1.1 christos *mem++ = ch; 683 1.1 christos } 684 1.1 christos return (mem); 685 1.1 christos } 686 1.1 christos 687 1.1 christos /* a bus error has occurred, perform a longjmp 688 1.1 christos to return execution and allow handling of the error */ 689 1.1 christos 690 1.1 christos void 691 1.1 christos handle_buserror () 692 1.1 christos { 693 1.1 christos longjmp (remcomEnv, 1); 694 1.1 christos } 695 1.1 christos 696 1.1 christos /* this function takes the 68000 exception number and attempts to 697 1.1 christos translate this number into a unix compatible signal value */ 698 1.1 christos int 699 1.1 christos computeSignal (exceptionVector) 700 1.1 christos int exceptionVector; 701 1.1 christos { 702 1.1 christos int sigval; 703 1.1 christos switch (exceptionVector) 704 1.1 christos { 705 1.1 christos case 2: 706 1.1 christos sigval = 10; 707 1.1 christos break; /* bus error */ 708 1.1 christos case 3: 709 1.1 christos sigval = 10; 710 1.1 christos break; /* address error */ 711 1.1 christos case 4: 712 1.1 christos sigval = 4; 713 1.1 christos break; /* illegal instruction */ 714 1.1 christos case 5: 715 1.1 christos sigval = 8; 716 1.1 christos break; /* zero divide */ 717 1.1 christos case 6: 718 1.1 christos sigval = 8; 719 1.1 christos break; /* chk instruction */ 720 1.1 christos case 7: 721 1.1 christos sigval = 8; 722 1.1 christos break; /* trapv instruction */ 723 1.1 christos case 8: 724 1.1 christos sigval = 11; 725 1.1 christos break; /* privilege violation */ 726 1.1 christos case 9: 727 1.1 christos sigval = 5; 728 1.1 christos break; /* trace trap */ 729 1.1 christos case 10: 730 1.1 christos sigval = 4; 731 1.1 christos break; /* line 1010 emulator */ 732 1.1 christos case 11: 733 1.1 christos sigval = 4; 734 1.1 christos break; /* line 1111 emulator */ 735 1.1 christos 736 1.7 christos /* Coprocessor protocol violation. Using a standard MMU or FPU 737 1.1 christos this cannot be triggered by software. Call it a SIGBUS. */ 738 1.1 christos case 13: 739 1.1 christos sigval = 10; 740 1.1 christos break; 741 1.1 christos 742 1.1 christos case 31: 743 1.1 christos sigval = 2; 744 1.1 christos break; /* interrupt */ 745 1.1 christos case 33: 746 1.1 christos sigval = 5; 747 1.1 christos break; /* breakpoint */ 748 1.1 christos 749 1.7 christos /* This is a trap #8 instruction. Apparently it is someone's software 750 1.7 christos convention for some sort of SIGFPE condition. Whose? How many 751 1.7 christos people are being screwed by having this code the way it is? 752 1.1 christos Is there a clean solution? */ 753 1.1 christos case 40: 754 1.1 christos sigval = 8; 755 1.1 christos break; /* floating point err */ 756 1.1 christos 757 1.1 christos case 48: 758 1.1 christos sigval = 8; 759 1.1 christos break; /* floating point err */ 760 1.1 christos case 49: 761 1.1 christos sigval = 8; 762 1.1 christos break; /* floating point err */ 763 1.1 christos case 50: 764 1.1 christos sigval = 8; 765 1.1 christos break; /* zero divide */ 766 1.1 christos case 51: 767 1.1 christos sigval = 8; 768 1.1 christos break; /* underflow */ 769 1.1 christos case 52: 770 1.1 christos sigval = 8; 771 1.1 christos break; /* operand error */ 772 1.1 christos case 53: 773 1.1 christos sigval = 8; 774 1.1 christos break; /* overflow */ 775 1.1 christos case 54: 776 1.1 christos sigval = 8; 777 1.1 christos break; /* NAN */ 778 1.1 christos default: 779 1.1 christos sigval = 7; /* "software generated" */ 780 1.1 christos } 781 1.1 christos return (sigval); 782 1.1 christos } 783 1.1 christos 784 1.1 christos /**********************************************/ 785 1.1 christos /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ 786 1.1 christos /* RETURN NUMBER OF CHARS PROCESSED */ 787 1.1 christos /**********************************************/ 788 1.1 christos int 789 1.1 christos hexToInt (char **ptr, int *intValue) 790 1.1 christos { 791 1.1 christos int numChars = 0; 792 1.1 christos int hexValue; 793 1.1 christos 794 1.1 christos *intValue = 0; 795 1.1 christos 796 1.1 christos while (**ptr) 797 1.1 christos { 798 1.1 christos hexValue = hex (**ptr); 799 1.1 christos if (hexValue >= 0) 800 1.1 christos { 801 1.1 christos *intValue = (*intValue << 4) | hexValue; 802 1.1 christos numChars++; 803 1.1 christos } 804 1.1 christos else 805 1.1 christos break; 806 1.1 christos 807 1.1 christos (*ptr)++; 808 1.1 christos } 809 1.1 christos 810 1.1 christos return (numChars); 811 1.1 christos } 812 1.1 christos 813 1.1 christos /* 814 1.1 christos * This function does all command procesing for interfacing to gdb. 815 1.1 christos */ 816 1.1 christos void 817 1.1 christos handle_exception (int exceptionVector) 818 1.1 christos { 819 1.1 christos int sigval, stepping; 820 1.1 christos int addr, length; 821 1.1 christos char *ptr; 822 1.1 christos int newPC; 823 1.1 christos Frame *frame; 824 1.1 christos 825 1.1 christos if (remote_debug) 826 1.1 christos printf ("vector=%d, sr=0x%x, pc=0x%x\n", 827 1.1 christos exceptionVector, registers[PS], registers[PC]); 828 1.1 christos 829 1.1 christos /* reply to host that an exception has occurred */ 830 1.1 christos sigval = computeSignal (exceptionVector); 831 1.1 christos remcomOutBuffer[0] = 'S'; 832 1.1 christos remcomOutBuffer[1] = hexchars[sigval >> 4]; 833 1.1 christos remcomOutBuffer[2] = hexchars[sigval % 16]; 834 1.1 christos remcomOutBuffer[3] = 0; 835 1.1 christos 836 1.1 christos putpacket (remcomOutBuffer); 837 1.1 christos 838 1.1 christos stepping = 0; 839 1.1 christos 840 1.1 christos while (1 == 1) 841 1.1 christos { 842 1.1 christos remcomOutBuffer[0] = 0; 843 1.1 christos ptr = getpacket (); 844 1.1 christos switch (*ptr++) 845 1.1 christos { 846 1.1 christos case '?': 847 1.1 christos remcomOutBuffer[0] = 'S'; 848 1.1 christos remcomOutBuffer[1] = hexchars[sigval >> 4]; 849 1.1 christos remcomOutBuffer[2] = hexchars[sigval % 16]; 850 1.1 christos remcomOutBuffer[3] = 0; 851 1.1 christos break; 852 1.1 christos case 'd': 853 1.1 christos remote_debug = !(remote_debug); /* toggle debug flag */ 854 1.1 christos break; 855 1.1 christos case 'g': /* return the value of the CPU registers */ 856 1.1 christos mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES); 857 1.1 christos break; 858 1.1 christos case 'G': /* set the value of the CPU registers - return OK */ 859 1.1 christos hex2mem (ptr, (char *) registers, NUMREGBYTES); 860 1.1 christos strcpy (remcomOutBuffer, "OK"); 861 1.1 christos break; 862 1.1 christos 863 1.1 christos /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 864 1.1 christos case 'm': 865 1.1 christos if (setjmp (remcomEnv) == 0) 866 1.1 christos { 867 1.1 christos exceptionHandler (2, handle_buserror); 868 1.1 christos 869 1.1 christos /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ 870 1.1 christos if (hexToInt (&ptr, &addr)) 871 1.1 christos if (*(ptr++) == ',') 872 1.1 christos if (hexToInt (&ptr, &length)) 873 1.1 christos { 874 1.1 christos ptr = 0; 875 1.1 christos mem2hex ((char *) addr, remcomOutBuffer, length); 876 1.1 christos } 877 1.1 christos 878 1.1 christos if (ptr) 879 1.1 christos { 880 1.1 christos strcpy (remcomOutBuffer, "E01"); 881 1.1 christos } 882 1.1 christos } 883 1.1 christos else 884 1.1 christos { 885 1.1 christos exceptionHandler (2, _catchException); 886 1.1 christos strcpy (remcomOutBuffer, "E03"); 887 1.1 christos debug_error ("bus error"); 888 1.1 christos } 889 1.1 christos 890 1.1 christos /* restore handler for bus error */ 891 1.1 christos exceptionHandler (2, _catchException); 892 1.1 christos break; 893 1.1 christos 894 1.1 christos /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 895 1.1 christos case 'M': 896 1.1 christos if (setjmp (remcomEnv) == 0) 897 1.1 christos { 898 1.1 christos exceptionHandler (2, handle_buserror); 899 1.1 christos 900 1.1 christos /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ 901 1.1 christos if (hexToInt (&ptr, &addr)) 902 1.1 christos if (*(ptr++) == ',') 903 1.1 christos if (hexToInt (&ptr, &length)) 904 1.1 christos if (*(ptr++) == ':') 905 1.1 christos { 906 1.1 christos hex2mem (ptr, (char *) addr, length); 907 1.1 christos ptr = 0; 908 1.1 christos strcpy (remcomOutBuffer, "OK"); 909 1.1 christos } 910 1.1 christos if (ptr) 911 1.1 christos { 912 1.1 christos strcpy (remcomOutBuffer, "E02"); 913 1.1 christos } 914 1.1 christos } 915 1.1 christos else 916 1.1 christos { 917 1.1 christos exceptionHandler (2, _catchException); 918 1.1 christos strcpy (remcomOutBuffer, "E03"); 919 1.1 christos debug_error ("bus error"); 920 1.1 christos } 921 1.1 christos 922 1.1 christos /* restore handler for bus error */ 923 1.1 christos exceptionHandler (2, _catchException); 924 1.1 christos break; 925 1.1 christos 926 1.1 christos /* cAA..AA Continue at address AA..AA(optional) */ 927 1.1 christos /* sAA..AA Step one instruction from AA..AA(optional) */ 928 1.1 christos case 's': 929 1.1 christos stepping = 1; 930 1.1 christos case 'c': 931 1.1 christos /* try to read optional parameter, pc unchanged if no parm */ 932 1.1 christos if (hexToInt (&ptr, &addr)) 933 1.1 christos registers[PC] = addr; 934 1.1 christos 935 1.1 christos newPC = registers[PC]; 936 1.1 christos 937 1.1 christos /* clear the trace bit */ 938 1.1 christos registers[PS] &= 0x7fff; 939 1.1 christos 940 1.1 christos /* set the trace bit if we're stepping */ 941 1.1 christos if (stepping) 942 1.1 christos registers[PS] |= 0x8000; 943 1.1 christos 944 1.1 christos /* 945 1.1 christos * look for newPC in the linked list of exception frames. 946 1.1 christos * if it is found, use the old frame it. otherwise, 947 1.1 christos * fake up a dummy frame in returnFromException(). 948 1.1 christos */ 949 1.1 christos if (remote_debug) 950 1.1 christos printf ("new pc = 0x%x\n", newPC); 951 1.1 christos frame = lastFrame; 952 1.1 christos while (frame) 953 1.1 christos { 954 1.1 christos if (remote_debug) 955 1.1 christos printf ("frame at 0x%x has pc=0x%x, except#=%d\n", 956 1.1 christos frame, frame->exceptionPC, frame->exceptionVector); 957 1.1 christos if (frame->exceptionPC == newPC) 958 1.1 christos break; /* bingo! a match */ 959 1.1 christos /* 960 1.1 christos * for a breakpoint instruction, the saved pc may 961 1.1 christos * be off by two due to re-executing the instruction 962 1.1 christos * replaced by the trap instruction. Check for this. 963 1.1 christos */ 964 1.1 christos if ((frame->exceptionVector == 33) && 965 1.1 christos (frame->exceptionPC == (newPC + 2))) 966 1.1 christos break; 967 1.1 christos if (frame == frame->previous) 968 1.1 christos { 969 1.1 christos frame = 0; /* no match found */ 970 1.1 christos break; 971 1.1 christos } 972 1.1 christos frame = frame->previous; 973 1.1 christos } 974 1.1 christos 975 1.1 christos /* 976 1.1 christos * If we found a match for the PC AND we are not returning 977 1.1 christos * as a result of a breakpoint (33), 978 1.1 christos * trace exception (9), nmi (31), jmp to 979 1.1 christos * the old exception handler as if this code never ran. 980 1.1 christos */ 981 1.1 christos if (frame) 982 1.1 christos { 983 1.1 christos if ((frame->exceptionVector != 9) && 984 1.1 christos (frame->exceptionVector != 31) && 985 1.1 christos (frame->exceptionVector != 33)) 986 1.1 christos { 987 1.1 christos /* 988 1.1 christos * invoke the previous handler. 989 1.1 christos */ 990 1.1 christos if (oldExceptionHook) 991 1.1 christos (*oldExceptionHook) (frame->exceptionVector); 992 1.1 christos newPC = registers[PC]; /* pc may have changed */ 993 1.1 christos if (newPC != frame->exceptionPC) 994 1.1 christos { 995 1.1 christos if (remote_debug) 996 1.1 christos printf ("frame at 0x%x has pc=0x%x, except#=%d\n", 997 1.1 christos frame, frame->exceptionPC, 998 1.1 christos frame->exceptionVector); 999 1.1 christos /* re-use the last frame, we're skipping it (longjump?) */ 1000 1.1 christos frame = (Frame *) 0; 1001 1.1 christos _returnFromException (frame); /* this is a jump */ 1002 1.1 christos } 1003 1.1 christos } 1004 1.1 christos } 1005 1.1 christos 1006 1.1 christos /* if we couldn't find a frame, create one */ 1007 1.1 christos if (frame == 0) 1008 1.1 christos { 1009 1.1 christos frame = lastFrame - 1; 1010 1.1 christos 1011 1.7 christos /* by using a bunch of print commands with breakpoints, 1012 1.7 christos it's possible for the frame stack to creep down. If it creeps 1013 1.7 christos too far, give up and reset it to the top. Normal use should 1014 1.1 christos not see this happen. 1015 1.1 christos */ 1016 1.1 christos if ((unsigned int) (frame - 2) < (unsigned int) &gdbFrameStack) 1017 1.1 christos { 1018 1.1 christos initializeRemcomErrorFrame (); 1019 1.1 christos frame = lastFrame; 1020 1.1 christos } 1021 1.1 christos frame->previous = lastFrame; 1022 1.1 christos lastFrame = frame; 1023 1.1 christos frame = 0; /* null so _return... will properly initialize it */ 1024 1.1 christos } 1025 1.1 christos 1026 1.1 christos _returnFromException (frame); /* this is a jump */ 1027 1.1 christos 1028 1.1 christos break; 1029 1.1 christos 1030 1.1 christos /* kill the program */ 1031 1.1 christos case 'k': /* do nothing */ 1032 1.1 christos break; 1033 1.1 christos } /* switch */ 1034 1.1 christos 1035 1.1 christos /* reply to the request */ 1036 1.1 christos putpacket (remcomOutBuffer); 1037 1.1 christos } 1038 1.1 christos } 1039 1.1 christos 1040 1.1 christos 1041 1.1 christos void 1042 1.1 christos initializeRemcomErrorFrame (void) 1043 1.1 christos { 1044 1.1 christos lastFrame = ((Frame *) & gdbFrameStack[FRAMESIZE - 1]) - 1; 1045 1.1 christos lastFrame->previous = lastFrame; 1046 1.1 christos } 1047 1.1 christos 1048 1.1 christos /* this function is used to set up exception handlers for tracing and 1049 1.1 christos breakpoints */ 1050 1.1 christos void 1051 1.1 christos set_debug_traps () 1052 1.1 christos { 1053 1.1 christos extern void _debug_level7 (); 1054 1.1 christos extern void remcomHandler (); 1055 1.1 christos int exception; 1056 1.1 christos 1057 1.1 christos initializeRemcomErrorFrame (); 1058 1.1 christos stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; 1059 1.1 christos 1060 1.1 christos for (exception = 2; exception <= 23; exception++) 1061 1.1 christos exceptionHandler (exception, _catchException); 1062 1.1 christos 1063 1.1 christos /* level 7 interrupt */ 1064 1.1 christos exceptionHandler (31, _debug_level7); 1065 1.1 christos 1066 1.1 christos /* breakpoint exception (trap #1) */ 1067 1.1 christos exceptionHandler (33, _catchException); 1068 1.1 christos 1069 1.1 christos /* This is a trap #8 instruction. Apparently it is someone's software 1070 1.1 christos convention for some sort of SIGFPE condition. Whose? How many 1071 1.1 christos people are being screwed by having this code the way it is? 1072 1.1 christos Is there a clean solution? */ 1073 1.1 christos exceptionHandler (40, _catchException); 1074 1.1 christos 1075 1.1 christos /* 48 to 54 are floating point coprocessor errors */ 1076 1.1 christos for (exception = 48; exception <= 54; exception++) 1077 1.1 christos exceptionHandler (exception, _catchException); 1078 1.1 christos 1079 1.1 christos if (oldExceptionHook != remcomHandler) 1080 1.1 christos { 1081 1.1 christos oldExceptionHook = exceptionHook; 1082 1.1 christos exceptionHook = remcomHandler; 1083 1.1 christos } 1084 1.1 christos 1085 1.1 christos initialized = 1; 1086 1.1 christos 1087 1.1 christos } 1088 1.1 christos 1089 1.1 christos /* This function will generate a breakpoint exception. It is used at the 1090 1.1 christos beginning of a program to sync up with a debugger and can be used 1091 1.1 christos otherwise as a quick means to stop program execution and "break" into 1092 1.1 christos the debugger. */ 1093 1.1 christos 1094 1.1 christos void 1095 1.1 christos breakpoint () 1096 1.1 christos { 1097 1.1 christos if (initialized) 1098 1.1 christos BREAKPOINT (); 1099 } 1100