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 M32R by Michael Snyder, 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 M32R 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.8 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 * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN 63 1.1 christos * AA..AA 64 1.1 christos * 65 1.1 christos * c Resume at current address SNN ( signal NN) 66 1.1 christos * cAA..AA Continue at address AA..AA SNN 67 1.1 christos * 68 1.1 christos * s Step one instruction SNN 69 1.1 christos * sAA..AA Step one instruction from AA..AA SNN 70 1.1 christos * 71 1.1 christos * k kill 72 1.1 christos * 73 1.1 christos * ? What was the last sigval ? SNN (signal NN) 74 1.1 christos * 75 1.1 christos * All commands and responses are sent with a packet which includes a 76 1.1 christos * checksum. A packet consists of 77 1.1 christos * 78 1.1 christos * $<packet info>#<checksum>. 79 1.1 christos * 80 1.1 christos * where 81 1.1 christos * <packet info> :: <characters representing the command or response> 82 1.1 christos * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>> 83 1.1 christos * 84 1.1 christos * When a packet is received, it is first acknowledged with either '+' or '-'. 85 1.1 christos * '+' indicates a successful transfer. '-' indicates a failed transfer. 86 1.1 christos * 87 1.1 christos * Example: 88 1.1 christos * 89 1.1 christos * Host: Reply: 90 1.1 christos * $m0,10#2a +$00010203040506070809101112131415#42 91 1.1 christos * 92 1.1 christos ****************************************************************************/ 93 1.1 christos 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 extern void putDebugChar (); /* write a single character */ 100 1.1 christos extern int getDebugChar (); /* read and return a single char */ 101 1.1 christos extern void exceptionHandler (); /* assign an exception handler */ 102 1.1 christos 103 1.1 christos /***************************************************************************** 104 1.1 christos * BUFMAX defines the maximum number of characters in inbound/outbound buffers 105 1.1 christos * at least NUMREGBYTES*2 are needed for register packets 106 1.1 christos */ 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 unsigned char hexchars[] = "0123456789abcdef"; 115 1.1 christos 116 1.1 christos #define NUMREGS 24 117 1.1 christos 118 1.1 christos /* Number of bytes of registers. */ 119 1.1 christos #define NUMREGBYTES (NUMREGS * 4) 120 1.1 christos enum regnames 121 1.1 christos { R0, R1, R2, R3, R4, R5, R6, R7, 122 1.1 christos R8, R9, R10, R11, R12, R13, R14, R15, 123 1.1 christos PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH 124 1.1 christos }; 125 1.1 christos 126 1.1 christos enum SYS_calls 127 1.1 christos { 128 1.1 christos SYS_null, 129 1.1 christos SYS_exit, 130 1.1 christos SYS_open, 131 1.1 christos SYS_close, 132 1.1 christos SYS_read, 133 1.1 christos SYS_write, 134 1.1 christos SYS_lseek, 135 1.1 christos SYS_unlink, 136 1.1 christos SYS_getpid, 137 1.1 christos SYS_kill, 138 1.1 christos SYS_fstat, 139 1.1 christos SYS_sbrk, 140 1.1 christos SYS_fork, 141 1.1 christos SYS_execve, 142 1.1 christos SYS_wait4, 143 1.1 christos SYS_link, 144 1.1 christos SYS_chdir, 145 1.1 christos SYS_stat, 146 1.1 christos SYS_utime, 147 1.1 christos SYS_chown, 148 1.1 christos SYS_chmod, 149 1.1 christos SYS_time, 150 1.1 christos SYS_pipe 151 1.1 christos }; 152 1.1 christos 153 1.1 christos static int registers[NUMREGS]; 154 1.1 christos 155 1.1 christos #define STACKSIZE 8096 156 1.1 christos static unsigned char remcomInBuffer[BUFMAX]; 157 1.1 christos static unsigned char remcomOutBuffer[BUFMAX]; 158 1.1 christos static int remcomStack[STACKSIZE / sizeof (int)]; 159 1.1 christos static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; 160 1.1 christos 161 1.1 christos static unsigned int save_vectors[18]; /* previous exception vectors */ 162 1.1 christos 163 1.1 christos /* Indicate to caller of mem2hex or hex2mem that there has been an error. */ 164 1.1 christos static volatile int mem_err = 0; 165 1.1 christos 166 1.1 christos /* Store the vector number here (since GDB only gets the signal 167 1.1 christos number through the usual means, and that's not very specific). */ 168 1.1 christos int gdb_m32r_vector = -1; 169 1.1 christos 170 1.1 christos #if 0 171 1.8 christos #include "syscall.h" 172 1.1 christos #endif 173 1.1 christos 174 1.1 christos /* Global entry points: 175 1.1 christos */ 176 1.1 christos 177 1.1 christos extern void handle_exception (int); 178 1.1 christos extern void set_debug_traps (void); 179 1.1 christos extern void breakpoint (void); 180 1.1 christos 181 1.1 christos /* Local functions: 182 1.1 christos */ 183 1.1 christos 184 1.1 christos static int computeSignal (int); 185 1.1 christos static void putpacket (unsigned char *); 186 1.1 christos static unsigned char *getpacket (void); 187 1.1 christos 188 1.1 christos static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int); 189 1.1 christos static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int); 190 1.1 christos static int hexToInt (unsigned char **, int *); 191 1.1 christos static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int); 192 1.1 christos static void stash_registers (void); 193 1.1 christos static void restore_registers (void); 194 1.1 christos static int prepare_to_step (int); 195 1.1 christos static int finish_from_step (void); 196 1.1 christos static unsigned long crc32 (unsigned char *, int, unsigned long); 197 1.1 christos 198 1.1 christos static void gdb_error (char *, char *); 199 1.1 christos static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int); 200 1.1 christos 201 1.1 christos static unsigned char *strcpy (unsigned char *, const unsigned char *); 202 1.1 christos static int strlen (const unsigned char *); 203 1.1 christos 204 1.1 christos /* 205 1.1 christos * This function does all command procesing for interfacing to gdb. 206 1.1 christos */ 207 1.1 christos 208 1.1 christos void 209 1.1 christos handle_exception (int exceptionVector) 210 1.1 christos { 211 1.1 christos int sigval, stepping; 212 1.1 christos int addr, length, i; 213 1.1 christos unsigned char *ptr; 214 1.1 christos unsigned char buf[16]; 215 1.1 christos int binary; 216 1.1 christos 217 1.1 christos if (!finish_from_step ()) 218 1.1 christos return; /* "false step": let the target continue */ 219 1.1 christos 220 1.1 christos gdb_m32r_vector = exceptionVector; 221 1.1 christos 222 1.1 christos if (remote_debug) 223 1.1 christos { 224 1.1 christos mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0); 225 1.1 christos gdb_error ("Handle exception %s, ", buf); 226 1.1 christos mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); 227 1.1 christos gdb_error ("PC == 0x%s\n", buf); 228 1.1 christos } 229 1.1 christos 230 1.1 christos /* reply to host that an exception has occurred */ 231 1.1 christos sigval = computeSignal (exceptionVector); 232 1.1 christos 233 1.1 christos ptr = remcomOutBuffer; 234 1.1 christos 235 1.1 christos *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ 236 1.1 christos *ptr++ = hexchars[sigval >> 4]; 237 1.1 christos *ptr++ = hexchars[sigval & 0xf]; 238 1.1 christos 239 1.1 christos *ptr++ = hexchars[PC >> 4]; 240 1.1 christos *ptr++ = hexchars[PC & 0xf]; 241 1.1 christos *ptr++ = ':'; 242 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */ 243 1.1 christos *ptr++ = ';'; 244 1.1 christos 245 1.1 christos *ptr++ = hexchars[R13 >> 4]; 246 1.1 christos *ptr++ = hexchars[R13 & 0xf]; 247 1.1 christos *ptr++ = ':'; 248 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */ 249 1.1 christos *ptr++ = ';'; 250 1.1 christos 251 1.1 christos *ptr++ = hexchars[R15 >> 4]; 252 1.1 christos *ptr++ = hexchars[R15 & 0xf]; 253 1.1 christos *ptr++ = ':'; 254 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */ 255 1.1 christos *ptr++ = ';'; 256 1.1 christos *ptr++ = 0; 257 1.1 christos 258 1.1 christos if (exceptionVector == 0) /* simulated SYS call stuff */ 259 1.1 christos { 260 1.1 christos mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); 261 1.1 christos switch (registers[R0]) 262 1.1 christos { 263 1.1 christos case SYS_exit: 264 1.1 christos gdb_error ("Target program has exited at %s\n", buf); 265 1.1 christos ptr = remcomOutBuffer; 266 1.1 christos *ptr++ = 'W'; 267 1.1 christos sigval = registers[R1] & 0xff; 268 1.1 christos *ptr++ = hexchars[sigval >> 4]; 269 1.1 christos *ptr++ = hexchars[sigval & 0xf]; 270 1.1 christos *ptr++ = 0; 271 1.1 christos break; 272 1.1 christos case SYS_open: 273 1.1 christos gdb_error ("Target attempts SYS_open call at %s\n", buf); 274 1.1 christos break; 275 1.1 christos case SYS_close: 276 1.1 christos gdb_error ("Target attempts SYS_close call at %s\n", buf); 277 1.1 christos break; 278 1.1 christos case SYS_read: 279 1.1 christos gdb_error ("Target attempts SYS_read call at %s\n", buf); 280 1.1 christos break; 281 1.1 christos case SYS_write: 282 1.1 christos if (registers[R1] == 1 || /* write to stdout */ 283 1.1 christos registers[R1] == 2) /* write to stderr */ 284 1.1 christos { /* (we can do that) */ 285 1.1 christos registers[R0] = 286 1.1 christos gdb_write ((void *) registers[R2], registers[R3]); 287 1.1 christos return; 288 1.1 christos } 289 1.1 christos else 290 1.1 christos gdb_error ("Target attempts SYS_write call at %s\n", buf); 291 1.1 christos break; 292 1.1 christos case SYS_lseek: 293 1.1 christos gdb_error ("Target attempts SYS_lseek call at %s\n", buf); 294 1.1 christos break; 295 1.1 christos case SYS_unlink: 296 1.1 christos gdb_error ("Target attempts SYS_unlink call at %s\n", buf); 297 1.1 christos break; 298 1.1 christos case SYS_getpid: 299 1.1 christos gdb_error ("Target attempts SYS_getpid call at %s\n", buf); 300 1.1 christos break; 301 1.1 christos case SYS_kill: 302 1.1 christos gdb_error ("Target attempts SYS_kill call at %s\n", buf); 303 1.1 christos break; 304 1.1 christos case SYS_fstat: 305 1.1 christos gdb_error ("Target attempts SYS_fstat call at %s\n", buf); 306 1.1 christos break; 307 1.1 christos default: 308 1.1 christos gdb_error ("Target attempts unknown SYS call at %s\n", buf); 309 1.1 christos break; 310 1.1 christos } 311 1.1 christos } 312 1.1 christos 313 1.1 christos putpacket (remcomOutBuffer); 314 1.1 christos 315 1.1 christos stepping = 0; 316 1.1 christos 317 1.1 christos while (1 == 1) 318 1.1 christos { 319 1.1 christos remcomOutBuffer[0] = 0; 320 1.1 christos ptr = getpacket (); 321 1.1 christos binary = 0; 322 1.1 christos switch (*ptr++) 323 1.1 christos { 324 1.1 christos default: /* Unknown code. Return an empty reply message. */ 325 1.1 christos break; 326 1.1 christos case 'R': 327 1.1 christos if (hexToInt (&ptr, &addr)) 328 1.1 christos registers[PC] = addr; 329 1.1 christos strcpy (remcomOutBuffer, "OK"); 330 1.1 christos break; 331 1.1 christos case '!': 332 1.1 christos strcpy (remcomOutBuffer, "OK"); 333 1.1 christos break; 334 1.1 christos case 'X': /* XAA..AA,LLLL:<binary data>#cs */ 335 1.1 christos binary = 1; 336 1.1 christos case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 337 1.1 christos /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ 338 1.1 christos { 339 1.1 christos if (hexToInt (&ptr, &addr)) 340 1.1 christos if (*(ptr++) == ',') 341 1.1 christos if (hexToInt (&ptr, &length)) 342 1.1 christos if (*(ptr++) == ':') 343 1.1 christos { 344 1.1 christos mem_err = 0; 345 1.1 christos if (binary) 346 1.1 christos bin2mem (ptr, (unsigned char *) addr, length, 1); 347 1.1 christos else 348 1.1 christos hex2mem (ptr, (unsigned char *) addr, length, 1); 349 1.1 christos if (mem_err) 350 1.1 christos { 351 1.1 christos strcpy (remcomOutBuffer, "E03"); 352 1.1 christos gdb_error ("memory fault", ""); 353 1.1 christos } 354 1.1 christos else 355 1.1 christos { 356 1.1 christos strcpy (remcomOutBuffer, "OK"); 357 1.1 christos } 358 1.1 christos ptr = 0; 359 1.1 christos } 360 1.1 christos if (ptr) 361 1.1 christos { 362 1.1 christos strcpy (remcomOutBuffer, "E02"); 363 1.1 christos } 364 1.1 christos } 365 1.1 christos break; 366 1.1 christos case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 367 1.1 christos /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ 368 1.1 christos if (hexToInt (&ptr, &addr)) 369 1.1 christos if (*(ptr++) == ',') 370 1.1 christos if (hexToInt (&ptr, &length)) 371 1.1 christos { 372 1.1 christos ptr = 0; 373 1.1 christos mem_err = 0; 374 1.1 christos mem2hex ((unsigned char *) addr, remcomOutBuffer, length, 375 1.1 christos 1); 376 1.1 christos if (mem_err) 377 1.1 christos { 378 1.1 christos strcpy (remcomOutBuffer, "E03"); 379 1.1 christos gdb_error ("memory fault", ""); 380 1.1 christos } 381 1.1 christos } 382 1.1 christos if (ptr) 383 1.1 christos { 384 1.1 christos strcpy (remcomOutBuffer, "E01"); 385 1.1 christos } 386 1.1 christos break; 387 1.1 christos case '?': 388 1.1 christos remcomOutBuffer[0] = 'S'; 389 1.1 christos remcomOutBuffer[1] = hexchars[sigval >> 4]; 390 1.1 christos remcomOutBuffer[2] = hexchars[sigval % 16]; 391 1.1 christos remcomOutBuffer[3] = 0; 392 1.1 christos break; 393 1.1 christos case 'd': 394 1.1 christos remote_debug = !(remote_debug); /* toggle debug flag */ 395 1.1 christos break; 396 1.1 christos case 'g': /* return the value of the CPU registers */ 397 1.1 christos mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES, 398 1.1 christos 0); 399 1.1 christos break; 400 1.1 christos case 'P': /* set the value of a single CPU register - return OK */ 401 1.1 christos { 402 1.1 christos int regno; 403 1.1 christos 404 1.1 christos if (hexToInt (&ptr, ®no) && *ptr++ == '=') 405 1.1 christos if (regno >= 0 && regno < NUMREGS) 406 1.1 christos { 407 1.1 christos int stackmode; 408 1.1 christos 409 1.1 christos hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0); 410 1.1 christos /* 411 1.1 christos * Since we just changed a single CPU register, let's 412 1.1 christos * make sure to keep the several stack pointers consistant. 413 1.1 christos */ 414 1.1 christos stackmode = registers[PSW] & 0x80; 415 1.1 christos if (regno == R15) /* stack pointer changed */ 416 1.1 christos { /* need to change SPI or SPU */ 417 1.1 christos if (stackmode == 0) 418 1.1 christos registers[SPI] = registers[R15]; 419 1.1 christos else 420 1.1 christos registers[SPU] = registers[R15]; 421 1.1 christos } 422 1.1 christos else if (regno == SPU) /* "user" stack pointer changed */ 423 1.1 christos { 424 1.1 christos if (stackmode != 0) /* stack in user mode: copy SP */ 425 1.1 christos registers[R15] = registers[SPU]; 426 1.1 christos } 427 1.1 christos else if (regno == SPI) /* "interrupt" stack pointer changed */ 428 1.1 christos { 429 1.1 christos if (stackmode == 0) /* stack in interrupt mode: copy SP */ 430 1.1 christos registers[R15] = registers[SPI]; 431 1.1 christos } 432 1.1 christos else if (regno == PSW) /* stack mode may have changed! */ 433 1.1 christos { /* force SP to either SPU or SPI */ 434 1.1 christos if (stackmode == 0) /* stack in user mode */ 435 1.1 christos registers[R15] = registers[SPI]; 436 1.1 christos else /* stack in interrupt mode */ 437 1.1 christos registers[R15] = registers[SPU]; 438 1.1 christos } 439 1.1 christos strcpy (remcomOutBuffer, "OK"); 440 1.1 christos break; 441 1.1 christos } 442 1.1 christos strcpy (remcomOutBuffer, "E01"); 443 1.1 christos break; 444 1.1 christos } 445 1.1 christos case 'G': /* set the value of the CPU registers - return OK */ 446 1.1 christos hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0); 447 1.1 christos strcpy (remcomOutBuffer, "OK"); 448 1.1 christos break; 449 1.1 christos case 's': /* sAA..AA Step one instruction from AA..AA(optional) */ 450 1.1 christos stepping = 1; 451 1.1 christos case 'c': /* cAA..AA Continue from address AA..AA(optional) */ 452 1.1 christos /* try to read optional parameter, pc unchanged if no parm */ 453 1.1 christos if (hexToInt (&ptr, &addr)) 454 1.1 christos registers[PC] = addr; 455 1.1 christos 456 1.1 christos if (stepping) /* single-stepping */ 457 1.1 christos { 458 1.1 christos if (!prepare_to_step (0)) /* set up for single-step */ 459 1.1 christos { 460 1.1 christos /* prepare_to_step has already emulated the target insn: 461 1.1 christos Send SIGTRAP to gdb, don't resume the target at all. */ 462 1.1 christos ptr = remcomOutBuffer; 463 1.1 christos *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */ 464 1.1 christos *ptr++ = '0'; 465 1.1 christos *ptr++ = '5'; 466 1.1 christos 467 1.1 christos *ptr++ = hexchars[PC >> 4]; /* send PC */ 468 1.1 christos *ptr++ = hexchars[PC & 0xf]; 469 1.1 christos *ptr++ = ':'; 470 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); 471 1.1 christos *ptr++ = ';'; 472 1.1 christos 473 1.1 christos *ptr++ = hexchars[R13 >> 4]; /* send FP */ 474 1.1 christos *ptr++ = hexchars[R13 & 0xf]; 475 1.1 christos *ptr++ = ':'; 476 1.1 christos ptr = 477 1.1 christos mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); 478 1.1 christos *ptr++ = ';'; 479 1.1 christos 480 1.1 christos *ptr++ = hexchars[R15 >> 4]; /* send SP */ 481 1.1 christos *ptr++ = hexchars[R15 & 0xf]; 482 1.1 christos *ptr++ = ':'; 483 1.1 christos ptr = 484 1.1 christos mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); 485 1.1 christos *ptr++ = ';'; 486 1.1 christos *ptr++ = 0; 487 1.1 christos 488 1.1 christos break; 489 1.1 christos } 490 1.1 christos } 491 1.1 christos else /* continuing, not single-stepping */ 492 1.1 christos { 493 1.1 christos /* OK, about to do a "continue". First check to see if the 494 1.7 christos target pc is on an odd boundary (second instruction in the 495 1.7 christos word). If so, we must do a single-step first, because 496 1.7 christos ya can't jump or return back to an odd boundary! */ 497 1.1 christos if ((registers[PC] & 2) != 0) 498 1.1 christos prepare_to_step (1); 499 1.1 christos } 500 1.1 christos 501 1.1 christos return; 502 1.1 christos 503 1.1 christos case 'D': /* Detach */ 504 1.1 christos #if 0 505 1.1 christos /* I am interpreting this to mean, release the board from control 506 1.1 christos by the remote stub. To do this, I am restoring the original 507 1.1 christos (or at least previous) exception vectors. 508 1.1 christos */ 509 1.1 christos for (i = 0; i < 18; i++) 510 1.1 christos exceptionHandler (i, save_vectors[i]); 511 1.1 christos putpacket ("OK"); 512 1.1 christos return; /* continue the inferior */ 513 1.1 christos #else 514 1.1 christos strcpy (remcomOutBuffer, "OK"); 515 1.1 christos break; 516 1.1 christos #endif 517 1.1 christos case 'q': 518 1.1 christos if (*ptr++ == 'C' && 519 1.1 christos *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':') 520 1.1 christos { 521 1.1 christos unsigned long start, len, our_crc; 522 1.1 christos 523 1.1 christos if (hexToInt (&ptr, (int *) &start) && 524 1.1 christos *ptr++ == ',' && hexToInt (&ptr, (int *) &len)) 525 1.1 christos { 526 1.1 christos remcomOutBuffer[0] = 'C'; 527 1.1 christos our_crc = crc32 ((unsigned char *) start, len, 0xffffffff); 528 1.1 christos mem2hex ((char *) &our_crc, 529 1.1 christos &remcomOutBuffer[1], sizeof (long), 0); 530 1.1 christos } /* else do nothing */ 531 1.1 christos } /* else do nothing */ 532 1.1 christos break; 533 1.1 christos 534 1.1 christos case 'k': /* kill the program */ 535 1.1 christos continue; 536 1.1 christos } /* switch */ 537 1.1 christos 538 1.1 christos /* reply to the request */ 539 1.1 christos putpacket (remcomOutBuffer); 540 1.1 christos } 541 1.1 christos } 542 1.1 christos 543 1.1 christos /* qCRC support */ 544 1.1 christos 545 1.6 christos /* Table used by the crc32 function to calculate the checksum. */ 546 1.1 christos static unsigned long crc32_table[256] = { 0, 0 }; 547 1.1 christos 548 1.1 christos static unsigned long 549 1.1 christos crc32 (unsigned char *buf, int len, unsigned long crc) 550 1.1 christos { 551 1.1 christos if (!crc32_table[1]) 552 1.1 christos { 553 1.1 christos /* Initialize the CRC table and the decoding table. */ 554 1.1 christos int i, j; 555 1.1 christos unsigned long c; 556 1.1 christos 557 1.1 christos for (i = 0; i < 256; i++) 558 1.1 christos { 559 1.1 christos for (c = i << 24, j = 8; j > 0; --j) 560 1.1 christos c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); 561 1.1 christos crc32_table[i] = c; 562 1.1 christos } 563 1.1 christos } 564 1.1 christos 565 1.1 christos while (len--) 566 1.1 christos { 567 1.1 christos crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; 568 1.1 christos buf++; 569 1.1 christos } 570 1.1 christos return crc; 571 1.1 christos } 572 1.1 christos 573 1.1 christos static int 574 1.1 christos hex (unsigned char ch) 575 1.1 christos { 576 1.1 christos if ((ch >= 'a') && (ch <= 'f')) 577 1.1 christos return (ch - 'a' + 10); 578 1.1 christos if ((ch >= '0') && (ch <= '9')) 579 1.1 christos return (ch - '0'); 580 1.1 christos if ((ch >= 'A') && (ch <= 'F')) 581 1.1 christos return (ch - 'A' + 10); 582 1.1 christos return (-1); 583 1.1 christos } 584 1.1 christos 585 1.1 christos /* scan for the sequence $<data>#<checksum> */ 586 1.1 christos 587 1.1 christos unsigned char * 588 1.1 christos getpacket (void) 589 1.1 christos { 590 1.1 christos unsigned char *buffer = &remcomInBuffer[0]; 591 1.1 christos unsigned char checksum; 592 1.1 christos unsigned char xmitcsum; 593 1.1 christos int count; 594 1.1 christos char ch; 595 1.1 christos 596 1.1 christos while (1) 597 1.1 christos { 598 1.1 christos /* wait around for the start character, ignore all other characters */ 599 1.1 christos while ((ch = getDebugChar ()) != '$') 600 1.1 christos ; 601 1.1 christos 602 1.1 christos retry: 603 1.1 christos checksum = 0; 604 1.1 christos xmitcsum = -1; 605 1.1 christos count = 0; 606 1.1 christos 607 1.1 christos /* now, read until a # or end of buffer is found */ 608 1.1 christos while (count < BUFMAX - 1) 609 1.1 christos { 610 1.1 christos ch = getDebugChar (); 611 1.1 christos if (ch == '$') 612 1.1 christos goto retry; 613 1.1 christos if (ch == '#') 614 1.1 christos break; 615 1.1 christos checksum = checksum + ch; 616 1.1 christos buffer[count] = ch; 617 1.1 christos count = count + 1; 618 1.1 christos } 619 1.1 christos buffer[count] = 0; 620 1.1 christos 621 1.1 christos if (ch == '#') 622 1.1 christos { 623 1.1 christos ch = getDebugChar (); 624 1.1 christos xmitcsum = hex (ch) << 4; 625 1.1 christos ch = getDebugChar (); 626 1.1 christos xmitcsum += hex (ch); 627 1.1 christos 628 1.1 christos if (checksum != xmitcsum) 629 1.1 christos { 630 1.1 christos if (remote_debug) 631 1.1 christos { 632 1.1 christos unsigned char buf[16]; 633 1.1 christos 634 1.1 christos mem2hex ((unsigned char *) &checksum, buf, 4, 0); 635 1.1 christos gdb_error ("Bad checksum: my count = %s, ", buf); 636 1.1 christos mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0); 637 1.1 christos gdb_error ("sent count = %s\n", buf); 638 1.1 christos gdb_error (" -- Bad buffer: \"%s\"\n", buffer); 639 1.1 christos } 640 1.1 christos putDebugChar ('-'); /* failed checksum */ 641 1.1 christos } 642 1.1 christos else 643 1.1 christos { 644 1.1 christos putDebugChar ('+'); /* successful transfer */ 645 1.1 christos 646 1.1 christos /* if a sequence char is present, reply the sequence ID */ 647 1.1 christos if (buffer[2] == ':') 648 1.1 christos { 649 1.1 christos putDebugChar (buffer[0]); 650 1.1 christos putDebugChar (buffer[1]); 651 1.1 christos 652 1.1 christos return &buffer[3]; 653 1.1 christos } 654 1.1 christos 655 1.1 christos return &buffer[0]; 656 1.1 christos } 657 1.1 christos } 658 1.1 christos } 659 1.1 christos } 660 1.1 christos 661 1.1 christos /* send the packet in buffer. */ 662 1.1 christos 663 1.1 christos static void 664 1.1 christos putpacket (unsigned char *buffer) 665 1.1 christos { 666 1.1 christos unsigned char checksum; 667 1.1 christos int count; 668 1.1 christos char ch; 669 1.1 christos 670 1.1 christos /* $<packet info>#<checksum>. */ 671 1.1 christos do 672 1.1 christos { 673 1.1 christos putDebugChar ('$'); 674 1.1 christos checksum = 0; 675 1.1 christos count = 0; 676 1.1 christos 677 1.1 christos while (ch = buffer[count]) 678 1.1 christos { 679 1.1 christos putDebugChar (ch); 680 1.1 christos checksum += ch; 681 1.1 christos count += 1; 682 1.1 christos } 683 1.1 christos putDebugChar ('#'); 684 1.1 christos putDebugChar (hexchars[checksum >> 4]); 685 1.1 christos putDebugChar (hexchars[checksum % 16]); 686 1.1 christos } 687 1.1 christos while (getDebugChar () != '+'); 688 1.1 christos } 689 1.1 christos 690 1.1 christos /* Address of a routine to RTE to if we get a memory fault. */ 691 1.1 christos 692 1.1 christos static void (*volatile mem_fault_routine) () = 0; 693 1.1 christos 694 1.1 christos static void 695 1.1 christos set_mem_err (void) 696 1.1 christos { 697 1.1 christos mem_err = 1; 698 1.1 christos } 699 1.1 christos 700 1.1 christos /* Check the address for safe access ranges. As currently defined, 701 1.1 christos this routine will reject the "expansion bus" address range(s). 702 1.1 christos To make those ranges useable, someone must implement code to detect 703 1.1 christos whether there's anything connected to the expansion bus. */ 704 1.1 christos 705 1.1 christos static int 706 1.1 christos mem_safe (unsigned char *addr) 707 1.1 christos { 708 1.1 christos #define BAD_RANGE_ONE_START ((unsigned char *) 0x600000) 709 1.1 christos #define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000) 710 1.1 christos #define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000) 711 1.1 christos #define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000) 712 1.1 christos 713 1.1 christos if (addr < BAD_RANGE_ONE_START) 714 1.1 christos return 1; /* safe */ 715 1.1 christos if (addr < BAD_RANGE_ONE_END) 716 1.1 christos return 0; /* unsafe */ 717 1.1 christos if (addr < BAD_RANGE_TWO_START) 718 1.1 christos return 1; /* safe */ 719 1.1 christos if (addr < BAD_RANGE_TWO_END) 720 1.1 christos return 0; /* unsafe */ 721 1.1 christos } 722 1.1 christos 723 1.1 christos /* These are separate functions so that they are so short and sweet 724 1.1 christos that the compiler won't save any registers (if there is a fault 725 1.1 christos to mem_fault, they won't get restored, so there better not be any 726 1.1 christos saved). */ 727 1.1 christos static int 728 1.1 christos get_char (unsigned char *addr) 729 1.1 christos { 730 1.1 christos #if 1 731 1.1 christos if (mem_fault_routine && !mem_safe (addr)) 732 1.1 christos { 733 1.1 christos mem_fault_routine (); 734 1.1 christos return 0; 735 1.1 christos } 736 1.1 christos #endif 737 1.1 christos return *addr; 738 1.1 christos } 739 1.1 christos 740 1.1 christos static void 741 1.1 christos set_char (unsigned char *addr, unsigned char val) 742 1.1 christos { 743 1.1 christos #if 1 744 1.1 christos if (mem_fault_routine && !mem_safe (addr)) 745 1.1 christos { 746 1.1 christos mem_fault_routine (); 747 1.1 christos return; 748 1.1 christos } 749 1.1 christos #endif 750 1.1 christos *addr = val; 751 1.1 christos } 752 1.1 christos 753 1.1 christos /* Convert the memory pointed to by mem into hex, placing result in buf. 754 1.1 christos Return a pointer to the last char put in buf (null). 755 1.1 christos If MAY_FAULT is non-zero, then we should set mem_err in response to 756 1.1 christos a fault; if zero treat a fault like any other fault in the stub. */ 757 1.1 christos 758 1.1 christos static unsigned char * 759 1.1 christos mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) 760 1.1 christos { 761 1.1 christos int i; 762 1.1 christos unsigned char ch; 763 1.1 christos 764 1.1 christos if (may_fault) 765 1.1 christos mem_fault_routine = set_mem_err; 766 1.1 christos for (i = 0; i < count; i++) 767 1.1 christos { 768 1.1 christos ch = get_char (mem++); 769 1.1 christos if (may_fault && mem_err) 770 1.1 christos return (buf); 771 1.1 christos *buf++ = hexchars[ch >> 4]; 772 1.1 christos *buf++ = hexchars[ch % 16]; 773 1.1 christos } 774 1.1 christos *buf = 0; 775 1.1 christos if (may_fault) 776 1.1 christos mem_fault_routine = 0; 777 1.1 christos return (buf); 778 1.1 christos } 779 1.1 christos 780 1.1 christos /* Convert the hex array pointed to by buf into binary to be placed in mem. 781 1.1 christos Return a pointer to the character AFTER the last byte written. */ 782 1.1 christos 783 1.1 christos static unsigned char * 784 1.1 christos hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) 785 1.1 christos { 786 1.1 christos int i; 787 1.1 christos unsigned char ch; 788 1.1 christos 789 1.1 christos if (may_fault) 790 1.1 christos mem_fault_routine = set_mem_err; 791 1.1 christos for (i = 0; i < count; i++) 792 1.1 christos { 793 1.1 christos ch = hex (*buf++) << 4; 794 1.1 christos ch = ch + hex (*buf++); 795 1.1 christos set_char (mem++, ch); 796 1.1 christos if (may_fault && mem_err) 797 1.1 christos return (mem); 798 1.1 christos } 799 1.1 christos if (may_fault) 800 1.1 christos mem_fault_routine = 0; 801 1.1 christos return (mem); 802 1.1 christos } 803 1.1 christos 804 1.1 christos /* Convert the binary stream in BUF to memory. 805 1.1 christos 806 1.1 christos Gdb will escape $, #, and the escape char (0x7d). 807 1.1 christos COUNT is the total number of bytes to write into 808 1.1 christos memory. */ 809 1.1 christos static unsigned char * 810 1.1 christos bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) 811 1.1 christos { 812 1.1 christos int i; 813 1.1 christos unsigned char ch; 814 1.1 christos 815 1.1 christos if (may_fault) 816 1.1 christos mem_fault_routine = set_mem_err; 817 1.1 christos for (i = 0; i < count; i++) 818 1.1 christos { 819 1.1 christos /* Check for any escaped characters. Be paranoid and 820 1.7 christos only unescape chars that should be escaped. */ 821 1.1 christos if (*buf == 0x7d) 822 1.1 christos { 823 1.1 christos switch (*(buf + 1)) 824 1.1 christos { 825 1.1 christos case 0x3: /* # */ 826 1.1 christos case 0x4: /* $ */ 827 1.1 christos case 0x5d: /* escape char */ 828 1.1 christos buf++; 829 1.1 christos *buf |= 0x20; 830 1.1 christos break; 831 1.1 christos default: 832 1.1 christos /* nothing */ 833 1.1 christos break; 834 1.1 christos } 835 1.1 christos } 836 1.1 christos 837 1.1 christos set_char (mem++, *buf++); 838 1.1 christos 839 1.1 christos if (may_fault && mem_err) 840 1.1 christos return mem; 841 1.1 christos } 842 1.1 christos 843 1.1 christos if (may_fault) 844 1.1 christos mem_fault_routine = 0; 845 1.1 christos return mem; 846 1.1 christos } 847 1.1 christos 848 1.1 christos /* this function takes the m32r exception vector and attempts to 849 1.1 christos translate this number into a unix compatible signal value */ 850 1.1 christos 851 1.1 christos static int 852 1.1 christos computeSignal (int exceptionVector) 853 1.1 christos { 854 1.1 christos int sigval; 855 1.1 christos switch (exceptionVector) 856 1.1 christos { 857 1.1 christos case 0: 858 1.1 christos sigval = 23; 859 1.1 christos break; /* I/O trap */ 860 1.1 christos case 1: 861 1.1 christos sigval = 5; 862 1.1 christos break; /* breakpoint */ 863 1.1 christos case 2: 864 1.1 christos sigval = 5; 865 1.1 christos break; /* breakpoint */ 866 1.1 christos case 3: 867 1.1 christos sigval = 5; 868 1.1 christos break; /* breakpoint */ 869 1.1 christos case 4: 870 1.1 christos sigval = 5; 871 1.1 christos break; /* breakpoint */ 872 1.1 christos case 5: 873 1.1 christos sigval = 5; 874 1.1 christos break; /* breakpoint */ 875 1.1 christos case 6: 876 1.1 christos sigval = 5; 877 1.1 christos break; /* breakpoint */ 878 1.1 christos case 7: 879 1.1 christos sigval = 5; 880 1.1 christos break; /* breakpoint */ 881 1.1 christos case 8: 882 1.1 christos sigval = 5; 883 1.1 christos break; /* breakpoint */ 884 1.1 christos case 9: 885 1.1 christos sigval = 5; 886 1.1 christos break; /* breakpoint */ 887 1.1 christos case 10: 888 1.1 christos sigval = 5; 889 1.1 christos break; /* breakpoint */ 890 1.1 christos case 11: 891 1.1 christos sigval = 5; 892 1.1 christos break; /* breakpoint */ 893 1.1 christos case 12: 894 1.1 christos sigval = 5; 895 1.1 christos break; /* breakpoint */ 896 1.1 christos case 13: 897 1.1 christos sigval = 5; 898 1.1 christos break; /* breakpoint */ 899 1.1 christos case 14: 900 1.1 christos sigval = 5; 901 1.1 christos break; /* breakpoint */ 902 1.1 christos case 15: 903 1.1 christos sigval = 5; 904 1.1 christos break; /* breakpoint */ 905 1.1 christos case 16: 906 1.1 christos sigval = 10; 907 1.1 christos break; /* BUS ERROR (alignment) */ 908 1.1 christos case 17: 909 1.1 christos sigval = 2; 910 1.1 christos break; /* INTerrupt */ 911 1.1 christos default: 912 1.1 christos sigval = 7; 913 1.1 christos break; /* "software generated" */ 914 1.1 christos } 915 1.1 christos return (sigval); 916 1.1 christos } 917 1.1 christos 918 1.1 christos /**********************************************/ 919 1.1 christos /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ 920 1.1 christos /* RETURN NUMBER OF CHARS PROCESSED */ 921 1.1 christos /**********************************************/ 922 1.1 christos static int 923 1.1 christos hexToInt (unsigned char **ptr, int *intValue) 924 1.1 christos { 925 1.1 christos int numChars = 0; 926 1.1 christos int hexValue; 927 1.1 christos 928 1.1 christos *intValue = 0; 929 1.1 christos while (**ptr) 930 1.1 christos { 931 1.1 christos hexValue = hex (**ptr); 932 1.1 christos if (hexValue >= 0) 933 1.1 christos { 934 1.1 christos *intValue = (*intValue << 4) | hexValue; 935 1.1 christos numChars++; 936 1.1 christos } 937 1.1 christos else 938 1.1 christos break; 939 1.1 christos (*ptr)++; 940 1.1 christos } 941 1.1 christos return (numChars); 942 1.1 christos } 943 1.1 christos 944 1.1 christos /* 945 1.1 christos Table of branch instructions: 946 1.1 christos 947 1.1 christos 10B6 RTE return from trap or exception 948 1.1 christos 1FCr JMP jump 949 1.1 christos 1ECr JL jump and link 950 1.1 christos 7Fxx BRA branch 951 1.1 christos FFxxxxxx BRA branch (long) 952 1.1 christos B09rxxxx BNEZ branch not-equal-zero 953 1.1 christos Br1rxxxx BNE branch not-equal 954 1.1 christos 7Dxx BNC branch not-condition 955 1.1 christos FDxxxxxx BNC branch not-condition (long) 956 1.1 christos B0Arxxxx BLTZ branch less-than-zero 957 1.1 christos B0Crxxxx BLEZ branch less-equal-zero 958 1.1 christos 7Exx BL branch and link 959 1.1 christos FExxxxxx BL branch and link (long) 960 1.1 christos B0Drxxxx BGTZ branch greater-than-zero 961 1.1 christos B0Brxxxx BGEZ branch greater-equal-zero 962 1.1 christos B08rxxxx BEQZ branch equal-zero 963 1.1 christos Br0rxxxx BEQ branch equal 964 1.1 christos 7Cxx BC branch condition 965 1.1 christos FCxxxxxx BC branch condition (long) 966 1.1 christos */ 967 1.1 christos 968 1.1 christos static int 969 1.1 christos isShortBranch (unsigned char *instr) 970 1.1 christos { 971 1.1 christos unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */ 972 1.1 christos 973 1.1 christos if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */ 974 1.1 christos return 1; /* return from trap or exception */ 975 1.1 christos 976 1.1 christos if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */ 977 1.1 christos if ((instr[1] & 0xF0) == 0xC0) 978 1.1 christos return 2; /* jump thru a register */ 979 1.1 christos 980 1.1 christos if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */ 981 1.1 christos instr0 == 0x7E || instr0 == 0x7F) 982 1.1 christos return 3; /* eight bit PC offset */ 983 1.1 christos 984 1.1 christos return 0; 985 1.1 christos } 986 1.1 christos 987 1.1 christos static int 988 1.1 christos isLongBranch (unsigned char *instr) 989 1.1 christos { 990 1.1 christos if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */ 991 1.1 christos instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */ 992 1.1 christos return 4; 993 1.1 christos if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */ 994 1.1 christos { 995 1.1 christos if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */ 996 1.1 christos (instr[1] & 0xF0) == 0x10) 997 1.1 christos return 5; 998 1.1 christos if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */ 999 1.1 christos if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 || 1000 1.1 christos (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 || 1001 1.1 christos (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0) 1002 1.1 christos return 6; 1003 1.1 christos } 1004 1.1 christos return 0; 1005 1.1 christos } 1006 1.1 christos 1007 1.1 christos /* if address is NOT on a 4-byte boundary, or high-bit of instr is zero, 1008 1.1 christos then it's a 2-byte instruction, else it's a 4-byte instruction. */ 1009 1.1 christos 1010 1.1 christos #define INSTRUCTION_SIZE(addr) \ 1011 1.1 christos ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4) 1012 1.1 christos 1013 1.1 christos static int 1014 1.1 christos isBranch (unsigned char *instr) 1015 1.1 christos { 1016 1.1 christos if (INSTRUCTION_SIZE (instr) == 2) 1017 1.1 christos return isShortBranch (instr); 1018 1.1 christos else 1019 1.1 christos return isLongBranch (instr); 1020 1.1 christos } 1021 1.1 christos 1022 1.1 christos static int 1023 1.1 christos willBranch (unsigned char *instr, int branchCode) 1024 1.1 christos { 1025 1.1 christos switch (branchCode) 1026 1.1 christos { 1027 1.1 christos case 0: 1028 1.1 christos return 0; /* not a branch */ 1029 1.1 christos case 1: 1030 1.1 christos return 1; /* RTE */ 1031 1.1 christos case 2: 1032 1.1 christos return 1; /* JL or JMP */ 1033 1.1 christos case 3: /* BC, BNC, BL, BRA (short) */ 1034 1.1 christos case 4: /* BC, BNC, BL, BRA (long) */ 1035 1.1 christos switch (instr[0] & 0x0F) 1036 1.1 christos { 1037 1.1 christos case 0xC: /* Branch if Condition Register */ 1038 1.1 christos return (registers[CBR] != 0); 1039 1.1 christos case 0xD: /* Branch if NOT Condition Register */ 1040 1.1 christos return (registers[CBR] == 0); 1041 1.1 christos case 0xE: /* Branch and Link */ 1042 1.1 christos case 0xF: /* Branch (unconditional) */ 1043 1.1 christos return 1; 1044 1.1 christos default: /* oops? */ 1045 1.1 christos return 0; 1046 1.1 christos } 1047 1.1 christos case 5: /* BNE, BEQ */ 1048 1.1 christos switch (instr[1] & 0xF0) 1049 1.1 christos { 1050 1.1 christos case 0x00: /* Branch if r1 equal to r2 */ 1051 1.1 christos return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]); 1052 1.1 christos case 0x10: /* Branch if r1 NOT equal to r2 */ 1053 1.1 christos return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]); 1054 1.1 christos default: /* oops? */ 1055 1.1 christos return 0; 1056 1.1 christos } 1057 1.1 christos case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */ 1058 1.1 christos switch (instr[1] & 0xF0) 1059 1.1 christos { 1060 1.1 christos case 0x80: /* Branch if reg equal to zero */ 1061 1.1 christos return (registers[instr[1] & 0x0F] == 0); 1062 1.1 christos case 0x90: /* Branch if reg NOT equal to zero */ 1063 1.1 christos return (registers[instr[1] & 0x0F] != 0); 1064 1.1 christos case 0xA0: /* Branch if reg less than zero */ 1065 1.1 christos return (registers[instr[1] & 0x0F] < 0); 1066 1.1 christos case 0xB0: /* Branch if reg greater or equal to zero */ 1067 1.1 christos return (registers[instr[1] & 0x0F] >= 0); 1068 1.1 christos case 0xC0: /* Branch if reg less than or equal to zero */ 1069 1.1 christos return (registers[instr[1] & 0x0F] <= 0); 1070 1.1 christos case 0xD0: /* Branch if reg greater than zero */ 1071 1.1 christos return (registers[instr[1] & 0x0F] > 0); 1072 1.1 christos default: /* oops? */ 1073 1.1 christos return 0; 1074 1.1 christos } 1075 1.1 christos default: /* oops? */ 1076 1.1 christos return 0; 1077 1.1 christos } 1078 1.1 christos } 1079 1.1 christos 1080 1.1 christos static int 1081 1.1 christos branchDestination (unsigned char *instr, int branchCode) 1082 1.1 christos { 1083 1.1 christos switch (branchCode) 1084 1.1 christos { 1085 1.1 christos default: 1086 1.1 christos case 0: /* not a branch */ 1087 1.1 christos return 0; 1088 1.1 christos case 1: /* RTE */ 1089 1.1 christos return registers[BPC] & ~3; /* pop BPC into PC */ 1090 1.1 christos case 2: /* JL or JMP */ 1091 1.1 christos return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */ 1092 1.1 christos case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */ 1093 1.1 christos return (((int) instr) & ~3) + ((char) instr[1] << 2); 1094 1.1 christos case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */ 1095 1.1 christos return ((int) instr + 1096 1.1 christos ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) << 1097 1.1 christos 2)); 1098 1.1 christos case 5: /* BNE, BEQ (16-bit relative offset) */ 1099 1.1 christos case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */ 1100 1.1 christos return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2)); 1101 1.1 christos } 1102 1.1 christos 1103 1.1 christos /* An explanatory note: in the last three return expressions, I have 1104 1.1 christos cast the most-significant byte of the return offset to char. 1105 1.1 christos What this accomplishes is sign extension. If the other 1106 1.1 christos less-significant bytes were signed as well, they would get sign 1107 1.1 christos extended too and, if negative, their leading bits would clobber 1108 1.1 christos the bits of the more-significant bytes ahead of them. There are 1109 1.1 christos other ways I could have done this, but sign extension from 1110 1.1 christos odd-sized integers is always a pain. */ 1111 1.1 christos } 1112 1.1 christos 1113 1.1 christos static void 1114 1.1 christos branchSideEffects (unsigned char *instr, int branchCode) 1115 1.1 christos { 1116 1.1 christos switch (branchCode) 1117 1.1 christos { 1118 1.1 christos case 1: /* RTE */ 1119 1.1 christos return; /* I <THINK> this is already handled... */ 1120 1.1 christos case 2: /* JL (or JMP) */ 1121 1.1 christos case 3: /* BL (or BC, BNC, BRA) */ 1122 1.1 christos case 4: 1123 1.1 christos if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */ 1124 1.1 christos registers[R14] = (registers[PC] & ~3) + 4; 1125 1.1 christos return; 1126 1.1 christos default: /* any other branch has no side effects */ 1127 1.1 christos return; 1128 1.1 christos } 1129 1.1 christos } 1130 1.1 christos 1131 1.1 christos static struct STEPPING_CONTEXT 1132 1.1 christos { 1133 1.1 christos int stepping; /* true when we've started a single-step */ 1134 1.1 christos unsigned long target_addr; /* the instr we're trying to execute */ 1135 1.1 christos unsigned long target_size; /* the size of the target instr */ 1136 1.1 christos unsigned long noop_addr; /* where we've inserted a no-op, if any */ 1137 1.1 christos unsigned long trap1_addr; /* the trap following the target instr */ 1138 1.1 christos unsigned long trap2_addr; /* the trap at a branch destination, if any */ 1139 1.1 christos unsigned short noop_save; /* instruction overwritten by our no-op */ 1140 1.1 christos unsigned short trap1_save; /* instruction overwritten by trap1 */ 1141 1.1 christos unsigned short trap2_save; /* instruction overwritten by trap2 */ 1142 1.1 christos unsigned short continue_p; /* true if NOT returning to gdb after step */ 1143 1.1 christos } stepping; 1144 1.1 christos 1145 1.1 christos /* Function: prepare_to_step 1146 1.1 christos Called from handle_exception to prepare the user program to single-step. 1147 1.1 christos Places a trap instruction after the target instruction, with special 1148 1.1 christos extra handling for branch instructions and for instructions in the 1149 1.1 christos second half-word of a word. 1150 1.1 christos 1151 1.1 christos Returns: True if we should actually execute the instruction; 1152 1.1 christos False if we are going to emulate executing the instruction, 1153 1.1 christos in which case we simply report to GDB that the instruction 1154 1.1 christos has already been executed. */ 1155 1.1 christos 1156 1.1 christos #define TRAP1 0x10f1; /* trap #1 instruction */ 1157 1.1 christos #define NOOP 0x7000; /* noop instruction */ 1158 1.1 christos 1159 1.1 christos static unsigned short trap1 = TRAP1; 1160 1.1 christos static unsigned short noop = NOOP; 1161 1.1 christos 1162 1.1 christos static int 1163 1.1 christos prepare_to_step (continue_p) 1164 1.1 christos int continue_p; /* if this isn't REALLY a single-step (see below) */ 1165 1.1 christos { 1166 1.1 christos unsigned long pc = registers[PC]; 1167 1.1 christos int branchCode = isBranch ((unsigned char *) pc); 1168 1.1 christos unsigned char *p; 1169 1.1 christos 1170 1.1 christos /* zero out the stepping context 1171 1.1 christos (paranoia -- it should already be zeroed) */ 1172 1.1 christos for (p = (unsigned char *) &stepping; 1173 1.1 christos p < ((unsigned char *) &stepping) + sizeof (stepping); p++) 1174 1.1 christos *p = 0; 1175 1.1 christos 1176 1.1 christos if (branchCode != 0) /* next instruction is a branch */ 1177 1.1 christos { 1178 1.1 christos branchSideEffects ((unsigned char *) pc, branchCode); 1179 1.1 christos if (willBranch ((unsigned char *) pc, branchCode)) 1180 1.1 christos registers[PC] = branchDestination ((unsigned char *) pc, branchCode); 1181 1.1 christos else 1182 1.1 christos registers[PC] = pc + INSTRUCTION_SIZE (pc); 1183 1.1 christos return 0; /* branch "executed" -- just notify GDB */ 1184 1.1 christos } 1185 1.1 christos else if (((int) pc & 2) != 0) /* "second-slot" instruction */ 1186 1.1 christos { 1187 1.1 christos /* insert no-op before pc */ 1188 1.1 christos stepping.noop_addr = pc - 2; 1189 1.1 christos stepping.noop_save = *(unsigned short *) stepping.noop_addr; 1190 1.1 christos *(unsigned short *) stepping.noop_addr = noop; 1191 1.1 christos /* insert trap after pc */ 1192 1.1 christos stepping.trap1_addr = pc + 2; 1193 1.1 christos stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; 1194 1.1 christos *(unsigned short *) stepping.trap1_addr = trap1; 1195 1.1 christos } 1196 1.1 christos else /* "first-slot" instruction */ 1197 1.1 christos { 1198 1.1 christos /* insert trap after pc */ 1199 1.1 christos stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc); 1200 1.1 christos stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; 1201 1.1 christos *(unsigned short *) stepping.trap1_addr = trap1; 1202 1.1 christos } 1203 1.1 christos /* "continue_p" means that we are actually doing a continue, and not 1204 1.1 christos being requested to single-step by GDB. Sometimes we have to do 1205 1.1 christos one single-step before continuing, because the PC is on a half-word 1206 1.1 christos boundary. There's no way to simply resume at such an address. */ 1207 1.1 christos stepping.continue_p = continue_p; 1208 1.1 christos stepping.stepping = 1; /* starting a single-step */ 1209 1.1 christos return 1; 1210 1.1 christos } 1211 1.1 christos 1212 1.1 christos /* Function: finish_from_step 1213 1.1 christos Called from handle_exception to finish up when the user program 1214 1.1 christos returns from a single-step. Replaces the instructions that had 1215 1.1 christos been overwritten by traps or no-ops, 1216 1.1 christos 1217 1.1 christos Returns: True if we should notify GDB that the target stopped. 1218 1.1 christos False if we only single-stepped because we had to before we 1219 1.1 christos could continue (ie. we were trying to continue at a 1220 1.1 christos half-word boundary). In that case don't notify GDB: 1221 1.1 christos just "continue continuing". */ 1222 1.1 christos 1223 1.1 christos static int 1224 1.1 christos finish_from_step (void) 1225 1.1 christos { 1226 1.1 christos if (stepping.stepping) /* anything to do? */ 1227 1.1 christos { 1228 1.1 christos int continue_p = stepping.continue_p; 1229 1.1 christos unsigned char *p; 1230 1.1 christos 1231 1.1 christos if (stepping.noop_addr) /* replace instr "under" our no-op */ 1232 1.1 christos *(unsigned short *) stepping.noop_addr = stepping.noop_save; 1233 1.1 christos if (stepping.trap1_addr) /* replace instr "under" our trap */ 1234 1.1 christos *(unsigned short *) stepping.trap1_addr = stepping.trap1_save; 1235 1.1 christos if (stepping.trap2_addr) /* ditto our other trap, if any */ 1236 1.1 christos *(unsigned short *) stepping.trap2_addr = stepping.trap2_save; 1237 1.1 christos 1238 1.1 christos for (p = (unsigned char *) &stepping; /* zero out the stepping context */ 1239 1.1 christos p < ((unsigned char *) &stepping) + sizeof (stepping); p++) 1240 1.1 christos *p = 0; 1241 1.1 christos 1242 1.1 christos return !(continue_p); 1243 1.1 christos } 1244 1.1 christos else /* we didn't single-step, therefore this must be a legitimate stop */ 1245 1.1 christos return 1; 1246 1.1 christos } 1247 1.1 christos 1248 1.1 christos struct PSWreg 1249 1.1 christos { /* separate out the bit flags in the PSW register */ 1250 1.1 christos int pad1:16; 1251 1.1 christos int bsm:1; 1252 1.1 christos int bie:1; 1253 1.1 christos int pad2:5; 1254 1.1 christos int bc:1; 1255 1.1 christos int sm:1; 1256 1.1 christos int ie:1; 1257 1.1 christos int pad3:5; 1258 1.1 christos int c:1; 1259 1.1 christos } *psw; 1260 1.1 christos 1261 1.1 christos /* Upon entry the value for LR to save has been pushed. 1262 1.1 christos We unpush that so that the value for the stack pointer saved is correct. 1263 1.1 christos Upon entry, all other registers are assumed to have not been modified 1264 1.8 christos since the interrupt/trap occurred. */ 1265 1.1 christos 1266 1.1 christos asm ("\n\ 1267 1.1 christos stash_registers:\n\ 1268 1.1 christos push r0\n\ 1269 1.1 christos push r1\n\ 1270 1.1 christos seth r1, #shigh(registers)\n\ 1271 1.1 christos add3 r1, r1, #low(registers)\n\ 1272 1.1 christos pop r0 ; r1\n\ 1273 1.1 christos st r0, @(4,r1)\n\ 1274 1.1 christos pop r0 ; r0\n\ 1275 1.1 christos st r0, @r1\n\ 1276 1.1 christos addi r1, #4 ; only add 4 as subsequent saves are `pre inc'\n\ 1277 1.1 christos st r2, @+r1\n\ 1278 1.1 christos st r3, @+r1\n\ 1279 1.1 christos st r4, @+r1\n\ 1280 1.1 christos st r5, @+r1\n\ 1281 1.1 christos st r6, @+r1\n\ 1282 1.1 christos st r7, @+r1\n\ 1283 1.1 christos st r8, @+r1\n\ 1284 1.1 christos st r9, @+r1\n\ 1285 1.1 christos st r10, @+r1\n\ 1286 1.1 christos st r11, @+r1\n\ 1287 1.1 christos st r12, @+r1\n\ 1288 1.1 christos st r13, @+r1 ; fp\n\ 1289 1.1 christos pop r0 ; lr (r14)\n\ 1290 1.1 christos st r0, @+r1\n\ 1291 1.1 christos st sp, @+r1 ; sp contains right value at this point\n\ 1292 1.1 christos mvfc r0, cr0\n\ 1293 1.1 christos st r0, @+r1 ; cr0 == PSW\n\ 1294 1.1 christos mvfc r0, cr1\n\ 1295 1.1 christos st r0, @+r1 ; cr1 == CBR\n\ 1296 1.1 christos mvfc r0, cr2\n\ 1297 1.1 christos st r0, @+r1 ; cr2 == SPI\n\ 1298 1.1 christos mvfc r0, cr3\n\ 1299 1.1 christos st r0, @+r1 ; cr3 == SPU\n\ 1300 1.1 christos mvfc r0, cr6\n\ 1301 1.1 christos st r0, @+r1 ; cr6 == BPC\n\ 1302 1.1 christos st r0, @+r1 ; PC == BPC\n\ 1303 1.1 christos mvfaclo r0\n\ 1304 1.1 christos st r0, @+r1 ; ACCL\n\ 1305 1.1 christos mvfachi r0\n\ 1306 1.1 christos st r0, @+r1 ; ACCH\n\ 1307 1.1 christos jmp lr"); 1308 1.1 christos 1309 1.1 christos /* C routine to clean up what stash_registers did. 1310 1.1 christos It is called after calling stash_registers. 1311 1.1 christos This is separate from stash_registers as we want to do this in C 1312 1.1 christos but doing stash_registers in C isn't straightforward. */ 1313 1.1 christos 1314 1.1 christos static void 1315 1.1 christos cleanup_stash (void) 1316 1.1 christos { 1317 1.1 christos psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */ 1318 1.1 christos psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */ 1319 1.1 christos psw->ie = psw->bie; 1320 1.1 christos psw->c = psw->bc; 1321 1.1 christos registers[CBR] = psw->bc; /* fix up pre-trap "C" register */ 1322 1.1 christos 1323 1.1 christos #if 0 /* FIXME: Was in previous version. Necessary? 1324 1.1 christos (Remember that we use the "rte" insn to return from the 1325 1.1 christos trap/interrupt so the values of bsm, bie, bc are important. */ 1326 1.1 christos psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */ 1327 1.1 christos #endif 1328 1.1 christos 1329 1.1 christos /* FIXME: Copied from previous version. This can probably be deleted 1330 1.1 christos since methinks stash_registers has already done this. */ 1331 1.1 christos registers[PC] = registers[BPC]; /* pre-trap PC */ 1332 1.1 christos 1333 1.1 christos /* FIXME: Copied from previous version. Necessary? */ 1334 1.1 christos if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */ 1335 1.1 christos registers[SPU] = registers[R15]; 1336 1.1 christos else 1337 1.1 christos registers[SPI] = registers[R15]; 1338 1.1 christos } 1339 1.1 christos 1340 1.1 christos asm ("\n\ 1341 1.1 christos restore_and_return:\n\ 1342 1.1 christos seth r0, #shigh(registers+8)\n\ 1343 1.1 christos add3 r0, r0, #low(registers+8)\n\ 1344 1.1 christos ld r2, @r0+ ; restore r2\n\ 1345 1.1 christos ld r3, @r0+ ; restore r3\n\ 1346 1.1 christos ld r4, @r0+ ; restore r4\n\ 1347 1.1 christos ld r5, @r0+ ; restore r5\n\ 1348 1.1 christos ld r6, @r0+ ; restore r6\n\ 1349 1.1 christos ld r7, @r0+ ; restore r7\n\ 1350 1.1 christos ld r8, @r0+ ; restore r8\n\ 1351 1.1 christos ld r9, @r0+ ; restore r9\n\ 1352 1.1 christos ld r10, @r0+ ; restore r10\n\ 1353 1.1 christos ld r11, @r0+ ; restore r11\n\ 1354 1.1 christos ld r12, @r0+ ; restore r12\n\ 1355 1.1 christos ld r13, @r0+ ; restore r13\n\ 1356 1.1 christos ld r14, @r0+ ; restore r14\n\ 1357 1.1 christos ld r15, @r0+ ; restore r15\n\ 1358 1.1 christos ld r1, @r0+ ; restore cr0 == PSW\n\ 1359 1.1 christos mvtc r1, cr0\n\ 1360 1.1 christos ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)\n\ 1361 1.1 christos mvtc r1, cr1\n\ 1362 1.1 christos ld r1, @r0+ ; restore cr2 == SPI\n\ 1363 1.1 christos mvtc r1, cr2\n\ 1364 1.1 christos ld r1, @r0+ ; restore cr3 == SPU\n\ 1365 1.1 christos mvtc r1, cr3\n\ 1366 1.1 christos addi r0, #4 ; skip BPC\n\ 1367 1.1 christos ld r1, @r0+ ; restore cr6 (BPC) == PC\n\ 1368 1.1 christos mvtc r1, cr6\n\ 1369 1.1 christos ld r1, @r0+ ; restore ACCL\n\ 1370 1.1 christos mvtaclo r1\n\ 1371 1.1 christos ld r1, @r0+ ; restore ACCH\n\ 1372 1.1 christos mvtachi r1\n\ 1373 1.1 christos seth r0, #shigh(registers)\n\ 1374 1.1 christos add3 r0, r0, #low(registers)\n\ 1375 1.1 christos ld r1, @(4,r0) ; restore r1\n\ 1376 1.1 christos ld r0, @r0 ; restore r0\n\ 1377 1.1 christos rte"); 1378 1.1 christos 1379 1.1 christos /* General trap handler, called after the registers have been stashed. 1380 1.1 christos NUM is the trap/exception number. */ 1381 1.1 christos 1382 1.1 christos static void 1383 1.1 christos process_exception (int num) 1384 1.1 christos { 1385 1.1 christos cleanup_stash (); 1386 1.1 christos asm volatile ("\n\ 1387 1.1 christos seth r1, #shigh(stackPtr)\n\ 1388 1.1 christos add3 r1, r1, #low(stackPtr)\n\ 1389 1.1 christos ld r15, @r1 ; setup local stack (protect user stack)\n\ 1390 1.1 christos mv r0, %0\n\ 1391 1.1 christos bl handle_exception\n\ 1392 1.1 christos bl restore_and_return"::"r" (num):"r0", "r1"); 1393 1.1 christos } 1394 1.1 christos 1395 1.1 christos void _catchException0 (); 1396 1.1 christos 1397 1.1 christos asm ("\n\ 1398 1.1 christos _catchException0:\n\ 1399 1.1 christos push lr\n\ 1400 1.1 christos bl stash_registers\n\ 1401 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1402 1.1 christos ldi r0, #0\n\ 1403 1.1 christos bl process_exception"); 1404 1.1 christos 1405 1.1 christos void _catchException1 (); 1406 1.1 christos 1407 1.1 christos asm ("\n\ 1408 1.1 christos _catchException1:\n\ 1409 1.1 christos push lr\n\ 1410 1.1 christos bl stash_registers\n\ 1411 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1412 1.1 christos bl cleanup_stash\n\ 1413 1.1 christos seth r1, #shigh(stackPtr)\n\ 1414 1.1 christos add3 r1, r1, #low(stackPtr)\n\ 1415 1.1 christos ld r15, @r1 ; setup local stack (protect user stack)\n\ 1416 1.1 christos seth r1, #shigh(registers + 21*4) ; PC\n\ 1417 1.1 christos add3 r1, r1, #low(registers + 21*4)\n\ 1418 1.1 christos ld r0, @r1\n\ 1419 1.1 christos addi r0, #-4 ; back up PC for breakpoint trap.\n\ 1420 1.1 christos st r0, @r1 ; FIXME: what about bp in right slot?\n\ 1421 1.1 christos ldi r0, #1\n\ 1422 1.1 christos bl handle_exception\n\ 1423 1.1 christos bl restore_and_return"); 1424 1.1 christos 1425 1.1 christos void _catchException2 (); 1426 1.1 christos 1427 1.1 christos asm ("\n\ 1428 1.1 christos _catchException2:\n\ 1429 1.1 christos push lr\n\ 1430 1.1 christos bl stash_registers\n\ 1431 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1432 1.1 christos ldi r0, #2\n\ 1433 1.1 christos bl process_exception"); 1434 1.1 christos 1435 1.1 christos void _catchException3 (); 1436 1.1 christos 1437 1.1 christos asm ("\n\ 1438 1.1 christos _catchException3:\n\ 1439 1.1 christos push lr\n\ 1440 1.1 christos bl stash_registers\n\ 1441 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1442 1.1 christos ldi r0, #3\n\ 1443 1.1 christos bl process_exception"); 1444 1.1 christos 1445 1.1 christos void _catchException4 (); 1446 1.1 christos 1447 1.1 christos asm ("\n\ 1448 1.1 christos _catchException4:\n\ 1449 1.1 christos push lr\n\ 1450 1.1 christos bl stash_registers\n\ 1451 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1452 1.1 christos ldi r0, #4\n\ 1453 1.1 christos bl process_exception"); 1454 1.1 christos 1455 1.1 christos void _catchException5 (); 1456 1.1 christos 1457 1.1 christos asm ("\n\ 1458 1.1 christos _catchException5:\n\ 1459 1.1 christos push lr\n\ 1460 1.1 christos bl stash_registers\n\ 1461 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1462 1.1 christos ldi r0, #5\n\ 1463 1.1 christos bl process_exception"); 1464 1.1 christos 1465 1.1 christos void _catchException6 (); 1466 1.1 christos 1467 1.1 christos asm ("\n\ 1468 1.1 christos _catchException6:\n\ 1469 1.1 christos push lr\n\ 1470 1.1 christos bl stash_registers\n\ 1471 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1472 1.1 christos ldi r0, #6\n\ 1473 1.1 christos bl process_exception"); 1474 1.1 christos 1475 1.1 christos void _catchException7 (); 1476 1.1 christos 1477 1.1 christos asm ("\n\ 1478 1.1 christos _catchException7:\n\ 1479 1.1 christos push lr\n\ 1480 1.1 christos bl stash_registers\n\ 1481 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1482 1.1 christos ldi r0, #7\n\ 1483 1.1 christos bl process_exception"); 1484 1.1 christos 1485 1.1 christos void _catchException8 (); 1486 1.1 christos 1487 1.1 christos asm ("\n\ 1488 1.1 christos _catchException8:\n\ 1489 1.1 christos push lr\n\ 1490 1.1 christos bl stash_registers\n\ 1491 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1492 1.1 christos ldi r0, #8\n\ 1493 1.1 christos bl process_exception"); 1494 1.1 christos 1495 1.1 christos void _catchException9 (); 1496 1.1 christos 1497 1.1 christos asm ("\n\ 1498 1.1 christos _catchException9:\n\ 1499 1.1 christos push lr\n\ 1500 1.1 christos bl stash_registers\n\ 1501 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1502 1.1 christos ldi r0, #9\n\ 1503 1.1 christos bl process_exception"); 1504 1.1 christos 1505 1.1 christos void _catchException10 (); 1506 1.1 christos 1507 1.1 christos asm ("\n\ 1508 1.1 christos _catchException10:\n\ 1509 1.1 christos push lr\n\ 1510 1.1 christos bl stash_registers\n\ 1511 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1512 1.1 christos ldi r0, #10\n\ 1513 1.1 christos bl process_exception"); 1514 1.1 christos 1515 1.1 christos void _catchException11 (); 1516 1.1 christos 1517 1.1 christos asm ("\n\ 1518 1.1 christos _catchException11:\n\ 1519 1.1 christos push lr\n\ 1520 1.1 christos bl stash_registers\n\ 1521 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1522 1.1 christos ldi r0, #11\n\ 1523 1.1 christos bl process_exception"); 1524 1.1 christos 1525 1.1 christos void _catchException12 (); 1526 1.1 christos 1527 1.1 christos asm ("\n\ 1528 1.1 christos _catchException12:\n\ 1529 1.1 christos push lr\n\ 1530 1.1 christos bl stash_registers\n\ 1531 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1532 1.1 christos ldi r0, #12\n\ 1533 1.1 christos bl process_exception"); 1534 1.1 christos 1535 1.1 christos void _catchException13 (); 1536 1.1 christos 1537 1.1 christos asm ("\n\ 1538 1.1 christos _catchException13:\n\ 1539 1.1 christos push lr\n\ 1540 1.1 christos bl stash_registers\n\ 1541 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1542 1.1 christos ldi r0, #13\n\ 1543 1.1 christos bl process_exception"); 1544 1.1 christos 1545 1.1 christos void _catchException14 (); 1546 1.1 christos 1547 1.1 christos asm ("\n\ 1548 1.1 christos _catchException14:\n\ 1549 1.1 christos push lr\n\ 1550 1.1 christos bl stash_registers\n\ 1551 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1552 1.1 christos ldi r0, #14\n\ 1553 1.1 christos bl process_exception"); 1554 1.1 christos 1555 1.1 christos void _catchException15 (); 1556 1.1 christos 1557 1.1 christos asm ("\n\ 1558 1.1 christos _catchException15:\n\ 1559 1.1 christos push lr\n\ 1560 1.1 christos bl stash_registers\n\ 1561 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1562 1.1 christos ldi r0, #15\n\ 1563 1.1 christos bl process_exception"); 1564 1.1 christos 1565 1.1 christos void _catchException16 (); 1566 1.1 christos 1567 1.1 christos asm ("\n\ 1568 1.1 christos _catchException16:\n\ 1569 1.1 christos push lr\n\ 1570 1.1 christos bl stash_registers\n\ 1571 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1572 1.1 christos ldi r0, #16\n\ 1573 1.1 christos bl process_exception"); 1574 1.1 christos 1575 1.1 christos void _catchException17 (); 1576 1.1 christos 1577 1.1 christos asm ("\n\ 1578 1.1 christos _catchException17:\n\ 1579 1.1 christos push lr\n\ 1580 1.1 christos bl stash_registers\n\ 1581 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\ 1582 1.1 christos ldi r0, #17\n\ 1583 1.1 christos bl process_exception"); 1584 1.1 christos 1585 1.1 christos 1586 1.1 christos /* this function is used to set up exception handlers for tracing and 1587 1.1 christos breakpoints */ 1588 1.1 christos void 1589 1.1 christos set_debug_traps (void) 1590 1.1 christos { 1591 1.1 christos /* extern void remcomHandler(); */ 1592 1.1 christos int i; 1593 1.1 christos 1594 1.1 christos for (i = 0; i < 18; i++) /* keep a copy of old vectors */ 1595 1.1 christos if (save_vectors[i] == 0) /* only copy them the first time */ 1596 1.1 christos save_vectors[i] = getExceptionHandler (i); 1597 1.1 christos 1598 1.1 christos stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; 1599 1.1 christos 1600 1.1 christos exceptionHandler (0, _catchException0); 1601 1.1 christos exceptionHandler (1, _catchException1); 1602 1.1 christos exceptionHandler (2, _catchException2); 1603 1.1 christos exceptionHandler (3, _catchException3); 1604 1.1 christos exceptionHandler (4, _catchException4); 1605 1.1 christos exceptionHandler (5, _catchException5); 1606 1.1 christos exceptionHandler (6, _catchException6); 1607 1.1 christos exceptionHandler (7, _catchException7); 1608 1.1 christos exceptionHandler (8, _catchException8); 1609 1.1 christos exceptionHandler (9, _catchException9); 1610 1.1 christos exceptionHandler (10, _catchException10); 1611 1.1 christos exceptionHandler (11, _catchException11); 1612 1.1 christos exceptionHandler (12, _catchException12); 1613 1.1 christos exceptionHandler (13, _catchException13); 1614 1.1 christos exceptionHandler (14, _catchException14); 1615 1.1 christos exceptionHandler (15, _catchException15); 1616 1.1 christos exceptionHandler (16, _catchException16); 1617 1.1 christos /* exceptionHandler (17, _catchException17); */ 1618 1.1 christos 1619 1.1 christos initialized = 1; 1620 1.1 christos } 1621 1.1 christos 1622 1.1 christos /* This function will generate a breakpoint exception. It is used at the 1623 1.1 christos beginning of a program to sync up with a debugger and can be used 1624 1.1 christos otherwise as a quick means to stop program execution and "break" into 1625 1.1 christos the debugger. */ 1626 1.1 christos 1627 1.1 christos #define BREAKPOINT() asm volatile (" trap #2"); 1628 1.1 christos 1629 1.1 christos void 1630 1.1 christos breakpoint (void) 1631 1.1 christos { 1632 1.1 christos if (initialized) 1633 1.1 christos BREAKPOINT (); 1634 1.1 christos } 1635 1.1 christos 1636 1.1 christos /* STDOUT section: 1637 1.1 christos Stuff pertaining to simulating stdout by sending chars to gdb to be echoed. 1638 1.1 christos Functions: gdb_putchar(char ch) 1639 1.7 christos gdb_puts(char *str) 1640 1.7 christos gdb_write(char *str, int len) 1641 1.7 christos gdb_error(char *format, char *parm) 1642 1.1 christos */ 1643 1.1 christos 1644 1.1 christos /* Function: gdb_putchar(int) 1645 1.1 christos Make gdb write a char to stdout. 1646 1.1 christos Returns: the char */ 1647 1.1 christos 1648 1.1 christos static int 1649 1.1 christos gdb_putchar (int ch) 1650 1.1 christos { 1651 1.1 christos char buf[4]; 1652 1.1 christos 1653 1.1 christos buf[0] = 'O'; 1654 1.1 christos buf[1] = hexchars[ch >> 4]; 1655 1.1 christos buf[2] = hexchars[ch & 0x0F]; 1656 1.1 christos buf[3] = 0; 1657 1.1 christos putpacket (buf); 1658 1.1 christos return ch; 1659 1.1 christos } 1660 1.1 christos 1661 1.1 christos /* Function: gdb_write(char *, int) 1662 1.1 christos Make gdb write n bytes to stdout (not assumed to be null-terminated). 1663 1.1 christos Returns: number of bytes written */ 1664 1.1 christos 1665 1.1 christos static int 1666 1.1 christos gdb_write (char *data, int len) 1667 1.1 christos { 1668 1.1 christos char *buf, *cpy; 1669 1.1 christos int i; 1670 1.1 christos 1671 1.1 christos buf = remcomOutBuffer; 1672 1.1 christos buf[0] = 'O'; 1673 1.1 christos i = 0; 1674 1.1 christos while (i < len) 1675 1.1 christos { 1676 1.1 christos for (cpy = buf + 1; 1677 1.1 christos i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++) 1678 1.1 christos { 1679 1.1 christos *cpy++ = hexchars[data[i] >> 4]; 1680 1.1 christos *cpy++ = hexchars[data[i] & 0x0F]; 1681 1.1 christos } 1682 1.1 christos *cpy = 0; 1683 1.1 christos putpacket (buf); 1684 1.1 christos } 1685 1.1 christos return len; 1686 1.1 christos } 1687 1.1 christos 1688 1.1 christos /* Function: gdb_puts(char *) 1689 1.1 christos Make gdb write a null-terminated string to stdout. 1690 1.1 christos Returns: the length of the string */ 1691 1.1 christos 1692 1.1 christos static int 1693 1.1 christos gdb_puts (char *str) 1694 1.1 christos { 1695 1.1 christos return gdb_write (str, strlen (str)); 1696 1.1 christos } 1697 1.1 christos 1698 1.1 christos /* Function: gdb_error(char *, char *) 1699 1.1 christos Send an error message to gdb's stdout. 1700 1.1 christos First string may have 1 (one) optional "%s" in it, which 1701 1.1 christos will cause the optional second string to be inserted. */ 1702 1.1 christos 1703 1.1 christos static void 1704 1.1 christos gdb_error (char *format, char *parm) 1705 1.1 christos { 1706 1.1 christos char buf[400], *cpy; 1707 1.1 christos int len; 1708 1.1 christos 1709 1.1 christos if (remote_debug) 1710 1.1 christos { 1711 1.1 christos if (format && *format) 1712 1.1 christos len = strlen (format); 1713 1.1 christos else 1714 1.1 christos return; /* empty input */ 1715 1.1 christos 1716 1.1 christos if (parm && *parm) 1717 1.1 christos len += strlen (parm); 1718 1.1 christos 1719 1.1 christos for (cpy = buf; *format;) 1720 1.1 christos { 1721 1.1 christos if (format[0] == '%' && format[1] == 's') /* include second string */ 1722 1.1 christos { 1723 1.1 christos format += 2; /* advance two chars instead of just one */ 1724 1.1 christos while (parm && *parm) 1725 1.1 christos *cpy++ = *parm++; 1726 1.1 christos } 1727 1.1 christos else 1728 1.1 christos *cpy++ = *format++; 1729 1.1 christos } 1730 1.1 christos *cpy = '\0'; 1731 1.1 christos gdb_puts (buf); 1732 1.1 christos } 1733 1.1 christos } 1734 1.1 christos 1735 1.1 christos static unsigned char * 1736 1.1 christos strcpy (unsigned char *dest, const unsigned char *src) 1737 1.1 christos { 1738 1.1 christos unsigned char *ret = dest; 1739 1.1 christos 1740 1.1 christos if (dest && src) 1741 1.1 christos { 1742 1.1 christos while (*src) 1743 1.1 christos *dest++ = *src++; 1744 1.1 christos *dest = 0; 1745 1.1 christos } 1746 1.1 christos return ret; 1747 1.1 christos } 1748 1.1 christos 1749 1.1 christos static int 1750 1.1 christos strlen (const unsigned char *src) 1751 1.1 christos { 1752 1.1 christos int ret; 1753 1.1 christos 1754 1.1 christos for (ret = 0; *src; src++) 1755 1.1 christos ret++; 1756 1.1 christos 1757 1.1 christos return ret; 1758 1.1 christos } 1759 1.1 christos 1760 1.1 christos #if 0 1761 1.1 christos void 1762 1.1 christos exit (code) 1763 1.1 christos int code; 1764 1.1 christos { 1765 1.1 christos _exit (code); 1766 1.1 christos } 1767 1.1 christos 1768 1.1 christos int 1769 1.1 christos atexit (void *p) 1770 1.1 christos { 1771 1.1 christos return 0; 1772 1.1 christos } 1773 1.1 christos 1774 1.1 christos void 1775 1.1 christos abort (void) 1776 1.1 christos { 1777 1.1 christos _exit (1); 1778 1.1 christos } 1779 1.1 christos #endif 1780