- add ability for openocd to communicate to gdb using pipes (stdin/stdout).
[openocd.git] / src / server / gdb_server.c
index 356483d2f66ce60c410dab764b7aac8fc1939138..72f14095a244ed13185ef20a0110252c2b511d28 100644 (file)
@@ -2,9 +2,12 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                      *
+ *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
@@ -34,6 +37,7 @@
 #include "jtag.h"
 #include "breakpoints.h"
 #include "flash.h"
+#include "target.h"
 #include "target_request.h"
 #include "configuration.h"
 
@@ -116,10 +120,10 @@ int check_pending(connection_t *connection, int timeout_s, int *got_data)
                *got_data = 1;
                return ERROR_OK;
        }
-       
+
        FD_ZERO(&read_fds);
        FD_SET(connection->fd, &read_fds);
-       
+
        tv.tv_sec = timeout_s;
        tv.tv_usec = 0;
        if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)
@@ -165,10 +169,18 @@ int gdb_get_char(connection_t *connection, int* next_char)
 
        for (;;)
        {
-               retval=check_pending(connection, 1, NULL);
-               if (retval!=ERROR_OK)
-                       return retval;
-               gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
+               if (connection->service->type == CONNECTION_PIPE)
+               {
+                       gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
+               }
+               else
+               {
+                       retval = check_pending(connection, 1, NULL);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
+               }
+               
                if (gdb_con->buf_cnt > 0)
                {
                        break;
@@ -264,10 +276,21 @@ int gdb_write(connection_t *connection, void *data, int len)
        gdb_connection_t *gdb_con = connection->priv;
        if (gdb_con->closed)
                return ERROR_SERVER_REMOTE_CLOSED;
-
-       if (write_socket(connection->fd, data, len) == len)
+       
+       if (connection->service->type == CONNECTION_PIPE)
        {
-               return ERROR_OK;
+               /* write to stdout */
+               if (write(STDOUT_FILENO, data, len) == len)
+               {
+                       return ERROR_OK;
+               }
+       }
+       else
+       {
+               if (write_socket(connection->fd, data, len) == len)
+               {
+                       return ERROR_OK;
+               }
        }
        gdb_con->closed = 1;
        return ERROR_SERVER_REMOTE_CLOSED;
@@ -288,7 +311,7 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                my_checksum += buffer[i];
 
 #ifdef _DEBUG_GDB_IO_
-       /* 
+       /*
         * At this point we should have nothing in the input queue from GDB,
         * however sometimes '-' is sent even though we've already received
         * an ACK (+) for everything we've sent off.
@@ -302,6 +325,13 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                        break;
                if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
                        return retval;
+               if( reply == '$' ){
+                       /* fix a problem with some IAR tools */
+                       gdb_putback_char( connection, reply );
+                       LOG_DEBUG("Unexpected start of new packet");
+                       break;
+               }
+
                LOG_WARNING("Discard unexpected char %c", reply);
        }
 #endif
@@ -325,7 +355,10 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                        local_buffer[len++] = '#';
                        local_buffer[len++] = DIGITS[(my_checksum >> 4) & 0xf];
                        local_buffer[len++] = DIGITS[my_checksum & 0xf];
-                       gdb_write(connection, local_buffer, len);
+                       if((retval = gdb_write(connection, local_buffer, len)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
                }
                else
                {
@@ -334,11 +367,23 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                        local_buffer[1] = '#';
                        local_buffer[2] = DIGITS[(my_checksum >> 4) & 0xf];
                        local_buffer[3] = DIGITS[my_checksum & 0xf];
-                       gdb_write(connection, local_buffer, 1);
-                       gdb_write(connection, buffer, len);
-                       gdb_write(connection, local_buffer+1, 3);
+                       if((retval = gdb_write(connection, local_buffer, 1)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if((retval = gdb_write(connection, buffer, len)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if((retval = gdb_write(connection, local_buffer+1, 3)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
                }
 
+               if (gdb_con->noack_mode)
+                       break;
+
                if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
                        return retval;
 
@@ -363,16 +408,25 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                                log_remove_callback(gdb_log_callback, connection);
                                LOG_WARNING("negative reply, retrying");
                        }
-                       else
-                       {
-                               LOG_ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
+                       else if( reply == '$' ){
+                               LOG_ERROR("GDB missing ack(1) - assumed good");
+                               gdb_putback_char( connection, reply );
+                               return ERROR_OK;
+                       } else {
+
+                               LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply);
                                gdb_con->closed=1;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        }
                }
+               else if( reply == '$' ){
+                       LOG_ERROR("GDB missing ack(2) - assumed good");
+                       gdb_putback_char( connection, reply );
+                       return ERROR_OK;
+               }
                else
                {
-                       LOG_ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
+                       LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply);
                        gdb_con->closed=1;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
@@ -389,16 +443,126 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
        gdb_con->busy = 1;
        int retval = gdb_put_packet_inner(connection, buffer, len);
        gdb_con->busy = 0;
+
+       /* we sent some data, reset timer for keep alive messages */
+       kept_alive();
+
        return retval;
 }
 
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
+static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, int noack, int *len, char *buffer)
 {
+       unsigned char my_checksum = 0;
+       char checksum[3];
        int character;
+       int retval;
+
+       gdb_connection_t *gdb_con = connection->priv;
+       my_checksum = 0;
        int count = 0;
+       count = 0;
+       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)
+               {
+                       LOG_ERROR("packet buffer too small");
+                       return ERROR_GDB_BUFFER_TOO_SMALL;
+               }
+
+               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+                       return retval;
+
+               if (character == '#')
+                       break;
+
+               if (character == '}')
+               {
+                       /* data transmitted in binary mode (X packet)
+                        * uses 0x7d as escape character */
+                       my_checksum += character & 0xff;
+                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+                               return retval;
+                       my_checksum += character & 0xff;
+                       buffer[count++] = (character ^ 0x20) & 0xff;
+               }
+               else
+               {
+                       my_checksum += character & 0xff;
+                       buffer[count++] = character & 0xff;
+               }
+       }
+
+       *len = count;
+
+       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               return retval;
+       checksum[0] = character;
+       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               return retval;
+       checksum[1] = character;
+       checksum[2] = 0;
+
+       if (!noack)
+       {
+               *checksum_ok=(my_checksum == strtoul(checksum, NULL, 16));
+       }
+
+       return ERROR_OK;
+}
+
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
+{
+       int character;
        int retval;
-       char checksum[3];
-       unsigned char my_checksum = 0;
        gdb_connection_t *gdb_con = connection->priv;
 
        while (1)
@@ -434,108 +598,35 @@ int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
                        }
                } while (character != '$');
 
-               my_checksum = 0;
-
-               count = 0;
-               gdb_connection_t *gdb_con = connection->priv;
-               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)
-                       {
-                               LOG_ERROR("packet buffer too small");
-                               return ERROR_GDB_BUFFER_TOO_SMALL;
-                       }
 
-                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+               int checksum_ok;
+               /* explicit code expansion here to get faster inlined code in -O3 by not
+                * calculating checksum
+                */
+               if (gdb_con->noack_mode)
+               {
+                       if ((retval=fetch_packet(connection, &checksum_ok, 1, len, buffer))!=ERROR_OK)
+                               return retval;
+               } else
+               {
+                       if ((retval=fetch_packet(connection, &checksum_ok, 0, len, buffer))!=ERROR_OK)
                                return retval;
-
-                       if (character == '#')
-                               break;
-
-                       if (character == '}')
-                       {
-                               /* data transmitted in binary mode (X packet)
-                                * uses 0x7d as escape character */
-                               my_checksum += character & 0xff;
-                               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                                       return retval;
-                               my_checksum += character & 0xff;
-                               buffer[count++] = (character ^ 0x20) & 0xff;
-                       }
-                       else
-                       {
-                               my_checksum += character & 0xff;
-                               buffer[count++] = character & 0xff;
-                       }
-
                }
 
-               *len = count;
-
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[0] = character;
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[1] = character;
-               checksum[2] = 0;
-
-               if (my_checksum == strtoul(checksum, NULL, 16))
+               if (gdb_con->noack_mode)
                {
-                       gdb_write(connection, "+", 1);
+                       /* checksum is not checked in noack mode */
+                       break;
+               }
+               if (checksum_ok)
+               {
+                       if ((retval = gdb_write(connection, "+", 1)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
                        break;
                }
-
-               LOG_WARNING("checksum error, requesting retransmission");
-               gdb_write(connection, "-", 1);
        }
        if (gdb_con->closed)
                return ERROR_SERVER_REMOTE_CLOSED;
@@ -568,10 +659,10 @@ int gdb_output_con(connection_t *connection, const char* line)
                snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);
        hex_buffer[bin_size*2+1] = 0;
 
-       gdb_put_packet(connection, hex_buffer, bin_size*2 + 1);
+       int retval = gdb_put_packet(connection, hex_buffer, bin_size*2 + 1);
 
        free(hex_buffer);
-       return ERROR_OK;
+       return retval;
 }
 
 int gdb_output(struct command_context_s *context, const char* line)
@@ -581,20 +672,11 @@ int gdb_output(struct command_context_s *context, const char* line)
        return ERROR_OK;
 }
 
-int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
-{
-       struct command_context_s *cmd_ctx = priv;
-
-       target_invoke_script(cmd_ctx, target, "gdb_program");
-       jtag_execute_queue();
-
-       return ERROR_OK;
-}
 
 static void gdb_frontend_halted(struct target_s *target, connection_t *connection)
 {
        gdb_connection_t *gdb_connection = connection->priv;
-       
+
        /* In the GDB protocol when we are stepping or coninuing execution,
         * we have a lingering reply. Upon receiving a halted event
         * when we have that lingering packet, we reply to the original
@@ -608,6 +690,7 @@ static void gdb_frontend_halted(struct target_s *target, connection_t *connectio
        {
                char sig_reply[4];
                int signal;
+
                /* stop forwarding log packets! */
                log_remove_callback(gdb_log_callback, connection);
 
@@ -629,15 +712,24 @@ static void gdb_frontend_halted(struct target_s *target, connection_t *connectio
 
 int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
 {
+       int retval;
        connection_t *connection = priv;
 
+       target_handle_event( target, event );
        switch (event)
        {
-               case TARGET_EVENT_HALTED:
+               case TARGET_EVENT_EARLY_HALTED:
                        gdb_frontend_halted(target, connection);
                        break;
-               case TARGET_EVENT_GDB_PROGRAM:
-                       gdb_program_handler(target, event, connection->cmd_ctx);
+               case TARGET_EVENT_HALTED:
+                       target_call_event_callbacks(target, TARGET_EVENT_GDB_END);
+                       break;
+               case TARGET_EVENT_GDB_FLASH_ERASE_START:
+                       target_handle_event( target, TARGET_EVENT_OLD_gdb_program_config );
+                       if((retval = jtag_execute_queue()) != ERROR_OK)
+                       {
+                               return retval;
+                       }
                        break;
                default:
                        break;
@@ -646,7 +738,6 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event
        return ERROR_OK;
 }
 
-
 int gdb_new_connection(connection_t *connection)
 {
        gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));
@@ -664,7 +755,8 @@ int gdb_new_connection(connection_t *connection)
        gdb_connection->vflash_image = NULL;
        gdb_connection->closed = 0;
        gdb_connection->busy = 0;
-       
+       gdb_connection->noack_mode = 0;
+
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
 
@@ -672,49 +764,49 @@ int gdb_new_connection(connection_t *connection)
        command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
 
        /* we must remove all breakpoints registered to the target as a previous
-        * GDB session could leave dangling breakpoints if e.g. communication 
+        * GDB session could leave dangling breakpoints if e.g. communication
         * timed out.
         */
        breakpoint_clear_target(gdb_service->target);
        watchpoint_clear_target(gdb_service->target);
-       
+
        /* register callback to be informed about target events */
        target_register_event_callback(gdb_target_callback_event_handler, connection);
 
        /* a gdb session just attached, try to put the target in halt mode.
-        * 
-        * DANGER!!!! 
-        * 
+        *
+        * DANGER!!!!
+        *
         * If the halt fails(e.g. target needs a reset, JTAG communication not
         * working, etc.), then the GDB connect will succeed as
         * the get_gdb_reg_list() will lie and return a register list with
         * dummy values.
-        * 
+        *
         * This allows GDB monitor commands to be run from a GDB init script to
         * initialize the target
-        * 
+        *
         * Also, since the halt() is asynchronous target connect will be
         * instantaneous and thus avoiding annoying timeout problems during
-        * connect. 
+        * connect.
         */
        target_halt(gdb_service->target);
        /* FIX!!!! could extended-remote work better here?
-        * 
+        *
         *  wait a tiny bit for halted state or we just continue. The
-        * GDB register packet will then contain garbage 
+        * GDB register packet will then contain garbage
         */
        target_wait_state(gdb_service->target, TARGET_HALTED, 500);
-       
+
        /* remove the initial ACK from the incoming buffer */
        if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
                return retval;
 
-       /* FIX!!!??? would we actually ever receive a + here??? 
+       /* FIX!!!??? would we actually ever receive a + here???
         * Not observed.
         */
        if (initial_ack != '+')
                gdb_putback_char(connection, initial_ack);
-
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH );
        return ERROR_OK;
 }
 
@@ -745,8 +837,11 @@ int gdb_connection_closed(connection_t *connection)
        }
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END);
        log_remove_callback(gdb_log_callback, connection);
 
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH );
+
        return ERROR_OK;
 }
 
@@ -770,9 +865,23 @@ int gdb_last_signal_packet(connection_t *connection, target_t *target, char* pac
        return ERROR_OK;
 }
 
-/* Convert register to string of bits. NB! The # of bits in the
+static int gdb_reg_pos(target_t *target, int pos, int len)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               return pos;
+       else
+               return len - 1 - pos;
+}
+
+/* Convert register to string of bytes. NB! The # of bits in the
  * register might be non-divisible by 8(a byte), in which
- * case an entire byte is shown. */
+ * case an entire byte is shown.
+ *
+ * NB! the format on the wire is the target endianess
+ *
+ * The format of reg->value is little endian
+ *
+ */
 void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
 {
        int i;
@@ -784,26 +893,44 @@ void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
 
        for (i = 0; i < buf_len; i++)
        {
-               tstr[i*2]   = DIGITS[(buf[i]>>4) & 0xf];
-               tstr[i*2+1] = DIGITS[buf[i]&0xf];
+               int j = gdb_reg_pos(target, i, buf_len);
+               tstr[i*2]   = DIGITS[(buf[j]>>4) & 0xf];
+               tstr[i*2+1] = DIGITS[buf[j]&0xf];
        }
 }
 
-void gdb_target_to_str(target_t *target, char *tstr, char *str)
+static int hextoint(char c)
 {
-       int str_len = strlen(tstr);
-       int i;
+       if (c>='0'&&c<='9')
+       {
+               return c-'0';
+       }
+       c=toupper(c);
+       if (c>='A'&&c<='F')
+       {
+               return c-'A'+10;
+       }
+       LOG_ERROR("BUG: invalid register value %08x", c);
+       return 0;
+}
 
+/* copy over in register buffer */
+void gdb_target_to_reg(target_t *target, char *tstr, int str_len, u8 *bin)
+{
        if (str_len % 2)
        {
                LOG_ERROR("BUG: gdb value with uneven number of characters encountered");
                exit(-1);
        }
 
+       int i;
        for (i = 0; i < str_len; i+=2)
        {
-               str[str_len - i - 1] = tstr[i + 1];
-               str[str_len - i - 2] = tstr[i];
+               u8 t = hextoint(tstr[i])<<4;
+               t |= hextoint(tstr[i+1]);
+
+               int j = gdb_reg_pos(target, i/2, str_len/2);
+               bin[j] = t;
        }
 }
 
@@ -888,31 +1015,27 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
        for (i = 0; i < reg_list_size; i++)
        {
                u8 *bin_buf;
-               char *hex_buf;
-               reg_arch_type_t *arch_type;
+               int chars = (CEIL(reg_list[i]->size, 8) * 2);
 
-               /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-               hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);
-               gdb_target_to_str(target, packet_p, hex_buf);
+               if (packet_p + chars > packet + packet_size)
+               {
+                       LOG_ERROR("BUG: register packet is too small for registers");
+               }
 
-               /* convert hex-string to binary buffer */
+               reg_arch_type_t *arch_type;
                bin_buf = malloc(CEIL(reg_list[i]->size, 8));
-               str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);
+               gdb_target_to_reg(target, packet_p, chars, bin_buf);
 
                /* get register arch_type, and call set method */
                arch_type = register_get_arch_type(reg_list[i]->arch_type);
-               if (arch_type == NULL)
-               {
-                       LOG_ERROR("BUG: encountered unregistered arch type");
-                       exit(-1);
-               }
+
                arch_type->set(reg_list[i], bin_buf);
 
                /* advance packet pointer */
-               packet_p += (CEIL(reg_list[i]->size, 8) * 2);
+               packet_p += chars;
+
 
                free(bin_buf);
-               free(hex_buf);
        }
 
        /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */
@@ -961,7 +1084,6 @@ int gdb_get_register_packet(connection_t *connection, target_t *target, char *pa
 int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
-       char *hex_buf;
        u8 *bin_buf;
        int reg_num = strtoul(packet + 1, &separator, 16);
        reg_t **reg_list;
@@ -979,7 +1101,7 @@ int gdb_set_register_packet(connection_t *connection, target_t *target, char *pa
        if (reg_list_size < reg_num)
        {
                LOG_ERROR("gdb requested a non-existing register");
-               return ERROR_SERVER_REMOTE_CLOSED;      
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if (*separator != '=')
@@ -989,26 +1111,20 @@ int gdb_set_register_packet(connection_t *connection, target_t *target, char *pa
        }
 
        /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-       hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
-       gdb_target_to_str(target, separator + 1, hex_buf);
-
-       /* convert hex-string to binary buffer */
        bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
-       str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);
+       int chars = (CEIL(reg_list[reg_num]->size, 8) * 2);
+
+       /* fix!!! add some sanity checks on packet size here */
 
-       /* get register arch_type, and call set method */
+       gdb_target_to_reg(target, separator + 1, chars, bin_buf);
+
+               /* get register arch_type, and call set method */
        arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
-       if (arch_type == NULL)
-       {
-               LOG_ERROR("BUG: encountered unregistered arch type");
-               exit(-1);
-       }
        arch_type->set(reg_list[reg_num], bin_buf);
 
        gdb_put_packet(connection, "OK", 2);
 
        free(bin_buf);
-       free(hex_buf);
        free(reg_list);
 
        return ERROR_OK;
@@ -1075,7 +1191,7 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac
 
        retval = target_read_buffer(target, addr, len, buffer);
 
-       if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))
+       if ((retval!=ERROR_OK)&&!gdb_report_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.
@@ -1245,7 +1361,7 @@ int gdb_step_continue_packet(connection_t *connection, target_t *target, char *p
        if (packet[0] == 'c')
        {
                LOG_DEBUG("continue");
-               target_invoke_script(connection->cmd_ctx, target, "pre_resume");
+               target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
                retval=target_resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
        }
        else if (packet[0] == 's')
@@ -1280,7 +1396,7 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
                wp_type = WPT_READ;
        else if (type == 4) /* access watchpoint */
                wp_type = WPT_ACCESS;
-       
+
        if (gdb_breakpoint_override&&((bp_type==BKPT_SOFT)||(bp_type==BKPT_HARD)))
        {
                bp_type=gdb_breakpoint_override_type;
@@ -1443,7 +1559,7 @@ static int compare_bank (const void * a, const void * b)
        flash_bank_t *b1, *b2;
        b1=*((flash_bank_t **)a);
        b2=*((flash_bank_t **)b);
-       
+
        if (b1->base==b2->base)
        {
                return 0;
@@ -1459,6 +1575,7 @@ static int compare_bank (const void * a, const void * b)
 int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        command_context_t *cmd_ctx = connection->cmd_ctx;
+       gdb_connection_t *gdb_connection = connection->priv;
 
        if (strstr(packet, "qRcmd,"))
        {
@@ -1536,7 +1653,7 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                int size = 0;
 
                xml_printf(&retval, &buffer, &pos, &size,
-                               "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
+                               "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
                                (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1)&&(flash_get_bank_count()>0)) ? '+' : '-');
 
                if (retval != ERROR_OK)
@@ -1576,15 +1693,15 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                length = strtoul(separator + 1, &separator, 16);
 
                xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");
-       
-               /* 
+
+               /*
                sort banks in ascending order, we need to make non-flash memory be ram(or rather
                read/write) by default for GDB.
                GDB does not have a concept of non-cacheable read/write memory.
                 */
                flash_bank_t **banks=malloc(sizeof(flash_bank_t *)*flash_get_bank_count());
                int i;
-               
+
                for (i=0; i<flash_get_bank_count(); i++)
                {
                        p = get_flash_bank_by_num(i);
@@ -1597,29 +1714,29 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                        }
                        banks[i]=p;
                }
-               
+
                qsort(banks, flash_get_bank_count(), sizeof(flash_bank_t *), compare_bank);
-               
+
                u32 ram_start=0;
                for (i=0; i<flash_get_bank_count(); i++)
                {
                        p = banks[i];
-                       
+
                        if (ram_start<p->base)
                        {
                                xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"0x%x\" length=\"0x%x\"/>\n",
                                        ram_start, p->base-ram_start);
                        }
-                       
+
                        /* if device has uneven sector sizes, eg. str7, lpc
                         * we pass the smallest sector size to gdb memory map */
                        blocksize = gdb_calc_blocksize(p);
-       
+
                        xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
                                "<property name=\"blocksize\">0x%x</property>\n" \
                                "</memory>\n", \
                                p->base, p->size, blocksize);
-                       ram_start=p->base+p->size;                      
+                       ram_start=p->base+p->size;
                }
                if (ram_start!=0)
                {
@@ -1630,7 +1747,7 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                        /* a flash chip could be at the very end of the 32 bit address space, in which case
                        ram_start will be precisely 0 */
                }
-               
+
                free(banks);
                banks = NULL;
 
@@ -1696,6 +1813,12 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                free(xml);
                return ERROR_OK;
        }
+       else if (strstr(packet, "QStartNoAckMode"))
+       {
+               gdb_connection->noack_mode = 1;
+               gdb_put_packet(connection, "OK", 2);
+               return ERROR_OK;
+       }
 
        gdb_put_packet(connection, "", 0);
        return ERROR_OK;
@@ -1748,10 +1871,12 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                flash_set_dirty();
 
                /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START);
+               result = flash_erase_address_range(gdb_service->target, addr, length );
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
-               if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
+               if (result != ERROR_OK)
                {
                        /* GDB doesn't evaluate the actual error number returned,
                         * treat a failed erase as an I/O error
@@ -1767,6 +1892,7 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
        if (strstr(packet, "vFlashWrite:"))
        {
+               int retval;
                unsigned long addr;
                unsigned long length;
                char *parse = packet + 12;
@@ -1792,7 +1918,10 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                }
 
                /* create new section with content from packet buffer */
-               image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);
+               if((retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse)) != ERROR_OK)
+               {
+                       return retval;
+               }
 
                gdb_put_packet(connection, "OK", 2);
 
@@ -1805,7 +1934,10 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
-               if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_START);
+               result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0);
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END);
+               if ( result != ERROR_OK)
                {
                        if (result == ERROR_FLASH_DST_OUT_OF_BANK)
                                gdb_put_packet(connection, "E.memtype", 9);
@@ -1831,10 +1963,11 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
 int gdb_detach(connection_t *connection, target_t *target)
 {
+
        switch( detach_mode )
        {
                case GDB_DETACH_RESUME:
-                       target_invoke_script(connection->cmd_ctx, target, "pre_resume");
+                       target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
                        target_resume(target, 1, 0, 1, 0);
                        break;
 
@@ -1852,7 +1985,6 @@ int gdb_detach(connection_t *connection, target_t *target)
        }
 
        gdb_put_packet(connection, "OK", 2);
-
        return ERROR_OK;
 }
 
@@ -1904,7 +2036,20 @@ int gdb_input_inner(connection_t *connection)
                /* terminate with zero */
                packet[packet_size] = 0;
 
-               LOG_DEBUG("received packet: '%s'", packet);
+               if( LOG_LEVEL_IS( LOG_LVL_DEBUG ) ){
+                       if( packet[0] == 'X' ){
+                               // binary packets spew junk into the debug log stream
+                               char buf[ 50 ];
+                               int x;
+                               for( x = 0 ; (x < 49) && (packet[x] != ':') ; x++ ){
+                                       buf[x] = packet[x];
+                               }
+                               buf[x] = 0;
+                               LOG_DEBUG("received packet: '%s:<binary-data>'", buf );
+                       } else {
+                               LOG_DEBUG("received packet: '%s'", packet );
+                       }
+               }
 
                if (packet_size > 0)
                {
@@ -1917,6 +2062,7 @@ int gdb_input_inner(connection_t *connection)
                                        gdb_put_packet(connection, NULL, 0);
                                        break;
                                case 'q':
+                               case 'Q':
                                        retval = gdb_query_packet(connection, target, packet, packet_size);
                                        break;
                                case 'g':
@@ -1956,16 +2102,17 @@ int gdb_input_inner(connection_t *connection)
                                                } else
                                                {
                                                        /* We're running/stepping, in which case we can
-                                                        * forward log output until the target is halted 
+                                                        * forward log output until the target is halted
                                                         */
                                                        gdb_connection_t *gdb_con = connection->priv;
                                                        gdb_con->frontend_state = TARGET_RUNNING;
                                                        log_add_callback(gdb_log_callback, connection);
+                                                       target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
                                                        int retval=gdb_step_continue_packet(connection, target, packet, packet_size);
                                                        if (retval!=ERROR_OK)
                                                        {
                                                                /* we'll never receive a halted condition... issue a false one.. */
-                                                               gdb_frontend_halted(target, connection); 
+                                                               gdb_frontend_halted(target, connection);
                                                        }
                                                }
                                        }
@@ -1993,6 +2140,8 @@ int gdb_input_inner(connection_t *connection)
                                        break;
                                case 'R':
                                        /* handle extended restart packet */
+                                       breakpoint_clear_target(gdb_service->target);
+                                       watchpoint_clear_target(gdb_service->target);
                                        command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %d", get_num_by_target(target));
                                        break;
                                default:
@@ -2028,10 +2177,10 @@ int gdb_input(connection_t *connection)
        if (retval == ERROR_SERVER_REMOTE_CLOSED)
                return retval;
 
-       /* logging does not propagate the error, yet can set th gdb_con->closed flag */
+       /* logging does not propagate the error, yet can set the gdb_con->closed flag */
        if (gdb_con->closed)
                return ERROR_SERVER_REMOTE_CLOSED;
-       
+
        /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */
        return ERROR_OK;
 }
@@ -2039,8 +2188,7 @@ int gdb_input(connection_t *connection)
 int gdb_init(void)
 {
        gdb_service_t *gdb_service;
-       target_t *target = targets;
-       int i = 0;
+       target_t *target = all_targets;
 
        if (!target)
        {
@@ -2048,29 +2196,37 @@ int gdb_init(void)
                return ERROR_OK;
        }
 
-       if (gdb_port == 0)
+       if (gdb_port == 0 && server_use_pipes == 0)
        {
                LOG_WARNING("no gdb port specified, using default port 3333");
                gdb_port = 3333;
        }
 
-       while (target)
+       if (server_use_pipes)
        {
-               char service_name[8];
-
-               snprintf(service_name, 8, "gdb-%2.2i", i);
-
+               /* only a single gdb connection when using a pipe */
+               
                gdb_service = malloc(sizeof(gdb_service_t));
                gdb_service->target = target;
 
-               add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
-
-               LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
+               add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
 
-               i++;
-               target = target->next;
+               LOG_DEBUG("gdb service for target %s using pipes", target->type->name);
        }
+       else
+       {
+               while (target)
+               {
+                       gdb_service = malloc(sizeof(gdb_service_t));
+                       gdb_service->target = target;
 
+                       add_service("gdb", CONNECTION_TCP, gdb_port + target->target_number, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+                       
+                       LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + target->target_number);
+                       target = target->next;
+               }
+       }
+       
        return ERROR_OK;
 }
 
@@ -2078,7 +2234,10 @@ int gdb_init(void)
 int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
        if (argc == 0)
+       {
+               command_print(cmd_ctx, "%d", gdb_port);
                return ERROR_OK;
+       }
 
        /* only if the port wasn't overwritten by cmdline */
        if (gdb_port == 0)
@@ -2111,10 +2270,11 @@ int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char
                        detach_mode = GDB_DETACH_NOTHING;
                        return ERROR_OK;
                }
+               else
+                       LOG_WARNING("invalid gdb_detach configuration directive: %s", args[0]);
        }
 
-       LOG_WARNING("invalid gdb_detach configuration directive: %s", args[0]);
-       return ERROR_OK;
+       return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
 int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -2131,10 +2291,11 @@ int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd,
                        gdb_use_memory_map = 0;
                        return ERROR_OK;
                }
+               else
+                       LOG_WARNING("invalid gdb_memory_map configuration directive %s", args[0]);
        }
 
-       LOG_WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
-       return ERROR_OK;
+       return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
 int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -2151,10 +2312,11 @@ int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cm
                        gdb_flash_program = 0;
                        return ERROR_OK;
                }
+               else
+                       LOG_WARNING("invalid gdb_flash_program configuration directive: %s", args[0]);
        }
 
-       LOG_WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
-       return ERROR_OK;
+       return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
 int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -2171,18 +2333,19 @@ int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char
                        gdb_report_data_abort = 0;
                        return ERROR_OK;
                }
+               else
+                       LOG_WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
        }
 
-       LOG_WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
-       return ERROR_OK;
+       return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
-/* daemon configuration command gdb_port */
+/* gdb_breakpoint_override */
 int handle_gdb_breakpoint_override_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
        if (argc == 0)
        {
-               
+
        } else if (argc==1)
        {
                gdb_breakpoint_override = 1;
@@ -2207,23 +2370,22 @@ int handle_gdb_breakpoint_override_command(struct command_context_s *cmd_ctx, ch
        {
                LOG_USER("breakpoint type is not overriden");
        }
-       
+
        return ERROR_OK;
 }
 
-
 int gdb_register_commands(command_context_t *command_context)
 {
        register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
-                       COMMAND_CONFIG, "");
+                       COMMAND_CONFIG, "daemon configuration command gdb_port");
        register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,
                        COMMAND_CONFIG, "");
        register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,
-                       COMMAND_CONFIG, "");
+                       COMMAND_CONFIG, "enable or disable memory map");
        register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,
-                       COMMAND_CONFIG, "");
+                       COMMAND_CONFIG, "enable or disable flash program");
        register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
-                       COMMAND_CONFIG, "");
+                       COMMAND_CONFIG, "enable or disable report data");
        register_command(command_context, NULL, "gdb_breakpoint_override", handle_gdb_breakpoint_override_command,
                        COMMAND_EXEC, "hard/soft/disabled - force breakpoint type for gdb 'break' commands."
                        "The raison d'etre for this option is to support GDB GUI's without "

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)