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