From a8cd41b472bd92316220c76137c29b5faac99a35 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 22 Jun 2006 15:20:47 +0000 Subject: [PATCH] * remote-utils.c (remote_escape_output, remote_unescape_input): New. (putpkt_binary): Renamed from putpkt and adjusted for binary data. (putpkt): New wrapper for putpkt_binary. (readchar): Don't mask off the high bit. (decode_X_packet): New function. * server.c (main): Call putpkt_binary if a handler sets the packet length. Save the length of the incoming packet. Handle 'X'. * server.h (gdb_byte, remote_escape_output, decode_X_packet): New. --- gdb/gdbserver/ChangeLog | 12 ++++ gdb/gdbserver/remote-utils.c | 131 +++++++++++++++++++++++++++++++++++++++++-- gdb/gdbserver/server.c | 22 +++++++- gdb/gdbserver/server.h | 9 +++ 4 files changed, 166 insertions(+), 8 deletions(-) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 1cf91b5018..5758995ef6 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,15 @@ +2006-06-22 Daniel Jacobowitz + + * remote-utils.c (remote_escape_output, remote_unescape_input): New. + (putpkt_binary): Renamed from putpkt and adjusted for binary + data. + (putpkt): New wrapper for putpkt_binary. + (readchar): Don't mask off the high bit. + (decode_X_packet): New function. + * server.c (main): Call putpkt_binary if a handler sets the packet + length. Save the length of the incoming packet. Handle 'X'. + * server.h (gdb_byte, remote_escape_output, decode_X_packet): New. + 2006-06-21 Daniel Jacobowitz * server.c (handle_query): Handle qSupported. diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 60403ff6bb..7a12b055fb 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -276,17 +276,98 @@ hexify (char *hex, const char *bin, int count) return i; } +/* Convert BUFFER, binary data at least LEN bytes long, into escaped + binary data in OUT_BUF. Set *OUT_LEN to the length of the data + encoded in OUT_BUF, and return the number of bytes in OUT_BUF + (which may be more than *OUT_LEN due to escape characters). The + total number of bytes in the output buffer will be at most + OUT_MAXLEN. */ + +int +remote_escape_output (const gdb_byte *buffer, int len, + gdb_byte *out_buf, int *out_len, + int out_maxlen) +{ + int input_index, output_index; + + output_index = 0; + for (input_index = 0; input_index < len; input_index++) + { + gdb_byte b = buffer[input_index]; + + if (b == '$' || b == '#' || b == '}' || b == '*') + { + /* These must be escaped. */ + if (output_index + 2 > out_maxlen) + break; + out_buf[output_index++] = '}'; + out_buf[output_index++] = b ^ 0x20; + } + else + { + if (output_index + 1 > out_maxlen) + break; + out_buf[output_index++] = b; + } + } + + *out_len = input_index; + return output_index; +} + +/* Convert BUFFER, escaped data LEN bytes long, into binary data + in OUT_BUF. Return the number of bytes written to OUT_BUF. + Raise an error if the total number of bytes exceeds OUT_MAXLEN. + + This function reverses remote_escape_output. It allows more + escaped characters than that function does, in particular because + '*' must be escaped to avoid the run-length encoding processing + in reading packets. */ + +static int +remote_unescape_input (const gdb_byte *buffer, int len, + gdb_byte *out_buf, int out_maxlen) +{ + int input_index, output_index; + int escaped; + + output_index = 0; + escaped = 0; + for (input_index = 0; input_index < len; input_index++) + { + gdb_byte b = buffer[input_index]; + + if (output_index + 1 > out_maxlen) + error ("Received too much data from the target."); + + if (escaped) + { + out_buf[output_index++] = b ^ 0x20; + escaped = 0; + } + else if (b == '}') + escaped = 1; + else + out_buf[output_index++] = b; + } + + if (escaped) + error ("Unmatched escape character in target response."); + + return output_index; +} + /* Send a packet to the remote machine, with error checking. - The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */ + The data of the packet is in BUF, and the length of the + packet is in CNT. Returns >= 0 on success, -1 otherwise. */ int -putpkt (char *buf) +putpkt_binary (char *buf, int cnt) { int i; unsigned char csum = 0; char *buf2; char buf3[1]; - int cnt = strlen (buf); char *p; buf2 = malloc (PBUFSIZ); @@ -353,6 +434,17 @@ putpkt (char *buf) return 1; /* Success! */ } +/* Send a packet to the remote machine, with error checking. The data + of the packet is in BUF, and the packet should be a NUL-terminated + string. Returns >= 0 on success, -1 otherwise. */ + +int +putpkt (char *buf) +{ + return putpkt_binary (buf, strlen (buf)); +} + + /* Come here when we get an input interrupt from the remote side. This interrupt should only be active while we are waiting for the child to do something. About the only thing that should come through is a ^C, which @@ -439,12 +531,12 @@ disable_async_io (void) static int readchar (void) { - static char buf[BUFSIZ]; + static unsigned char buf[BUFSIZ]; static int bufcnt = 0; - static char *bufp; + static unsigned char *bufp; if (bufcnt-- > 0) - return *bufp++ & 0x7f; + return *bufp++; bufcnt = read (remote_desc, buf, sizeof (buf)); @@ -755,6 +847,33 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, convert_ascii_to_int (&from[i++], to, *len_ptr); } +int +decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr, unsigned char *to) +{ + int i = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + while ((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } + + if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i, + to, *len_ptr) != *len_ptr) + return -1; + + return 0; +} + /* Ask GDB for the address of NAME, and return it in ADDRP if found. Returns 1 if the symbol is found, 0 if it is not, -1 on error. */ diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 8099ef4189..f8803d6555 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -440,9 +440,16 @@ main (int argc, char *argv[]) restart: setjmp (toplevel); - while (getpkt (own_buf) > 0) + while (1) { unsigned char sig; + int packet_len; + int new_packet_len = -1; + + packet_len = getpkt (own_buf); + if (packet_len <= 0) + break; + i = 0; ch = own_buf[i++]; switch (ch) @@ -547,6 +554,14 @@ main (int argc, char *argv[]) else write_enn (own_buf); break; + case 'X': + if (decode_X_packet (&own_buf[1], packet_len - 1, + &mem_addr, &len, mem_buf) < 0 + || write_inferior_memory (mem_addr, mem_buf, len) != 0) + write_enn (own_buf); + else + write_ok (own_buf); + break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) @@ -714,7 +729,10 @@ main (int argc, char *argv[]) break; } - putpkt (own_buf); + if (new_packet_len != -1) + putpkt_binary (own_buf, new_packet_len); + else + putpkt (own_buf); if (status == 'W') fprintf (stderr, diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index a659bbbe32..5147094ca9 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -57,6 +57,9 @@ extern char *strerror (int); /* X3.159-1989 4.11.6.2 */ #endif #endif +/* A type used for binary buffers. */ +typedef unsigned char gdb_byte; + /* FIXME: This should probably be autoconf'd for. It's an integer type at least the size of a (void *). */ typedef long long CORE_ADDR; @@ -133,6 +136,7 @@ extern jmp_buf toplevel; extern int all_symbols_looked_up; int putpkt (char *buf); +int putpkt_binary (char *buf, int len); int getpkt (char *buf); void remote_open (char *name); void remote_close (void); @@ -152,9 +156,14 @@ void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr); void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr, unsigned char *to); +int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr, + unsigned int *len_ptr, unsigned char *to); int unhexify (char *bin, const char *hex, int count); int hexify (char *hex, const char *bin, int count); +int remote_escape_output (const gdb_byte *buffer, int len, + gdb_byte *out_buf, int *out_len, + int out_maxlen); int look_up_one_symbol (const char *name, CORE_ADDR *addrp); -- 2.11.0