2 * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * GDB stub for remote debugging
30 typedef uint32_t gdbreg_t
;
33 POSIX_EINVAL
= 0x1c, /* used to report bad arguments to GDB */
34 SIZEOF_PAYLOAD
= 256, /* buffer size of GDB payload data */
35 DR7_CLEAR
= 0x00000400, /* disable hardware breakpoints */
36 DR6_CLEAR
= 0xffff0ff0, /* clear breakpoint status */
39 /* The register snapshot, this must be in sync with interrupt handler and the
59 GDBMACH_SIZEOF_REGS
= GDBMACH_NREGS
* sizeof(gdbreg_t
)
62 /* Breakpoint types */
72 int exit_handler
; /* leave interrupt handler */
77 void (*parse
) (struct gdbstub
* stub
, char ch
);
80 /* Buffer for payload data when parsing a packet. Once the
81 * packet has been received, this buffer is used to hold
82 * the reply payload. */
83 char buf
[SIZEOF_PAYLOAD
+ 4]; /* $...PAYLOAD...#XX */
84 char *payload
; /* start of payload */
85 int len
; /* length of payload */
88 /** Hardware breakpoint, fields stored in x86 bit pattern form */
90 int type
; /* type (1=write watchpoint, 3=access watchpoint) */
91 unsigned long addr
; /* linear address */
92 size_t len
; /* length (0=1-byte, 1=2-byte, 3=4-byte) */
96 static struct hwbp hwbps
[4];
97 static gdbreg_t dr7
= DR7_CLEAR
;
99 static inline void gdbmach_set_pc(gdbreg_t
* regs
, gdbreg_t pc
)
101 regs
[GDBMACH_EIP
] = pc
;
104 static inline void gdbmach_set_single_step(gdbreg_t
* regs
, int step
)
106 regs
[GDBMACH_EFLAGS
] &= ~(1 << 8); /* Trace Flag (TF) */
107 regs
[GDBMACH_EFLAGS
] |= (step
<< 8);
110 static inline void gdbmach_breakpoint(void)
112 __asm__
__volatile__("int $3\n");
115 static struct hwbp
*gdbmach_find_hwbp(int type
, unsigned long addr
, size_t len
)
117 struct hwbp
*available
= NULL
;
119 for (i
= 0; i
< sizeof hwbps
/ sizeof hwbps
[0]; i
++) {
120 if (hwbps
[i
].type
== type
&& hwbps
[i
].addr
== addr
121 && hwbps
[i
].len
== len
) {
124 if (!hwbps
[i
].enabled
) {
125 available
= &hwbps
[i
];
131 static void gdbmach_commit_hwbp(struct hwbp
*bp
)
133 int regnum
= bp
- hwbps
;
135 /* Set breakpoint address */
138 __asm__
__volatile__("movl %0, %%dr0\n": :"r"(bp
->addr
));
141 __asm__
__volatile__("movl %0, %%dr1\n": :"r"(bp
->addr
));
144 __asm__
__volatile__("movl %0, %%dr2\n": :"r"(bp
->addr
));
147 __asm__
__volatile__("movl %0, %%dr3\n": :"r"(bp
->addr
));
152 dr7
&= ~(0x3 << (16 + 4 * regnum
));
153 dr7
|= bp
->type
<< (16 + 4 * regnum
);
156 dr7
&= ~(0x3 << (18 + 4 * regnum
));
157 dr7
|= bp
->len
<< (18 + 4 * regnum
);
159 /* Set/clear local enable bit */
160 dr7
&= ~(0x3 << 2 * regnum
);
161 dr7
|= bp
->enabled
<< 2 * regnum
;
164 int gdbmach_set_breakpoint(int type
, unsigned long addr
, size_t len
, int enable
)
168 /* Check and convert breakpoint type to x86 type */
177 return 0; /* unsupported breakpoint type */
180 /* Only lengths 1, 2, and 4 are supported */
181 if (len
!= 2 && len
!= 4) {
184 len
--; /* convert to x86 breakpoint length bit pattern */
186 /* Set up the breakpoint */
187 bp
= gdbmach_find_hwbp(type
, addr
, len
);
189 return 0; /* ran out of hardware breakpoints */
194 bp
->enabled
= enable
;
195 gdbmach_commit_hwbp(bp
);
199 static void gdbmach_disable_hwbps(void)
201 /* Store and clear hardware breakpoints */
202 __asm__
__volatile__("movl %0, %%dr7\n"::"r"(DR7_CLEAR
));
205 static void gdbmach_enable_hwbps(void)
207 /* Clear breakpoint status register */
208 __asm__
__volatile__("movl %0, %%dr6\n"::"r"(DR6_CLEAR
));
210 /* Restore hardware breakpoints */
211 __asm__
__volatile__("movl %0, %%dr7\n"::"r"(dr7
));
214 /* Packet parser states */
215 static void gdbstub_state_new(struct gdbstub
*stub
, char ch
);
216 static void gdbstub_state_data(struct gdbstub
*stub
, char ch
);
217 static void gdbstub_state_cksum1(struct gdbstub
*stub
, char ch
);
218 static void gdbstub_state_cksum2(struct gdbstub
*stub
, char ch
);
219 static void gdbstub_state_wait_ack(struct gdbstub
*stub
, char ch
);
221 static void serial_write(void *buf
, size_t len
)
228 static uint8_t gdbstub_from_hex_digit(char ch
)
230 if (ch
>= '0' && ch
<= '9')
232 else if (ch
>= 'A' && ch
<= 'F')
233 return ch
- 'A' + 0xa;
235 return (ch
- 'a' + 0xa) & 0xf;
238 static uint8_t gdbstub_to_hex_digit(uint8_t b
)
241 return (b
< 0xa ? '0' : 'a' - 0xa) + b
;
245 * To make reading/writing device memory atomic, we check for
246 * 2- or 4-byte aligned operations and handle them specially.
249 static void gdbstub_from_hex_buf(char *dst
, char *src
, int lenbytes
)
251 if (lenbytes
== 2 && ((unsigned long)dst
& 0x1) == 0) {
252 uint16_t i
= gdbstub_from_hex_digit(src
[2]) << 12 |
253 gdbstub_from_hex_digit(src
[3]) << 8 |
254 gdbstub_from_hex_digit(src
[0]) << 4 |
255 gdbstub_from_hex_digit(src
[1]);
256 *(uint16_t *) dst
= i
;
257 } else if (lenbytes
== 4 && ((unsigned long)dst
& 0x3) == 0) {
258 uint32_t i
= gdbstub_from_hex_digit(src
[6]) << 28 |
259 gdbstub_from_hex_digit(src
[7]) << 24 |
260 gdbstub_from_hex_digit(src
[4]) << 20 |
261 gdbstub_from_hex_digit(src
[5]) << 16 |
262 gdbstub_from_hex_digit(src
[2]) << 12 |
263 gdbstub_from_hex_digit(src
[3]) << 8 |
264 gdbstub_from_hex_digit(src
[0]) << 4 |
265 gdbstub_from_hex_digit(src
[1]);
266 *(uint32_t *) dst
= i
;
268 while (lenbytes
-- > 0) {
269 *dst
++ = gdbstub_from_hex_digit(src
[0]) << 4 |
270 gdbstub_from_hex_digit(src
[1]);
276 static void gdbstub_to_hex_buf(char *dst
, char *src
, int lenbytes
)
278 if (lenbytes
== 2 && ((unsigned long)src
& 0x1) == 0) {
279 uint16_t i
= *(uint16_t *) src
;
280 dst
[0] = gdbstub_to_hex_digit(i
>> 4);
281 dst
[1] = gdbstub_to_hex_digit(i
);
282 dst
[2] = gdbstub_to_hex_digit(i
>> 12);
283 dst
[3] = gdbstub_to_hex_digit(i
>> 8);
284 } else if (lenbytes
== 4 && ((unsigned long)src
& 0x3) == 0) {
285 uint32_t i
= *(uint32_t *) src
;
286 dst
[0] = gdbstub_to_hex_digit(i
>> 4);
287 dst
[1] = gdbstub_to_hex_digit(i
);
288 dst
[2] = gdbstub_to_hex_digit(i
>> 12);
289 dst
[3] = gdbstub_to_hex_digit(i
>> 8);
290 dst
[4] = gdbstub_to_hex_digit(i
>> 20);
291 dst
[5] = gdbstub_to_hex_digit(i
>> 16);
292 dst
[6] = gdbstub_to_hex_digit(i
>> 28);
293 dst
[7] = gdbstub_to_hex_digit(i
>> 24);
295 while (lenbytes
-- > 0) {
296 *dst
++ = gdbstub_to_hex_digit(*src
>> 4);
297 *dst
++ = gdbstub_to_hex_digit(*src
);
303 static uint8_t gdbstub_cksum(char *data
, int len
)
307 cksum
+= (uint8_t) * data
++;
312 static void gdbstub_tx_packet(struct gdbstub
*stub
)
314 uint8_t cksum
= gdbstub_cksum(stub
->payload
, stub
->len
);
316 stub
->buf
[stub
->len
+ 1] = '#';
317 stub
->buf
[stub
->len
+ 2] = gdbstub_to_hex_digit(cksum
>> 4);
318 stub
->buf
[stub
->len
+ 3] = gdbstub_to_hex_digit(cksum
);
319 serial_write(stub
->buf
, stub
->len
+ 4);
320 stub
->parse
= gdbstub_state_wait_ack
;
324 static void gdbstub_send_ok(struct gdbstub
*stub
)
326 stub
->payload
[0] = 'O';
327 stub
->payload
[1] = 'K';
329 gdbstub_tx_packet(stub
);
332 static void gdbstub_send_num_packet(struct gdbstub
*stub
, char reply
, int num
)
334 stub
->payload
[0] = reply
;
335 stub
->payload
[1] = gdbstub_to_hex_digit((char)num
>> 4);
336 stub
->payload
[2] = gdbstub_to_hex_digit((char)num
);
338 gdbstub_tx_packet(stub
);
341 /* Format is arg1,arg2,...,argn:data where argn are hex integers and data is not an argument */
342 static int gdbstub_get_packet_args(struct gdbstub
*stub
, unsigned long *args
,
343 int nargs
, int *stop_idx
)
348 unsigned long val
= 0;
349 for (i
= 1; i
< stub
->len
&& argc
< nargs
; i
++) {
350 ch
= stub
->payload
[i
];
353 } else if (ch
== ',') {
357 val
= (val
<< 4) | gdbstub_from_hex_digit(ch
);
366 return ((i
== stub
->len
|| ch
== ':') && argc
== nargs
);
369 static void gdbstub_send_errno(struct gdbstub
*stub
, int errno
)
371 gdbstub_send_num_packet(stub
, 'E', errno
);
374 static void gdbstub_report_signal(struct gdbstub
*stub
)
376 gdbstub_send_num_packet(stub
, 'S', stub
->signo
);
379 static void gdbstub_read_regs(struct gdbstub
*stub
)
381 gdbstub_to_hex_buf(stub
->payload
, (char *)stub
->regs
, GDBMACH_SIZEOF_REGS
);
382 stub
->len
= GDBMACH_SIZEOF_REGS
* 2;
383 gdbstub_tx_packet(stub
);
386 static void gdbstub_write_regs(struct gdbstub
*stub
)
388 if (stub
->len
!= 1 + GDBMACH_SIZEOF_REGS
* 2) {
389 gdbstub_send_errno(stub
, POSIX_EINVAL
);
392 gdbstub_from_hex_buf((char *)stub
->regs
, &stub
->payload
[1],
393 GDBMACH_SIZEOF_REGS
);
394 gdbstub_send_ok(stub
);
397 static void gdbstub_read_mem(struct gdbstub
*stub
)
399 unsigned long args
[2];
400 if (!gdbstub_get_packet_args
401 (stub
, args
, sizeof args
/ sizeof args
[0], NULL
)) {
402 gdbstub_send_errno(stub
, POSIX_EINVAL
);
405 args
[1] = (args
[1] < SIZEOF_PAYLOAD
/ 2) ? args
[1] : SIZEOF_PAYLOAD
/ 2;
406 gdbstub_to_hex_buf(stub
->payload
, (char *)args
[0], args
[1]);
407 stub
->len
= args
[1] * 2;
408 gdbstub_tx_packet(stub
);
411 static void gdbstub_write_mem(struct gdbstub
*stub
)
413 unsigned long args
[2];
415 if (!gdbstub_get_packet_args
416 (stub
, args
, sizeof args
/ sizeof args
[0], &colon
) || colon
>= stub
->len
417 || stub
->payload
[colon
] != ':' || (stub
->len
- colon
- 1) % 2 != 0) {
418 gdbstub_send_errno(stub
, POSIX_EINVAL
);
421 gdbstub_from_hex_buf((char *)args
[0], &stub
->payload
[colon
+ 1],
422 (stub
->len
- colon
- 1) / 2);
423 gdbstub_send_ok(stub
);
426 static void gdbstub_continue(struct gdbstub
*stub
, int single_step
)
430 && gdbstub_get_packet_args(stub
, (unsigned long *)&pc
, 1, NULL
)) {
431 gdbmach_set_pc(stub
->regs
, pc
);
433 gdbmach_set_single_step(stub
->regs
, single_step
);
434 stub
->exit_handler
= 1;
435 /* Reply will be sent when we hit the next breakpoint or interrupt */
438 static void gdbstub_breakpoint(struct gdbstub
*stub
)
440 unsigned long args
[3];
441 int enable
= stub
->payload
[0] == 'Z' ? 1 : 0;
442 if (!gdbstub_get_packet_args
443 (stub
, args
, sizeof args
/ sizeof args
[0], NULL
)) {
444 gdbstub_send_errno(stub
, POSIX_EINVAL
);
447 if (gdbmach_set_breakpoint(args
[0], args
[1], args
[2], enable
)) {
448 gdbstub_send_ok(stub
);
452 gdbstub_tx_packet(stub
);
456 static void gdbstub_rx_packet(struct gdbstub
*stub
)
458 switch (stub
->payload
[0]) {
460 gdbstub_report_signal(stub
);
463 gdbstub_read_regs(stub
);
466 gdbstub_write_regs(stub
);
469 gdbstub_read_mem(stub
);
472 gdbstub_write_mem(stub
);
474 case 'c': /* Continue */
477 case 'D': /* Detach */
478 gdbstub_continue(stub
, stub
->payload
[0] == 's');
479 if (stub
->payload
[0] == 'D') {
480 gdbstub_send_ok(stub
);
483 case 'Z': /* Insert breakpoint */
484 case 'z': /* Remove breakpoint */
485 gdbstub_breakpoint(stub
);
489 gdbstub_tx_packet(stub
);
494 /* GDB packet parser */
495 static void gdbstub_state_new(struct gdbstub
*stub
, char ch
)
499 stub
->parse
= gdbstub_state_data
;
503 static void gdbstub_state_data(struct gdbstub
*stub
, char ch
)
506 stub
->parse
= gdbstub_state_cksum1
;
507 } else if (ch
== '$') {
508 stub
->len
= 0; /* retry new packet */
510 /* If the length exceeds our buffer, let the checksum fail */
511 if (stub
->len
< SIZEOF_PAYLOAD
) {
512 stub
->payload
[stub
->len
++] = ch
;
517 static void gdbstub_state_cksum1(struct gdbstub
*stub
, char ch
)
519 stub
->cksum1
= gdbstub_from_hex_digit(ch
) << 4;
520 stub
->parse
= gdbstub_state_cksum2
;
523 static void gdbstub_state_cksum2(struct gdbstub
*stub
, char ch
)
528 stub
->parse
= gdbstub_state_new
;
529 their_cksum
= stub
->cksum1
+ gdbstub_from_hex_digit(ch
);
530 our_cksum
= gdbstub_cksum(stub
->payload
, stub
->len
);
532 if (their_cksum
== our_cksum
) {
533 serial_write("+", 1);
535 gdbstub_rx_packet(stub
);
538 serial_write("-", 1);
542 static void gdbstub_state_wait_ack(struct gdbstub
*stub
, char ch
)
545 stub
->parse
= gdbstub_state_new
;
547 /* This retransmit is very aggressive but necessary to keep
548 * in sync with GDB. */
549 gdbstub_tx_packet(stub
);
553 void gdbstub_handler(int signo
, gdbreg_t
* regs
)
557 gdbmach_disable_hwbps();
559 stub
.parse
= gdbstub_state_new
;
560 stub
.payload
= &stub
.buf
[1];
563 stub
.exit_handler
= 0;
564 gdbstub_report_signal(&stub
);
565 while (!stub
.exit_handler
)
566 stub
.parse(&stub
, serial_getc());
568 gdbmach_enable_hwbps();