]> git.sur5r.net Git - openocd/commitdiff
big endian fix for GDB. Probably fixes a memory corruption(not reported) as well.
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 18 Nov 2008 19:26:07 +0000 (19:26 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 18 Nov 2008 19:26:07 +0000 (19:26 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@1174 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/server/gdb_server.c

index ea6f6b75aa7ad2242b28298526d01cc18f009996..4c8afbdfa23a43b756ec3a91c3b443c6e91ac501 100644 (file)
@@ -847,9 +847,24 @@ 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;
@@ -861,26 +876,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]);
+
+               int j = gdb_reg_pos(target, i/2, str_len/2);
+               bin[j] = t;
        }
 }
 
@@ -965,16 +998,16 @@ 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);
@@ -982,10 +1015,10 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
                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 */
@@ -1034,7 +1067,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;
@@ -1062,21 +1094,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);
 
-       /* get register arch_type, and call set method */
+       /* 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);
 
        gdb_put_packet(connection, "OK", 2);
 
        free(bin_buf);
-       free(hex_buf);
        free(reg_list);
 
        return ERROR_OK;