d81b6e57ae4a19c8852258e3757480f7d5f97f3c
[binutils-gdb.git] / gdb / sparc-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 SPARC by Stu Grossman, 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 *************
42 *
43 * The following gdb commands are supported:
44 *
45 * command function Return value
46 *
47 * g return the value of the CPU registers hex data or ENN
48 * G set the value of the CPU registers OK or ENN
49 *
50 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
51 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
52 *
53 * c Resume at current address SNN ( signal NN)
54 * cAA..AA Continue at address AA..AA SNN
55 *
56 * s Step one instruction SNN
57 * sAA..AA Step one instruction from AA..AA SNN
58 *
59 * k kill
60 *
61 * ? What was the last sigval ? SNN (signal NN)
62 *
63 * All commands and responses are sent with a packet which includes a
64 * checksum. A packet consists of
65 *
66 * $<packet info>#<checksum>.
67 *
68 * where
69 * <packet info> :: <characters representing the command or response>
70 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
71 *
72 * When a packet is received, it is first acknowledged with either '+' or '-'.
73 * '+' indicates a successful transfer. '-' indicates a failed transfer.
74 *
75 * Example:
76 *
77 * Host: Reply:
78 * $m0,10#2a +$00010203040506070809101112131415#42
79 *
80 ****************************************************************************/
81
82 #include <stdio.h>
83 #include <string.h>
84 #include <signal.h>
85 #include <memory.h>
86
87 /************************************************************************
88 *
89 * external low-level support routines
90 */
91
92 extern putDebugChar(); /* write a single character */
93 extern getDebugChar(); /* read and return a single char */
94
95 /************************************************************************/
96 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
97 /* at least NUMREGBYTES*2 are needed for register packets */
98 #define BUFMAX 2048
99
100 static int initialized; /* boolean flag. != 0 means we've been initialized */
101
102 static void set_mem_fault_trap();
103
104 int remote_debug;
105 /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
106
107 static const char hexchars[]="0123456789abcdef";
108
109 #define NUMREGS 72
110
111 /* Number of bytes of registers. */
112 #define NUMREGBYTES (NUMREGS * 4)
113 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
114 O0, O1, O2, O3, O4, O5, SP, O7,
115 L0, L1, L2, L3, L4, L5, L6, L7,
116 I0, I1, I2, I3, I4, I5, FP, I7,
117
118 F0, F1, F2, F3, F4, F5, F6, F7,
119 F8, F9, F10, F11, F12, F13, F14, F15,
120 F16, F17, F18, F19, F20, F21, F22, F23,
121 F24, F25, F26, F27, F28, F29, F30, F31,
122 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
123
124 static unsigned long registers[NUMREGS] __attribute__ ((aligned (8)));
125
126 /*************************** ASSEMBLY CODE MACROS *************************/
127 /* */
128
129 #define BREAKPOINT() asm(" ta 1");
130
131 extern unsigned long rdtbr();
132
133 asm("
134 .text
135 !
136 ! FUNCTION
137 ! _chk4ovflo
138 !
139 ! DESCRIPTION
140 ! This code is branched to before each trap (except reset,
141 ! _win_unf, and _win_ovf) handler.
142 ! It checks to see if we've moved into the invalid window
143 ! and performs fixup ala _win_ovf.
144 !
145 ! INPUTS
146 ! - %l1 = pc at trap time.
147 ! - %l2 = npc at trap time.
148 ! - %l7 = return address.
149 !
150 ! INTERNAL DESCRIPTION
151 !
152 ! RETURNS
153 ! - None.
154 !
155
156 .align 4
157
158 _chk4ovflo:
159 mov %psr, %l0 ! get the psr
160 and %l0, 0x1F, %l3 ! get the cwp
161 mov 1, %l4 ! compare cwp with the wim
162 sll %l4, %l3, %l3 ! compare
163 mov %wim, %l4 ! read the wim
164 btst %l4, %l3
165 bz _retsave ! not invalid window, just return
166 nop
167 ! in line version of _win_ovf
168 or %l0, 0xf20, %l3 ! enable traps, disable interrupts.
169 mov %l3, %psr
170 mov %g1, %l0 ! Save %g1.
171 srl %l4, 1, %g1 ! Next WIM = %g1 = rol(WIM, 1, NWINDOW)
172 sll %l4, 8-1, %l3
173 bset %l3, %g1
174 save %g0, %g0, %g0 ! Get into window to be saved.
175 mov %g1, %wim ! Install new wim.
176 nop ! must delay three instructions
177 nop ! before using these registers, so
178 nop ! put nops in just to be safe
179
180 std %l0, [%sp + 0 * 4] ! save all local registers
181 std %l2, [%sp + 2 * 4]
182 std %l4, [%sp + 4 * 4]
183 std %l6, [%sp + 6 * 4]
184
185 std %i0, [%sp + 8 * 4]
186 std %i2, [%sp + 10 * 4]
187 std %i4, [%sp + 12 * 4]
188 std %i6, [%sp + 14 * 4]
189
190 restore ! Go back to trap window.
191 mov %l0, %g1 ! Restore %g1.
192
193 _retsave:
194 ! It is safe now to allocate a stack frame for this window
195 ! because all overflow handling will have been accomplished
196 ! in the event we trapped into the invalid window.
197 ! ie. all of this window's %o regs (next window's %i regs)
198 ! will have been safely stored to the stack before we overwrite %sp.
199
200 jmpl %l7+8, %g0 ! Window is valid, just return
201 sub %fp, (16+1+6+1)*4, %sp ! Make room for input & locals
202 ! + hidden arg + arg spill
203 ! + doubleword alignment
204
205 ! Read the TBR.
206
207 .globl _rdtbr
208 _rdtbr:
209 retl
210 mov %tbr, %o0
211
212 ! This function is called when any SPARC trap (except window overflow or
213 ! underflow) occurs. It makes sure that the invalid register window is still
214 ! available before jumping into C code. It will also restore the world if you
215 ! return from handle_exception.
216
217 _trap_low:
218 set _registers, %l0
219
220 std %g0, [%l0 + 0 * 4] ! registers[Gx]
221 std %g2, [%l0 + 2 * 4]
222 std %g4, [%l0 + 4 * 4]
223 std %g6, [%l0 + 6 * 4]
224
225 std %i0, [%l0 + 8 * 4] ! registers[Ox]
226 std %i2, [%l0 + 10 * 4]
227 std %i4, [%l0 + 12 * 4]
228 std %i6, [%l0 + 14 * 4]
229 ! F0->F31 not implemented
230 mov %y, %l4
231 mov %psr, %l5
232 mov %wim, %l6
233 mov %tbr, %l7
234 std %l4, [%l0 + 64 * 4] ! Y & PSR
235 std %l6, [%l0 + 66 * 4] ! WIM & TBR
236 st %l1, [%l0 + 68 * 4] ! PC
237 st %l2, [%l0 + 69 * 4] ! NPC
238
239 ! CPSR and FPSR not impl
240
241 sethi %hi(_chk4ovflo), %l7 ! Must call this routine via %l7
242 jmpl %l7+%lo(_chk4ovflo), %l7 ! because o regs may not be available yet
243 nop
244 mov %psr, %o1
245 bset 0xf20, %o1
246 mov %o1, %psr ! Turn on traps, disable interrupts
247
248 call _handle_exception
249 nop
250 mov %o0, %l7 ! Save return value
251
252 ! Reload all of the registers that aren't on the stack
253
254 set _registers, %l0 ! Need to use reg immune from save/rest
255
256 ld [%l0 + 1 * 4], %g1 ! registers[Gx]
257 ldd [%l0 + 2 * 4], %g2
258 ldd [%l0 + 4 * 4], %g4
259 ldd [%l0 + 6 * 4], %g6
260
261 ldd [%l0 + 8 * 4], %o0 ! registers[Ox]
262 ldd [%l0 + 10 * 4], %o2
263 ldd [%l0 + 12 * 4], %o4
264 ldd [%l0 + 14 * 4], %o6
265
266 restore ! Ensure that previous window is valid
267 save %g0, %g0, %g0 ! by causing a window_underflow trap
268
269 ld [%l0 + 64 * 4], %l3 ! registers[Y]
270 mov %l3, %y
271 ld [%l0 + 65 * 4], %l3 ! registers[PSR]
272 ld [%l0 + 68 * 4], %l1 ! registers[PC]
273 ld [%l0 + 69 * 4], %l2 ! registers[NPC]
274
275 tst %l7 ! Did handle_exception tell
276 bg retskip ! us to skip the next inst?
277 nop
278
279 mov %l3, %psr ! Make sure that traps are disabled
280 ! for rett
281 jmpl %l1, %g0 ! Restore old PC
282 rett %l2 ! Restore old nPC
283
284 mov %l3, %psr ! Make sure that traps are disabled
285 ! for rett
286 retskip: ! Come here to skip the next instruction
287 jmpl %l2, %g0 ! Old nPC
288 rett %l2+4 ! Old nPC+4
289 ");
290
291 /* Convert ch from a hex digit to an int */
292
293 static int
294 hex(ch)
295 unsigned char ch;
296 {
297 if (ch >= 'a' && ch <= 'f')
298 return ch-'a'+10;
299 if (ch >= '0' && ch <= '9')
300 return ch-'0';
301 if (ch >= 'A' && ch <= 'F')
302 return ch-'A'+10;
303 return -1;
304 }
305
306 /* scan for the sequence $<data>#<checksum> */
307
308 static void
309 getpacket(buffer)
310 char *buffer;
311 {
312 unsigned char checksum;
313 unsigned char xmitcsum;
314 int i;
315 int count;
316 unsigned char ch;
317
318 do
319 {
320 /* wait around for the start character, ignore all other characters */
321 while ((ch = getDebugChar()) != '$') ;
322
323 checksum = 0;
324 xmitcsum = -1;
325
326 count = 0;
327
328 /* now, read until a # or end of buffer is found */
329 while (count < BUFMAX)
330 {
331 ch = getDebugChar();
332 if (ch == '#')
333 break;
334 checksum = checksum + ch;
335 buffer[count] = ch;
336 count = count + 1;
337 }
338
339 if (count >= BUFMAX)
340 continue;
341
342 buffer[count] = 0;
343
344 if (ch == '#')
345 {
346 xmitcsum = hex(getDebugChar()) << 4;
347 xmitcsum |= hex(getDebugChar());
348 #ifdef DEBUG
349 if (remote_debug && checksum != xmitcsum)
350 {
351 fprintf(stderr, "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
352 checksum,xmitcsum,buffer);
353 }
354 #endif
355 #if 1
356 /* Humans shouldn't have to figure out checksums to type to it. */
357 putDebugChar ('+');
358 return;
359 #endif
360 if (checksum != xmitcsum)
361 putDebugChar('-'); /* failed checksum */
362 else
363 {
364 putDebugChar('+'); /* successful transfer */
365 /* if a sequence char is present, reply the sequence ID */
366 if (buffer[2] == ':')
367 {
368 putDebugChar(buffer[0]);
369 putDebugChar(buffer[1]);
370 /* remove sequence chars from buffer */
371 count = strlen(buffer);
372 for (i=3; i <= count; i++)
373 buffer[i-3] = buffer[i];
374 }
375 }
376 }
377 }
378 while (checksum != xmitcsum);
379 }
380
381 /* send the packet in buffer. */
382
383 static void
384 putpacket(buffer)
385 unsigned char *buffer;
386 {
387 unsigned char checksum;
388 int count;
389 unsigned char ch;
390
391 /* $<packet info>#<checksum>. */
392 do
393 {
394 putDebugChar('$');
395 checksum = 0;
396 count = 0;
397
398 while (ch = buffer[count])
399 {
400 if (! putDebugChar(ch))
401 return;
402 checksum += ch;
403 count += 1;
404 }
405
406 putDebugChar('#');
407 putDebugChar(hexchars[checksum >> 4]);
408 putDebugChar(hexchars[checksum & 0xf]);
409
410 }
411 while (getDebugChar() != '+');
412 }
413
414 static unsigned char remcomInBuffer[BUFMAX];
415 static unsigned char remcomOutBuffer[BUFMAX];
416 static short error;
417
418 static void
419 debug_error(format, parm)
420 char *format;
421 char *parm;
422 {
423 #ifdef DEBUG
424 if (remote_debug)
425 fprintf(stderr,format,parm);
426 #endif
427 }
428
429 /* Address of a routine to RTE to if we get a memory fault. */
430 static void (*mem_fault_routine)() = NULL;
431
432 /* Indicate to caller of mem2hex or hex2mem that there has been an
433 error. */
434
435 static volatile int mem_err = 0;
436
437 /* These are separate functions so that they are so short and sweet
438 that the compiler won't save any registers (if there is a fault
439 to mem_fault, they won't get restored, so there better not be any
440 saved). */
441 static int
442 get_char (addr)
443 char *addr;
444 {
445 return *addr;
446 }
447
448 static void
449 set_char (addr, val)
450 char *addr;
451 int val;
452 {
453 *addr = val;
454 }
455
456 /* Convert the memory pointed to by mem into hex, placing result in buf.
457 * Return a pointer to the last char put in buf (null), in case of mem fault,
458 * return 0.
459 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
460 * a 0, else treat a fault like any other fault in the stub.
461 */
462
463 static unsigned char *
464 mem2hex(mem, buf, count, may_fault)
465 unsigned char *mem;
466 unsigned char *buf;
467 int count;
468 int may_fault;
469 {
470 unsigned char ch;
471
472 set_mem_fault_trap(may_fault);
473
474 while (count-- > 0)
475 {
476 ch = get_char(mem++);
477 if (mem_err)
478 return 0;
479 *buf++ = hexchars[ch >> 4];
480 *buf++ = hexchars[ch & 0xf];
481 }
482
483 *buf = 0;
484
485 set_mem_fault_trap(0);
486
487 return buf;
488 }
489
490 /* convert the hex array pointed to by buf into binary to be placed in mem
491 * return a pointer to the character AFTER the last byte written */
492
493 static char *
494 hex2mem(buf, mem, count, may_fault)
495 unsigned char *buf;
496 unsigned char *mem;
497 int count;
498 int may_fault;
499 {
500 int i;
501 unsigned char ch;
502
503 set_mem_fault_trap(may_fault);
504
505 for (i=0; i<count; i++)
506 {
507 ch = hex(*buf++) << 4;
508 ch |= hex(*buf++);
509 set_char(mem++, ch);
510 if (mem_err)
511 return 0;
512 }
513
514 set_mem_fault_trap(0);
515
516 return mem;
517 }
518
519 /* this function takes the SPARC trap type code and attempts to
520 translate this number into a unix compatible signal value */
521
522 static int
523 computeSignal(tt)
524 int tt;
525 {
526 int sigval;
527
528 switch (tt)
529 {
530 case 1:
531 sigval = SIGSEGV; break; /* instruction access error */
532 case 2:
533 sigval = SIGILL; break; /* privileged instruction */
534 case 3:
535 sigval = SIGILL; break; /* illegal instruction */
536 case 4:
537 sigval = SIGEMT; break; /* fp disabled */
538 case 36:
539 sigval = SIGEMT; break; /* cp disabled */
540 case 7:
541 sigval = SIGBUS; break; /* mem address not aligned */
542 case 9:
543 sigval = SIGSEGV; break; /* data access exception */
544 case 10:
545 sigval = SIGEMT; break; /* tag overflow */
546 case 128+1: /* ta 1 - normal breakpoint instruction */
547 case 255: /* breakpoint hardware unique to SPARClite */
548 sigval = SIGTRAP; break; /* breakpoint trap */
549 default:
550 sigval = SIGHUP; /* "software generated"*/
551 }
552 return (sigval);
553 }
554
555 /*
556 * While we find nice hex chars, build an int.
557 * Return number of chars processed.
558 */
559
560 static int
561 hexToInt(char **ptr, int *intValue)
562 {
563 int numChars = 0;
564 int hexValue;
565
566 *intValue = 0;
567
568 while (**ptr)
569 {
570 hexValue = hex(**ptr);
571 if (hexValue >=0)
572 {
573 *intValue = (*intValue <<4) | hexValue;
574 numChars ++;
575 }
576 else
577 break;
578
579 (*ptr)++;
580 }
581
582 return (numChars);
583 }
584
585 /*
586 * This function does all command procesing for interfacing to gdb. It
587 * returns 1 if you should skip the instruction at the trap address, 0
588 * otherwise.
589 */
590
591 static int
592 handle_exception ()
593 {
594 int tt; /* Trap type */
595 int sigval;
596 int addr;
597 int length;
598 char *ptr;
599 int newPC;
600 unsigned char *sp;
601 unsigned char *com;
602
603 /* First, we must force all of the windows to be spilled out */
604
605 asm(" save %g0, -64, %g0
606 save %g0, -64, %g0
607 save %g0, -64, %g0
608 save %g0, -64, %g0
609 save %g0, -64, %g0
610 save %g0, -64, %g0
611 save %g0, -64, %g0
612 save %g0, -64, %g0
613 restore
614 restore
615 restore
616 restore
617 restore
618 restore
619 restore
620 restore
621 ");
622
623 #if 0
624 writez(1, "Got to handle_exception()\r\n ");
625
626 writez(1, "psr = 0x");
627 numout(registers[PSR], 16);
628 writez(1, " tbr = 0x");
629 numout(registers[TBR], 16);
630 writez(1, " oldpc = 0x");
631 numout(registers[PC], 16);
632 writez(1, " oldnpc = 0x");
633 numout(registers[NPC], 16);
634 writez(1, "\r\n");
635 #endif
636
637 sp = (unsigned char *)registers[SP];
638
639 tt = (registers[TBR] >> 4) & 0xff;
640
641 #ifdef DEBUG
642 if (remote_debug)
643 printf("tbr=0x%x, tt=%d, psr=0x%x, pc=0x%x, npc=0x%x\n",
644 registers[TBR], (registers[TBR] >> 4) & 0xff, registers[PSR], registers[PC], registers[NPC]);
645 #endif
646
647 /* reply to host that an exception has occurred */
648 sigval = computeSignal(tt);
649 com = remcomOutBuffer;
650
651 *com++ = 'T';
652 *com++ = hexchars[sigval >> 4];
653 *com++ = hexchars[sigval & 0xf];
654
655 *com++ = hexchars[PC >> 4];
656 *com++ = hexchars[PC & 0xf];
657 com = mem2hex((char *)&registers[PC], com, 4, 0);
658
659 *com++ = hexchars[FP >> 4];
660 *com++ = hexchars[FP & 0xf];
661 com = mem2hex(sp + (8 + 6) * 4, com, 4, 0); /* FP */
662
663 *com++ = hexchars[SP >> 4];
664 *com++ = hexchars[SP & 0xf];
665 com = mem2hex((char *)&registers[SP], com, 4, 0);
666
667 *com++ = hexchars[NPC >> 4];
668 *com++ = hexchars[NPC & 0xf];
669 com = mem2hex((char *)&registers[NPC], com, 4, 0);
670
671 *com++ = 0;
672
673 putpacket(remcomOutBuffer);
674
675 while (1)
676 {
677 error = 0;
678 remcomOutBuffer[0] = 0;
679
680 getpacket(remcomInBuffer);
681 switch (remcomInBuffer[0])
682 {
683 case '?':
684 remcomOutBuffer[0] = 'S';
685 remcomOutBuffer[1] = hexchars[sigval >> 4];
686 remcomOutBuffer[2] = hexchars[sigval & 0xf];
687 remcomOutBuffer[3] = 0;
688 break;
689
690 case 'd':
691 remote_debug = !remote_debug; /* toggle debug flag */
692 break;
693
694 case 'g': /* return the value of the CPU registers */
695 {
696 com = remcomOutBuffer;
697 com = mem2hex((char *)registers, com, 16 * 4, 0); /* G & O regs */
698 com = mem2hex(sp + 0 * 4, com, 8 * 4, 0); /* L regs */
699 com = mem2hex(sp + 8 * 4, com, 8 * 4, 0); /* I regs */
700 memset(com, '0', 32 * 8); /* Floating point */
701 mem2hex((char *)&registers[Y],
702 com + 32 * 4 * 2,
703 8 * 4,
704 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
705 }
706 break;
707
708 case 'G': /* set the value of the CPU registers - return OK */
709 {
710 com = &remcomInBuffer[1];
711 hex2mem(com, (char *)registers, 16 * 4, 0); /* G & O regs */
712 hex2mem(com + 16 * 4 * 2, sp + 0 * 4, 8 * 4, 0); /* L regs */
713 hex2mem(com + 24 * 4 * 2, sp + 8 * 4, 8 * 4, 0); /* I regs */
714 hex2mem(com + 64 * 4 * 2, (char *)&registers[Y],
715 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
716 strcpy(remcomOutBuffer,"OK");
717 }
718 break;
719
720 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
721 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
722
723 ptr = &remcomInBuffer[1];
724
725 if (hexToInt(&ptr, &addr)
726 && *ptr++ == ','
727 && hexToInt(&ptr, &length))
728 {
729 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
730 break;
731
732 strcpy (remcomOutBuffer, "E03");
733 debug_error ("memory fault");
734 }
735 else
736 {
737 strcpy(remcomOutBuffer,"E01");
738 debug_error("malformed read memory command: %s",remcomInBuffer);
739 }
740 break;
741
742 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
743 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
744
745 ptr = &remcomInBuffer[1];
746
747 if (hexToInt(&ptr, &addr)
748 && *ptr++ == ','
749 && hexToInt(&ptr, &length)
750 && *ptr++ == ':')
751 {
752 if (hex2mem(ptr, (char *)addr, length, 1))
753 strcpy(remcomOutBuffer, "OK");
754 else
755 {
756 strcpy(remcomOutBuffer, "E03");
757 debug_error("memory fault");
758 }
759 }
760 else
761 {
762 strcpy(remcomOutBuffer, "E02");
763 debug_error("malformed write memory command: %s",remcomInBuffer);
764 }
765 break;
766
767 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
768 case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
769 /* try to read optional parameter, pc unchanged if no parm */
770
771 ptr = &remcomInBuffer[1];
772 if (hexToInt(&ptr, &addr))
773 {
774 registers[PC] = addr;
775 registers[NPC] = addr + 4;
776 }
777
778 return 0;
779
780 /* kill the program */
781 case 'k' : /* do nothing */
782 break;
783 } /* switch */
784
785 /* reply to the request */
786 putpacket(remcomOutBuffer);
787 }
788 }
789
790 /* Each entry in the trap vector occupies four words. */
791
792 struct trap_entry
793 {
794 unsigned long ti[4];
795 };
796
797 #define NUMTRAPS 256
798
799 /* static struct trap_entry oldvec[NUMTRAPS];*/
800
801 extern struct trap_entry fltr_proto;
802 extern struct trap_entry fltr_set_mem_err;
803 asm ("
804 .data
805 .globl _fltr_proto
806 .align 4
807 _fltr_proto: ! First level trap routine prototype
808 sethi %hi(_trap_low), %l0
809 jmpl %lo(_trap_low)+%l0, %g0
810 nop
811 nop
812
813 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
814 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
815 ! 0 would ever contain code that could mem fault. This routine will skip
816 ! past the faulting instruction after setting mem_err.
817
818 _fltr_set_mem_err:
819 sethi %hi(_mem_err), %l0
820 st %l1, [%l0 + %lo(_mem_err)]
821 jmpl %l2, %g0
822 rett %l2+4
823
824 .text
825 ");
826
827 /* this function is used to set up exception handlers for tracing and
828 breakpoints */
829
830 void
831 set_debug_traps()
832 {
833 int exception;
834 struct trap_entry *tb; /* Trap vector base address */
835
836 writez(1, "Got to set_debug_traps\r\n");
837
838 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
839
840 writez(1, "tb = 0x");
841 numout(tb, 16);
842 writez(1, " trap ins = 0x");
843 numout(fltr_proto, 16);
844 writez(1, "\r\n");
845
846 tb[1] = fltr_proto; /* instruction access exception */
847 tb[2] = fltr_proto; /* privileged instruction */
848 tb[3] = fltr_proto; /* illegal instruction */
849 tb[4] = fltr_proto; /* fp disabled */
850 tb[36] = fltr_proto; /* cp disabled */
851 tb[7] = fltr_proto; /* mem address not aligned */
852 tb[9] = fltr_proto; /* data access exception */
853 tb[10] = fltr_proto; /* tag overflow */
854 tb[128+1] = fltr_proto; /* breakpoint instruction (ta 1) */
855 tb[255] = fltr_proto; /* hardware breakpoint trap */
856
857 /* In case GDB is started before us, ack any packets (presumably
858 "$?#xx") sitting there. */
859
860 putDebugChar ('+');
861
862 initialized = 1;
863 }
864
865 static void
866 set_mem_fault_trap(enable)
867 int enable;
868 {
869 struct trap_entry *tb; /* Trap vector base address */
870
871 mem_err = 0;
872
873 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
874
875 if (enable)
876 tb[9] = fltr_set_mem_err;
877 else
878 tb[9] = fltr_proto;
879 }
880
881 /* This function will generate a breakpoint exception. It is used at the
882 beginning of a program to sync up with a debugger and can be used
883 otherwise as a quick means to stop program execution and "break" into
884 the debugger. */
885
886 void
887 breakpoint()
888 {
889 writez(1, "About to do a breakpoint\r\n\n");
890 if (initialized)
891 BREAKPOINT();
892 }