From 5eedf3e1cef2f2b440519f867c9cb449f616b8cd Mon Sep 17 00:00:00 2001 From: ntfreak Date: Thu, 10 Jan 2008 19:29:52 +0000 Subject: [PATCH] - added faster gdb packet handling (thanks to oyvind harboe for the patch) - code reformat git-svn-id: svn://svn.berlios.de/openocd/trunk@251 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- src/helper/command.c | 8 ++-- src/server/gdb_server.c | 84 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index e9ea06927..afd866729 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -79,12 +79,12 @@ int build_unique_lengths(command_context_t *context, command_t *commands) /* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n). * Makes a difference on ARM7 types machines and is not observable on GHz machines. */ -static int unique_length_dirty=1; +static int unique_length_dirty = 1; command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help) { command_t *c, *p; - unique_length_dirty=1; + unique_length_dirty = 1; if (!context || !name) return NULL; @@ -138,7 +138,7 @@ command_t* register_command(command_context_t *context, command_t *parent, char int unregister_command(command_context_t *context, char *name) { - unique_length_dirty=1; + unique_length_dirty = 1; command_t *c, *p = NULL, *c2; @@ -316,7 +316,7 @@ int find_and_run_command(command_context_t *context, command_t *commands, char * if (unique_length_dirty) { - unique_length_dirty=0; + unique_length_dirty = 0; /* update unique lengths */ build_unique_lengths(context, context->commands); } diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 161448518..01d09791a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -38,7 +38,7 @@ #include #include -#if 0 +#if 1 #define _DEBUG_GDB_IO_ #endif @@ -185,7 +185,9 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len) int i; unsigned char my_checksum = 0; char checksum[3]; +#ifdef _DEBUG_GDB_IO_ char *debug_buffer; +#endif int reply; int retval; gdb_connection_t *gdb_con = connection->priv; @@ -195,12 +197,13 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len) while (1) { +#ifdef _DEBUG_GDB_IO_ debug_buffer = malloc(len + 1); memcpy(debug_buffer, buffer, len); debug_buffer[len] = 0; DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); free(debug_buffer); - +#endif write_socket(connection->fd, "$", 1); if (len > 0) write_socket(connection->fd, buffer, len); @@ -283,9 +286,63 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) } while (character != '$'); my_checksum = 0; - - do + + for (;;) { + /* The common case is that we have an entire packet with no escape chars. + * We need to leave at least 2 bytes in the buffer to have + * gdb_get_char() update various bits and bobs correctly. + */ + if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len)) + { + /* The compiler will struggle a bit with constant propagation and + * aliasing, so we help it by showing that these values do not + * change inside the loop + */ + int i; + char *buf = gdb_con->buf_p; + int run = gdb_con->buf_cnt - 2; + i = 0; + int done = 0; + while (i < run) + { + character = *buf++; + i++; + if (character == '#') + { + /* Danger! character can be '#' when esc is + * used so we need an explicit boolean for done here. + */ + done = 1; + break; + } + + if (character == '}') + { + /* data transmitted in binary mode (X packet) + * uses 0x7d as escape character */ + my_checksum += character & 0xff; + character = *buf++; + i++; + my_checksum += character & 0xff; + buffer[count++] = (character ^ 0x20) & 0xff; + } else + { + my_checksum += character & 0xff; + buffer[count++] = character & 0xff; + } + } + gdb_con->buf_p += i; + gdb_con->buf_cnt -= i; + if (done) + break; + } + if (count > *len) + { + ERROR("packet buffer too small"); + return ERROR_GDB_BUFFER_TOO_SMALL; + } + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) return retval; @@ -308,12 +365,7 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) buffer[count++] = character & 0xff; } - if (count > *len) - { - ERROR("packet buffer too small"); - return ERROR_GDB_BUFFER_TOO_SMALL; - } - } while (1); + } *len = count; @@ -910,6 +962,18 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac retval = target->type->read_memory(target, addr, 1, len, buffer); } +#if 0 + if (retval == ERROR_TARGET_DATA_ABORT) + { + /* TODO : Here we have to lie and send back all zero's lest stack traces won't work. + * At some point this might be fixed in GDB, in which case this code can be removed. + * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395 + */ + memset(buffer, 0, len); + retval = ERROR_OK; + } +#endif + if (retval == ERROR_OK) { hex_buffer = malloc(len * 2 + 1);