1 /****************************************************************************
3 * Module name: remcom.c $
5 * Date: 91/03/09 12:29:49 $
6 * Contributor: Lake Stevens Instrument Division$
8 * Description: low level support for gdb debugger. $
10 * Considerations: only works on target hardware $
12 * Written by: Glenn Engel $
13 * ModuleState: Experimental $
17 * Modified for SPARC by Stu Grossman, Cygnus Support.
19 * This code has been extensively tested on the Fujitsu SPARClite demo board.
21 * To enable debugger support, two things need to happen. One, a
22 * call to set_debug_traps() is necessary in order to allow any breakpoints
23 * or error conditions to be properly intercepted and reported to gdb.
24 * Two, a breakpoint needs to be generated to begin communication. This
25 * is most easily accomplished by a call to breakpoint(). Breakpoint()
26 * simulates a breakpoint by executing a trap #1.
30 * The following gdb commands are supported:
32 * command function Return value
34 * g return the value of the CPU registers hex data or ENN
35 * G set the value of the CPU registers OK or ENN
37 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
38 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
40 * c Resume at current address SNN ( signal NN)
41 * cAA..AA Continue at address AA..AA SNN
43 * s Step one instruction SNN
44 * sAA..AA Step one instruction from AA..AA SNN
48 * ? What was the last sigval ? SNN (signal NN)
50 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
53 * All commands and responses are sent with a packet which includes a
54 * checksum. A packet consists of
56 * $<packet info>#<checksum>.
59 * <packet info> :: <characters representing the command or response>
60 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
62 * When a packet is received, it is first acknowledged with either '+' or '-'.
63 * '+' indicates a successful transfer. '-' indicates a failed transfer.
68 * $m0,10#2a +$00010203040506070809101112131415#42
70 ****************************************************************************/
78 /************************************************************************
80 * external low-level support routines
83 extern putchar(); /* write a single character */
84 extern getchar(); /* read and return a single char */
86 /************************************************************************/
88 /* Stuff for stdio-like gets_debugger_check() */
90 #define CTRL(x) ('x'&0x1f)
96 #define BUFSIZE 512 /* Big enough for register packets */
98 static int initialized
= 0; /* !0 means we've been initialized */
100 static char hexchars
[]="0123456789abcdef";
102 extern unsigned int _regs
[]; /* Saved registers from client */
104 /* Convert ch from a hex digit to an int */
110 if (ch
>= 'a' && ch
<= 'f')
112 if (ch
>= '0' && ch
<= '9')
114 if (ch
>= 'A' && ch
<= 'F')
119 /* scan for the sequence $<data>#<checksum> */
125 unsigned char checksum
;
126 unsigned char xmitcsum
;
131 /* At this point, the start character ($) has been received through
132 * the debug monitor parser. Get the remaining characters and
140 /* read until a # or end of buffer is found */
142 while (count
< BUFSIZE
)
147 checksum
= checksum
+ ch
;
152 if (count
>= BUFSIZE
)
157 xmitcsum
= hex(getchar()) << 4;
158 xmitcsum
|= hex(getchar());
160 /* Humans shouldn't have to figure out checksums to type to it. */
165 if (checksum
!= xmitcsum
)
167 putchar('-'); /* failed checksum */
168 return; /* Back to monitor loop */
172 putchar('+'); /* successful transfer */
174 /* if a sequence char is present, reply the sequence ID */
176 if (buffer
[2] == ':')
181 /* remove sequence chars from buffer */
183 count
= strlen(buffer
);
184 for (i
=3; i
<= count
; i
++)
185 buffer
[i
-3] = buffer
[i
];
188 /* Buffer command received- go and process it. */
196 /* send the packet in buffer. */
200 unsigned char *buffer
;
202 unsigned char checksum
;
206 /* $<packet info>#<checksum>. */
213 while (ch
= buffer
[count
])
222 putchar(hexchars
[checksum
>> 4]);
223 putchar(hexchars
[checksum
& 0xf]);
226 while (getchar() != '+');
229 static char remcomInBuffer
[BUFSIZE
];
230 static char remcomOutBuffer
[BUFSIZE
];
232 /* Indicate to caller of mem2hex or hex2mem that there has been an error. */
234 static volatile int mem_err
= 0;
236 /* Convert the memory pointed to by mem into hex, placing result in buf.
237 * Return a pointer to the last char put in buf (null), in case of mem fault,
239 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
240 * a 0, else treat a fault like any other fault in the stub.
243 static unsigned char *
244 mem2hex(mem
, buf
, count
, may_fault
)
257 *buf
++ = hexchars
[ch
>> 4];
258 *buf
++ = hexchars
[ch
& 0xf];
266 /* convert the hex array pointed to by buf into binary to be placed in mem
267 * return a pointer to the character AFTER the last byte written */
270 hex2mem(buf
, mem
, count
, may_fault
)
279 for (i
=0; i
<count
; i
++)
281 ch
= hex(*buf
++) << 4;
291 /* This table contains the mapping between SPARC hardware trap types, and
292 signals, which are primarily what GDB understands. It also indicates
293 which hardware traps we need to commandeer when initializing the stub. */
295 static struct hard_trap_info
297 unsigned char tt
; /* Trap type code for SPARClite */
298 unsigned char signo
; /* Signal that we map this trap into */
299 } hard_trap_info
[] = {
300 {0x06, SIGSEGV
}, /* instruction access error */
301 {0x0a, SIGILL
}, /* privileged instruction */
302 {0x0a, SIGILL
}, /* illegal instruction */
303 {0x0b, SIGEMT
}, /* cp disabled */
304 {0x07, SIGSEGV
}, /* data access exception */
305 {0x09, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
306 {0, 0} /* Must be last */
309 /* Convert the SPARC hardware trap type code to a unix signal number. */
315 struct hard_trap_info
*ht
;
317 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
321 return SIGHUP
; /* default for things we don't know about */
325 * While we find nice hex chars, build an int.
326 * Return number of chars processed.
330 hexToInt(char **ptr
, int *intValue
)
339 hexValue
= hex(**ptr
);
343 *intValue
= (*intValue
<< 4) | hexValue
;
352 /* This function lets GDB know that an exception has occured. */
355 debug_handle_exception ()
357 int tt
; /* Trap type */
361 tt
= (_regs
[R_CAUSE
] >> 2) & 0x0f;
363 /* reply to host that an exception has occurred */
364 sigval
= computeSignal(tt
);
365 ptr
= remcomOutBuffer
;
368 *ptr
++ = hexchars
[sigval
>> 4];
369 *ptr
++ = hexchars
[sigval
& 0xf];
371 *ptr
++ = hexchars
[R_EPC
>> 4];
372 *ptr
++ = hexchars
[R_EPC
& 0xf];
374 ptr
= mem2hex((char *)&_regs
[R_EPC
], ptr
, 4, 0);
377 *ptr
++ = hexchars
[R_FP
>> 4];
378 *ptr
++ = hexchars
[R_FP
& 0xf];
380 ptr
= mem2hex((char *)&_regs
[R_FP
], ptr
, 4, 0);
383 *ptr
++ = hexchars
[R_SP
>> 4];
384 *ptr
++ = hexchars
[R_SP
& 0xf];
386 ptr
= mem2hex((char *)&_regs
[R_SP
], ptr
, 4, 0);
391 putpacket(remcomOutBuffer
);
397 void process_packet()
404 int tt
; /* Trap type */
406 remcomOutBuffer
[0] = 0;
407 getpacket(remcomInBuffer
);
408 switch (remcomInBuffer
[0])
411 /* Return Last SIGVAL */
414 tt
= (_regs
[R_CAUSE
] >> 2) & 0x0f;
415 sigval
= computeSignal(tt
);
416 remcomOutBuffer
[0] = 'S';
417 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
418 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
419 remcomOutBuffer
[3] = 0;
422 /* toggle debug flag */
427 /* Return the values of the CPU registers */
430 ptr
= remcomOutBuffer
;
431 ptr
= mem2hex((char *)_regs
, ptr
, 32 * 4, 0); /* General Purpose Registers */
432 ptr
= mem2hex((char *)&_regs
[R_EPC
], ptr
, 9 * 4, 0); /* CP0 Registers */
435 /* set the value of the CPU registers - return OK */
438 ptr
= &remcomInBuffer
[1];
439 hex2mem(ptr
, (char *)_regs
, 32 * 4, 0); /* General Purpose Registers */
440 hex2mem(ptr
+ 32 * 4 * 2, (char *)&_regs
[R_EPC
], 9 * 4, 0); /* CP0 Registers */
441 strcpy(remcomOutBuffer
,"OK");
444 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
447 ptr
= &remcomInBuffer
[1];
448 if (hexToInt(&ptr
, &addr
) && *ptr
++ == ',' && hexToInt(&ptr
, &length
))
450 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
452 strcpy (remcomOutBuffer
, "E03");
455 strcpy(remcomOutBuffer
,"E01");
458 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
461 ptr
= &remcomInBuffer
[1];
462 if (hexToInt(&ptr
, &addr
) && *ptr
++ == ',' && hexToInt(&ptr
, &length
) && *ptr
++ == ':')
464 if (hex2mem(ptr
, (char *)addr
, length
, 1))
465 strcpy(remcomOutBuffer
, "OK");
467 strcpy(remcomOutBuffer
, "E03");
470 strcpy(remcomOutBuffer
, "E02");
473 /* cAA..AA Continue at address AA..AA(optional) */
477 /* try to read optional parameter, pc unchanged if no parm */
479 ptr
= &remcomInBuffer
[1];
480 if (hexToInt(&ptr
, &addr
))
490 /* kill the program */
504 /* Reply to the request */
506 putpacket(remcomOutBuffer
);
511 * gets_debugger_check - This is the same as the stdio gets, but we also
512 * check for a leading $ in the buffer. This so we
513 * gracefully handle the GDB protocol packets.
517 gets_debugger_check(buf
)
530 /* quote next char */
539 if (bufp
< &buf
[LINESIZE
-3])
570 printf("^U\n%s", PROMPT
);
580 * Make sure there's room for this character
581 * plus a trailing \n and 0 byte
583 if (isprint(c
) && bufp
< &buf
[LINESIZE
-3])
585 rmw_byte ( bufp
++, c
);