/* Target description support for GDB.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery.
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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "arch-utils.h"
/* The current architecture should not have any target description
specified. It should have been cleared, e.g. when we
disconnected from the previous target. */
- gdb_assert (gdbarch_target_desc (current_gdbarch) == NULL);
+ gdb_assert (gdbarch_target_desc (target_gdbarch) == NULL);
/* First try to fetch an XML description from the user-specified
file. */
{
struct tdesc_arch_data *data;
- data = gdbarch_data (current_gdbarch, tdesc_data);
+ data = gdbarch_data (target_gdbarch, tdesc_data);
if (tdesc_has_registers (current_target_desc)
&& data->registers == NULL)
warning (_("Target-supplied registers are not supported "
return feature->name;
}
+/* Predefined types. Note that none of these types depend on the
+ current architecture; some of the builtin_type_foo variables are
+ swapped based on the architecture. */
+static struct
+{
+ const char *name;
+ struct type **type;
+} tdesc_predefined_types[] =
+ {
+ { "int8", &builtin_type_int8 },
+ { "int16", &builtin_type_int16 },
+ { "int32", &builtin_type_int32 },
+ { "int64", &builtin_type_int64 },
+ { "int128", &builtin_type_int128 },
+ { "uint8", &builtin_type_uint8 },
+ { "uint16", &builtin_type_uint16 },
+ { "uint32", &builtin_type_uint32 },
+ { "uint64", &builtin_type_uint64 },
+ { "uint128", &builtin_type_uint128 },
+ { "ieee_single", &builtin_type_ieee_single },
+ { "ieee_double", &builtin_type_ieee_double },
+ { "arm_fpa_ext", &builtin_type_arm_ext }
+ };
+
/* Return the type associated with ID in the context of FEATURE, or
NULL if none. */
if (strcmp (TYPE_NAME (gdb_type), id) == 0)
return gdb_type;
- /* Next try some predefined types. Note that none of these types
- depend on the current architecture; some of the builtin_type_foo
- variables are swapped based on the architecture. */
- if (strcmp (id, "int8") == 0)
- return builtin_type_int8;
-
- if (strcmp (id, "int16") == 0)
- return builtin_type_int16;
-
- if (strcmp (id, "int32") == 0)
- return builtin_type_int32;
-
- if (strcmp (id, "int64") == 0)
- return builtin_type_int64;
-
- if (strcmp (id, "uint8") == 0)
- return builtin_type_uint8;
-
- if (strcmp (id, "uint16") == 0)
- return builtin_type_uint16;
-
- if (strcmp (id, "uint32") == 0)
- return builtin_type_uint32;
-
- if (strcmp (id, "uint64") == 0)
- return builtin_type_uint64;
-
- if (strcmp (id, "code_ptr") == 0)
- return builtin_type_void_func_ptr;
-
- if (strcmp (id, "data_ptr") == 0)
- return builtin_type_void_data_ptr;
-
- if (strcmp (id, "arm_fpa_ext") == 0)
- return builtin_type_arm_ext;
+ /* Next try the predefined types. */
+ for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++)
+ if (strcmp (tdesc_predefined_types[ix].name, id) == 0)
+ return *tdesc_predefined_types[ix].type;
return NULL;
}
/* Search FEATURE for a register named NAME. */
-int
-tdesc_numbered_register (const struct tdesc_feature *feature,
- struct tdesc_arch_data *data,
- int regno, const char *name)
+static struct tdesc_reg *
+tdesc_find_register_early (const struct tdesc_feature *feature,
+ const char *name)
{
int ixr;
struct tdesc_reg *reg;
VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
ixr++)
if (strcasecmp (reg->name, name) == 0)
- {
- /* Make sure the vector includes a REGNO'th element. */
- while (regno >= VEC_length (tdesc_reg_p, data->registers))
- VEC_safe_push (tdesc_reg_p, data->registers, NULL);
- VEC_replace (tdesc_reg_p, data->registers, regno, reg);
- return 1;
- }
+ return reg;
- return 0;
+ return NULL;
}
-/* Search FEATURE for a register whose name is in NAMES. */
+/* Search FEATURE for a register named NAME. Assign REGNO to it. */
+
+int
+tdesc_numbered_register (const struct tdesc_feature *feature,
+ struct tdesc_arch_data *data,
+ int regno, const char *name)
+{
+ struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
+
+ if (reg == NULL)
+ return 0;
+
+ /* Make sure the vector includes a REGNO'th element. */
+ while (regno >= VEC_length (tdesc_reg_p, data->registers))
+ VEC_safe_push (tdesc_reg_p, data->registers, NULL);
+ VEC_replace (tdesc_reg_p, data->registers, regno, reg);
+ return 1;
+}
+
+/* Search FEATURE for a register whose name is in NAMES and assign
+ REGNO to it. */
int
tdesc_numbered_register_choices (const struct tdesc_feature *feature,
return 0;
}
+/* Search FEATURE for a register named NAME, and return its size in
+ bits. The register must exist. */
+
+int
+tdesc_register_size (const struct tdesc_feature *feature,
+ const char *name)
+{
+ struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
+
+ gdb_assert (reg != NULL);
+ return reg->bitsize;
+}
+
/* Look up a register by its GDB internal register number. */
static struct tdesc_reg *
return NULL;
}
-static const char *
-tdesc_register_name (int regno)
+/* Return the name of register REGNO, from the target description or
+ from an architecture-provided pseudo_register_name method. */
+
+const char *
+tdesc_register_name (struct gdbarch *gdbarch, int regno)
{
- struct tdesc_reg *reg = tdesc_find_register (current_gdbarch, regno);
- int num_regs = gdbarch_num_regs (current_gdbarch);
- int num_pseudo_regs = gdbarch_num_pseudo_regs (current_gdbarch);
+ struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
+ int num_regs = gdbarch_num_regs (gdbarch);
+ int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
if (reg != NULL)
return reg->name;
if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
{
- struct tdesc_arch_data *data = gdbarch_data (current_gdbarch,
- tdesc_data);
+ struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
gdb_assert (data->pseudo_register_name != NULL);
- return data->pseudo_register_name (regno);
+ return data->pseudo_register_name (gdbarch, regno);
}
return "";
if (strcmp (reg->type, "float") == 0)
{
if (reg->bitsize == gdbarch_float_bit (gdbarch))
- return builtin_type_float;
+ return builtin_type (gdbarch)->builtin_float;
else if (reg->bitsize == gdbarch_double_bit (gdbarch))
- return builtin_type_double;
+ return builtin_type (gdbarch)->builtin_double;
else if (reg->bitsize == gdbarch_long_double_bit (gdbarch))
- return builtin_type_long_double;
+ return builtin_type (gdbarch)->builtin_long_double;
}
else if (strcmp (reg->type, "int") == 0)
{
if (reg->bitsize == gdbarch_long_bit (gdbarch))
- return builtin_type_long;
+ return builtin_type (gdbarch)->builtin_long;
else if (reg->bitsize == TARGET_CHAR_BIT)
- return builtin_type_char;
+ return builtin_type (gdbarch)->builtin_char;
else if (reg->bitsize == gdbarch_short_bit (gdbarch))
- return builtin_type_short;
+ return builtin_type (gdbarch)->builtin_short;
else if (reg->bitsize == gdbarch_int_bit (gdbarch))
- return builtin_type_int;
+ return builtin_type (gdbarch)->builtin_int;
else if (reg->bitsize == gdbarch_long_long_bit (gdbarch))
- return builtin_type_long_long;
+ return builtin_type (gdbarch)->builtin_long_long;
else if (reg->bitsize == gdbarch_ptr_bit (gdbarch))
/* A bit desperate by this point... */
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
}
+ else if (strcmp (reg->type, "code_ptr") == 0)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else if (strcmp (reg->type, "data_ptr") == 0)
+ return builtin_type (gdbarch)->builtin_data_ptr;
else
internal_error (__FILE__, __LINE__,
"Register \"%s\" has an unknown type \"%s\"",
warning (_("Register \"%s\" has an unsupported size (%d bits)"),
reg->name, reg->bitsize);
- return builtin_type_long;
+ return builtin_type (gdbarch)->builtin_long;
}
static int
/* Check whether REGNUM is a member of REGGROUP. Registers from the
target description may be classified as general, float, or vector.
- Registers with no group specified go to the default reggroup
- function and are handled by type.
+ Unlike a gdbarch register_reggroup_p method, this function will
+ return -1 if it does not know; the caller should handle registers
+ with no specified group.
Arbitrary strings (other than "general", "float", and "vector")
from the description are not used; they cause the register to be
The save-restore flag is also implemented here. */
-static int
-tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno,
- struct reggroup *reggroup)
+int
+tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno,
+ struct reggroup *reggroup)
{
- int num_regs = gdbarch_num_regs (gdbarch);
- int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
- if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs)
- {
- struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
- gdb_assert (data->pseudo_register_reggroup_p != NULL);
- return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
- }
-
if (reg != NULL && reg->group != NULL)
{
int general_p = 0, float_p = 0, vector_p = 0;
&& (reggroup == save_reggroup || reggroup == restore_reggroup))
return reg->save_restore;
+ return -1;
+}
+
+/* Check whether REGNUM is a member of REGGROUP. Registers with no
+ group specified go to the default reggroup function and are handled
+ by type. */
+
+static int
+tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno,
+ struct reggroup *reggroup)
+{
+ int num_regs = gdbarch_num_regs (gdbarch);
+ int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+ int ret;
+
+ if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
+ {
+ struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
+ gdb_assert (data->pseudo_register_reggroup_p != NULL);
+ return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
+ }
+
+ ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup);
+ if (ret != -1)
+ return ret;
+
return default_register_reggroup_p (gdbarch, regno, reggroup);
}
void
tdesc_use_registers (struct gdbarch *gdbarch,
+ const struct target_desc *target_desc,
struct tdesc_arch_data *early_data)
{
int num_regs = gdbarch_num_regs (gdbarch);
int i, ixf, ixr;
- const struct target_desc *target_desc;
struct tdesc_feature *feature;
struct tdesc_reg *reg;
struct tdesc_arch_data *data;
htab_t reg_hash;
- target_desc = gdbarch_target_desc (gdbarch);
-
/* We can't use the description for registers if it doesn't describe
any. This function should only be called after validating
registers, so the caller should know that registers are
htab_remove_elt (reg_hash, reg);
/* Assign numbers to the remaining registers and add them to the
- list of registers. The new numbers are always above NUM_REGS.
+ list of registers. The new numbers are always above gdbarch_num_regs.
Iterate over the features, not the hash table, so that the order
matches that in the target description. */
reg->save_restore = save_restore;
reg->group = group ? xstrdup (group) : NULL;
reg->bitsize = bitsize;
- reg->type = type ? xstrdup (type) : NULL;
+ reg->type = type ? xstrdup (type) : xstrdup ("<unknown>");
/* If the register's type is target-defined, look it up now. We may not
have easy access to the containing feature when we want it later. */
target_find_description ();
}
+static const char *
+tdesc_type_id (struct type *type)
+{
+ int ix;
+
+ for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++)
+ if (TYPE_MAIN_TYPE (*tdesc_predefined_types[ix].type)
+ == TYPE_MAIN_TYPE (type))
+ return tdesc_predefined_types[ix].name;
+
+ return TYPE_NAME (type);
+}
+
+static void
+maint_print_c_tdesc_cmd (char *args, int from_tty)
+{
+ const struct target_desc *tdesc;
+ const char *filename, *inp;
+ char *function, *outp;
+ struct property *prop;
+ struct tdesc_feature *feature;
+ struct tdesc_reg *reg;
+ struct type *type;
+ int ix, ix2, ix3;
+
+ /* Use the global target-supplied description, not the current
+ architecture's. This lets a GDB for one architecture generate C
+ for another architecture's description, even though the gdbarch
+ initialization code will reject the new description. */
+ tdesc = current_target_desc;
+ if (tdesc == NULL)
+ error (_("There is no target description to print."));
+
+ if (target_description_filename == NULL)
+ error (_("The current target description did not come from an XML file."));
+
+ filename = lbasename (target_description_filename);
+ function = alloca (strlen (filename) + 1);
+ for (inp = filename, outp = function; *inp != '\0'; inp++)
+ if (*inp == '.')
+ break;
+ else if (*inp == '-')
+ *outp++ = '_';
+ else
+ *outp++ = *inp;
+ *outp = '\0';
+
+ /* Standard boilerplate. */
+ printf_unfiltered ("/* THIS FILE IS GENERATED. Original: %s */\n\n",
+ filename);
+ printf_unfiltered ("#include \"defs.h\"\n");
+ printf_unfiltered ("#include \"gdbtypes.h\"\n");
+ printf_unfiltered ("#include \"target-descriptions.h\"\n");
+ printf_unfiltered ("\n");
+
+ printf_unfiltered ("struct target_desc *tdesc_%s;\n", function);
+ printf_unfiltered ("static void\n");
+ printf_unfiltered ("initialize_tdesc_%s (void)\n", function);
+ printf_unfiltered ("{\n");
+ printf_unfiltered
+ (" struct target_desc *result = allocate_target_description ();\n");
+ printf_unfiltered (" struct tdesc_feature *feature;\n");
+ printf_unfiltered (" struct type *field_type, *type;\n");
+ printf_unfiltered ("\n");
+
+ if (tdesc_architecture (tdesc) != NULL)
+ {
+ printf_unfiltered
+ (" set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n",
+ tdesc_architecture (tdesc)->printable_name);
+ printf_unfiltered ("\n");
+ }
+
+ for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop);
+ ix++)
+ {
+ printf_unfiltered (" set_tdesc_property (result, \"%s\", \"%s\");\n",
+ prop->key, prop->value);
+ }
+
+ for (ix = 0;
+ VEC_iterate (tdesc_feature_p, tdesc->features, ix, feature);
+ ix++)
+ {
+ printf_unfiltered (" feature = tdesc_create_feature (result, \"%s\");\n",
+ feature->name);
+
+ for (ix2 = 0;
+ VEC_iterate (type_p, feature->types, ix2, type);
+ ix2++)
+ {
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ printf_unfiltered
+ (" field_type = tdesc_named_type (feature, \"%s\");\n",
+ tdesc_type_id (TYPE_TARGET_TYPE (type)));
+ printf_unfiltered
+ (" type = init_vector_type (field_type, %d);\n",
+ TYPE_LENGTH (type) / TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
+ printf_unfiltered
+ (" TYPE_NAME (type) = xstrdup (\"%s\");\n", TYPE_NAME (type));
+ break;
+ case TYPE_CODE_UNION:
+ printf_unfiltered
+ (" type = init_composite_type (NULL, TYPE_CODE_UNION);\n");
+ printf_unfiltered
+ (" TYPE_NAME (type) = xstrdup (\"%s\");\n", TYPE_NAME (type));
+ for (ix3 = 0; ix3 < TYPE_NFIELDS (type); ix3++)
+ {
+ printf_unfiltered
+ (" field_type = tdesc_named_type (feature, \"%s\");\n",
+ tdesc_type_id (TYPE_FIELD_TYPE (type, ix3)));
+ printf_unfiltered
+ (" append_composite_type_field (type, "
+ "xstrdup (\"%s\"), field_type);\n",
+ TYPE_FIELD_NAME (type, ix3));
+ }
+ if (TYPE_VECTOR (type))
+ printf_unfiltered
+ (" TYPE_VECTOR (type) = 1;\n");
+ break;
+ default:
+ error (_("C output is not supported type \"%s\"."), TYPE_NAME (type));
+ }
+ printf_unfiltered (" tdesc_record_type (feature, type);\n");
+ printf_unfiltered ("\n");
+ }
+
+ for (ix2 = 0;
+ VEC_iterate (tdesc_reg_p, feature->registers, ix2, reg);
+ ix2++)
+ {
+ printf_unfiltered (" tdesc_create_reg (feature, \"%s\", %ld, %d, ",
+ reg->name, reg->target_regnum, reg->save_restore);
+ if (reg->group)
+ printf_unfiltered ("\"%s\", ", reg->group);
+ else
+ printf_unfiltered ("NULL, ");
+ printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+ }
+
+ printf_unfiltered ("\n");
+ }
+
+ printf_unfiltered (" tdesc_%s = result;\n", function);
+ printf_unfiltered ("}\n");
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_target_descriptions;
+
void
_initialize_target_descriptions (void)
{
Unset the file to read for an XML target description. When unset,\n\
GDB will read the description from the target."),
&tdesc_unset_cmdlist);
+
+ add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\
+Print the current target description as a C source file."),
+ &maintenanceprintlist);
}