Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2008 Stefan Hajnoczi <stefanha (at) gmail.com>.
      3  *
      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.
      8  *
      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.
     13  *
     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.
     17  */
     18 
     19 /**
     20  * @file
     21  *
     22  * GDB stub for remote debugging
     23  *
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <stdio.h>
     28 #include <string.h>
     29 #include <ctype.h>
     30 #include <byteswap.h>
     31 #include <gpxe/gdbstub.h>
     32 #include "gdbmach.h"
     33 
     34 enum {
     35 	POSIX_EINVAL = 0x1c,  /* used to report bad arguments to GDB */
     36 	SIZEOF_PAYLOAD = 256, /* buffer size of GDB payload data */
     37 };
     38 
     39 struct gdbstub {
     40 	struct gdb_transport *trans;
     41 	int exit_handler; /* leave interrupt handler */
     42 
     43 	int signo;
     44 	gdbreg_t *regs;
     45 
     46 	void ( * parse ) ( struct gdbstub *stub, char ch );
     47 	uint8_t cksum1;
     48 
     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 */
     55 };
     56 
     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 );
     63 
     64 static uint8_t gdbstub_from_hex_digit ( char ch ) {
     65 	return ( isdigit ( ch ) ? ch - '0' : tolower ( ch ) - 'a' + 0xa ) & 0xf;
     66 }
     67 
     68 static uint8_t gdbstub_to_hex_digit ( uint8_t b ) {
     69 	b &= 0xf;
     70 	return ( b < 0xa ? '0' : 'a' - 0xa ) + b;
     71 }
     72 
     73 /*
     74  * To make reading/writing device memory atomic, we check for
     75  * 2- or 4-byte aligned operations and handle them specially.
     76  */
     77 
     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 );
     95 	} else {
     96 		while ( lenbytes-- > 0 ) {
     97 			*dst++ = gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
     98 				gdbstub_from_hex_digit ( src [ 1 ] );
     99 			src += 2;
    100 		}
    101 	}
    102 }
    103 
    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 );
    121 	} else {
    122 		while ( lenbytes-- > 0 ) {
    123 			*dst++ = gdbstub_to_hex_digit ( *src >> 4 );
    124 			*dst++ = gdbstub_to_hex_digit ( *src );
    125 			src++;
    126 		}
    127 	}
    128 }
    129 
    130 static uint8_t gdbstub_cksum ( char *data, int len ) {
    131 	uint8_t cksum = 0;
    132 	while ( len-- > 0 ) {
    133 		cksum += ( uint8_t ) *data++;
    134 	}
    135 	return cksum;
    136 }
    137 
    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;
    146 }
    147 
    148 /* GDB commands */
    149 static void gdbstub_send_ok ( struct gdbstub *stub ) {
    150 	stub->payload [ 0 ] = 'O';
    151 	stub->payload [ 1 ] = 'K';
    152 	stub->len = 2;
    153 	gdbstub_tx_packet ( stub );
    154 }
    155 
    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 );
    160 	stub->len = 3;
    161 	gdbstub_tx_packet ( stub );
    162 }
    163 
    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 ) {
    166 	int i;
    167 	char ch = 0;
    168 	int argc = 0;
    169 	unsigned long val = 0;
    170 	for ( i = 1; i < stub->len && argc < nargs; i++ ) {
    171 		ch = stub->payload [ i ];
    172 		if ( ch == ':' ) {
    173 			break;
    174 		} else if ( ch == ',' ) {
    175 			args [ argc++ ] = val;
    176 			val = 0;
    177 		} else {
    178 			val = ( val << 4 ) | gdbstub_from_hex_digit ( ch );
    179 		}
    180 	}
    181 	if ( stop_idx ) {
    182 		*stop_idx = i;
    183 	}
    184 	if ( argc < nargs ) {
    185 		args [ argc++ ] = val;
    186 	}
    187 	return ( ( i == stub->len || ch == ':' ) && argc == nargs );
    188 }
    189 
    190 static void gdbstub_send_errno ( struct gdbstub *stub, int errno ) {
    191 	gdbstub_send_num_packet ( stub, 'E', errno );
    192 }
    193 
    194 static void gdbstub_report_signal ( struct gdbstub *stub ) {
    195 	gdbstub_send_num_packet ( stub, 'S', stub->signo );
    196 }
    197 
    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 );
    202 }
    203 
    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 );
    207 		return;
    208 	}
    209 	gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], GDBMACH_SIZEOF_REGS );
    210 	gdbstub_send_ok ( stub );
    211 }
    212 
    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 );
    217 		return;
    218 	}
    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 );
    223 }
    224 
    225 static void gdbstub_write_mem ( struct gdbstub *stub ) {
    226 	unsigned long args [ 2 ];
    227 	int colon;
    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 );
    232 		return;
    233 	}
    234 	gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], ( stub->len - colon - 1 ) / 2 );
    235 	gdbstub_send_ok ( stub );
    236 }
    237 
    238 static void gdbstub_continue ( struct gdbstub *stub, int single_step ) {
    239 	gdbreg_t pc;
    240 	if ( stub->len > 1 && gdbstub_get_packet_args ( stub, &pc, 1, NULL ) ) {
    241 		gdbmach_set_pc ( stub->regs, pc );
    242 	}
    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 */
    246 }
    247 
    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 );
    253 		return;
    254 	}
    255 	if ( gdbmach_set_breakpoint ( args [ 0 ], args [ 1 ], args [ 2 ], enable ) ) {
    256 		gdbstub_send_ok ( stub );
    257 	} else {
    258 		/* Not supported */
    259 		stub->len = 0;
    260 		gdbstub_tx_packet ( stub );
    261 	}
    262 }
    263 
    264 static void gdbstub_rx_packet ( struct gdbstub *stub ) {
    265 	switch ( stub->payload [ 0 ] ) {
    266 		case '?':
    267 			gdbstub_report_signal ( stub );
    268 			break;
    269 		case 'g':
    270 			gdbstub_read_regs ( stub );
    271 			break;
    272 		case 'G':
    273 			gdbstub_write_regs ( stub );
    274 			break;
    275 		case 'm':
    276 			gdbstub_read_mem ( stub );
    277 			break;
    278 		case 'M':
    279 			gdbstub_write_mem ( stub );
    280 			break;
    281 		case 'c': /* Continue */
    282 		case 'k': /* Kill */
    283 		case 's': /* Step */
    284 		case 'D': /* Detach */
    285 			gdbstub_continue ( stub, stub->payload [ 0 ] == 's' );
    286 			if ( stub->payload [ 0 ] == 'D' ) {
    287 				gdbstub_send_ok ( stub );
    288 			}
    289 			break;
    290 		case 'Z': /* Insert breakpoint */
    291 		case 'z': /* Remove breakpoint */
    292 			gdbstub_breakpoint ( stub );
    293 			break;
    294 		default:
    295 			stub->len = 0;
    296 			gdbstub_tx_packet ( stub );
    297 			break;
    298 	}
    299 }
    300 
    301 /* GDB packet parser */
    302 static void gdbstub_state_new ( struct gdbstub *stub, char ch ) {
    303 	if ( ch == '$' ) {
    304 		stub->len = 0;
    305 		stub->parse = gdbstub_state_data;
    306 	}
    307 }
    308 
    309 static void gdbstub_state_data ( struct gdbstub *stub, char ch ) {
    310 	if ( ch == '#' ) {
    311 		stub->parse = gdbstub_state_cksum1;
    312 	} else if ( ch == '$' ) {
    313 		stub->len = 0; /* retry new packet */
    314 	} else {
    315 		/* If the length exceeds our buffer, let the checksum fail */
    316 		if ( stub->len < SIZEOF_PAYLOAD ) {
    317 			stub->payload [ stub->len++ ] = ch;
    318 		}
    319 	}
    320 }
    321 
    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;
    325 }
    326 
    327 static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch ) {
    328 	uint8_t their_cksum;
    329 	uint8_t our_cksum;
    330 
    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 );
    338 		}
    339 	} else {
    340 		stub->trans->send ( "-", 1 );
    341 	}
    342 }
    343 
    344 static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch ) {
    345 	if ( ch == '+' ) {
    346 		stub->parse = gdbstub_state_new;
    347 	} else {
    348 		/* This retransmit is very aggressive but necessary to keep
    349 		 * in sync with GDB. */
    350 		gdbstub_tx_packet ( stub );
    351 	}
    352 }
    353 
    354 static void gdbstub_parse ( struct gdbstub *stub, char ch ) {
    355 	stub->parse ( stub, ch );
    356 }
    357 
    358 static struct gdbstub stub = {
    359 	.parse = gdbstub_state_new
    360 };
    361 
    362 void gdbstub_handler ( int signo, gdbreg_t *regs ) {
    363 	char packet [ SIZEOF_PAYLOAD + 4 ];
    364 	size_t len, i;
    365 
    366 	/* A transport must be set up */
    367 	if ( !stub.trans ) {
    368 		return;
    369 	}
    370 
    371 	stub.signo = signo;
    372 	stub.regs = regs;
    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 ] );
    378 		}
    379 	}
    380 }
    381 
    382 struct gdb_transport *find_gdb_transport ( const char *name ) {
    383 	struct gdb_transport *trans;
    384 
    385 	for_each_table_entry ( trans, GDB_TRANSPORTS ) {
    386 		if ( strcmp ( trans->name, name ) == 0 ) {
    387 			return trans;
    388 		}
    389 	}
    390 	return NULL;
    391 }
    392 
    393 void gdbstub_start ( struct gdb_transport *trans ) {
    394 	stub.trans = trans;
    395 	stub.payload = &stub.buf [ 1 ];
    396 	gdbmach_breakpoint();
    397 }
    398