| 
				
			 | 
			
			
				
				@@ -0,0 +1,330 @@ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				1
			 | 
			
			
				
				+/* 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				2
			 | 
			
			
				
				+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha@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 <stddef.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				28
			 | 
			
			
				
				+#include <stdio.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				29
			 | 
			
			
				
				+#include <ctype.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				30
			 | 
			
			
				
				+#include <assert.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				31
			 | 
			
			
				
				+#include <gpxe/process.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				32
			 | 
			
			
				
				+#include <gpxe/serial.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				33
			 | 
			
			
				
				+#include "gdbmach.h" 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				34
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				35
			 | 
			
			
				
				+enum { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				36
			 | 
			
			
				
				+	POSIX_EINVAL = 0x1c /* used to report bad arguments to GDB */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				37
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				38
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				39
			 | 
			
			
				
				+struct gdbstub { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				40
			 | 
			
			
				
				+	int signo; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				41
			 | 
			
			
				
				+	gdbreg_t *regs; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				42
			 | 
			
			
				
				+	int exit_handler; /* leave interrupt handler */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				43
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				44
			 | 
			
			
				
				+	void ( * parse ) ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				45
			 | 
			
			
				
				+	uint8_t cksum1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				46
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				47
			 | 
			
			
				
				+	/* Buffer for payload data when parsing a packet.  Once the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				48
			 | 
			
			
				
				+	 * packet has been received, this buffer is used to hold 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				49
			 | 
			
			
				
				+	 * the reply payload. */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				50
			 | 
			
			
				
				+	char payload [ 256 ]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				51
			 | 
			
			
				
				+	int len; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				52
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				53
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				54
			 | 
			
			
				
				+/* Packet parser states */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				55
			 | 
			
			
				
				+static void gdbstub_state_new ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				56
			 | 
			
			
				
				+static void gdbstub_state_data ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				57
			 | 
			
			
				
				+static void gdbstub_state_cksum1 ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				58
			 | 
			
			
				
				+static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				59
			 | 
			
			
				
				+static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				60
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				61
			 | 
			
			
				
				+static uint8_t gdbstub_from_hex_digit ( char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				62
			 | 
			
			
				
				+	return ( isdigit ( ch ) ? ch - '0' : tolower ( ch ) - 'a' + 0xa ) & 0xf; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				63
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				64
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				65
			 | 
			
			
				
				+static uint8_t gdbstub_to_hex_digit ( uint8_t b ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				66
			 | 
			
			
				
				+	b &= 0xf; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				67
			 | 
			
			
				
				+	return ( b < 0xa ? '0' : 'a' - 0xa ) + b; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				68
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				69
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				70
			 | 
			
			
				
				+static void gdbstub_from_hex_buf ( char *dst, char *src, int len ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				71
			 | 
			
			
				
				+	while ( len-- > 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				72
			 | 
			
			
				
				+		*dst = gdbstub_from_hex_digit ( *src++ ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				73
			 | 
			
			
				
				+		if ( len-- > 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				74
			 | 
			
			
				
				+			*dst = (*dst << 4) | gdbstub_from_hex_digit ( *src++ ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				75
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				76
			 | 
			
			
				
				+		dst++; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				77
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				78
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				79
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				80
			 | 
			
			
				
				+static void gdbstub_to_hex_buf ( char *dst, char *src, int len ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				81
			 | 
			
			
				
				+	while ( len-- > 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				82
			 | 
			
			
				
				+		*dst++ = gdbstub_to_hex_digit ( *src >> 4 ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				83
			 | 
			
			
				
				+		*dst++ = gdbstub_to_hex_digit ( *src++ ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				84
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				87
			 | 
			
			
				
				+static uint8_t gdbstub_cksum ( char *data, int len ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				
				+	uint8_t cksum = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				
				+	while ( len-- > 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				
				+		cksum += ( uint8_t ) *data++; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				
				+	return cksum; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				93
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				94
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				95
			 | 
			
			
				
				+static int gdbstub_getchar ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				96
			 | 
			
			
				
				+	if ( stub->exit_handler ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				
				+		return -1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				98
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				99
			 | 
			
			
				
				+	return serial_getc(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				100
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				101
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				102
			 | 
			
			
				
				+static void gdbstub_putchar ( struct gdbstub * stub __unused, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				103
			 | 
			
			
				
				+	serial_putc ( ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				104
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				105
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				106
			 | 
			
			
				
				+static void gdbstub_tx_packet ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				107
			 | 
			
			
				
				+	uint8_t cksum = gdbstub_cksum ( stub->payload, stub->len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				108
			 | 
			
			
				
				+	int i; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				109
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				110
			 | 
			
			
				
				+	gdbstub_putchar ( stub, '$' ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				111
			 | 
			
			
				
				+	for ( i = 0; i < stub->len; i++ ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				112
			 | 
			
			
				
				+		gdbstub_putchar ( stub, stub->payload [ i ] ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				113
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				114
			 | 
			
			
				
				+	gdbstub_putchar ( stub, '#' ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				115
			 | 
			
			
				
				+	gdbstub_putchar ( stub, gdbstub_to_hex_digit ( cksum >> 4 ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				116
			 | 
			
			
				
				+	gdbstub_putchar ( stub, gdbstub_to_hex_digit ( cksum ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				117
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				118
			 | 
			
			
				
				+	stub->parse = gdbstub_state_wait_ack; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				119
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				120
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				121
			 | 
			
			
				
				+/* GDB commands */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				122
			 | 
			
			
				
				+static void gdbstub_send_ok ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				123
			 | 
			
			
				
				+	stub->payload [ 0 ] = 'O'; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				124
			 | 
			
			
				
				+	stub->payload [ 1 ] = 'K'; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				125
			 | 
			
			
				
				+	stub->len = 2; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				126
			 | 
			
			
				
				+	gdbstub_tx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				127
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				128
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				129
			 | 
			
			
				
				+static void gdbstub_send_num_packet ( struct gdbstub *stub, char reply, int num ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				130
			 | 
			
			
				
				+	stub->payload [ 0 ] = reply; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				131
			 | 
			
			
				
				+	stub->payload [ 1 ] = gdbstub_to_hex_digit ( ( char ) num >> 4 ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				132
			 | 
			
			
				
				+	stub->payload [ 2 ] = gdbstub_to_hex_digit ( ( char ) num ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				133
			 | 
			
			
				
				+	stub->len = 3; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				134
			 | 
			
			
				
				+	gdbstub_tx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				135
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				136
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				137
			 | 
			
			
				
				+/* Format is arg1,arg2,...,argn:data where argn are hex integers and data is not an argument */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				138
			 | 
			
			
				
				+static int gdbstub_get_packet_args ( struct gdbstub *stub, unsigned long *args, int nargs, int *stop_idx ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				139
			 | 
			
			
				
				+	int i; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				140
			 | 
			
			
				
				+	char ch = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				141
			 | 
			
			
				
				+	int argc = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				142
			 | 
			
			
				
				+	unsigned long val = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				143
			 | 
			
			
				
				+	for ( i = 1; i < stub->len && argc < nargs; i++ ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				144
			 | 
			
			
				
				+		ch = stub->payload [ i ]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				145
			 | 
			
			
				
				+		if ( ch == ':' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				146
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				147
			 | 
			
			
				
				+		} else if ( ch == ',' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				148
			 | 
			
			
				
				+			args [ argc++ ] = val; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				149
			 | 
			
			
				
				+			val = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				150
			 | 
			
			
				
				+		} else { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				151
			 | 
			
			
				
				+			val = ( val << 4 ) | gdbstub_from_hex_digit ( ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				152
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				153
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				154
			 | 
			
			
				
				+	if ( stop_idx ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				155
			 | 
			
			
				
				+		*stop_idx = i; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				156
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				157
			 | 
			
			
				
				+	if ( argc < nargs ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				158
			 | 
			
			
				
				+		args [ argc++ ] = val; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				159
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				160
			 | 
			
			
				
				+	return ( ( i == stub->len || ch == ':' ) && argc == nargs ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				161
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				162
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				163
			 | 
			
			
				
				+static void gdbstub_send_errno ( struct gdbstub *stub, int errno ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				164
			 | 
			
			
				
				+	gdbstub_send_num_packet ( stub, 'E', errno ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				165
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				166
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				167
			 | 
			
			
				
				+static void gdbstub_report_signal ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				168
			 | 
			
			
				
				+	gdbstub_send_num_packet ( stub, 'S', stub->signo ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				169
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				170
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				171
			 | 
			
			
				
				+static void gdbstub_read_regs ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				172
			 | 
			
			
				
				+	gdbstub_to_hex_buf ( stub->payload, ( char * ) stub->regs, GDBMACH_SIZEOF_REGS ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				
				+	stub->len = GDBMACH_SIZEOF_REGS * 2; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				174
			 | 
			
			
				
				+	gdbstub_tx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				175
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				176
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				177
			 | 
			
			
				
				+static void gdbstub_write_regs ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				178
			 | 
			
			
				
				+	if ( stub->len != 1 + GDBMACH_SIZEOF_REGS * 2 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				179
			 | 
			
			
				
				+		gdbstub_send_errno ( stub, POSIX_EINVAL ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				180
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				181
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				182
			 | 
			
			
				
				+	gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], stub->len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				183
			 | 
			
			
				
				+	gdbstub_send_ok ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				184
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				185
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				186
			 | 
			
			
				
				+static void gdbstub_read_mem ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				187
			 | 
			
			
				
				+	unsigned long args [ 2 ]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				188
			 | 
			
			
				
				+	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], NULL ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				189
			 | 
			
			
				
				+		gdbstub_send_errno ( stub, POSIX_EINVAL ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				190
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				191
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				192
			 | 
			
			
				
				+	args [ 1 ] = ( args [ 1 ] < sizeof stub->payload / 2 ) ? args [ 1 ] : sizeof stub->payload / 2; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				193
			 | 
			
			
				
				+	gdbstub_to_hex_buf ( stub->payload, ( char * ) args [ 0 ], args [ 1 ] ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				194
			 | 
			
			
				
				+	stub->len = args [ 1 ] * 2; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				195
			 | 
			
			
				
				+	gdbstub_tx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				196
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				197
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				198
			 | 
			
			
				
				+static void gdbstub_write_mem ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				199
			 | 
			
			
				
				+	unsigned long args [ 2 ]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				200
			 | 
			
			
				
				+	int colon; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				201
			 | 
			
			
				
				+	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], &colon ) || 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				202
			 | 
			
			
				
				+			colon >= stub->len || stub->payload [ colon ] != ':' || 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				203
			 | 
			
			
				
				+			( stub->len - colon - 1 ) % 2 != 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				204
			 | 
			
			
				
				+		gdbstub_send_errno ( stub, POSIX_EINVAL ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				205
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				206
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				207
			 | 
			
			
				
				+	gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], stub->len - colon - 1 ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				208
			 | 
			
			
				
				+	gdbstub_send_ok ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				209
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				210
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				211
			 | 
			
			
				
				+static void gdbstub_continue ( struct gdbstub *stub, int single_step ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				212
			 | 
			
			
				
				+	gdbreg_t pc; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				213
			 | 
			
			
				
				+	if ( stub->len > 1 && gdbstub_get_packet_args ( stub, &pc, 1, NULL ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				214
			 | 
			
			
				
				+		gdbmach_set_pc ( stub->regs, pc ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				215
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				216
			 | 
			
			
				
				+	gdbmach_set_single_step ( stub->regs, single_step ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				217
			 | 
			
			
				
				+	stub->exit_handler = 1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				218
			 | 
			
			
				
				+	/* Reply will be sent when we hit the next breakpoint or interrupt */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				219
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				220
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				221
			 | 
			
			
				
				+static void gdbstub_rx_packet ( struct gdbstub *stub ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				222
			 | 
			
			
				
				+	switch ( stub->payload [ 0 ] ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				223
			 | 
			
			
				
				+		case '?': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				
				+			gdbstub_report_signal ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				225
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				
				+		case 'g': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				
				+			gdbstub_read_regs ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				228
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				229
			 | 
			
			
				
				+		case 'G': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				230
			 | 
			
			
				
				+			gdbstub_write_regs ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				231
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				232
			 | 
			
			
				
				+		case 'm': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				233
			 | 
			
			
				
				+			gdbstub_read_mem ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				234
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				235
			 | 
			
			
				
				+		case 'M': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				236
			 | 
			
			
				
				+			gdbstub_write_mem ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				
				+		case 'c': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				239
			 | 
			
			
				
				+			gdbstub_continue ( stub, 0 ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				240
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				
				+		case 's': 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				
				+			gdbstub_continue ( stub, 1 ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				243
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				244
			 | 
			
			
				
				+		default: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				245
			 | 
			
			
				
				+			stub->len = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				246
			 | 
			
			
				
				+			gdbstub_tx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				247
			 | 
			
			
				
				+			break; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				249
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				250
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				251
			 | 
			
			
				
				+/* GDB packet parser */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				252
			 | 
			
			
				
				+static void gdbstub_state_new ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				253
			 | 
			
			
				
				+	if ( ch == '$' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				254
			 | 
			
			
				
				+		stub->len = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				255
			 | 
			
			
				
				+		stub->parse = gdbstub_state_data; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				256
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				257
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				258
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				259
			 | 
			
			
				
				+static void gdbstub_state_data ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				260
			 | 
			
			
				
				+	if ( ch == '#' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				261
			 | 
			
			
				
				+		stub->parse = gdbstub_state_cksum1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				262
			 | 
			
			
				
				+	} else if ( ch == '$' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				263
			 | 
			
			
				
				+		stub->len = 0; /* retry new packet */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				264
			 | 
			
			
				
				+	} else { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				265
			 | 
			
			
				
				+		/* If the length exceeds our buffer, let the checksum fail */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				266
			 | 
			
			
				
				+		if ( stub->len < ( int ) sizeof stub->payload ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				267
			 | 
			
			
				
				+			stub->payload [ stub->len++ ] = ch; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				268
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				269
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				270
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				271
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				272
			 | 
			
			
				
				+static void gdbstub_state_cksum1 ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				273
			 | 
			
			
				
				+	stub->cksum1 = gdbstub_from_hex_digit ( ch ) << 4; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				274
			 | 
			
			
				
				+	stub->parse = gdbstub_state_cksum2; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				275
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				276
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				277
			 | 
			
			
				
				+static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				278
			 | 
			
			
				
				+	uint8_t their_cksum; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				279
			 | 
			
			
				
				+	uint8_t our_cksum; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				280
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				281
			 | 
			
			
				
				+	stub->parse = gdbstub_state_new; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				282
			 | 
			
			
				
				+	their_cksum = stub->cksum1 + gdbstub_from_hex_digit ( ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				283
			 | 
			
			
				
				+	our_cksum = gdbstub_cksum ( stub->payload, stub->len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				284
			 | 
			
			
				
				+	if ( their_cksum == our_cksum ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				285
			 | 
			
			
				
				+		gdbstub_putchar ( stub, '+' ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				286
			 | 
			
			
				
				+		if ( stub->len > 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				287
			 | 
			
			
				
				+			gdbstub_rx_packet ( stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				288
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				289
			 | 
			
			
				
				+	} else { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				290
			 | 
			
			
				
				+		gdbstub_putchar ( stub, '-' ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				291
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				292
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				293
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				294
			 | 
			
			
				
				+static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				295
			 | 
			
			
				
				+	if ( ch == '+' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				296
			 | 
			
			
				
				+		stub->parse = gdbstub_state_new; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				297
			 | 
			
			
				
				+	} else if ( ch == '-' ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				298
			 | 
			
			
				
				+		gdbstub_tx_packet ( stub ); /* retransmit */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				299
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				300
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				301
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				302
			 | 
			
			
				
				+static void gdbstub_parse ( struct gdbstub *stub, char ch ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				303
			 | 
			
			
				
				+	stub->parse ( stub, ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				304
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				305
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				306
			 | 
			
			
				
				+static struct gdbstub stub = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				307
			 | 
			
			
				
				+	.parse = gdbstub_state_new 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				308
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				309
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				310
			 | 
			
			
				
				+__cdecl void gdbstub_handler ( int signo, gdbreg_t *regs ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				311
			 | 
			
			
				
				+	int ch; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				312
			 | 
			
			
				
				+	stub.signo = signo; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				313
			 | 
			
			
				
				+	stub.regs = regs; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				314
			 | 
			
			
				
				+	stub.exit_handler = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				315
			 | 
			
			
				
				+	gdbstub_report_signal ( &stub ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				316
			 | 
			
			
				
				+	while ( ( ch = gdbstub_getchar( &stub ) ) != -1 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				317
			 | 
			
			
				
				+		gdbstub_parse ( &stub, ch ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				318
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				319
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				320
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				321
			 | 
			
			
				
				+/* Activity monitor to detect packets from GDB when we are not active */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				322
			 | 
			
			
				
				+static void gdbstub_activity_step ( struct process *process __unused ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				323
			 | 
			
			
				
				+	if ( serial_ischar() ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				324
			 | 
			
			
				
				+		gdbmach_breakpoint(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				325
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				326
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				327
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				328
			 | 
			
			
				
				+struct process gdbstub_activity_process __permanent_process = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				329
			 | 
			
			
				
				+	.step = gdbstub_activity_step, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				330
			 | 
			
			
				
				+}; 
			 |