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
31 #include <gpxe/gdbstub.h>
35 POSIX_EINVAL
= 0x1c, /* used to report bad arguments to GDB */
36 SIZEOF_PAYLOAD
= 256, /* buffer size of GDB payload data */
40 struct gdb_transport
*trans
;
41 int exit_handler
; /* leave interrupt handler */
46 void ( * parse
) ( struct gdbstub
*stub
, char ch
);
49 /* Buffer for payload data when parsing a packet. Once the
50 * packet has been received, this buffer is used to hold
51 * the reply payload. */
52 char buf
[ SIZEOF_PAYLOAD
+ 4 ]; /* $...PAYLOAD...#XX */
53 char *payload
; /* start of payload */
54 int len
; /* length of payload */
57 /* Packet parser states */
58 static void gdbstub_state_new ( struct gdbstub
*stub
, char ch
);
59 static void gdbstub_state_data ( struct gdbstub
*stub
, char ch
);
60 static void gdbstub_state_cksum1 ( struct gdbstub
*stub
, char ch
);
61 static void gdbstub_state_cksum2 ( struct gdbstub
*stub
, char ch
);
62 static void gdbstub_state_wait_ack ( struct gdbstub
*stub
, char ch
);
64 static uint8_t gdbstub_from_hex_digit ( char ch
) {
65 return ( isdigit ( ch
) ? ch
- '0' : tolower ( ch
) - 'a' + 0xa ) & 0xf;
68 static uint8_t gdbstub_to_hex_digit ( uint8_t b
) {
70 return ( b
< 0xa ? '0' : 'a' - 0xa ) + b
;
74 * To make reading/writing device memory atomic, we check for
75 * 2- or 4-byte aligned operations and handle them specially.
78 static void gdbstub_from_hex_buf ( char *dst
, char *src
, int lenbytes
) {
79 if ( lenbytes
== 2 && ( ( unsigned long ) dst
& 0x1 ) == 0 ) {
80 uint16_t i
= gdbstub_from_hex_digit ( src
[ 2 ] ) << 12 |
81 gdbstub_from_hex_digit ( src
[ 3 ] ) << 8 |
82 gdbstub_from_hex_digit ( src
[ 0 ] ) << 4 |
83 gdbstub_from_hex_digit ( src
[ 1 ] );
84 * ( uint16_t * ) dst
= cpu_to_le16 ( i
);
85 } else if ( lenbytes
== 4 && ( ( unsigned long ) dst
& 0x3 ) == 0 ) {
86 uint32_t i
= gdbstub_from_hex_digit ( src
[ 6 ] ) << 28 |
87 gdbstub_from_hex_digit ( src
[ 7 ] ) << 24 |
88 gdbstub_from_hex_digit ( src
[ 4 ] ) << 20 |
89 gdbstub_from_hex_digit ( src
[ 5 ] ) << 16 |
90 gdbstub_from_hex_digit ( src
[ 2 ] ) << 12 |
91 gdbstub_from_hex_digit ( src
[ 3 ] ) << 8 |
92 gdbstub_from_hex_digit ( src
[ 0 ] ) << 4 |
93 gdbstub_from_hex_digit ( src
[ 1 ] );
94 * ( uint32_t * ) dst
= cpu_to_le32 ( i
);
96 while ( lenbytes
-- > 0 ) {
97 *dst
++ = gdbstub_from_hex_digit ( src
[ 0 ] ) << 4 |
98 gdbstub_from_hex_digit ( src
[ 1 ] );
104 static void gdbstub_to_hex_buf ( char *dst
, char *src
, int lenbytes
) {
105 if ( lenbytes
== 2 && ( ( unsigned long ) src
& 0x1 ) == 0 ) {
106 uint16_t i
= cpu_to_le16 ( * ( uint16_t * ) src
);
107 dst
[ 0 ] = gdbstub_to_hex_digit ( i
>> 4 );
108 dst
[ 1 ] = gdbstub_to_hex_digit ( i
);
109 dst
[ 2 ] = gdbstub_to_hex_digit ( i
>> 12 );
110 dst
[ 3 ] = gdbstub_to_hex_digit ( i
>> 8 );
111 } else if ( lenbytes
== 4 && ( ( unsigned long ) src
& 0x3 ) == 0 ) {
112 uint32_t i
= cpu_to_le32 ( * ( uint32_t * ) src
);
113 dst
[ 0 ] = gdbstub_to_hex_digit ( i
>> 4 );
114 dst
[ 1 ] = gdbstub_to_hex_digit ( i
);
115 dst
[ 2 ] = gdbstub_to_hex_digit ( i
>> 12 );
116 dst
[ 3 ] = gdbstub_to_hex_digit ( i
>> 8 );
117 dst
[ 4 ] = gdbstub_to_hex_digit ( i
>> 20 );
118 dst
[ 5 ] = gdbstub_to_hex_digit ( i
>> 16);
119 dst
[ 6 ] = gdbstub_to_hex_digit ( i
>> 28 );
120 dst
[ 7 ] = gdbstub_to_hex_digit ( i
>> 24 );
122 while ( lenbytes
-- > 0 ) {
123 *dst
++ = gdbstub_to_hex_digit ( *src
>> 4 );
124 *dst
++ = gdbstub_to_hex_digit ( *src
);
130 static uint8_t gdbstub_cksum ( char *data
, int len
) {
132 while ( len
-- > 0 ) {
133 cksum
+= ( uint8_t ) *data
++;
138 static void gdbstub_tx_packet ( struct gdbstub
*stub
) {
139 uint8_t cksum
= gdbstub_cksum ( stub
->payload
, stub
->len
);
140 stub
->buf
[ 0 ] = '$';
141 stub
->buf
[ stub
->len
+ 1 ] = '#';
142 stub
->buf
[ stub
->len
+ 2 ] = gdbstub_to_hex_digit ( cksum
>> 4 );
143 stub
->buf
[ stub
->len
+ 3 ] = gdbstub_to_hex_digit ( cksum
);
144 stub
->trans
->send ( stub
->buf
, stub
->len
+ 4 );
145 stub
->parse
= gdbstub_state_wait_ack
;
149 static void gdbstub_send_ok ( struct gdbstub
*stub
) {
150 stub
->payload
[ 0 ] = 'O';
151 stub
->payload
[ 1 ] = 'K';
153 gdbstub_tx_packet ( stub
);
156 static void gdbstub_send_num_packet ( struct gdbstub
*stub
, char reply
, int num
) {
157 stub
->payload
[ 0 ] = reply
;
158 stub
->payload
[ 1 ] = gdbstub_to_hex_digit ( ( char ) num
>> 4 );
159 stub
->payload
[ 2 ] = gdbstub_to_hex_digit ( ( char ) num
);
161 gdbstub_tx_packet ( stub
);
164 /* Format is arg1,arg2,...,argn:data where argn are hex integers and data is not an argument */
165 static int gdbstub_get_packet_args ( struct gdbstub
*stub
, unsigned long *args
, int nargs
, int *stop_idx
) {
169 unsigned long val
= 0;
170 for ( i
= 1; i
< stub
->len
&& argc
< nargs
; i
++ ) {
171 ch
= stub
->payload
[ i
];
174 } else if ( ch
== ',' ) {
175 args
[ argc
++ ] = val
;
178 val
= ( val
<< 4 ) | gdbstub_from_hex_digit ( ch
);
184 if ( argc
< nargs
) {
185 args
[ argc
++ ] = val
;
187 return ( ( i
== stub
->len
|| ch
== ':' ) && argc
== nargs
);
190 static void gdbstub_send_errno ( struct gdbstub
*stub
, int errno
) {
191 gdbstub_send_num_packet ( stub
, 'E', errno
);
194 static void gdbstub_report_signal ( struct gdbstub
*stub
) {
195 gdbstub_send_num_packet ( stub
, 'S', stub
->signo
);
198 static void gdbstub_read_regs ( struct gdbstub
*stub
) {
199 gdbstub_to_hex_buf ( stub
->payload
, ( char * ) stub
->regs
, GDBMACH_SIZEOF_REGS
);
200 stub
->len
= GDBMACH_SIZEOF_REGS
* 2;
201 gdbstub_tx_packet ( stub
);
204 static void gdbstub_write_regs ( struct gdbstub
*stub
) {
205 if ( stub
->len
!= 1 + GDBMACH_SIZEOF_REGS
* 2 ) {
206 gdbstub_send_errno ( stub
, POSIX_EINVAL
);
209 gdbstub_from_hex_buf ( ( char * ) stub
->regs
, &stub
->payload
[ 1 ], GDBMACH_SIZEOF_REGS
);
210 gdbstub_send_ok ( stub
);
213 static void gdbstub_read_mem ( struct gdbstub
*stub
) {
214 unsigned long args
[ 2 ];
215 if ( !gdbstub_get_packet_args ( stub
, args
, sizeof args
/ sizeof args
[ 0 ], NULL
) ) {
216 gdbstub_send_errno ( stub
, POSIX_EINVAL
);
219 args
[ 1 ] = ( args
[ 1 ] < SIZEOF_PAYLOAD
/ 2 ) ? args
[ 1 ] : SIZEOF_PAYLOAD
/ 2;
220 gdbstub_to_hex_buf ( stub
->payload
, ( char * ) args
[ 0 ], args
[ 1 ] );
221 stub
->len
= args
[ 1 ] * 2;
222 gdbstub_tx_packet ( stub
);
225 static void gdbstub_write_mem ( struct gdbstub
*stub
) {
226 unsigned long args
[ 2 ];
228 if ( !gdbstub_get_packet_args ( stub
, args
, sizeof args
/ sizeof args
[ 0 ], &colon
) ||
229 colon
>= stub
->len
|| stub
->payload
[ colon
] != ':' ||
230 ( stub
->len
- colon
- 1 ) % 2 != 0 ) {
231 gdbstub_send_errno ( stub
, POSIX_EINVAL
);
234 gdbstub_from_hex_buf ( ( char * ) args
[ 0 ], &stub
->payload
[ colon
+ 1 ], ( stub
->len
- colon
- 1 ) / 2 );
235 gdbstub_send_ok ( stub
);
238 static void gdbstub_continue ( struct gdbstub
*stub
, int single_step
) {
240 if ( stub
->len
> 1 && gdbstub_get_packet_args ( stub
, &pc
, 1, NULL
) ) {
241 gdbmach_set_pc ( stub
->regs
, pc
);
243 gdbmach_set_single_step ( stub
->regs
, single_step
);
244 stub
->exit_handler
= 1;
245 /* Reply will be sent when we hit the next breakpoint or interrupt */
248 static void gdbstub_breakpoint ( struct gdbstub
*stub
) {
249 unsigned long args
[ 3 ];
250 int enable
= stub
->payload
[ 0 ] == 'Z' ? 1 : 0;
251 if ( !gdbstub_get_packet_args ( stub
, args
, sizeof args
/ sizeof args
[ 0 ], NULL
) ) {
252 gdbstub_send_errno ( stub
, POSIX_EINVAL
);
255 if ( gdbmach_set_breakpoint ( args
[ 0 ], args
[ 1 ], args
[ 2 ], enable
) ) {
256 gdbstub_send_ok ( stub
);
260 gdbstub_tx_packet ( stub
);
264 static void gdbstub_rx_packet ( struct gdbstub
*stub
) {
265 switch ( stub
->payload
[ 0 ] ) {
267 gdbstub_report_signal ( stub
);
270 gdbstub_read_regs ( stub
);
273 gdbstub_write_regs ( stub
);
276 gdbstub_read_mem ( stub
);
279 gdbstub_write_mem ( stub
);
281 case 'c': /* Continue */
284 case 'D': /* Detach */
285 gdbstub_continue ( stub
, stub
->payload
[ 0 ] == 's' );
286 if ( stub
->payload
[ 0 ] == 'D' ) {
287 gdbstub_send_ok ( stub
);
290 case 'Z': /* Insert breakpoint */
291 case 'z': /* Remove breakpoint */
292 gdbstub_breakpoint ( stub
);
296 gdbstub_tx_packet ( stub
);
301 /* GDB packet parser */
302 static void gdbstub_state_new ( struct gdbstub
*stub
, char ch
) {
305 stub
->parse
= gdbstub_state_data
;
309 static void gdbstub_state_data ( struct gdbstub
*stub
, char ch
) {
311 stub
->parse
= gdbstub_state_cksum1
;
312 } else if ( ch
== '$' ) {
313 stub
->len
= 0; /* retry new packet */
315 /* If the length exceeds our buffer, let the checksum fail */
316 if ( stub
->len
< SIZEOF_PAYLOAD
) {
317 stub
->payload
[ stub
->len
++ ] = ch
;
322 static void gdbstub_state_cksum1 ( struct gdbstub
*stub
, char ch
) {
323 stub
->cksum1
= gdbstub_from_hex_digit ( ch
) << 4;
324 stub
->parse
= gdbstub_state_cksum2
;
327 static void gdbstub_state_cksum2 ( struct gdbstub
*stub
, char ch
) {
331 stub
->parse
= gdbstub_state_new
;
332 their_cksum
= stub
->cksum1
+ gdbstub_from_hex_digit ( ch
);
333 our_cksum
= gdbstub_cksum ( stub
->payload
, stub
->len
);
334 if ( their_cksum
== our_cksum
) {
335 stub
->trans
->send ( "+", 1 );
336 if ( stub
->len
> 0 ) {
337 gdbstub_rx_packet ( stub
);
340 stub
->trans
->send ( "-", 1 );
344 static void gdbstub_state_wait_ack ( struct gdbstub
*stub
, char ch
) {
346 stub
->parse
= gdbstub_state_new
;
348 /* This retransmit is very aggressive but necessary to keep
349 * in sync with GDB. */
350 gdbstub_tx_packet ( stub
);
354 static void gdbstub_parse ( struct gdbstub
*stub
, char ch
) {
355 stub
->parse ( stub
, ch
);
358 static struct gdbstub stub
= {
359 .parse
= gdbstub_state_new
362 void gdbstub_handler ( int signo
, gdbreg_t
*regs
) {
363 char packet
[ SIZEOF_PAYLOAD
+ 4 ];
366 /* A transport must be set up */
373 stub
.exit_handler
= 0;
374 gdbstub_report_signal ( &stub
);
375 while ( !stub
.exit_handler
&& ( len
= stub
.trans
->recv ( packet
, sizeof ( packet
) ) ) > 0 ) {
376 for ( i
= 0; i
< len
; i
++ ) {
377 gdbstub_parse ( &stub
, packet
[ i
] );
382 struct gdb_transport
*find_gdb_transport ( const char *name
) {
383 struct gdb_transport
*trans
;
385 for_each_table_entry ( trans
, GDB_TRANSPORTS
) {
386 if ( strcmp ( trans
->name
, name
) == 0 ) {
393 void gdbstub_start ( struct gdb_transport
*trans
) {
395 stub
.payload
= &stub
.buf
[ 1 ];
396 gdbmach_breakpoint();