diff options
Diffstat (limited to 'kernel/debug/gdbstub.c')
| -rw-r--r-- | kernel/debug/gdbstub.c | 76 | 
1 files changed, 63 insertions, 13 deletions
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 481a7bd2dfe..19d9a578c75 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c @@ -31,6 +31,7 @@  #include <linux/kernel.h>  #include <linux/kgdb.h>  #include <linux/kdb.h> +#include <linux/serial_core.h>  #include <linux/reboot.h>  #include <linux/uaccess.h>  #include <asm/cacheflush.h> @@ -42,6 +43,8 @@  /* Our I/O buffers. */  static char			remcom_in_buffer[BUFMAX];  static char			remcom_out_buffer[BUFMAX]; +static int			gdbstub_use_prev_in_buf; +static int			gdbstub_prev_in_buf_pos;  /* Storage for the registers, in GDB format. */  static unsigned long		gdb_regs[(NUMREGBYTES + @@ -58,6 +61,13 @@ static int gdbstub_read_wait(void)  	int ret = -1;  	int i; +	if (unlikely(gdbstub_use_prev_in_buf)) { +		if (gdbstub_prev_in_buf_pos < gdbstub_use_prev_in_buf) +			return remcom_in_buffer[gdbstub_prev_in_buf_pos++]; +		else +			gdbstub_use_prev_in_buf = 0; +	} +  	/* poll any additional I/O interfaces that are defined */  	while (ret < 0)  		for (i = 0; kdb_poll_funcs[i] != NULL; i++) { @@ -109,7 +119,6 @@ static void get_packet(char *buffer)  			buffer[count] = ch;  			count = count + 1;  		} -		buffer[count] = 0;  		if (ch == '#') {  			xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4; @@ -124,6 +133,7 @@ static void get_packet(char *buffer)  			if (dbg_io_ops->flush)  				dbg_io_ops->flush();  		} +		buffer[count] = 0;  	} while (checksum != xmitcsum);  } @@ -208,7 +218,7 @@ void gdbstub_msg_write(const char *s, int len)  		/* Pack in hex chars */  		for (i = 0; i < wcount; i++) -			bufptr = pack_hex_byte(bufptr, s[i]); +			bufptr = hex_byte_pack(bufptr, s[i]);  		*bufptr = '\0';  		/* Move up */ @@ -240,7 +250,7 @@ char *kgdb_mem2hex(char *mem, char *buf, int count)  	if (err)  		return NULL;  	while (count > 0) { -		buf = pack_hex_byte(buf, *tmp); +		buf = hex_byte_pack(buf, *tmp);  		tmp++;  		count--;  	} @@ -402,14 +412,14 @@ static char *pack_threadid(char *pkt, unsigned char *id)  	limit = id + (BUF_THREAD_ID_SIZE / 2);  	while (id < limit) {  		if (!lzero || *id != 0) { -			pkt = pack_hex_byte(pkt, *id); +			pkt = hex_byte_pack(pkt, *id);  			lzero = 0;  		}  		id++;  	}  	if (lzero) -		pkt = pack_hex_byte(pkt, 0); +		pkt = hex_byte_pack(pkt, 0);  	return pkt;  } @@ -477,7 +487,7 @@ static void gdb_cmd_status(struct kgdb_state *ks)  	dbg_remove_all_break();  	remcom_out_buffer[0] = 'S'; -	pack_hex_byte(&remcom_out_buffer[1], ks->signo); +	hex_byte_pack(&remcom_out_buffer[1], ks->signo);  }  static void gdb_get_regs_helper(struct kgdb_state *ks) @@ -773,7 +783,10 @@ static void gdb_cmd_query(struct kgdb_state *ks)  			len = len / 2;  			remcom_out_buffer[len++] = 0; +			kdb_common_init_state(ks);  			kdb_parse(remcom_out_buffer); +			kdb_common_deinit_state(); +  			strcpy(remcom_out_buffer, "OK");  		}  		break; @@ -945,7 +958,7 @@ int gdb_serial_stub(struct kgdb_state *ks)  		/* Reply to host that an exception has occurred */  		ptr = remcom_out_buffer;  		*ptr++ = 'T'; -		ptr = pack_hex_byte(ptr, ks->signo); +		ptr = hex_byte_pack(ptr, ks->signo);  		ptr += strlen(strcpy(ptr, "thread:"));  		int_to_threadref(thref, shadow_pid(current->pid));  		ptr = pack_threadid(ptr, thref); @@ -1082,14 +1095,51 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd)  	case 'c':  		strcpy(remcom_in_buffer, cmd);  		return 0; -	case '?': -		gdb_cmd_status(ks); -		break; -	case '\0': -		strcpy(remcom_out_buffer, ""); -		break; +	case '$': +		strcpy(remcom_in_buffer, cmd); +		gdbstub_use_prev_in_buf = strlen(remcom_in_buffer); +		gdbstub_prev_in_buf_pos = 0; +		return 0;  	}  	dbg_io_ops->write_char('+');  	put_packet(remcom_out_buffer);  	return 0;  } + +/** + * gdbstub_exit - Send an exit message to GDB + * @status: The exit code to report. + */ +void gdbstub_exit(int status) +{ +	unsigned char checksum, ch, buffer[3]; +	int loop; + +	if (!kgdb_connected) +		return; +	kgdb_connected = 0; + +	if (!dbg_io_ops || dbg_kdb_mode) +		return; + +	buffer[0] = 'W'; +	buffer[1] = hex_asc_hi(status); +	buffer[2] = hex_asc_lo(status); + +	dbg_io_ops->write_char('$'); +	checksum = 0; + +	for (loop = 0; loop < 3; loop++) { +		ch = buffer[loop]; +		checksum += ch; +		dbg_io_ops->write_char(ch); +	} + +	dbg_io_ops->write_char('#'); +	dbg_io_ops->write_char(hex_asc_hi(checksum)); +	dbg_io_ops->write_char(hex_asc_lo(checksum)); + +	/* make sure the output is flushed, lest the bootloader clobber it */ +	if (dbg_io_ops->flush) +		dbg_io_ops->flush(); +}  | 
