gdb_server: support gdb target description 82/1382/9
authorHsiangkai Wang <hsiangkai@gmail.com>
Tue, 7 May 2013 13:43:35 +0000 (21:43 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 7 Aug 2013 21:00:40 +0000 (21:00 +0000)
* Add a parameter in .get_gdb_reg_list() to return different
  register lists as generating target description.
* Modify STRUCT REG to let gdb generate target description
  according to register information.

The modified structure of register is
struct reg {
        const char *name;
        uint32_t number;  /* for regnum="num" */
        struct reg_feature *feature;  /* for register group feature name */
        bool caller_save;  /* for save-restore="yes|no" */
        void *value;
        bool dirty;
        bool valid;
        bool exist;
        uint32_t size;
        struct reg_data_type *reg_data_type;  /* for type="type" */
        const char *group;  /* for group="general|float|vector" */
        void *arch_info;
        const struct reg_arch_type *type;
};

Change-Id: I2096b67adf94518ba0b8b23d8c6a9f64ad7932b8
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1382
Tested-by: jenkins
Reviewed-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
16 files changed:
src/rtos/linux.c
src/server/gdb_server.c
src/target/arm.h
src/target/armv4_5.c
src/target/armv7m.c
src/target/armv7m.h
src/target/avr32_ap7k.c
src/target/dsp563xx.c
src/target/mips32.c
src/target/mips32.h
src/target/nds32.c
src/target/nds32.h
src/target/register.h
src/target/target.c
src/target/target.h
src/target/target_type.h

index 0fc763557c6929e34e20b3ea34e6a880f093d677..80d84d73e7779b919d70fdcbda78a04e1fa2704a 100644 (file)
@@ -226,7 +226,8 @@ static int linux_os_thread_reg_list(struct rtos *rtos,
                /*LOG_INFO("thread %lx current on core %x",thread_id,
                 * target->coreid);*/
                retval =
-                       target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+                       target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                                       REG_CLASS_GENERAL);
 
                if (retval != ERROR_OK)
                        return retval;
@@ -498,7 +499,7 @@ int get_current(struct target *target, int create)
                int retval;
 
                if (target_get_gdb_reg_list(head->target, &reg_list,
-                               &reg_list_size) != ERROR_OK) {
+                               &reg_list_size, REG_CLASS_GENERAL) != ERROR_OK) {
                        free(buffer);
                        return ERROR_TARGET_FAILURE;
                }
index e17ccffa9f3eefa65336880be46fed7a325276c5..beeeedcce1470fc804cdd96274e650370c4c3528 100644 (file)
  *   Copyright (C) ST-Ericsson SA 2011                                     *
  *   michel.jaouen@stericsson.com : smp minimum support                    *
  *                                                                         *
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   Copyright (C) 2013 Franck Jullien                                     *
+ *   elec4fun@gmail.com                                                    *
+ *                                                                         *
  *   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     *
@@ -114,6 +120,11 @@ static int gdb_flash_program = 1;
  */
 static int gdb_report_data_abort;
 
+/* set if we are sending target descriptions to gdb
+ * via qXfer:features:read packet */
+/* disabled by default */
+static int gdb_use_target_description;
+
 static int gdb_last_signal(struct target *target)
 {
        switch (target->debug_reason) {
@@ -968,7 +979,8 @@ static int gdb_get_registers_packet(struct connection *connection,
        if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection)))
                return ERROR_OK;
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_GENERAL);
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
 
@@ -1027,7 +1039,8 @@ static int gdb_set_registers_packet(struct connection *connection,
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_GENERAL);
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
 
@@ -1072,7 +1085,8 @@ static int gdb_get_register_packet(struct connection *connection,
        LOG_DEBUG("-");
 #endif
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_ALL);
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
 
@@ -1109,7 +1123,8 @@ static int gdb_set_register_packet(struct connection *connection,
 
        LOG_DEBUG("-");
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_ALL);
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
 
@@ -1670,6 +1685,331 @@ static int gdb_memory_map(struct connection *connection,
        return ERROR_OK;
 }
 
+static const char *gdb_get_reg_type_name(enum reg_type type)
+{
+       switch (type) {
+               case REG_TYPE_INT8:
+                       return "int8";
+               case REG_TYPE_INT16:
+                       return "int16";
+               case REG_TYPE_INT32:
+                       return "int32";
+               case REG_TYPE_INT64:
+                       return "int64";
+               case REG_TYPE_INT128:
+                       return "int128";
+               case REG_TYPE_UINT8:
+                       return "uint8";
+               case REG_TYPE_UINT16:
+                       return "uint16";
+               case REG_TYPE_UINT32:
+                       return "uint32";
+               case REG_TYPE_UINT64:
+                       return "uint64";
+               case REG_TYPE_UINT128:
+                       return "uint128";
+               case REG_TYPE_CODE_PTR:
+                       return "code_ptr";
+               case REG_TYPE_DATA_PTR:
+                       return "data_ptr";
+               case REG_TYPE_IEEE_SINGLE:
+                       return "ieee_single";
+               case REG_TYPE_IEEE_DOUBLE:
+                       return "ieee_double";
+               case REG_TYPE_ARCH_DEFINED:
+                       return "int"; /* return arbitrary string to avoid compile warning. */
+       }
+
+       return "int"; /* "int" as default value */
+}
+
+static int gdb_generate_reg_type_description(struct target *target,
+               char **tdesc, int *pos, int *size, struct reg_data_type *type)
+{
+       int retval = ERROR_OK;
+
+       if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+               /* <vector id="id" type="type" count="count"/> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+                               type->id, type->reg_type_vector->type->id,
+                               type->reg_type_vector->count);
+
+       } else if (type->type_class == REG_TYPE_CLASS_UNION) {
+               /* <union id="id">
+                *  <field name="name" type="type"/> ...
+                * </union> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<union id=\"%s\">\n",
+                               type->id);
+
+               struct reg_data_type_union_field *field;
+               field = type->reg_type_union->fields;
+               while (field != NULL) {
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<field name=\"%s\" type=\"%s\"/>\n",
+                                       field->name, field->type->id);
+
+                       field = field->next;
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</union>\n");
+
+       } else if (type->type_class == REG_TYPE_CLASS_STRUCT) {
+               struct reg_data_type_struct_field *field;
+               field = type->reg_type_struct->fields;
+
+               if (field->use_bitfields) {
+                       /* <struct id="id" size="size">
+                        *  <field name="name" start="start" end="end"/> ...
+                        * </struct> */
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<struct id=\"%s\" size=\"%d\">\n",
+                                       type->id, type->reg_type_struct->size);
+                       while (field != NULL) {
+                               xml_printf(&retval, tdesc, pos, size,
+                                               "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
+                                               field->name, field->bitfield->start,
+                                               field->bitfield->end);
+
+                               field = field->next;
+                       }
+               } else {
+                       /* <struct id="id">
+                        *  <field name="name" type="type"/> ...
+                        * </struct> */
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<struct id=\"%s\">\n",
+                                       type->id);
+                       while (field != NULL) {
+                               xml_printf(&retval, tdesc, pos, size,
+                                               "<field name=\"%s\" type=\"%s\"/>\n",
+                                               field->name, field->type->id);
+
+                               field = field->next;
+                       }
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</struct>\n");
+
+       } else if (type->type_class == REG_TYPE_CLASS_FLAGS) {
+               /* <flags id="id" size="size">
+                *  <field name="name" start="start" end="end"/> ...
+                * </flags> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<flags id=\"%s\" size=\"%d\">\n",
+                               type->id, type->reg_type_flags->size);
+
+               struct reg_data_type_flags_field *field;
+               field = type->reg_type_flags->fields;
+               while (field != NULL) {
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
+                                       field->name, field->bitfield->start, field->bitfield->end);
+
+                       field = field->next;
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</flags>\n");
+
+       }
+
+       return ERROR_OK;
+}
+
+/* Get a list of available target registers features. feature_list must
+ * be freed by caller.
+ */
+int get_reg_features_list(struct target *target, char **feature_list[], int *feature_list_size,
+               struct reg **reg_list, int reg_list_size)
+{
+       int tbl_sz = 0;
+
+       /* Start with only one element */
+       *feature_list = calloc(1, sizeof(char *));
+
+       for (int i = 0; i < reg_list_size; i++) {
+               if (reg_list[i]->exist == false)
+                       continue;
+
+               if ((reg_list[i]->feature->name != NULL)
+                       && (strcmp(reg_list[i]->feature->name, ""))) {
+                       /* We found a feature, check if the feature is already in the
+                        * table. If not, allocate a new entry for the table and
+                        * put the new feature in it.
+                        */
+                       for (int j = 0; j < (tbl_sz + 1); j++) {
+                               if (!((*feature_list)[j])) {
+                                       (*feature_list)[tbl_sz++] = strdup(reg_list[i]->feature->name);
+                                       *feature_list = realloc(*feature_list, sizeof(char *) * (tbl_sz + 1));
+                                       (*feature_list)[tbl_sz] = NULL;
+                                       break;
+                               } else {
+                                       if (!strcmp((*feature_list)[j], reg_list[i]->feature->name))
+                                               break;
+                               }
+                       }
+               }
+       }
+
+       if (feature_list_size)
+               *feature_list_size = tbl_sz;
+
+       return ERROR_OK;
+}
+
+static int gdb_generate_target_description(struct target *target, char **tdesc)
+{
+       int retval = ERROR_OK;
+       struct reg **reg_list;
+       int reg_list_size;
+       int pos = 0;
+       int size = 0;
+
+       xml_printf(&retval, tdesc, &pos, &size,
+                       "<?xml version=\"1.0\"?>\n"
+                       "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
+                       "<target version=\"1.0\">\n");
+
+       retval = target_get_gdb_reg_list(target, &reg_list,
+                       &reg_list_size, REG_CLASS_ALL);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("get register list failed");
+               return ERROR_FAIL;
+       }
+
+       if (reg_list_size <= 0)
+               return ERROR_FAIL;
+
+       char **features = NULL;
+       /* Get a list of available target registers features */
+       retval = get_reg_features_list(target, &features, NULL, reg_list, reg_list_size);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Can't get the registers feature list");
+               return ERROR_FAIL;
+       }
+
+       /* If we found some features associated with registers, create sections */
+       int current_feature = 0;
+
+       /* generate target description according to register list */
+       if (features != NULL) {
+               while (features[current_feature]) {
+
+                       xml_printf(&retval, tdesc, &pos, &size,
+                                       "<feature name=\"%s\">\n",
+                                       features[current_feature]);
+
+                       int i;
+                       for (i = 0; i < reg_list_size; i++) {
+
+                               if (reg_list[i]->exist == false)
+                                       continue;
+
+                               if (strcmp(reg_list[i]->feature->name, features[current_feature]))
+                                       continue;
+
+                               const char *type_str;
+                               if (reg_list[i]->reg_data_type != NULL) {
+                                       if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
+                                               /* generate <type... first, if there are architecture-defined types. */
+                                               gdb_generate_reg_type_description(target, tdesc, &pos, &size,
+                                                               reg_list[i]->reg_data_type);
+
+                                               type_str = reg_list[i]->reg_data_type->id;
+                                       } else {
+                                               /* predefined type */
+                                               type_str = gdb_get_reg_type_name(
+                                                               reg_list[i]->reg_data_type->type);
+                                       }
+                               } else {
+                                       /* Default type is "int" */
+                                       type_str = "int";
+                               }
+
+                               xml_printf(&retval, tdesc, &pos, &size,
+                                               "<reg name=\"%s\"", reg_list[i]->name);
+                               xml_printf(&retval, tdesc, &pos, &size,
+                                               " bitsize=\"%d\"", reg_list[i]->size);
+                               xml_printf(&retval, tdesc, &pos, &size,
+                                               " regnum=\"%d\"", reg_list[i]->number);
+                               if (reg_list[i]->caller_save)
+                                       xml_printf(&retval, tdesc, &pos, &size,
+                                                       " save-restore=\"yes\"");
+                               else
+                                       xml_printf(&retval, tdesc, &pos, &size,
+                                                       " save-restore=\"no\"");
+
+                               xml_printf(&retval, tdesc, &pos, &size,
+                                               " type=\"%s\"", type_str);
+
+                               if (reg_list[i]->group != NULL)
+                                       xml_printf(&retval, tdesc, &pos, &size,
+                                                       " group=\"%s\"", reg_list[i]->group);
+
+                               xml_printf(&retval, tdesc, &pos, &size,
+                                               "/>\n");
+                       }
+
+                       xml_printf(&retval, tdesc, &pos, &size,
+                                       "</feature>\n");
+
+                       current_feature++;
+               }
+       }
+
+       xml_printf(&retval, tdesc, &pos, &size,
+                       "</target>\n");
+
+       if (reg_list != NULL)
+               free(reg_list);
+
+       if (features != NULL)
+               free(features);
+
+       return ERROR_OK;
+}
+
+static int gdb_get_target_description_chunk(struct target *target, char **chunk,
+               int32_t offset, uint32_t length)
+{
+       static char *tdesc;
+       static uint32_t tdesc_length;
+
+       if (tdesc == NULL) {
+               gdb_generate_target_description(target, &tdesc);
+               tdesc_length = strlen(tdesc);
+       }
+
+       char transfer_type;
+
+       if (length < (tdesc_length - offset))
+               transfer_type = 'm';
+       else
+               transfer_type = 'l';
+
+       *chunk = malloc(length + 2);
+       (*chunk)[0] = transfer_type;
+       if (transfer_type == 'm') {
+               strncpy((*chunk) + 1, tdesc + offset, length);
+               (*chunk)[1 + length] = '\0';
+       } else {
+               strncpy((*chunk) + 1, tdesc + offset, tdesc_length - offset);
+               (*chunk)[1 + (tdesc_length - offset)] = '\0';
+
+               /* After gdb-server sends out last chunk, invalidate tdesc. */
+               free(tdesc);
+               tdesc = NULL;
+               tdesc_length = 0;
+       }
+
+       return ERROR_OK;
+}
+
 static int gdb_query_packet(struct connection *connection,
                char *packet, int packet_size)
 {
@@ -1744,9 +2084,10 @@ static int gdb_query_packet(struct connection *connection,
                        &buffer,
                        &pos,
                        &size,
-                       "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
+                       "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;QStartNoAckMode+",
                        (GDB_BUFFER_SIZE - 1),
-                       ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-');
+                       ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
+                       (gdb_use_target_description == 1) ? '+' : '-');
 
                if (retval != ERROR_OK) {
                        gdb_send_error(connection, 01);
@@ -1762,8 +2103,6 @@ static int gdb_query_packet(struct connection *connection,
                return gdb_memory_map(connection, packet, packet_size);
        else if (strncmp(packet, "qXfer:features:read:", 20) == 0) {
                char *xml = NULL;
-               int size = 0;
-               int pos = 0;
                int retval = ERROR_OK;
 
                int offset;
@@ -1778,17 +2117,12 @@ static int gdb_query_packet(struct connection *connection,
                        return ERROR_OK;
                }
 
-               if (strcmp(annex, "target.xml") != 0) {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-
-               xml_printf(&retval,
-                       &xml,
-                       &pos,
-                       &size, \
-                       "l < target version=\"1.0\">\n < architecture > arm</architecture>\n</target>\n");
-
+               /* Target should prepare correct target description for annex.
+                * The first character of returned xml is 'm' or 'l'. 'm' for
+                * there are *more* chunks to transfer. 'l' for it is the *last*
+                * chunk of target description.
+                */
+               retval = gdb_get_target_description_chunk(target, &xml, offset, length);
                if (retval != ERROR_OK) {
                        gdb_error(connection, retval);
                        return retval;
@@ -2372,6 +2706,54 @@ COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_gdb_target_description_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_target_description);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_gdb_save_tdesc_command)
+{
+       static char *tdesc;
+       static uint32_t tdesc_length;
+       struct target *target = get_current_target(CMD_CTX);
+       char *tdesc_filename;
+
+       if (tdesc == NULL) {
+               gdb_generate_target_description(target, &tdesc);
+               tdesc_length = strlen(tdesc);
+       }
+
+       struct fileio fileio;
+       size_t size_written;
+
+       tdesc_filename = malloc(strlen(target_type_name(target)) + 5);
+       sprintf(tdesc_filename, "%s.xml", target_type_name(target));
+
+       int retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
+
+       free(tdesc_filename);
+
+       if (retval != ERROR_OK) {
+               LOG_WARNING("Can't open %s for writing", tdesc_filename);
+               return ERROR_FAIL;
+       }
+
+       retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
+
+       fileio_close(&fileio);
+
+       if (retval != ERROR_OK) {
+               LOG_WARNING("Error while writing the tdesc file");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
 static const struct command_registration gdb_command_handlers[] = {
        {
                .name = "gdb_sync",
@@ -2424,6 +2806,19 @@ static const struct command_registration gdb_command_handlers[] = {
                        "to be used by gdb 'break' commands.",
                .usage = "('hard'|'soft'|'disable')"
        },
+       {
+               .name = "gdb_target_description",
+               .handler = handle_gdb_target_description_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable target description",
+               .usage = "('enable'|'disable')"
+       },
+       {
+               .name = "gdb_save_tdesc",
+               .handler = handle_gdb_save_tdesc_command,
+               .mode = COMMAND_EXEC,
+               .help = "Save the target description file",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
index 4a4d928c65ed89b942bf05e12caffaca85ff6b1b..e2d264615570edb014a18e8bc21557d1d65b7660 100644 (file)
@@ -211,7 +211,8 @@ extern const struct command_registration arm_command_handlers[];
 
 int arm_arch_state(struct target *target);
 int arm_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size);
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class);
 
 int arm_init_arch_info(struct target *target, struct arm *arm);
 
index 91830f57c90472931909bad1d4a4cfb735c1357e..a2f055753bfa1d176af1e90209dd9f3af9a27ac7 100644 (file)
@@ -1051,7 +1051,8 @@ const struct command_registration arm_command_handlers[] = {
 };
 
 int arm_get_gdb_reg_list(struct target *target,
-       struct reg **reg_list[], int *reg_list_size)
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class)
 {
        struct arm *arm = target_to_arm(target);
        int i;
index 622de490e990aadb9a29d5e09084a9f98edd190b..d32352a75c7eeccf11021e15014c41560879519a 100644 (file)
@@ -259,7 +259,8 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r,
  * hardware, so this also fakes a set of long-obsolete FPA registers that
  * are not used in EABI based software stacks.
  */
-int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+               int *reg_list_size, enum target_register_class reg_class)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
        int i;
index bc245fb7fd1cc5bf683672aa6a9cd1211e9e20d0..d028f4efbb3680201ac3ff78b90d14b2e48724a4 100644 (file)
@@ -195,7 +195,8 @@ int armv7m_mode_to_number(enum armv7m_mode mode);
 
 int armv7m_arch_state(struct target *target);
 int armv7m_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size);
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class);
 
 int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m);
 
index cc9ab5afaa3741f02456b31a2bbc4e8b20b63925..7c97234df0dc0fddfbc3795d345d8a51eed932de 100644 (file)
@@ -576,7 +576,8 @@ int avr32_ap7k_arch_state(struct target *target)
        return ERROR_OK;
 }
 
-int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+               int *reg_list_size, enum target_register_class reg_class)
 {
 #if 0
        /* get pointers to arch-specific information */
index 1211ac562c35461ec46c29f89a5e844c345daa48..8c470168684edad104fb9a35a7ceb3cf51e72f82 100644 (file)
@@ -354,7 +354,8 @@ static uint8_t gdb_reg_list_idx[] = {
 
 static int dsp563xx_get_gdb_reg_list(struct target *target,
        struct reg **reg_list[],
-       int *reg_list_size)
+       int *reg_list_size,
+       enum target_register_class reg_class)
 {
        int i;
        struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target);
index 1067f7b631bdc078312e7808563c8a219bc29249..c9cbf86e4aee668f2b92d88c335beb2e619eef82 100644 (file)
@@ -173,7 +173,8 @@ static int mips32_write_core_reg(struct target *target, int num)
        return ERROR_OK;
 }
 
-int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+               int *reg_list_size, enum target_register_class reg_class)
 {
        /* get pointers to arch-specific information */
        struct mips32_common *mips32 = target_to_mips32(target);
index 97fb5d03729d1b1d4ec709b10f234cfae1bbe7a6..951b2ed72659c1bfb2b2be518d71c11c62fee094 100644 (file)
@@ -243,7 +243,8 @@ int mips32_examine(struct target *target);
 int mips32_register_commands(struct command_context *cmd_ctx);
 
 int mips32_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size);
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class);
 int mips32_checksum_memory(struct target *target, uint32_t address,
                uint32_t count, uint32_t *checksum);
 int mips32_blank_check_memory(struct target *target,
index 2d47709775ed44d32152b03cd9fe6984740c1d67..95a249d0535bf553cf4176260cf461c2cf052c48 100644 (file)
@@ -91,21 +91,23 @@ static int nds32_get_core_reg(struct reg *reg)
                return ERROR_OK;
        }
 
+       int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
        if (reg_arch_info->enable == false) {
                reg_arch_info->value = NDS32_REGISTER_DISABLE;
                retval = ERROR_FAIL;
        } else {
                if ((nds32->fpu_enable == false) &&
-                       (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+                       (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
                        reg_arch_info->value = 0;
                        retval = ERROR_OK;
                } else if ((nds32->audio_enable == false) &&
-                       (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+                       (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
                        reg_arch_info->value = 0;
                        retval = ERROR_OK;
                } else {
                        retval = aice_read_register(aice,
-                                       reg_arch_info->num, &(reg_arch_info->value));
+                                       mapped_regnum, &(reg_arch_info->value));
                }
 
                LOG_DEBUG("reading register %i(%s), value: 0x%8.8" PRIx32,
@@ -301,44 +303,46 @@ static int nds32_set_core_reg(struct reg *reg, uint8_t *buf)
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
        /* ignore values that will generate exception */
-       if (nds32_reg_exception(reg_arch_info->num, value))
+       if (nds32_reg_exception(mapped_regnum, value))
                return ERROR_OK;
 
        LOG_DEBUG("writing register %i(%s) with value 0x%8.8" PRIx32,
                        reg_arch_info->num, reg->name, value);
 
        if ((nds32->fpu_enable == false) &&
-               (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+               (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
 
                buf_set_u32(reg->value, 0, 32, 0);
        } else if ((nds32->audio_enable == false) &&
-               (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+               (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
 
                buf_set_u32(reg->value, 0, 32, 0);
        } else {
                buf_set_u32(reg->value, 0, 32, value);
-               aice_write_register(aice, reg_arch_info->num, reg_arch_info->value);
+               aice_write_register(aice, mapped_regnum, reg_arch_info->value);
 
                /* After set value to registers, read the value from target
                 * to avoid W1C inconsistency. */
-               aice_read_register(aice, reg_arch_info->num, &(reg_arch_info->value));
+               aice_read_register(aice, mapped_regnum, &(reg_arch_info->value));
        }
 
        reg->valid = true;
        reg->dirty = false;
 
        /* update registers to take effect right now */
-       if (IR0 == reg_arch_info->num) {
+       if (IR0 == mapped_regnum) {
                nds32_update_psw(nds32);
-       } else if (MR0 == reg_arch_info->num) {
+       } else if (MR0 == mapped_regnum) {
                nds32_update_mmu_info(nds32);
-       } else if ((MR6 == reg_arch_info->num) || (MR7 == reg_arch_info->num)) {
+       } else if ((MR6 == mapped_regnum) || (MR7 == mapped_regnum)) {
                /* update lm information */
                nds32_update_lm_info(nds32);
-       } else if (MR8 == reg_arch_info->num) {
+       } else if (MR8 == mapped_regnum) {
                nds32_update_cache_info(nds32);
-       } else if (FUCPR == reg_arch_info->num) {
+       } else if (FUCPR == mapped_regnum) {
                /* update audio/fpu setting */
                nds32_check_extension(nds32);
        }
@@ -415,17 +419,62 @@ static struct reg_cache *nds32_build_reg_cache(struct target *target,
                reg_arch_info[i].enable = false;
 
                reg_list[i].name = nds32_reg_simple_name(i);
+               reg_list[i].number = reg_arch_info[i].num;
                reg_list[i].size = nds32_reg_size(i);
                reg_list[i].arch_info = &reg_arch_info[i];
 
+               reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
+
                if (FD0 <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31) {
                        reg_list[i].value = &(reg_arch_info[i].value_64);
                        reg_list[i].type = &nds32_reg_access_type_64;
+
+                       reg_list[i].reg_data_type->type = REG_TYPE_IEEE_DOUBLE;
+                       reg_list[i].reg_data_type->id = "ieee_double";
+                       reg_list[i].group = "float";
                } else {
                        reg_list[i].value = &(reg_arch_info[i].value);
                        reg_list[i].type = &nds32_reg_access_type;
+                       reg_list[i].group = "general";
+
+                       if ((FS0 <= reg_arch_info[i].num) && (reg_arch_info[i].num <= FS31)) {
+                               reg_list[i].reg_data_type->type = REG_TYPE_IEEE_SINGLE;
+                               reg_list[i].reg_data_type->id = "ieee_single";
+                               reg_list[i].group = "float";
+                       } else if ((reg_arch_info[i].num == FPCSR) ||
+                                  (reg_arch_info[i].num == FPCFG)) {
+                               reg_list[i].group = "float";
+                       } else if ((reg_arch_info[i].num == R28) ||
+                                  (reg_arch_info[i].num == R29) ||
+                                  (reg_arch_info[i].num == R31)) {
+                               reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR;
+                               reg_list[i].reg_data_type->id = "data_ptr";
+                       } else if ((reg_arch_info[i].num == R30) ||
+                                  (reg_arch_info[i].num == PC)) {
+                               reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR;
+                               reg_list[i].reg_data_type->id = "code_ptr";
+                       } else {
+                               reg_list[i].reg_data_type->type = REG_TYPE_UINT32;
+                               reg_list[i].reg_data_type->id = "uint32";
+                       }
                }
 
+               if (R16 <= reg_arch_info[i].num && reg_arch_info[i].num <= R25)
+                       reg_list[i].caller_save = true;
+               else
+                       reg_list[i].caller_save = false;
+
+               reg_list[i].feature = malloc(sizeof(struct reg_feature));
+
+               if (R0 <= reg_arch_info[i].num && reg_arch_info[i].num <= IFC_LP)
+                       reg_list[i].feature->name = "org.gnu.gdb.nds32.core";
+               else if (CR0 <= reg_arch_info[i].num && reg_arch_info[i].num <= SECUR0)
+                       reg_list[i].feature->name = "org.gnu.gdb.nds32.system";
+               else if (D0L24 <= reg_arch_info[i].num && reg_arch_info[i].num <= CBE3)
+                       reg_list[i].feature->name = "org.gnu.gdb.nds32.audio";
+               else if (FPCSR <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31)
+                       reg_list[i].feature->name = "org.gnu.gdb.nds32.fpu";
+
                cache->num_regs++;
        }
 
@@ -451,9 +500,7 @@ static struct reg *nds32_reg_current(struct nds32 *nds32, unsigned regnum)
 {
        struct reg *r;
 
-       /* Register mapping, pass user-view registers to gdb */
-       int mapped_regnum = nds32->register_map(nds32, regnum);
-       r = nds32->core_cache->reg_list + mapped_regnum;
+       r = nds32->core_cache->reg_list + regnum;
 
        return r;
 }
@@ -512,12 +559,36 @@ int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value)
        return r->type->set(r, set_value);
 }
 
+/** get general register list */
+static int nds32_get_general_reg_list(struct nds32 *nds32,
+               struct reg **reg_list[], int *reg_list_size)
+{
+       struct reg *reg_current;
+       int i;
+       int current_idx;
+
+       /** freed in gdb_server.c */
+       *reg_list = malloc(sizeof(struct reg *) * (IFC_LP - R0 + 1));
+       current_idx = 0;
+
+       for (i = R0; i < IFC_LP + 1; i++) {
+               reg_current = nds32_reg_current(nds32, i);
+               if (((struct nds32_reg *)reg_current->arch_info)->enable) {
+                       (*reg_list)[current_idx] = reg_current;
+                       current_idx++;
+               }
+       }
+       *reg_list_size = current_idx;
+
+       return ERROR_OK;
+}
+
 /** get all register list */
-int nds32_get_gdb_reg_list(struct target *target,
+static int nds32_get_all_reg_list(struct nds32 *nds32,
                struct reg **reg_list[], int *reg_list_size)
 {
-       struct nds32 *nds32 = target_to_nds32(target);
        struct reg_cache *reg_cache = nds32->core_cache;
+       struct reg *reg_current;
        unsigned int i;
 
        *reg_list_size = reg_cache->num_regs;
@@ -525,12 +596,35 @@ int nds32_get_gdb_reg_list(struct target *target,
        /** freed in gdb_server.c */
        *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
 
-       for (i = 0; i < reg_cache->num_regs; i++)
-               (*reg_list)[i] = nds32_reg_current(nds32, i);
+       for (i = 0; i < reg_cache->num_regs; i++) {
+               reg_current = nds32_reg_current(nds32, i);
+               reg_current->exist = ((struct nds32_reg *)
+                               reg_current->arch_info)->enable;
+               (*reg_list)[i] = reg_current;
+       }
 
        return ERROR_OK;
 }
 
+/** get all register list */
+int nds32_get_gdb_reg_list(struct target *target,
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       switch (reg_class) {
+               case REG_CLASS_ALL:
+                       return nds32_get_all_reg_list(nds32, reg_list, reg_list_size);
+               case REG_CLASS_GENERAL:
+                       return nds32_get_general_reg_list(nds32, reg_list, reg_list_size);
+               default:
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_FAIL;
+}
+
 static int nds32_select_memory_mode(struct target *target, uint32_t address,
                uint32_t length, uint32_t *end_address)
 {
index f585c2d30539b18fd24fcf0df22e98b24629d01a..b7e787cf00defc571ab3cac96e7489b98ef12ec7 100644 (file)
@@ -341,7 +341,7 @@ struct nds32 {
 };
 
 struct nds32_reg {
-       uint32_t num;
+       int32_t num;
        uint32_t value;
        uint64_t value_64;
        struct target *target;
@@ -364,7 +364,8 @@ extern int nds32_remove_software_breakpoint(struct target *target,
                struct breakpoint *breakpoint);
 
 extern int nds32_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size);
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class);
 
 extern int nds32_write_buffer(struct target *target, uint32_t address,
                uint32_t size, const uint8_t *buffer);
index 3810d145b9a9273287f4eb2d2603ffb0c3137535..9e0f1ce834e0ffca4fee9db0c1c78f61d35d3c23 100644 (file)
 
 struct target;
 
+enum reg_type {
+       REG_TYPE_INT8,
+       REG_TYPE_INT16,
+       REG_TYPE_INT32,
+       REG_TYPE_INT64,
+       REG_TYPE_INT128,
+       REG_TYPE_UINT8,
+       REG_TYPE_UINT16,
+       REG_TYPE_UINT32,
+       REG_TYPE_UINT64,
+       REG_TYPE_UINT128,
+       REG_TYPE_CODE_PTR,
+       REG_TYPE_DATA_PTR,
+       REG_TYPE_IEEE_SINGLE,
+       REG_TYPE_IEEE_DOUBLE,
+       REG_TYPE_ARCH_DEFINED,
+};
+
+struct reg_feature {
+       const char *name;
+};
+
+struct reg_data_type_vector {
+       struct reg_data_type *type;
+       uint32_t count;
+};
+
+struct reg_data_type_union_field {
+       const char *name;
+       struct reg_data_type *type;
+       struct reg_data_type_union_field *next;
+};
+
+struct reg_data_type_union {
+       struct reg_data_type_union_field *fields;
+};
+
+struct reg_data_type_bitfield {
+       uint32_t start;
+       uint32_t end;
+};
+
+struct reg_data_type_struct_field {
+       const char *name;
+       bool use_bitfields;
+       union {
+               struct reg_data_type_bitfield *bitfield;
+               struct reg_data_type *type;
+       };
+       struct reg_data_type_struct_field *next;
+};
+
+struct reg_data_type_struct {
+       uint32_t size;
+       struct reg_data_type_struct_field *fields;
+};
+
+struct reg_data_type_flags_field {
+       const char *name;
+       struct reg_data_type_bitfield *bitfield;
+       struct reg_data_type_flags_field *next;
+};
+
+struct reg_data_type_flags {
+       uint32_t size;
+       struct reg_data_type_flags_field *fields;
+};
+
+enum reg_data_type_class {
+       REG_TYPE_CLASS_VECTOR,
+       REG_TYPE_CLASS_UNION,
+       REG_TYPE_CLASS_STRUCT,
+       REG_TYPE_CLASS_FLAGS,
+};
+
+struct reg_data_type {
+       enum reg_type type;
+       const char *id;
+       enum reg_data_type_class type_class;
+       union {
+               struct reg_data_type_vector *reg_type_vector;
+               struct reg_data_type_union *reg_type_union;
+               struct reg_data_type_struct *reg_type_struct;
+               struct reg_data_type_flags *reg_type_flags;
+       };
+};
+
 struct reg {
        const char *name;
+       uint32_t number;
+       struct reg_feature *feature;
+       bool caller_save;
        void *value;
        bool dirty;
        bool valid;
+       bool exist;
        uint32_t size;
+       struct reg_data_type *reg_data_type;
+       const char *group;
        void *arch_info;
        const struct reg_arch_type *type;
 };
index 1f517ac068c0a17fd2bbc649b99e3e4f5f7e105c..c5b80d6476745325fc854ce372d3d1426ea3dbe3 100644 (file)
@@ -1037,9 +1037,10 @@ int target_remove_watchpoint(struct target *target,
 }
 
 int target_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size)
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class)
 {
-       return target->type->get_gdb_reg_list(target, reg_list, reg_list_size);
+       return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
 }
 int target_step(struct target *target,
                int current, uint32_t address, int handle_breakpoints)
index 38bb8753cfcd4cf26bd6dd0f23f273f672087324..42414c69207d9676f7a3b4fcc1d8ade6b1b799b4 100644 (file)
@@ -114,6 +114,12 @@ struct backoff_timer {
        int count;
 };
 
+/* split target registers into multiple class */
+enum target_register_class {
+       REG_CLASS_ALL,
+       REG_CLASS_GENERAL,
+};
+
 /* target_type.h contains the full definition of struct target_type */
 struct target {
        struct target_type *type;                       /* target type definition (name, access functions) */
@@ -399,7 +405,8 @@ int target_remove_watchpoint(struct target *target,
  * This routine is a wrapper for target->type->get_gdb_reg_list.
  */
 int target_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size);
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class);
 
 /**
  * Step the target.
index 3a3de7a266878a8b72a4bb2e7390f88198defa73..4d9a33f99764f20ea58ee1cea10b907f2df9a5c0 100644 (file)
@@ -101,7 +101,8 @@ struct target_type {
         * list, however it is after GDB is connected that monitor commands can
         * be run to properly initialize the target
         */
-       int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size);
+       int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[],
+                       int *reg_list_size, enum target_register_class reg_class);
 
        /* target memory access
        * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)

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)