- fixed arm926 cp15 command bug (thanks to Vincent Palatin for this patch)
[openocd.git] / src / server / gdb_server.c
index 125206dcb358a7075eb93ba259af5cefc9097ae5..34b66050791a6215fd462eef863be04322b2d8c9 100644 (file)
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "replacements.h"
+
 #include "gdb_server.h"
 
 #include "server.h"
 #include <unistd.h>
 #include <stdlib.h>
 
-// -ino: 060521-1116
-#ifdef __FreeBSD__
-#include <stdio.h>
-char * strndup(char * str, int n) {
-  unsigned char * tmp = malloc((size_t)n+1);
-  if (! tmp) perror("gdb_server malloc failed");
-  if (strlcpy(tmp, str, n) > n) perror("gdb_server strndup:  too long");
-  return tmp;
-}
-#endif
 #if 0
 #define _DEBUG_GDB_IO_
 #endif
@@ -86,11 +82,26 @@ int gdb_get_char(connection_t *connection, int* next_char)
                return ERROR_OK;
        }
 
-       while ((gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE)) <= 0)
+       while ((gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE)) <= 0)
        {
                if (gdb_con->buf_cnt == 0)
                        return ERROR_SERVER_REMOTE_CLOSED;
                
+#ifdef _WIN32
+               errno = WSAGetLastError();
+
+               switch(errno)
+               {
+                       case WSAEWOULDBLOCK:
+                               usleep(1000);
+                               break;
+                       case WSAECONNABORTED:
+                               return ERROR_SERVER_REMOTE_CLOSED;
+                       default:
+                               ERROR("read: %d", errno);
+                               exit(-1);
+               }
+#else
                switch(errno)
                {
                        case EAGAIN:
@@ -104,6 +115,7 @@ int gdb_get_char(connection_t *connection, int* next_char)
                                ERROR("read: %s", strerror(errno));
                                exit(-1);
                }
+#endif
        }
        
        debug_buffer = malloc(gdb_con->buf_cnt + 1);
@@ -126,6 +138,23 @@ int gdb_get_char(connection_t *connection, int* next_char)
        return ERROR_OK;
 }
 
+int gdb_putback_char(connection_t *connection, int last_char)
+{
+       gdb_connection_t *gdb_con = connection->priv;
+       
+       if (gdb_con->buf_p > gdb_con->buffer)
+       {
+               *(--gdb_con->buf_p) = last_char;
+               gdb_con->buf_cnt++;
+       }
+       else
+       {
+               ERROR("BUG: couldn't put character back");      
+       }
+       
+       return ERROR_OK;
+}
+
 int gdb_put_packet(connection_t *connection, char *buffer, int len)
 {
        int i;
@@ -148,14 +177,14 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
                DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
                free(debug_buffer);
                
-               write(connection->fd, "$", 1);
+               write_socket(connection->fd, "$", 1);
                if (len > 0)
-                       write(connection->fd, buffer, len);
-               write(connection->fd, "#", 1);
+                       write_socket(connection->fd, buffer, len);
+               write_socket(connection->fd, "#", 1);
        
                snprintf(checksum, 3, "%2.2x", my_checksum);
        
-               write(connection->fd, checksum, 2);
+               write_socket(connection->fd, checksum, 2);
 
                if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
                        return retval;
@@ -195,7 +224,7 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
        int count = 0;
        int retval;
        int first_char = 0;
-       int packet_type;
+       int packet_type = '\0';
        char checksum[3];
        unsigned char my_checksum = 0;
        gdb_connection_t *gdb_con = connection->priv;
@@ -207,6 +236,8 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
                        if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
                                return retval;
 
+                       DEBUG("character: '%c'", character);
+
                        switch (character)
                        {
                                case '$':
@@ -303,12 +334,12 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
                
                if (my_checksum == strtoul(checksum, NULL, 16))
                {
-                       write (connection->fd, "+", 1);
+                       write_socket(connection->fd, "+", 1);
                        break;
                }
 
                WARNING("checksum error, requesting retransmission");
-               write(connection->fd, "-", 1);
+               write_socket(connection->fd, "-", 1);
        }
 
        return ERROR_OK;
@@ -415,6 +446,9 @@ int gdb_new_connection(connection_t *connection)
        if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
                return retval;
                
+       if (initial_ack != '+')
+               gdb_putback_char(connection, initial_ack);
+               
        return ERROR_OK;
 }
 
@@ -430,6 +464,13 @@ int gdb_connection_closed(connection_t *connection)
        return ERROR_OK;
 }
 
+void gdb_send_error(connection_t *connection, u8 the_error)
+{
+    char err[4];
+    snprintf(err, 4, "E%2.2X", the_error );
+    gdb_put_packet(connection, err, 3);
+}
+
 int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
 {
        char sig_reply[4];
@@ -443,7 +484,63 @@ int gdb_last_signal_packet(connection_t *connection, target_t *target, char* pac
        return ERROR_OK;
 }
 
-void gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
+void gdb_str_to_target(target_t *target, char *str, char *tstr)
+{
+       int str_len = strlen(str);
+       int i;
+       
+       if (str_len % 2)
+       {
+               ERROR("BUG: gdb value with uneven number of characters encountered: %s", str);
+               exit(-1);
+       }
+       
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = 0; i < str_len; i+=2)
+               {
+                       tstr[str_len - i - 1] = str[i + 1];
+                       tstr[str_len - i - 2] = str[i];
+               }
+       }
+       else
+       {
+               for (i = 0; i < str_len; i++)
+               {
+                       tstr[i] = str[i];
+               }
+       }       
+}
+
+void gdb_target_to_str(target_t *target, char *tstr, char *str)
+{
+       int str_len = strlen(tstr);
+       int i;
+
+       if (str_len % 2)
+       {
+               ERROR("BUG: gdb value with uneven number of characters encountered");
+               exit(-1);
+       }
+       
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = 0; i < str_len; i+=2)
+               {
+                       str[str_len - i - 1] = tstr[i + 1];
+                       str[str_len - i - 2] = tstr[i];
+               }
+       }
+       else
+       {
+               for (i = 0; i < str_len; i++)
+               {
+                       str[i] = tstr[i];
+               }
+       }       
+}
+
+int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
 {
        reg_t **reg_list;
        int reg_list_size;
@@ -453,16 +550,17 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
        char *reg_packet_p;
        int i;
        
-       DEBUG("");
+       DEBUG("-");
 
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb requested registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -478,14 +576,10 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
        
        for (i = 0; i < reg_list_size; i++)
        {
-               int j;
-               char *hex_buf = buf_to_char(reg_list[i]->value, reg_list[i]->size);
+               char *hex_buf = buf_to_str(reg_list[i]->value, reg_list[i]->size, 16);
                DEBUG("hex_buf: %s", hex_buf);
-               for (j = CEIL(reg_list[i]->size, 8) * 2; j > 0; j -= 2)
-               {
-                       *reg_packet_p++ = hex_buf[j - 2];
-                       *reg_packet_p++ = hex_buf[j - 1];
-               }
+               gdb_str_to_target(target, hex_buf, reg_packet_p);
+               reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
                free(hex_buf);
        }
 
@@ -496,9 +590,12 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
        gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
        free(reg_packet);
        
+       free(reg_list);
+       
+       return ERROR_OK;
 }
 
-void gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        int i;
        reg_t **reg_list;
@@ -506,7 +603,7 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
        int retval;
        char *packet_p;
        
-       DEBUG("");
+       DEBUG("-");
 
        /* skip command character */
        packet++;
@@ -514,8 +611,8 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
 
        if (packet_size % 2)
        {
-               WARNING("GDB set_registers packet with uneven characters received");
-               return;
+               WARNING("GDB set_registers packet with uneven characters received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
@@ -523,9 +620,10 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb tried to registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -534,34 +632,62 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
        packet_p = packet;
        for (i = 0; i < reg_list_size; i++)
        {
-               char_to_buf(packet, CEIL(reg_list[i]->size, 8) * 2, reg_list[i]->value, reg_list[i]->size);
-               reg_list[i]->dirty = 1;
+               u8 *bin_buf;
+               char *hex_buf;
+               reg_arch_type_t *arch_type;
+               
+               /* 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);
+               
+               /* convert hex-string to binary buffer */
+               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);
+
+               /* get register arch_type, and call set method */       
+               arch_type = register_get_arch_type(reg_list[i]->arch_type);
+               if (arch_type == NULL)
+               {
+                       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);
+               
+               free(bin_buf);
+               free(hex_buf);
        }
+       
+       /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ 
+       free(reg_list);
 
        gdb_put_packet(connection, "OK", 2);
+       
+       return ERROR_OK;
 }
 
-void gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
-       char *hex_buf;
        char *reg_packet;
-       char *reg_packet_p;
        int reg_num = strtoul(packet + 1, NULL, 16);
        reg_t **reg_list;
        int reg_list_size;
        int retval;
-       int i;
+       char *hex_buf;
        
-       DEBUG("");
+       DEBUG("-");
        
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb requested registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -573,40 +699,43 @@ void gdb_get_register_packet(connection_t *connection, target_t *target, char *p
                exit(-1);
        }
 
-       hex_buf = buf_to_char(reg_list[reg_num]->value, reg_list[reg_num]->size);
-       reg_packet = reg_packet_p = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+
+       hex_buf = buf_to_str(reg_list[reg_num]->value, reg_list[reg_num]->size, 16);
        
-       for (i = CEIL(reg_list[reg_num]->size, 8) * 2; i > 0; i -= 2)
-       {
-               *reg_packet_p++ = hex_buf[i - 2];
-               *reg_packet_p++ = hex_buf[i - 1];
-       }
+       gdb_str_to_target(target, hex_buf, reg_packet);
        
        gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
        
+       free(reg_list);
        free(reg_packet);
        free(hex_buf);
        
+       return ERROR_OK;
 }
 
-void gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+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;
        int reg_list_size;
        int retval;
-
-       DEBUG("");
+       reg_arch_type_t *arch_type;
+       
+       DEBUG("-");
        
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb tried to set a register but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -615,23 +744,67 @@ void gdb_set_register_packet(connection_t *connection, target_t *target, char *p
        if (reg_list_size < reg_num)
        {
                ERROR("gdb requested a non-existing register");
-               exit(-1);
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if (*separator != '=')
        {
-               ERROR("GDB set register packet, but no '=' following the register number");
-               exit(-1);
+               ERROR("GDB 'set register packet', but no '=' following the register number");
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
        
-       char_to_buf(separator + 1, CEIL(reg_list[reg_num]->size, 8) * 2, reg_list[reg_num]->value, reg_list[reg_num]->size);
-       reg_list[reg_num]->dirty = 1;
+       /* 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);
+
+       /* get register arch_type, and call set method */       
+       arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
+       if (arch_type == NULL)
+       {
+               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;
 }
 
-void gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_memory_packet_error(connection_t *connection, int retval)
+{
+       switch (retval)
+       {
+               case ERROR_TARGET_NOT_HALTED:
+                       ERROR("gdb tried to read memory but we're not halted, dropping connection");
+                       return ERROR_SERVER_REMOTE_CLOSED;
+                       break;
+               case ERROR_TARGET_DATA_ABORT:
+                       gdb_send_error(connection, EIO);
+                       break;
+               case ERROR_TARGET_TRANSLATION_FAULT:
+                       gdb_send_error(connection, EFAULT);
+                       break;
+               case ERROR_TARGET_UNALIGNED_ACCESS:
+                       gdb_send_error(connection, EFAULT);
+                       break;
+               default:
+                       ERROR("BUG: unexpected error %i", retval);
+                       exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
@@ -641,6 +814,7 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        char *hex_buffer;
 
        int i;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -648,7 +822,10 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete read memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, NULL, 16);
 
@@ -660,35 +837,46 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        {
                case 4:
                        if ((addr % 4) == 0)
-                               target->type->read_memory(target, addr, 4, 1, buffer);
+                               retval = target->type->read_memory(target, addr, 4, 1, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
                        break;
                case 2:
                        if ((addr % 2) == 0)
-                               target->type->read_memory(target, addr, 2, 1, buffer);
+                               retval = target->type->read_memory(target, addr, 2, 1, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
                        break;
                default:
                        if (((addr % 4) == 0) && ((len % 4) == 0))
-                               target->type->read_memory(target, addr, 4, len / 4, buffer);
+                               retval = target->type->read_memory(target, addr, 4, len / 4, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
        }
 
-       hex_buffer = malloc(len * 2 + 1);
+       if (retval == ERROR_OK)
+       {
+               hex_buffer = malloc(len * 2 + 1);
+               
+               for (i=0; i<len; i++)
+                       snprintf(hex_buffer + 2*i, 3, "%2.2x", buffer[i]);
        
-       for (i=0; i<len; i++)
-               snprintf(hex_buffer + 2*i, 3, "%2.2x", buffer[i]);
-
-       gdb_put_packet(connection, hex_buffer, len * 2);
+               gdb_put_packet(connection, hex_buffer, len * 2);
        
-       free(hex_buffer);
+               free(hex_buffer);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
+
        free(buffer);
+       
+       return ERROR_OK;
 }
 
-void gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
@@ -697,6 +885,7 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
        u8 *buffer;
 
        int i;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -704,12 +893,18 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete write memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, &separator, 16);
 
        if (*(separator++) != ':')
-               return;
+       {
+               ERROR("incomplete write memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        buffer = malloc(len);
 
@@ -722,43 +917,55 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
                buffer[i] = tmp;
        }
 
+       retval = ERROR_OK;
        switch (len)
        {
                /* handle sized writes */
                case 4:
                        if ((addr % 4) == 0)
-                               target->type->write_memory(target, addr, 4, 1, buffer);
+                               retval = target->type->write_memory(target, addr, 4, 1, buffer);
                        else
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                case 2:
                        if ((addr % 2) == 0)
-                               target->type->write_memory(target, addr, 2, 1, buffer);
+                               retval = target->type->write_memory(target, addr, 2, 1, buffer);
                        else
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                case 3:
                case 1:
-                       target->type->write_memory(target, addr, 1, len, buffer);
+                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                /* handle bulk writes */
                default:
-                       target_write_buffer(target, addr, len, buffer);
+                       retval = target_write_buffer(target, addr, len, buffer);
                        break;
        }
 
-       gdb_put_packet(connection, "OK", 2);
+       if (retval == ERROR_OK)
+       {
+               gdb_put_packet(connection, "OK", 2);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
        
        free(buffer);
+       
+       return ERROR_OK;
 }
 
-void gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
        u32 len = 0;
 
        u8 *buffer;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -766,13 +973,20 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target,
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete write memory binary packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, &separator, 16);
 
        if (*(separator++) != ':')
-               return;
+       {
+               ERROR("incomplete write memory binary packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
+       retval = ERROR_OK;
        if( len ) {
                
                buffer = malloc(len);
@@ -785,29 +999,39 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target,
                {
                        case 4:
                                if ((addr % 4) == 0)
-                                       target->type->write_memory(target, addr, 4, 1, buffer);
+                                       retval = target->type->write_memory(target, addr, 4, 1, buffer);
                                else
-                                       target->type->write_memory(target, addr, 1, len, buffer);
+                                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        case 2:
                                if ((addr % 2) == 0)
-                                       target->type->write_memory(target, addr, 2, 1, buffer);
+                                       retval = target->type->write_memory(target, addr, 2, 1, buffer);
                                else
-                                       target->type->write_memory(target, addr, 1, len, buffer);
+                                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        case 3:
                        case 1:
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        default:
-                               target_write_buffer(target, addr, len, buffer);
+                               retval = target_write_buffer(target, addr, len, buffer);
                                break;
                }
                
                free(buffer);
        }
 
-       gdb_put_packet(connection, "OK", 2);
+       if (retval == ERROR_OK)
+       {
+               gdb_put_packet(connection, "OK", 2);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
+       
+       return ERROR_OK;
 }
 
 void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
@@ -815,11 +1039,10 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char *
        int current = 0;
        u32 address = 0x0;
 
-       DEBUG("");
+       DEBUG("-");
 
        if (packet_size > 1)
        {
-               u32 address = 0;
                packet[packet_size] = 0;
                address = strtoul(packet + 1, NULL, 16);
        }
@@ -840,17 +1063,36 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char *
        }
 }
 
-void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_bp_wp_packet_error(connection_t *connection, int retval)
+{
+       switch (retval)
+       {
+               case ERROR_TARGET_NOT_HALTED:
+                       ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");
+                       return ERROR_SERVER_REMOTE_CLOSED;
+                       break;
+               case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+                       gdb_send_error(connection, EBUSY);
+                       break;
+               default:
+                       ERROR("BUG: unexpected error %i", retval);
+                       exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        int type;
-       enum breakpoint_type bp_type;
+       enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
        enum watchpoint_rw wp_type;
        u32 address;
        u32 size;
        char *separator;
        int retval;
 
-       DEBUG("");
+       DEBUG("-");
 
        type = strtoul(packet + 1, &separator, 16);
        
@@ -866,12 +1108,18 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target
                wp_type = WPT_ACCESS;
                
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        address = strtoul(separator+1, &separator, 16);
 
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        size = strtoul(separator+1, &separator, 16);
 
@@ -883,41 +1131,53 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target
                        {
                                if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
                                {
-                                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                                       {
-                                               gdb_put_packet(connection, "E00", 3);
-                                               break;
-                                       }
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
+                                               return retval;
+                               }
+                               else
+                               {
+                                       gdb_put_packet(connection, "OK", 2);
                                }
                        }
                        else
                        {
                                breakpoint_remove(target, address);
+                               gdb_put_packet(connection, "OK", 2);
                        }
-                       gdb_put_packet(connection, "OK", 2);
                        break;
                case 2:
                case 3:
                case 4:
                {
                        if (packet[0] == 'Z')
-                               watchpoint_add(target, address, size, type-2, 0, 0xffffffffu);
+                       {
+                               if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)
+                               {
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
+                                               return retval;
+                               }
+                               else
+                               {
+                                       gdb_put_packet(connection, "OK", 2);
+                               }
+                       }
                        else
+                       {
                                watchpoint_remove(target, address);
-                       gdb_put_packet(connection, "OK", 2);
+                               gdb_put_packet(connection, "OK", 2);
+                       }
                        break;
                }
                default:
                        break;
        }
 
+       return ERROR_OK;
 }
 
 void gdb_query_packet(connection_t *connection, char *packet, int packet_size)
 {
        command_context_t *cmd_ctx = connection->cmd_ctx;
-       gdb_service_t *gdb_service = connection->service->priv;
-       target_t *target = gdb_service->target;
 
        if (strstr(packet, "qRcmd,"))
        {
@@ -966,7 +1226,7 @@ int gdb_input(connection_t *connection)
                                case ERROR_SERVER_REMOTE_CLOSED:
                                        return ERROR_SERVER_REMOTE_CLOSED;
                                default:
-                                       ERROR("unexpected error");
+                                       ERROR("BUG: unexpected error");
                                        exit(-1);
                        }
                }
@@ -978,6 +1238,7 @@ int gdb_input(connection_t *connection)
                
                if (packet_size > 0)
                {
+                       retval = ERROR_OK;
                        switch (packet[0])
                        {
                                case 'H':
@@ -989,26 +1250,26 @@ int gdb_input(connection_t *connection)
                                        gdb_query_packet(connection, packet, packet_size);
                                        break;
                                case 'g':
-                                       gdb_get_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);
                                        break;
                                case 'G':
-                                       gdb_set_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);
                                        break;
                                case 'p':
-                                       gdb_get_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);
                                        break;
                                case 'P':
-                                       gdb_set_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);
                                        break;
                                case 'm':
-                                       gdb_read_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);
                                        break;
                                case 'M':
-                                       gdb_write_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);
                                        break;
                                case 'z':
                                case 'Z':
-                                       gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
+                                       retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
                                        break;
                                case '?':
                                        gdb_last_signal_packet(connection, target, packet, packet_size);
@@ -1022,7 +1283,8 @@ int gdb_input(connection_t *connection)
                                        gdb_put_packet(connection, "OK", 2);
                                        break;
                                case 'X':
-                                       gdb_write_memory_binary_packet(connection, target, packet, packet_size);
+                                       if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)
+                                               return retval;
                                        break;
                                case 'k':
                                        gdb_put_packet(connection, "OK", 2);
@@ -1033,6 +1295,10 @@ int gdb_input(connection_t *connection)
                                        gdb_put_packet(connection, NULL, 0);
                                        break;
                        }
+                       
+                       /* if a packet handler returned an error, exit input loop */
+                       if (retval != ERROR_OK)
+                               return retval;
                }
                                
                if (gdb_con->ctrl_c)
@@ -1080,6 +1346,7 @@ int gdb_init()
                
                DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
                
+               i++;
                target = target->next;
        }
        

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)