cygwin 1.7 build fixes
[openocd.git] / src / server / gdb_server.c
index 85855d9140aa0cbd8b3887e88a03d5e1613eddb1..cf62864188feffda109dc007d92ed083479a7cbf 100644 (file)
@@ -2,7 +2,7 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
+ *   Copyright (C) 2007-2009 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2008 by Spencer Oliver                                  *
 #include "config.h"
 #endif
 
-#include "gdb_server.h"
-#include "target_request.h"
-#include "register.h"
+#include <target/breakpoints.h>
+#include <target/target_request.h>
+#include <target/register.h>
 #include "server.h"
-#include "flash.h"
-#include "image.h"
-#include "jtag.h"
+#include <flash/nor/core.h>
+#include "gdb_server.h"
+#include <target/image.h>
+#include <jtag/jtag.h>
+
+
+/* private connection data for GDB */
+struct gdb_connection
+{
+       char buffer[GDB_BUFFER_SIZE];
+       char *buf_p;
+       int buf_cnt;
+       int ctrl_c;
+       enum target_state frontend_state;
+       struct image *vflash_image;
+       int closed;
+       int busy;
+       int noack_mode;
+       bool sync;      /* set flag to true if you want the next stepi to return immediately.
+                      allowing GDB to pick up a fresh set of register values from the target
+                      without modifying the target state. */
+
+};
 
 
 #if 0
@@ -47,12 +67,13 @@ static enum breakpoint_type gdb_breakpoint_override_type;
 
 extern int gdb_error(struct connection *connection, int retval);
 static unsigned short gdb_port = 3333;
+static unsigned short gdb_port_next = 0;
 static const char *DIGITS = "0123456789abcdef";
 
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string);
 
-/* number of gdb connections, mainly to supress gdb related debugging spam
+/* number of gdb connections, mainly to suppress gdb related debugging spam
  * in helper/log.c when no gdb connections are actually active */
 int gdb_actual_connections;
 
@@ -67,7 +88,7 @@ int gdb_flash_program = 1;
  * see the code in gdb_read_memory_packet() for further explanations */
 int gdb_report_data_abort = 0;
 
-int gdb_last_signal(target_t *target)
+int gdb_last_signal(struct target *target)
 {
        switch (target->debug_reason)
        {
@@ -128,30 +149,11 @@ int check_pending(struct connection *connection, int timeout_s, int *got_data)
        return ERROR_OK;
 }
 
-int gdb_get_char(struct connection *connection, int* next_char)
+static int gdb_get_char_inner(struct connection *connection, int* next_char)
 {
        struct gdb_connection *gdb_con = connection->priv;
        int retval = ERROR_OK;
 
-#ifdef _DEBUG_GDB_IO_
-       char *debug_buffer;
-#endif
-
-       if (gdb_con->buf_cnt-- > 0)
-       {
-               *next_char = *(gdb_con->buf_p++);
-               if (gdb_con->buf_cnt > 0)
-                       connection->input_pending = 1;
-               else
-                       connection->input_pending = 0;
-
-#ifdef _DEBUG_GDB_IO_
-               LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
-               return ERROR_OK;
-       }
-
        for (;;)
        {
                if (connection->service->type == CONNECTION_PIPE)
@@ -236,6 +238,50 @@ int gdb_get_char(struct connection *connection, int* next_char)
        return retval;
 }
 
+/**
+ * The cool thing about this fn is that it allows buf_p and buf_cnt to be
+ * held in registers in the inner loop.
+ *
+ * For small caches and embedded systems this is important!
+ */
+static inline int gdb_get_char_fast(struct connection *connection, int* next_char, char **buf_p, int *buf_cnt)
+{
+       int retval = ERROR_OK;
+
+       if ((*buf_cnt)-- > 0)
+       {
+               *next_char = **buf_p;
+               (*buf_p)++;
+               if (*buf_cnt > 0)
+                       connection->input_pending = 1;
+               else
+                       connection->input_pending = 0;
+
+#ifdef _DEBUG_GDB_IO_
+               LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
+#endif
+
+               return ERROR_OK;
+       }
+
+       struct gdb_connection *gdb_con = connection->priv;
+       gdb_con->buf_p = *buf_p;
+       gdb_con->buf_cnt = *buf_cnt;
+       retval = gdb_get_char_inner(connection, next_char);
+       *buf_p = gdb_con->buf_p;
+       *buf_cnt = gdb_con->buf_cnt;
+
+       return retval;
+}
+
+
+int gdb_get_char(struct connection *connection, int* next_char)
+{
+       struct gdb_connection *gdb_con = connection->priv;
+       return gdb_get_char_fast(connection, next_char, &gdb_con->buf_p, &gdb_con->buf_cnt);
+}
+
+
 int gdb_putback_char(struct connection *connection, int last_char)
 {
        struct gdb_connection *gdb_con = connection->priv;
@@ -440,27 +486,33 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
        unsigned char my_checksum = 0;
        char checksum[3];
        int character;
-       int retval;
+       int retval = ERROR_OK;
 
        struct gdb_connection *gdb_con = connection->priv;
        my_checksum = 0;
        int count = 0;
        count = 0;
+
+       /* move this over into local variables to use registers and give the
+        * more freedom to optimize */
+       char *buf_p = gdb_con->buf_p;
+       int buf_cnt = gdb_con->buf_cnt;
+
        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))
+               if ((buf_cnt > 2) && ((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;
+                       char *buf = buf_p;
+                       int run = buf_cnt - 2;
                        i = 0;
                        int done = 0;
                        while (i < run)
@@ -492,19 +544,21 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                                        buffer[count++] = character & 0xff;
                                }
                        }
-                       gdb_con->buf_p += i;
-                       gdb_con->buf_cnt -= i;
+                       buf_p += i;
+                       buf_cnt -= i;
                        if (done)
                                break;
                }
                if (count > *len)
                {
                        LOG_ERROR("packet buffer too small");
-                       return ERROR_GDB_BUFFER_TOO_SMALL;
+                       retval = ERROR_GDB_BUFFER_TOO_SMALL;
+                       break;
                }
 
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
+               retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt);
+               if (retval != ERROR_OK)
+                       break;
 
                if (character == '#')
                        break;
@@ -514,8 +568,11 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                        /* 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;
+
+                       retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt);
+                       if (retval != ERROR_OK)
+                               break;
+
                        my_checksum += character & 0xff;
                        buffer[count++] = (character ^ 0x20) & 0xff;
                }
@@ -526,6 +583,12 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                }
        }
 
+       gdb_con->buf_p = buf_p;
+       gdb_con->buf_cnt = buf_cnt;
+
+       if (retval != ERROR_OK)
+               return retval;
+
        *len = count;
 
        if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
@@ -567,7 +630,7 @@ int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len)
                                        break;
                                case '+':
                                        /* gdb sends a dummy ack '+' at every remote connect - see remote_start_remote (remote.c)
-                                        * incase anyone tries to debug why they receive this warning every time */
+                                        * in case anyone tries to debug why they receive this warning every time */
                                        LOG_WARNING("acknowledgment received, but no packet pending");
                                        break;
                                case '-':
@@ -650,7 +713,7 @@ int gdb_output_con(struct connection *connection, const char* line)
        return retval;
 }
 
-int gdb_output(struct command_context_s *context, const char* line)
+int gdb_output(struct command_context *context, const char* line)
 {
        /* this will be dumped to the log and also sent as an O packet if possible */
        LOG_USER_N("%s", line);
@@ -658,7 +721,7 @@ int gdb_output(struct command_context_s *context, const char* line)
 }
 
 
-static void gdb_frontend_halted(struct target_s *target, struct connection *connection)
+static void gdb_frontend_halted(struct target *target, struct connection *connection)
 {
        struct gdb_connection *gdb_connection = connection->priv;
 
@@ -695,7 +758,7 @@ static void gdb_frontend_halted(struct target_s *target, struct connection *conn
        }
 }
 
-int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
+int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv)
 {
        int retval;
        struct connection *connection = priv;
@@ -773,7 +836,7 @@ int gdb_new_connection(struct connection *connection)
        gdb_actual_connections++;
        LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s",
                  gdb_actual_connections,
-                 gdb_service->target->cmd_name,
+                 target_name(gdb_service->target),
                  target_state_name(gdb_service->target));
 
        return ERROR_OK;
@@ -791,7 +854,7 @@ int gdb_connection_closed(struct connection *connection)
 
        gdb_actual_connections--;
        LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d",
-                 gdb_service->target->cmd_name,
+                 target_name(gdb_service->target),
                  target_state_name(gdb_service->target),
                  gdb_actual_connections);
 
@@ -833,7 +896,7 @@ void gdb_send_error(struct connection *connection, uint8_t the_error)
        gdb_put_packet(connection, err, 3);
 }
 
-int gdb_last_signal_packet(struct connection *connection, target_t *target, char* packet, int packet_size)
+int gdb_last_signal_packet(struct connection *connection, struct target *target, char* packet, int packet_size)
 {
        char sig_reply[4];
        int signal;
@@ -846,7 +909,7 @@ int gdb_last_signal_packet(struct connection *connection, target_t *target, char
        return ERROR_OK;
 }
 
-static int gdb_reg_pos(target_t *target, int pos, int len)
+static int gdb_reg_pos(struct target *target, int pos, int len)
 {
        if (target->endianness == TARGET_LITTLE_ENDIAN)
                return pos;
@@ -858,19 +921,19 @@ static int gdb_reg_pos(target_t *target, int pos, int len)
  * register might be non-divisible by 8(a byte), in which
  * case an entire byte is shown.
  *
- * NB! the format on the wire is the target endianess
+ * NB! the format on the wire is the target endianness
  *
  * The format of reg->value is little endian
  *
  */
-void gdb_str_to_target(target_t *target, char *tstr, struct reg *reg)
+void gdb_str_to_target(struct target *target, char *tstr, struct reg *reg)
 {
        int i;
 
        uint8_t *buf;
        int buf_len;
        buf = reg->value;
-       buf_len = CEIL(reg->size, 8);
+       buf_len = DIV_ROUND_UP(reg->size, 8);
 
        for (i = 0; i < buf_len; i++)
        {
@@ -880,7 +943,7 @@ void gdb_str_to_target(target_t *target, char *tstr, struct reg *reg)
        }
 }
 
-static int hextoint(char c)
+static int hextoint(int c)
 {
        if (c>='0'&&c<='9')
        {
@@ -896,7 +959,7 @@ static int hextoint(char c)
 }
 
 /* copy over in register buffer */
-void gdb_target_to_reg(target_t *target, char *tstr, int str_len, uint8_t *bin)
+void gdb_target_to_reg(struct target *target, char *tstr, int str_len, uint8_t *bin)
 {
        if (str_len % 2)
        {
@@ -915,7 +978,7 @@ void gdb_target_to_reg(target_t *target, char *tstr, int str_len, uint8_t *bin)
        }
 }
 
-int gdb_get_registers_packet(struct connection *connection, target_t *target, char* packet, int packet_size)
+int gdb_get_registers_packet(struct connection *connection, struct target *target, char* packet, int packet_size)
 {
        struct reg **reg_list;
        int reg_list_size;
@@ -939,25 +1002,25 @@ int gdb_get_registers_packet(struct connection *connection, target_t *target, ch
                reg_packet_size += reg_list[i]->size;
        }
 
-       reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);
+       reg_packet = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2);
        reg_packet_p = reg_packet;
 
        for (i = 0; i < reg_list_size; i++)
        {
                gdb_str_to_target(target, reg_packet_p, reg_list[i]);
-               reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
+               reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
        }
 
 #ifdef _DEBUG_GDB_IO_
        {
                char *reg_packet_p;
-               reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
+               reg_packet_p = strndup(reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2);
                LOG_DEBUG("reg_packet: %s", reg_packet_p);
                free(reg_packet_p);
        }
 #endif
 
-       gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
+       gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2);
        free(reg_packet);
 
        free(reg_list);
@@ -965,7 +1028,7 @@ int gdb_get_registers_packet(struct connection *connection, target_t *target, ch
        return ERROR_OK;
 }
 
-int gdb_set_registers_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_set_registers_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        int i;
        struct reg **reg_list;
@@ -996,21 +1059,17 @@ int gdb_set_registers_packet(struct connection *connection, target_t *target, ch
        for (i = 0; i < reg_list_size; i++)
        {
                uint8_t *bin_buf;
-               int chars = (CEIL(reg_list[i]->size, 8) * 2);
+               int chars = (DIV_ROUND_UP(reg_list[i]->size, 8) * 2);
 
                if (packet_p + chars > packet + packet_size)
                {
                        LOG_ERROR("BUG: register packet is too small for registers");
                }
 
-               struct reg_arch_type *arch_type;
-               bin_buf = malloc(CEIL(reg_list[i]->size, 8));
+               bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8));
                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);
-
-               arch_type->set(reg_list[i], bin_buf);
+               reg_list[i]->type->set(reg_list[i], bin_buf);
 
                /* advance packet pointer */
                packet_p += chars;
@@ -1027,7 +1086,7 @@ int gdb_set_registers_packet(struct connection *connection, target_t *target, ch
        return ERROR_OK;
 }
 
-int gdb_get_register_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_get_register_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        char *reg_packet;
        int reg_num = strtoul(packet + 1, NULL, 16);
@@ -1050,11 +1109,11 @@ int gdb_get_register_packet(struct connection *connection, target_t *target, cha
                exit(-1);
        }
 
-       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+       reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
 
        gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
 
-       gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
+       gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
 
        free(reg_list);
        free(reg_packet);
@@ -1062,7 +1121,7 @@ int gdb_get_register_packet(struct connection *connection, target_t *target, cha
        return ERROR_OK;
 }
 
-int gdb_set_register_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_set_register_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        char *separator;
        uint8_t *bin_buf;
@@ -1070,7 +1129,6 @@ int gdb_set_register_packet(struct connection *connection, target_t *target, cha
        struct reg **reg_list;
        int reg_list_size;
        int retval;
-       struct reg_arch_type *arch_type;
 
        LOG_DEBUG("-");
 
@@ -1092,16 +1150,14 @@ int gdb_set_register_packet(struct connection *connection, target_t *target, cha
        }
 
        /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-       bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
-       int chars = (CEIL(reg_list[reg_num]->size, 8) * 2);
+       bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8));
+       int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
 
        /* fix!!! add some sanity checks on packet size here */
 
        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);
-       arch_type->set(reg_list[reg_num], bin_buf);
+       reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
 
        gdb_put_packet(connection, "OK", 2);
 
@@ -1142,7 +1198,7 @@ int gdb_error(struct connection *connection, int retval)
  *
  * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
-int gdb_read_memory_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_read_memory_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        char *separator;
        uint32_t addr = 0;
@@ -1216,7 +1272,7 @@ int gdb_read_memory_packet(struct connection *connection, target_t *target, char
        return retval;
 }
 
-int gdb_write_memory_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        char *separator;
        uint32_t addr = 0;
@@ -1273,7 +1329,7 @@ int gdb_write_memory_packet(struct connection *connection, target_t *target, cha
        return retval;
 }
 
-int gdb_write_memory_binary_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_binary_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        char *separator;
        uint32_t addr = 0;
@@ -1321,7 +1377,7 @@ int gdb_write_memory_binary_packet(struct connection *connection, target_t *targ
        return ERROR_OK;
 }
 
-int gdb_step_continue_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_step_continue_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        int current = 0;
        uint32_t address = 0x0;
@@ -1354,7 +1410,7 @@ int gdb_step_continue_packet(struct connection *connection, target_t *target, ch
        return retval;
 }
 
-int gdb_breakpoint_watchpoint_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        int type;
        enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
@@ -1520,7 +1576,7 @@ static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len
        return 0;
 }
 
-int gdb_calc_blocksize(flash_bank_t *bank)
+int gdb_calc_blocksize(struct flash_bank *bank)
 {
        uint32_t i;
        uint32_t block_size = 0xffffffff;
@@ -1538,9 +1594,9 @@ int gdb_calc_blocksize(flash_bank_t *bank)
 
 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);
+       struct flash_bank *b1, *b2;
+       b1=*((struct flash_bank **)a);
+       b2=*((struct flash_bank **)b);
 
        if (b1->base == b2->base)
        {
@@ -1554,9 +1610,9 @@ static int compare_bank (const void * a, const void * b)
        }
 }
 
-int gdb_query_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_query_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
-       command_context_t *cmd_ctx = connection->cmd_ctx;
+       struct command_context *cmd_ctx = connection->cmd_ctx;
        struct gdb_connection *gdb_connection = connection->priv;
 
        if (strstr(packet, "qRcmd,"))
@@ -1661,7 +1717,7 @@ int gdb_query_packet(struct connection *connection, target_t *target, char *pack
                 * Normally we only execute this code once, but no big deal if we
                 * have to regenerate it a couple of times. */
 
-               flash_bank_t *p;
+               struct flash_bank *p;
                char *xml = NULL;
                int size = 0;
                int pos = 0;
@@ -1685,7 +1741,7 @@ int gdb_query_packet(struct connection *connection, target_t *target, char *pack
                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());
+               struct flash_bank **banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count());
                int i;
 
                for (i = 0; i < flash_get_bank_count(); i++)
@@ -1701,7 +1757,7 @@ int gdb_query_packet(struct connection *connection, target_t *target, char *pack
                        banks[i]=p;
                }
 
-               qsort(banks, flash_get_bank_count(), sizeof(flash_bank_t *), compare_bank);
+               qsort(banks, flash_get_bank_count(), sizeof(struct flash_bank *), compare_bank);
 
                uint32_t ram_start = 0;
                for (i = 0; i < flash_get_bank_count(); i++)
@@ -1810,7 +1866,7 @@ int gdb_query_packet(struct connection *connection, target_t *target, char *pack
        return ERROR_OK;
 }
 
-int gdb_v_packet(struct connection *connection, target_t *target, char *packet, int packet_size)
+int gdb_v_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
 {
        struct gdb_connection *gdb_connection = connection->priv;
        struct gdb_service *gdb_service = connection->service->priv;
@@ -1947,7 +2003,7 @@ int gdb_v_packet(struct connection *connection, target_t *target, char *packet,
        return ERROR_OK;
 }
 
-int gdb_detach(struct connection *connection, target_t *target)
+int gdb_detach(struct connection *connection, struct target *target)
 {
        struct gdb_service *gdb_service = connection->service->priv;
 
@@ -1985,7 +2041,7 @@ static void gdb_sig_halted(struct connection *connection)
 int gdb_input_inner(struct connection *connection)
 {
        struct gdb_service *gdb_service = connection->service->priv;
-       target_t *target = gdb_service->target;
+       struct target *target = gdb_service->target;
        char *packet = gdb_packet_buffer;
        int packet_size;
        int retval;
@@ -2144,10 +2200,10 @@ int gdb_input_inner(struct connection *connection)
                                        watchpoint_clear_target(gdb_service->target);
                                        command_run_linef(connection->cmd_ctx,
                                                        "ocd_gdb_restart %s",
-                                                       target->cmd_name);
+                                                       target_name(target));
                                        break;
                                default:
-                                       /* ignore unkown packets */
+                                       /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
                                        gdb_put_packet(connection, NULL, 0);
                                        break;
@@ -2195,55 +2251,72 @@ int gdb_input(struct connection *connection)
        return ERROR_OK;
 }
 
-int gdb_init(void)
+static int gdb_target_start(struct target *target, uint16_t port)
 {
-       struct gdb_service *gdb_service;
-       target_t *target = all_targets;
+       bool use_pipes = 0 == port;
+       struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service));
+       if (NULL == gdb_service)
+               return -ENOMEM;
 
-       if (!target)
-       {
-               LOG_WARNING("no gdb ports allocated as no target has been specified");
-               return ERROR_OK;
-       }
+       gdb_service->target = target;
+
+       add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP,
+                       port, 1, &gdb_new_connection, &gdb_input,
+                       &gdb_connection_closed, gdb_service);
+
+       const char *name = target_name(target);
+       if (use_pipes)
+               LOG_DEBUG("gdb service for target '%s' using pipes", name);
+       else
+               LOG_DEBUG("gdb service for target '%s' on TCP port %u", name, port);
+       return ERROR_OK;
+}
 
+int gdb_target_add_one(struct target *target)
+{
        if (gdb_port == 0 && server_use_pipes == 0)
        {
                LOG_INFO("gdb port disabled");
                return ERROR_OK;
        }
+       if (0 == gdb_port_next)
+               gdb_port_next = gdb_port;
 
-       if (server_use_pipes)
+       bool use_pipes = server_use_pipes;
+       static bool server_started_with_pipes = false;
+       if (server_started_with_pipes)
        {
-               /* only a single gdb connection when using a pipe */
+               LOG_WARNING("gdb service permits one target when using pipes");
+               if (0 == gdb_port)
+                       return ERROR_OK;
 
-               gdb_service = malloc(sizeof(struct gdb_service));
-               gdb_service->target = target;
+               use_pipes = false;
+       }
 
-               add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+       int e = gdb_target_start(target, use_pipes ? 0 : gdb_port_next);
+       if (ERROR_OK == e)
+       {
+               server_started_with_pipes |= use_pipes;
+               gdb_port_next++;
+       }
+       return e;
+}
 
-               LOG_DEBUG("gdb service for target %s using pipes",
-                               target_get_name(target));
+int gdb_target_add_all(struct target *target)
+{
+       if (NULL == target)
+       {
+               LOG_WARNING("gdb services need one or more targets defined");
+               return ERROR_OK;
        }
-       else
+
+       while (NULL != target)
        {
-               unsigned short port = gdb_port;
+               int retval = gdb_target_add_one(target);
+               if (ERROR_OK != retval)
+                       return retval;
 
-               while (target)
-               {
-                       gdb_service = malloc(sizeof(struct gdb_service));
-                       gdb_service->target = target;
-
-                       add_service("gdb", CONNECTION_TCP,
-                                       port, 1,
-                                       gdb_new_connection, gdb_input,
-                                       gdb_connection_closed, gdb_service);
-
-                       LOG_DEBUG("gdb service for target %s at TCP port %i",
-                                       target_get_name(target),
-                                       port);
-                       target = target->next;
-                       port++;
-               }
+               target = target->next;
        }
 
        return ERROR_OK;
@@ -2251,14 +2324,14 @@ int gdb_init(void)
 
 COMMAND_HANDLER(handle_gdb_sync_command)
 {
-       if (argc != 0)
+       if (CMD_ARGC != 0)
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        if (current_gdb_connection == NULL)
        {
-               command_print(cmd_ctx,
+               command_print(CMD_CTX,
                                "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
                return ERROR_FAIL;
        }
@@ -2271,68 +2344,32 @@ COMMAND_HANDLER(handle_gdb_sync_command)
 /* daemon configuration command gdb_port */
 COMMAND_HANDLER(handle_gdb_port_command)
 {
-       return CALL_COMMAND_HANDLER(server_port_command, &gdb_port);
+       int retval = CALL_COMMAND_HANDLER(server_port_command, &gdb_port);
+       if (ERROR_OK == retval)
+               gdb_port_next = gdb_port;
+       return retval;
 }
 
 COMMAND_HANDLER(handle_gdb_memory_map_command)
 {
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_use_memory_map = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_use_memory_map = 0;
-                       return ERROR_OK;
-               }
-               else
-                       LOG_WARNING("invalid gdb_memory_map configuration directive %s", args[0]);
-       }
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map);
 
        return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
 COMMAND_HANDLER(handle_gdb_flash_program_command)
 {
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_flash_program = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_flash_program = 0;
-                       return ERROR_OK;
-               }
-               else
-                       LOG_WARNING("invalid gdb_flash_program configuration directive: %s", args[0]);
-       }
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program);
 
        return ERROR_COMMAND_SYNTAX_ERROR;
 }
 
 COMMAND_HANDLER(handle_gdb_report_data_abort_command)
 {
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_report_data_abort = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_report_data_abort = 0;
-                       return ERROR_OK;
-               }
-               else
-                       LOG_WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
-       }
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort);
 
        return ERROR_COMMAND_SYNTAX_ERROR;
 }
@@ -2340,19 +2377,19 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command)
 /* gdb_breakpoint_override */
 COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
 {
-       if (argc == 0)
+       if (CMD_ARGC == 0)
        {
 
-       } else if (argc == 1)
+       } else if (CMD_ARGC == 1)
        {
                gdb_breakpoint_override = 1;
-               if (strcmp(args[0], "hard") == 0)
+               if (strcmp(CMD_ARGV[0], "hard") == 0)
                {
                        gdb_breakpoint_override_type = BKPT_HARD;
-               } else if (strcmp(args[0], "soft") == 0)
+               } else if (strcmp(CMD_ARGV[0], "soft") == 0)
                {
                        gdb_breakpoint_override_type = BKPT_SOFT;
-               } else if (strcmp(args[0], "disable") == 0)
+               } else if (strcmp(CMD_ARGV[0], "disable") == 0)
                {
                        gdb_breakpoint_override = 0;
                }
@@ -2365,33 +2402,61 @@ COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
                LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD)?"hard":"soft");
        } else
        {
-               LOG_USER("breakpoint type is not overriden");
+               LOG_USER("breakpoint type is not overridden");
        }
 
        return ERROR_OK;
 }
 
-int gdb_register_commands(command_context_t *command_context)
+static const struct command_registration gdb_command_handlers[] = {
+       {
+               .name = "gdb_sync",
+               .handler = &handle_gdb_sync_command,
+               .mode = COMMAND_ANY,
+               .help = "next stepi will return immediately allowing "
+                       "GDB to fetch register state without affecting "
+                       "target state",
+       },
+       {
+               .name = "gdb_port",
+               .handler = &handle_gdb_port_command,
+               .mode = COMMAND_ANY,
+               .help = "daemon configuration command gdb_port",
+               .usage = "<port>",
+       },
+       {
+               .name = "gdb_memory_map",
+               .handler = &handle_gdb_memory_map_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable memory map",
+               .usage = "enable|disable"
+       },
+       {
+               .name = "gdb_flash_program",
+               .handler = &handle_gdb_flash_program_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable flash program",
+               .usage = "enable|disable"
+       },
+       {
+               .name = "gdb_report_data_abort",
+               .handler = &handle_gdb_report_data_abort_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable reporting data aborts",
+               .usage = "enable|disable"
+       },
+       {
+               .name = "gdb_breakpoint_override",
+               .handler = &handle_gdb_breakpoint_override_command,
+               .mode = COMMAND_EXEC,
+               .help = "force type of breakpoint "
+                       "used by gdb 'break' commands.",
+               .usage = "hard|soft|disable",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int gdb_register_commands(struct command_context *cmd_ctx)
 {
-       register_command(command_context, NULL, "gdb_sync",
-                       handle_gdb_sync_command, COMMAND_ANY,
-                       "next stepi will return immediately allowing GDB to "
-                       "fetch register state without affecting target state");
-       register_command(command_context, NULL, "gdb_port",
-                       handle_gdb_port_command, COMMAND_ANY,
-                       "daemon configuration command gdb_port");
-       register_command(command_context, NULL, "gdb_memory_map",
-                       handle_gdb_memory_map_command, COMMAND_CONFIG,
-                       "enable or disable memory map");
-       register_command(command_context, NULL, "gdb_flash_program",
-                       handle_gdb_flash_program_command, COMMAND_CONFIG,
-                       "enable or disable flash program");
-       register_command(command_context, NULL, "gdb_report_data_abort",
-                       handle_gdb_report_data_abort_command, COMMAND_CONFIG,
-                       "enable or disable reporting data aborts");
-       register_command(command_context, NULL, "gdb_breakpoint_override",
-                       handle_gdb_breakpoint_override_command, COMMAND_EXEC,
-                       "hard/soft/disable - force type of breakpoint "
-                       "used by gdb 'break' commands.");
-       return ERROR_OK;
+       return register_commands(cmd_ctx, NULL, gdb_command_handlers);
 }

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)