1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or its performance and the
7 user accepts the software "AS IS" with all faults.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for FreeBSD by Stu Grossman.
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.
41 * The external function exceptionHandler() is
42 * used to attach a specific handler to a specific 386 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 * Also, need to assign exceptionHook and oldExceptionHook.
48 * Because gdb will sometimes write to the stack area to execute function
49 * calls, this program cannot rely on using the supervisor stack so it
50 * uses its own stack area reserved in the int array remcomStack.
54 * The following gdb commands are supported:
56 * command function Return value
58 * g return the value of the CPU registers hex data or ENN
59 * G set the value of the CPU registers OK or ENN
61 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
62 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
64 * c Resume at current address SNN ( signal NN)
65 * cAA..AA Continue at address AA..AA SNN
67 * s Step one instruction SNN
68 * sAA..AA Step one instruction from AA..AA SNN
72 * ? What was the last sigval ? SNN (signal NN)
76 * All commands and responses are sent with a packet which includes a
77 * checksum. A packet consists of
79 * $<packet info>#<checksum>.
82 * <packet info> :: <characters representing the command or response>
83 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
85 * When a packet is received, it is first acknowledged with either '+' or '-'.
86 * '+' indicates a successful transfer. '-' indicates a failed transfer.
91 * $m0,10#2a +$00010203040506070809101112131415#42
93 ****************************************************************************/
95 * $FreeBSD: src/sys/i386/i386/i386-gdbstub.c,v 1.13.2.1 2000/08/03 00:54:41 peter Exp $
96 * $DragonFly: src/sys/cpu/amd64/misc/amd64-gdbstub.c,v 1.1 2008/08/29 17:07:09 dillon Exp $
101 #include <sys/param.h>
102 #include <sys/reboot.h>
103 #include <sys/systm.h>
104 #include <sys/cons.h>
110 void gdb_handle_exception (db_regs_t
*, int, int);
112 /************************************************************************/
114 extern jmp_buf db_jmpbuf
;
116 /************************************************************************/
117 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
118 /* at least NUMREGBYTES*2 are needed for register packets */
121 /* Create private copies of common functions used by the stub. This prevents
122 nasty interactions between app code and the stub (for instance if user steps
123 into strlen, etc..) */
125 #define strlen gdb_strlen
126 #define strcpy gdb_strcpy
129 strlen (const char *s
)
133 while (*s1
++ != '\000');
139 strcpy (char *dst
, const char *src
)
143 while ((*dst
++ = *src
++) != '\000');
149 putDebugChar (int c
) /* write a single character */
153 gdb_tab
->cn_putc(gdb_tab
->cn_gdbprivate
, c
);
158 getDebugChar (void) /* read and return a single char */
162 return gdb_tab
->cn_getc(gdb_tab
->cn_gdbprivate
);
165 static const char hexchars
[]="0123456789abcdef";
170 if ((ch
>= 'a') && (ch
<= 'f')) return (ch
-'a'+10);
171 if ((ch
>= '0') && (ch
<= '9')) return (ch
-'0');
172 if ((ch
>= 'A') && (ch
<= 'F')) return (ch
-'A'+10);
176 /* scan for the sequence $<data>#<checksum> */
178 getpacket (char *buffer
)
180 unsigned char checksum
;
181 unsigned char xmitcsum
;
188 /* wait around for the start character, ignore all other characters */
190 while ((ch
= (getDebugChar () & 0x7f)) != '$');
197 /* now, read until a # or end of buffer is found */
199 while (count
< BUFMAX
)
201 ch
= getDebugChar () & 0x7f;
204 checksum
= checksum
+ ch
;
212 xmitcsum
= hex (getDebugChar () & 0x7f) << 4;
213 xmitcsum
+= hex (getDebugChar () & 0x7f);
215 if (checksum
!= xmitcsum
)
216 putDebugChar ('-'); /* failed checksum */
219 putDebugChar ('+'); /* successful transfer */
220 /* if a sequence char is present, reply the sequence ID */
221 if (buffer
[2] == ':')
223 putDebugChar (buffer
[0]);
224 putDebugChar (buffer
[1]);
226 /* remove sequence chars from buffer */
228 count
= strlen (buffer
);
229 for (i
=3; i
<= count
; i
++)
230 buffer
[i
-3] = buffer
[i
];
235 while (checksum
!= xmitcsum
);
238 /* send the packet in buffer. */
241 putpacket (char *buffer
)
243 unsigned char checksum
;
247 /* $<packet info>#<checksum>. */
251 * This is a non-standard hack to allow use of the serial console for
252 * operation as well as debugging. Simply turn on 'remotechat' in gdb.
254 * This extension is not part of the Cygnus protocol, is kinda gross,
255 * but gets the job done.
257 #ifdef GDB_REMOTE_CHAT
267 while ((ch
=buffer
[count
]) != 0)
275 putDebugChar (hexchars
[checksum
>> 4]);
276 putDebugChar (hexchars
[checksum
& 0xf]);
278 while ((getDebugChar () & 0x7f) != '+');
281 static char remcomInBuffer
[BUFMAX
];
282 static char remcomOutBuffer
[BUFMAX
];
285 get_char (vm_offset_t addr
)
289 if (setjmp (db_jmpbuf
))
292 db_read_bytes (addr
, 1, &data
);
298 set_char (vm_offset_t addr
, int val
)
302 if (setjmp (db_jmpbuf
))
307 db_write_bytes (addr
, 1, &data
);
311 /* convert the memory pointed to by mem into hex, placing result in buf */
312 /* return a pointer to the last char put in buf (null) */
315 mem2hex (vm_offset_t mem
, char *buf
, int count
)
320 for (i
=0;i
<count
;i
++) {
321 ch
= get_char (mem
++);
324 *buf
++ = hexchars
[ch
>> 4];
325 *buf
++ = hexchars
[ch
% 16];
331 /* convert the hex array pointed to by buf into binary to be placed in mem */
332 /* return a pointer to the character AFTER the last byte written */
334 hex2mem (char *buf
, vm_offset_t mem
, int count
)
340 for (i
=0;i
<count
;i
++) {
341 ch
= hex(*buf
++) << 4;
342 ch
= ch
+ hex(*buf
++);
343 rv
= set_char (mem
++, ch
);
350 /* this function takes the 386 exception vector and attempts to
351 translate this number into a unix compatible signal value */
353 computeSignal (int exceptionVector
)
356 switch (exceptionVector
& ~T_USER
)
358 case 0: sigval
= 8; break; /* divide by zero */
359 case 1: sigval
= 5; break; /* debug exception */
360 case 3: sigval
= 5; break; /* breakpoint */
361 case 4: sigval
= 16; break; /* into instruction (overflow) */
362 case 5: sigval
= 16; break; /* bound instruction */
363 case 6: sigval
= 4; break; /* Invalid opcode */
364 case 7: sigval
= 8; break; /* coprocessor not available */
365 case 8: sigval
= 7; break; /* double fault */
366 case 9: sigval
= 11; break; /* coprocessor segment overrun */
367 case 10: sigval
= 5; break; /* Invalid TSS (also single-step) */
368 case 11: sigval
= 11; break; /* Segment not present */
369 case 12: sigval
= 11; break; /* stack exception */
370 case 13: sigval
= 11; break; /* general protection */
371 case 14: sigval
= 11; break; /* page fault */
372 case 16: sigval
= 7; break; /* coprocessor error */
374 sigval
= 7; /* "software generated"*/
380 * While we find nice hex chars, build an int.
381 * Return number of chars processed.
385 hexToInt(char **ptr
, int *intValue
)
394 hexValue
= hex(**ptr
);
397 *intValue
= (*intValue
<<4) | hexValue
;
410 * While we find nice hex chars, build a long.
411 * Return number of chars processed.
415 hexToLong(char **ptr
, long *longValue
)
424 hexValue
= hex(**ptr
);
427 *longValue
= (*longValue
<<4) | hexValue
;
439 #define NUMREGBYTES (sizeof registers)
446 * This function does all command procesing for interfacing to gdb.
449 gdb_handle_exception (db_regs_t
*raw_regs
, int type
, int code
)
473 unsigned long rflags
;
477 struct amd64regs registers
;
479 registers
.rax
= raw_regs
->tf_rax
;
480 registers
.rbx
= raw_regs
->tf_rbx
;
481 registers
.rcx
= raw_regs
->tf_rcx
;
482 registers
.rdx
= raw_regs
->tf_rdx
;
484 registers
.rsp
= raw_regs
->tf_rsp
;
485 registers
.rbp
= raw_regs
->tf_rbp
;
486 registers
.rsi
= raw_regs
->tf_rsi
;
487 registers
.rdi
= raw_regs
->tf_rdi
;
489 registers
.r8
= raw_regs
->tf_r8
;
490 registers
.r9
= raw_regs
->tf_r9
;
491 registers
.r10
= raw_regs
->tf_r10
;
492 registers
.r11
= raw_regs
->tf_r11
;
493 registers
.r12
= raw_regs
->tf_r12
;
494 registers
.r13
= raw_regs
->tf_r13
;
495 registers
.r14
= raw_regs
->tf_r14
;
496 registers
.r15
= raw_regs
->tf_r15
;
498 registers
.rip
= raw_regs
->tf_rip
;
499 registers
.rflags
= raw_regs
->tf_rflags
;
501 registers
.cs
= raw_regs
->tf_cs
;
502 registers
.ss
= raw_regs
->tf_ss
;
504 /* reply to host that an exception has occurred */
505 sigval
= computeSignal (type
);
506 ptr
= remcomOutBuffer
;
509 *ptr
++ = hexchars
[sigval
>> 4];
510 *ptr
++ = hexchars
[sigval
& 0xf];
512 *ptr
++ = hexchars
[PC
>> 4];
513 *ptr
++ = hexchars
[PC
& 0xf];
515 ptr
= mem2hex ((vm_offset_t
)®isters
.rip
, ptr
, 8);
518 *ptr
++ = hexchars
[FP
>> 4];
519 *ptr
++ = hexchars
[FP
& 0xf];
521 ptr
= mem2hex ((vm_offset_t
)®isters
.rbp
, ptr
, 8);
524 *ptr
++ = hexchars
[SP
>> 4];
525 *ptr
++ = hexchars
[SP
& 0xf];
527 ptr
= mem2hex ((vm_offset_t
)®isters
.rsp
, ptr
, 8);
532 putpacket (remcomOutBuffer
);
536 remcomOutBuffer
[0] = 0;
538 getpacket (remcomInBuffer
);
539 switch (remcomInBuffer
[0])
542 remcomOutBuffer
[0] = 'S';
543 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
544 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
545 remcomOutBuffer
[3] = 0;
548 case 'D': /* detach; say OK and turn off gdb */
549 putpacket(remcomOutBuffer
);
550 boothowto
&= ~RB_GDB
;
553 case 'g': /* return the value of the CPU registers */
554 mem2hex ((vm_offset_t
)®isters
, remcomOutBuffer
, NUMREGBYTES
);
557 case 'G': /* set the value of the CPU registers - return OK */
558 hex2mem (&remcomInBuffer
[1], (vm_offset_t
)®isters
, NUMREGBYTES
);
559 strcpy (remcomOutBuffer
, "OK");
562 case 'P': /* Set the value of one register */
566 ptr
= &remcomInBuffer
[1];
568 if (hexToInt (&ptr
, ®no
)
573 hex2mem (ptr
, (vm_offset_t
)®isters
+ regno
* 8, 8);
574 strcpy(remcomOutBuffer
,"OK");
577 strcpy (remcomOutBuffer
, "P01");
580 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
581 /* Try to read %x,%x. */
583 ptr
= &remcomInBuffer
[1];
585 if (hexToLong (&ptr
, &addr
)
587 && hexToInt (&ptr
, &length
))
589 if (mem2hex((vm_offset_t
) addr
, remcomOutBuffer
, length
) == NULL
)
590 strcpy (remcomOutBuffer
, "E03");
594 strcpy (remcomOutBuffer
, "E01");
597 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
599 /* Try to read '%x,%x:'. */
601 ptr
= &remcomInBuffer
[1];
603 if (hexToLong(&ptr
,&addr
)
605 && hexToInt(&ptr
, &length
)
608 if (hex2mem(ptr
, (vm_offset_t
) addr
, length
) == NULL
)
609 strcpy (remcomOutBuffer
, "E03");
611 strcpy (remcomOutBuffer
, "OK");
614 strcpy (remcomOutBuffer
, "E02");
617 /* cAA..AA Continue at address AA..AA(optional) */
618 /* sAA..AA Step one instruction from AA..AA(optional) */
621 /* try to read optional parameter, pc unchanged if no parm */
623 ptr
= &remcomInBuffer
[1];
624 if (hexToLong(&ptr
,&addr
))
625 registers
.rip
= addr
;
628 /* set the trace bit if we're stepping */
629 if (remcomInBuffer
[0] == 's')
630 registers
.rflags
|= PSL_T
;
632 registers
.rflags
&= ~PSL_T
;
634 raw_regs
->tf_rax
= registers
.rax
;
635 raw_regs
->tf_rbx
= registers
.rbx
;
636 raw_regs
->tf_rcx
= registers
.rcx
;
637 raw_regs
->tf_rdx
= registers
.rdx
;
639 raw_regs
->tf_rsp
= registers
.rsp
;
640 raw_regs
->tf_rbp
= registers
.rbp
;
641 raw_regs
->tf_rsi
= registers
.rsi
;
642 raw_regs
->tf_rdi
= registers
.rdi
;
644 raw_regs
->tf_r8
= registers
.r8
;
645 raw_regs
->tf_r9
= registers
.r9
;
646 raw_regs
->tf_r10
= registers
.r10
;
647 raw_regs
->tf_r11
= registers
.r11
;
648 raw_regs
->tf_r12
= registers
.r12
;
649 raw_regs
->tf_r13
= registers
.r13
;
650 raw_regs
->tf_r14
= registers
.r14
;
651 raw_regs
->tf_r15
= registers
.r15
;
653 raw_regs
->tf_rip
= registers
.rip
;
654 raw_regs
->tf_rflags
= registers
.rflags
;
656 raw_regs
->tf_cs
= registers
.cs
;
657 raw_regs
->tf_ss
= registers
.ss
;
662 /* reply to the request */
663 putpacket (remcomOutBuffer
);