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