* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
(xml-tdesc.o): Update. * xml-support.c: Add a comment. (gdb_xml_enums_boolean): New variable. (gdb_xml_parse_attr_enum): Use strcasecmp. * xml-support.h (gdb_xml_enums_boolean): Declare. * xml-tdesc.c (struct tdesc_parsing_data): Record current_feature, next_regnum, and current_union. (tdesc_start_feature, tdesc_start_reg, tdesc_start_union) (tdesc_end_union, tdesc_start_field, tdesc_start_vector) (field_attributes, union_children, reg_attributes, union_attributes) (vector_attributes, feature_attributes, feature_children): New. (target_children): Make static. Add <feature>. (tdesc_elements): Make static. * target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p) (struct tdesc_feature, tdesc_feature_p): New types. (struct target_desc): Add features member. (struct tdesc_arch_data, tdesc_data): New. (target_find_description): Clarify error message. Warn about ignored register descriptions. (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) (tdesc_named_type, tdesc_data_init, tdesc_data_alloc) (tdesc_data_cleanup, tdesc_numbered_register) (tdesc_numbered_register_choices, tdesc_find_register) (tdesc_register_name, tdesc_register_type) (tdesc_remote_register_number, tdesc_register_reggroup_p) (set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type) (set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers) (tdesc_free_reg, tdesc_create_reg, tdesc_free_feature) (tdesc_create_feature, tdesc_record_type): New. (free_target_description): Free features. (_initialize_target_descriptions): Initialize tdesc_data. * arch-utils.c (default_remote_register_number): New. * arch-utils.h (default_remote_register_number): New prototype. * target-descriptions.h (set_tdesc_pseudo_register_name) (set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p) (tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup) (tdesc_numbered_register, tdesc_numbered_register_choices) (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) (tdesc_named_type, tdesc_create_feature, tdesc_record_type) (tdesc_create_reg): Declare. * gdbarch.sh (remote_register_number): New entry. * gdbarch.c, gdbarch.h: Regenerate. * remote.c (init_remote_state): Use gdbarch_remote_register_number. * features/gdb-target.dtd: Add feature, reg, vector, union, and field. * arm-tdep.c (arm_register_aliases): New. (arm_register_name_strings): Rename to... (arm_register_names): ...this. Make const. Delete the old version. (current_option, arm_register_byte): Delete. (set_disassembly_style): Simplify. Do not adjust arm_register_names. (value_of_arm_user_reg): New. (arm_gdbarch_init): Verify any described registers. Call tdesc_use_registers. Don't use arm_register_byte. Create aliases for standard register names. (_initialize_arm_tdep): Do not adjust arm_register_names. * user-regs.c (struct user_reg): Add baton member. (append_user_reg, user_reg_add_builtin, user_regs_init) (user_reg_add, value_of_user_reg): Use a baton for user register functions. * std-regs.c: Update. * user-regs.h (user_reg_read_ftype, user_reg_add_builtin) (user_reg_add): Add baton argument. * NEWS: Mention target description register support. * features/arm-core.xml, features/arm-fpa.xml: New. * eval.c (evaluate_subexp_standard): Allow ptype $register when the program is not running. * gdb.texinfo (-target-disconnect): Use @smallexample. (Requirements): Add anchor for Expat. Update description. (Target Descriptions): Mention Expat. (Target Description Format): Document new elements. Use @smallexample. (Predefined Target Types, Standard Target Features): New sections. * doc/gdbint.texinfo (Target Descriptions): New section. * gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp, gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files.
This commit is contained in:
parent
1183581f7f
commit
123dc83914
30 changed files with 1857 additions and 114 deletions
|
@ -1,3 +1,73 @@
|
|||
2007-02-08 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
|
||||
(xml-tdesc.o): Update.
|
||||
* xml-support.c: Add a comment.
|
||||
(gdb_xml_enums_boolean): New variable.
|
||||
(gdb_xml_parse_attr_enum): Use strcasecmp.
|
||||
* xml-support.h (gdb_xml_enums_boolean): Declare.
|
||||
* xml-tdesc.c (struct tdesc_parsing_data): Record current_feature,
|
||||
next_regnum, and current_union.
|
||||
(tdesc_start_feature, tdesc_start_reg, tdesc_start_union)
|
||||
(tdesc_end_union, tdesc_start_field, tdesc_start_vector)
|
||||
(field_attributes, union_children, reg_attributes, union_attributes)
|
||||
(vector_attributes, feature_attributes, feature_children): New.
|
||||
(target_children): Make static. Add <feature>.
|
||||
(tdesc_elements): Make static.
|
||||
* target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p)
|
||||
(struct tdesc_feature, tdesc_feature_p): New types.
|
||||
(struct target_desc): Add features member.
|
||||
(struct tdesc_arch_data, tdesc_data): New.
|
||||
(target_find_description): Clarify error message. Warn about
|
||||
ignored register descriptions.
|
||||
(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
|
||||
(tdesc_named_type, tdesc_data_init, tdesc_data_alloc)
|
||||
(tdesc_data_cleanup, tdesc_numbered_register)
|
||||
(tdesc_numbered_register_choices, tdesc_find_register)
|
||||
(tdesc_register_name, tdesc_register_type)
|
||||
(tdesc_remote_register_number, tdesc_register_reggroup_p)
|
||||
(set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type)
|
||||
(set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers)
|
||||
(tdesc_free_reg, tdesc_create_reg, tdesc_free_feature)
|
||||
(tdesc_create_feature, tdesc_record_type): New.
|
||||
(free_target_description): Free features.
|
||||
(_initialize_target_descriptions): Initialize tdesc_data.
|
||||
* arch-utils.c (default_remote_register_number): New.
|
||||
* arch-utils.h (default_remote_register_number): New prototype.
|
||||
* target-descriptions.h (set_tdesc_pseudo_register_name)
|
||||
(set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p)
|
||||
(tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup)
|
||||
(tdesc_numbered_register, tdesc_numbered_register_choices)
|
||||
(tdesc_has_registers, tdesc_find_feature, tdesc_feature_name)
|
||||
(tdesc_named_type, tdesc_create_feature, tdesc_record_type)
|
||||
(tdesc_create_reg): Declare.
|
||||
* gdbarch.sh (remote_register_number): New entry.
|
||||
* gdbarch.c, gdbarch.h: Regenerate.
|
||||
* remote.c (init_remote_state): Use gdbarch_remote_register_number.
|
||||
* features/gdb-target.dtd: Add feature, reg, vector, union, and field.
|
||||
|
||||
* arm-tdep.c (arm_register_aliases): New.
|
||||
(arm_register_name_strings): Rename to...
|
||||
(arm_register_names): ...this. Make const. Delete the old version.
|
||||
(current_option, arm_register_byte): Delete.
|
||||
(set_disassembly_style): Simplify. Do not adjust arm_register_names.
|
||||
(value_of_arm_user_reg): New.
|
||||
(arm_gdbarch_init): Verify any described registers. Call
|
||||
tdesc_use_registers. Don't use arm_register_byte. Create aliases
|
||||
for standard register names.
|
||||
(_initialize_arm_tdep): Do not adjust arm_register_names.
|
||||
* user-regs.c (struct user_reg): Add baton member.
|
||||
(append_user_reg, user_reg_add_builtin, user_regs_init)
|
||||
(user_reg_add, value_of_user_reg): Use a baton for user
|
||||
register functions.
|
||||
* std-regs.c: Update.
|
||||
* user-regs.h (user_reg_read_ftype, user_reg_add_builtin)
|
||||
(user_reg_add): Add baton argument.
|
||||
* NEWS: Mention target description register support.
|
||||
* features/arm-core.xml, features/arm-fpa.xml: New.
|
||||
* eval.c (evaluate_subexp_standard): Allow ptype $register
|
||||
when the program is not running.
|
||||
|
||||
2007-02-09 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* mi/mi-cmd-var.c (mi_cmd_var_create): Add value field.
|
||||
|
|
|
@ -1823,7 +1823,8 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
|
|||
$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \
|
||||
$(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \
|
||||
$(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
|
||||
$(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h)
|
||||
$(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) \
|
||||
$(target_descriptions_h) $(user_regs_h)
|
||||
auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
|
||||
$(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
|
||||
$(elf_common_h)
|
||||
|
@ -1986,7 +1987,7 @@ eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
|
|||
$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
|
||||
$(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \
|
||||
$(parser_defs_h) $(cp_support_h) $(gdb_assert_h) $(exceptions_h) \
|
||||
$(uiout_h)
|
||||
$(uiout_h) $(regcache_h)
|
||||
event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
|
||||
$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
|
||||
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
|
||||
|
@ -2793,7 +2794,8 @@ target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
|
|||
$(exceptions_h) $(target_descriptions_h)
|
||||
target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \
|
||||
$(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \
|
||||
$(gdbcmd_h) $(gdb_assert_h)
|
||||
$(gdbcmd_h) $(gdb_assert_h) $(gdbtypes_h) $(reggroups_h) \
|
||||
$(xml_support_h) $(gdb_obstack_h) $(hashtab_h)
|
||||
target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \
|
||||
$(memory_map_h) $(gdb_assert_h)
|
||||
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
|
||||
|
@ -2892,7 +2894,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \
|
|||
xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \
|
||||
$(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h)
|
||||
xml-tdesc.o: xml-tdesc.c $(defs_h) $(target_h) $(target_descriptions_h) \
|
||||
$(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h)
|
||||
$(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h) \
|
||||
$(gdbtypes_h)
|
||||
xml-support.o: xml-support.c $(defs_h) $(xml_support_h) $(exceptions_h) \
|
||||
$(gdbcmd_h) $(gdb_string_h) $(gdb_expat_h) $(safe_ctype_h)
|
||||
xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \
|
||||
|
|
4
gdb/NEWS
4
gdb/NEWS
|
@ -18,6 +18,10 @@ a local file or over the remote serial protocol.
|
|||
* Arrays of explicitly SIGNED or UNSIGNED CHARs are now printed as arrays
|
||||
of numbers.
|
||||
|
||||
* Target descriptions can now describe target-specific registers,
|
||||
for architectures which have implemented the support (currently
|
||||
only ARM).
|
||||
|
||||
* New commands
|
||||
|
||||
set mem inaccessible-by-default
|
||||
|
|
|
@ -263,6 +263,13 @@ generic_instruction_nullified (struct gdbarch *gdbarch,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
default_remote_register_number (struct gdbarch *gdbarch,
|
||||
int regno)
|
||||
{
|
||||
return regno;
|
||||
}
|
||||
|
||||
|
||||
/* Functions to manipulate the endianness of the target. */
|
||||
|
||||
|
|
|
@ -109,6 +109,9 @@ extern int default_stabs_argument_has_addr (struct gdbarch *gdbarch,
|
|||
extern int generic_instruction_nullified (struct gdbarch *gdbarch,
|
||||
struct regcache *regcache);
|
||||
|
||||
int default_remote_register_number (struct gdbarch *gdbarch,
|
||||
int regno);
|
||||
|
||||
/* For compatibility with older architectures, returns
|
||||
(LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
|
||||
name. */
|
||||
|
|
199
gdb/arm-tdep.c
199
gdb/arm-tdep.c
|
@ -41,6 +41,8 @@
|
|||
#include "dwarf2-frame.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "prologue-value.h"
|
||||
#include "target-descriptions.h"
|
||||
#include "user-regs.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "gdb/sim-arm.h"
|
||||
|
@ -103,13 +105,58 @@ static const char *arm_abi_string = "auto";
|
|||
/* Number of different reg name sets (options). */
|
||||
static int num_disassembly_options;
|
||||
|
||||
/* We have more registers than the disassembler as gdb can print the value
|
||||
of special registers as well.
|
||||
The general register names are overwritten by whatever is being used by
|
||||
the disassembler at the moment. We also adjust the case of cpsr and fps. */
|
||||
/* The standard register names, and all the valid aliases for them. */
|
||||
static const struct
|
||||
{
|
||||
const char *name;
|
||||
int regnum;
|
||||
} arm_register_aliases[] = {
|
||||
/* Basic register numbers. */
|
||||
{ "r0", 0 },
|
||||
{ "r1", 1 },
|
||||
{ "r2", 2 },
|
||||
{ "r3", 3 },
|
||||
{ "r4", 4 },
|
||||
{ "r5", 5 },
|
||||
{ "r6", 6 },
|
||||
{ "r7", 7 },
|
||||
{ "r8", 8 },
|
||||
{ "r9", 9 },
|
||||
{ "r10", 10 },
|
||||
{ "r11", 11 },
|
||||
{ "r12", 12 },
|
||||
{ "r13", 13 },
|
||||
{ "r14", 14 },
|
||||
{ "r15", 15 },
|
||||
/* Synonyms (argument and variable registers). */
|
||||
{ "a1", 0 },
|
||||
{ "a2", 1 },
|
||||
{ "a3", 2 },
|
||||
{ "a4", 3 },
|
||||
{ "v1", 4 },
|
||||
{ "v2", 5 },
|
||||
{ "v3", 6 },
|
||||
{ "v4", 7 },
|
||||
{ "v5", 8 },
|
||||
{ "v6", 9 },
|
||||
{ "v7", 10 },
|
||||
{ "v8", 11 },
|
||||
/* Other platform-specific names for r9. */
|
||||
{ "sb", 9 },
|
||||
{ "tr", 9 },
|
||||
/* Special names. */
|
||||
{ "ip", 12 },
|
||||
{ "sp", 13 },
|
||||
{ "lr", 14 },
|
||||
{ "pc", 15 },
|
||||
/* Names used by GCC (not listed in the ARM EABI). */
|
||||
{ "sl", 10 },
|
||||
{ "fp", 11 },
|
||||
/* A special name from the older ATPCS. */
|
||||
{ "wr", 7 },
|
||||
};
|
||||
|
||||
/* Initial value: Register names used in ARM's ISA documentation. */
|
||||
static char * arm_register_name_strings[] =
|
||||
static const char *const arm_register_names[] =
|
||||
{"r0", "r1", "r2", "r3", /* 0 1 2 3 */
|
||||
"r4", "r5", "r6", "r7", /* 4 5 6 7 */
|
||||
"r8", "r9", "r10", "r11", /* 8 9 10 11 */
|
||||
|
@ -117,15 +164,12 @@ static char * arm_register_name_strings[] =
|
|||
"f0", "f1", "f2", "f3", /* 16 17 18 19 */
|
||||
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
|
||||
"fps", "cpsr" }; /* 24 25 */
|
||||
static char **arm_register_names = arm_register_name_strings;
|
||||
|
||||
/* Valid register name styles. */
|
||||
static const char **valid_disassembly_styles;
|
||||
|
||||
/* Disassembly style to use. Default to "std" register names. */
|
||||
static const char *disassembly_style;
|
||||
/* Index to that option in the opcodes table. */
|
||||
static int current_option;
|
||||
|
||||
/* This is used to keep the bfd arch_info in sync with the disassembly
|
||||
style. */
|
||||
|
@ -1343,23 +1387,6 @@ arm_register_type (struct gdbarch *gdbarch, int regnum)
|
|||
return builtin_type_uint32;
|
||||
}
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
static int
|
||||
arm_register_byte (int regnum)
|
||||
{
|
||||
if (regnum < ARM_F0_REGNUM)
|
||||
return regnum * INT_REGISTER_SIZE;
|
||||
else if (regnum < ARM_PS_REGNUM)
|
||||
return (NUM_GREGS * INT_REGISTER_SIZE
|
||||
+ (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
|
||||
else
|
||||
return (NUM_GREGS * INT_REGISTER_SIZE
|
||||
+ NUM_FREGS * FP_REGISTER_SIZE
|
||||
+ (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
|
||||
}
|
||||
|
||||
/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
|
||||
static int
|
||||
arm_register_sim_regno (int regnum)
|
||||
|
@ -2461,32 +2488,13 @@ arm_register_name (int i)
|
|||
static void
|
||||
set_disassembly_style (void)
|
||||
{
|
||||
const char *setname, *setdesc, *const *regnames;
|
||||
int numregs, j;
|
||||
int current;
|
||||
|
||||
/* Find the style that the user wants in the opcodes table. */
|
||||
int current = 0;
|
||||
numregs = get_arm_regnames (current, &setname, &setdesc, ®names);
|
||||
while ((disassembly_style != setname)
|
||||
&& (current < num_disassembly_options))
|
||||
get_arm_regnames (++current, &setname, &setdesc, ®names);
|
||||
current_option = current;
|
||||
|
||||
/* Fill our copy. */
|
||||
for (j = 0; j < numregs; j++)
|
||||
arm_register_names[j] = (char *) regnames[j];
|
||||
|
||||
/* Adjust case. */
|
||||
if (isupper (*regnames[ARM_PC_REGNUM]))
|
||||
{
|
||||
arm_register_names[ARM_FPS_REGNUM] = "FPS";
|
||||
arm_register_names[ARM_PS_REGNUM] = "CPSR";
|
||||
}
|
||||
else
|
||||
{
|
||||
arm_register_names[ARM_FPS_REGNUM] = "fps";
|
||||
arm_register_names[ARM_PS_REGNUM] = "cpsr";
|
||||
}
|
||||
/* Find the style that the user wants. */
|
||||
for (current = 0; current < num_disassembly_options; current++)
|
||||
if (disassembly_style == valid_disassembly_styles[current])
|
||||
break;
|
||||
gdb_assert (current < num_disassembly_options);
|
||||
|
||||
/* Synchronize the disassembler. */
|
||||
set_arm_regname_option (current);
|
||||
|
@ -2544,6 +2552,13 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid)
|
|||
write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
|
||||
}
|
||||
}
|
||||
|
||||
static struct value *
|
||||
value_of_arm_user_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
const int *reg_p = baton;
|
||||
return value_of_register (*reg_p, frame);
|
||||
}
|
||||
|
||||
static enum gdb_osabi
|
||||
arm_elf_osabi_sniffer (bfd *abfd)
|
||||
|
@ -2580,6 +2595,65 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||
struct gdbarch_list *best_arch;
|
||||
enum arm_abi_kind arm_abi = arm_abi_global;
|
||||
enum arm_float_model fp_model = arm_fp_model;
|
||||
struct tdesc_arch_data *tdesc_data = NULL;
|
||||
int i;
|
||||
|
||||
/* Check any target description for validity. */
|
||||
if (tdesc_has_registers (info.target_desc))
|
||||
{
|
||||
/* For most registers we require GDB's default names; but also allow
|
||||
the numeric names for sp / lr / pc, as a convenience. */
|
||||
static const char *const arm_sp_names[] = { "r13", "sp", NULL };
|
||||
static const char *const arm_lr_names[] = { "r14", "lr", NULL };
|
||||
static const char *const arm_pc_names[] = { "r15", "pc", NULL };
|
||||
|
||||
const struct tdesc_feature *feature;
|
||||
int i, valid_p;
|
||||
|
||||
feature = tdesc_find_feature (info.target_desc,
|
||||
"org.gnu.gdb.arm.core");
|
||||
if (feature == NULL)
|
||||
return NULL;
|
||||
|
||||
tdesc_data = tdesc_data_alloc ();
|
||||
|
||||
valid_p = 1;
|
||||
for (i = 0; i < ARM_SP_REGNUM; i++)
|
||||
valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
|
||||
arm_register_names[i]);
|
||||
valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
|
||||
ARM_SP_REGNUM,
|
||||
arm_sp_names);
|
||||
valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
|
||||
ARM_LR_REGNUM,
|
||||
arm_lr_names);
|
||||
valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
|
||||
ARM_PC_REGNUM,
|
||||
arm_pc_names);
|
||||
valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
||||
ARM_PS_REGNUM, "cpsr");
|
||||
|
||||
if (!valid_p)
|
||||
{
|
||||
tdesc_data_cleanup (tdesc_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
feature = tdesc_find_feature (info.target_desc,
|
||||
"org.gnu.gdb.arm.fpa");
|
||||
if (feature != NULL)
|
||||
{
|
||||
valid_p = 1;
|
||||
for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
|
||||
valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
|
||||
arm_register_names[i]);
|
||||
if (!valid_p)
|
||||
{
|
||||
tdesc_data_cleanup (tdesc_data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have an object to base this architecture on, try to determine
|
||||
its ABI. */
|
||||
|
@ -2709,7 +2783,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||
}
|
||||
|
||||
if (best_arch != NULL)
|
||||
return best_arch->gdbarch;
|
||||
{
|
||||
if (tdesc_data != NULL)
|
||||
tdesc_data_cleanup (tdesc_data);
|
||||
return best_arch->gdbarch;
|
||||
}
|
||||
|
||||
tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
|
||||
gdbarch = gdbarch_alloc (&info, tdep);
|
||||
|
@ -2784,7 +2862,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||
set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
|
||||
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
|
||||
set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
|
||||
set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
|
||||
set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
|
||||
set_gdbarch_register_type (gdbarch, arm_register_type);
|
||||
|
||||
|
@ -2842,6 +2919,16 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
|
||||
}
|
||||
|
||||
if (tdesc_data)
|
||||
tdesc_use_registers (gdbarch, tdesc_data);
|
||||
|
||||
/* Add standard register aliases. We add aliases even for those
|
||||
nanes which are used by the current architecture - it's simpler,
|
||||
and does no harm, since nothing ever lists user registers. */
|
||||
for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
|
||||
user_reg_add (gdbarch, arm_register_aliases[i].name,
|
||||
value_of_arm_user_reg, &arm_register_aliases[i].regnum);
|
||||
|
||||
return gdbarch;
|
||||
}
|
||||
|
||||
|
@ -2906,13 +2993,11 @@ _initialize_arm_tdep (void)
|
|||
length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
|
||||
rdptr += length;
|
||||
rest -= length;
|
||||
/* Copy the default names (if found) and synchronize disassembler. */
|
||||
/* When we find the default names, tell the disassembler to use
|
||||
them. */
|
||||
if (!strcmp (setname, "std"))
|
||||
{
|
||||
disassembly_style = setname;
|
||||
current_option = i;
|
||||
for (j = 0; j < numregs; j++)
|
||||
arm_register_names[j] = (char *) regnames[j];
|
||||
set_arm_regname_option (i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2007-02-08 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (-target-disconnect): Use @smallexample.
|
||||
(Requirements): Add anchor for Expat. Update description.
|
||||
(Target Descriptions): Mention Expat.
|
||||
(Target Description Format): Document new elements. Use
|
||||
@smallexample.
|
||||
(Predefined Target Types, Standard Target Features): New sections.
|
||||
* doc/gdbint.texinfo (Target Descriptions): New section.
|
||||
|
||||
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Target Description Format): Add section on XInclude.
|
||||
|
|
|
@ -21047,9 +21047,9 @@ The corresponding @value{GDBN} command is @samp{detach}.
|
|||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@example
|
||||
@smallexample
|
||||
-target-disconnect
|
||||
@end example
|
||||
@end smallexample
|
||||
|
||||
Disconnect from the remote target. There's no output and the target is
|
||||
generally not resumed.
|
||||
|
@ -22222,6 +22222,7 @@ working C90 compiler, e.g.@: GCC.
|
|||
@heading Tools/packages optional for building @value{GDBN}
|
||||
@table @asis
|
||||
@item Expat
|
||||
@anchor{Expat}
|
||||
@value{GDBN} can use the Expat XML parsing library. This library may be
|
||||
included with your operating system distribution; if it is not, you
|
||||
can get the latest version from @url{http://expat.sourceforge.net}.
|
||||
|
@ -22229,8 +22230,8 @@ The @code{configure} script will search for this library in several
|
|||
standard locations; if it is installed in an unusual path, you can
|
||||
use the @option{--with-libexpat-prefix} option to specify its location.
|
||||
|
||||
Expat is used currently only used to implement some remote-specific
|
||||
features.
|
||||
Expat is used for remote protocol memory maps (@pxref{Memory map format})
|
||||
and for target descriptions (@pxref{Target Descriptions}).
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -25738,9 +25739,15 @@ actually describe its own features. This lets @value{GDBN} support
|
|||
processor variants it has never seen before --- to the extent that the
|
||||
descriptions are accurate, and that @value{GDBN} understands them.
|
||||
|
||||
@value{GDBN} must be compiled with Expat support to support XML target
|
||||
descriptions. @xref{Expat}.
|
||||
|
||||
@menu
|
||||
* Retrieving Descriptions:: How descriptions are fetched from a target.
|
||||
* Target Description Format:: The contents of a target description.
|
||||
* Predefined Target Types:: Standard types available for target
|
||||
descriptions.
|
||||
* Standard Target Features:: Features @value{GDBN} knows about.
|
||||
@end menu
|
||||
|
||||
@node Retrieving Descriptions
|
||||
|
@ -25787,32 +25794,35 @@ check that your feature descriptions are well-formed and valid.
|
|||
However, to help people unfamiliar with XML write descriptions for
|
||||
their targets, we also describe the grammar here.
|
||||
|
||||
At the moment, target descriptions can only provide minimal information
|
||||
about the architecture of the remote target. @value{GDBN} can use this
|
||||
information to autoconfigure, or to warn you if you connect to an
|
||||
unsupported target.
|
||||
Target descriptions can identify the architecture of the remote target
|
||||
and (for some architectures) provide information about custom register
|
||||
sets. @value{GDBN} can use this information to autoconfigure for your
|
||||
target, or to warn you if you connect to an unsupported target.
|
||||
|
||||
Here is a simple target description:
|
||||
|
||||
@example
|
||||
@smallexample
|
||||
<target>
|
||||
<architecture>i386:x86-64</architecture>
|
||||
</target>
|
||||
@end example
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
This minimal description only says that the target uses
|
||||
the x86-64 architecture.
|
||||
|
||||
A target description has the overall form:
|
||||
A target description has the following overall form, with [ ] marking
|
||||
optional elements and @dots{} marking repeatable elements. The elements
|
||||
are explained further below.
|
||||
|
||||
@example
|
||||
@smallexample
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target>
|
||||
<architecture>@var{arch name}</architecture>
|
||||
@r{[}@var{architecture}@r{]}
|
||||
@r{[}@var{feature}@dots{}@r{]}
|
||||
</target>
|
||||
@end example
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The description is generally insensitive to whitespace and line
|
||||
|
@ -25821,10 +25831,6 @@ declaration and document type declaration can generally be omitted
|
|||
(@value{GDBN} does not require them), but specifying them may be
|
||||
useful for XML validation tools.
|
||||
|
||||
The content of the @samp{<architecture>} element is an architecture
|
||||
name, from the same selection accepted by @code{set architecture}
|
||||
(@pxref{Targets, ,Specifying a Debugging Target}).
|
||||
|
||||
@subsection Inclusion
|
||||
@cindex target descriptions, inclusion
|
||||
@cindex XInclude
|
||||
|
@ -25838,9 +25844,9 @@ share files between different possible target descriptions. You can
|
|||
divide a description into multiple files by replacing any element of
|
||||
the target description with an inclusion directive of the form:
|
||||
|
||||
@example
|
||||
@smallexample
|
||||
<xi:include href="@var{document}"/>
|
||||
@end example
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
When @value{GDBN} encounters an element of this form, it will retrieve
|
||||
|
@ -25852,6 +25858,208 @@ current description was read from a file, @value{GDBN} will look for
|
|||
@var{document} as a file in the same directory where it found the
|
||||
original description.
|
||||
|
||||
@subsection Architecture
|
||||
@cindex <architecture>
|
||||
|
||||
An @samp{<architecture>} element has this form:
|
||||
|
||||
@smallexample
|
||||
<architecture>@var{arch}</architecture>
|
||||
@end smallexample
|
||||
|
||||
@var{arch} is an architecture name from the same selection
|
||||
accepted by @code{set architecture} (@pxref{Targets, ,Specifying a
|
||||
Debugging Target}).
|
||||
|
||||
@subsection Features
|
||||
@cindex <feature>
|
||||
|
||||
Each @samp{<feature>} describes some logical portion of the target
|
||||
system. Features are currently used to describe available CPU
|
||||
registers and the types of their contents. A @samp{<feature>} element
|
||||
has this form:
|
||||
|
||||
@smallexample
|
||||
<feature name="@var{name}">
|
||||
@r{[}@var{type}@dots{}@r{]}
|
||||
@var{reg}@dots{}
|
||||
</feature>
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
Each feature's name should be unique within the description. The name
|
||||
of a feature does not matter unless @value{GDBN} has some special
|
||||
knowledge of the contents of that feature; if it does, the feature
|
||||
should have its standard name. @xref{Standard Target Features}.
|
||||
|
||||
@subsection Types
|
||||
|
||||
Any register's value is a collection of bits which @value{GDBN} must
|
||||
interpret. The default interpretation is a two's complement integer,
|
||||
but other types can be requested by name in the register description.
|
||||
Some predefined types are provided by @value{GDBN} (@pxref{Predefined
|
||||
Target Types}), and the description can define additional composite types.
|
||||
|
||||
Each type element must have an @samp{id} attribute, which gives
|
||||
a unique (within the containing @samp{<feature>}) name to the type.
|
||||
Types must be defined before they are used.
|
||||
|
||||
@cindex <vector>
|
||||
Some targets offer vector registers, which can be treated as arrays
|
||||
of scalar elements. These types are written as @samp{<vector>} elements,
|
||||
specifying the array element type, @var{type}, and the number of elements,
|
||||
@var{count}:
|
||||
|
||||
@smallexample
|
||||
<vector id="@var{id}" type="@var{type}" count="@var{count}"/>
|
||||
@end smallexample
|
||||
|
||||
@cindex <union>
|
||||
If a register's value is usefully viewed in multiple ways, define it
|
||||
with a union type containing the useful representations. The
|
||||
@samp{<union>} element contains one or more @samp{<field>} elements,
|
||||
each of which has a @var{name} and a @var{type}:
|
||||
|
||||
@smallexample
|
||||
<union id="@var{id}">
|
||||
<field name="@var{name}" type="@var{type}"/>
|
||||
@dots{}
|
||||
</union>
|
||||
@end smallexample
|
||||
|
||||
@subsection Registers
|
||||
@cindex <reg>
|
||||
|
||||
Each register is represented as an element with this form:
|
||||
|
||||
@smallexample
|
||||
<reg name="@var{name}"
|
||||
bitsize="@var{size}"
|
||||
@r{[}regnum="@var{num}"@r{]}
|
||||
@r{[}save-restore="@var{save-restore}"@r{]}
|
||||
@r{[}type="@var{type}"@r{]}
|
||||
@r{[}group="@var{group}"@r{]}/>
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The components are as follows:
|
||||
|
||||
@table @var
|
||||
|
||||
@item name
|
||||
The register's name; it must be unique within the target description.
|
||||
|
||||
@item bitsize
|
||||
The register's size, in bits.
|
||||
|
||||
@item regnum
|
||||
The register's number. If omitted, a register's number is one greater
|
||||
than that of the previous register (either in the current feature or in
|
||||
a preceeding feature); the first register in the target description
|
||||
defaults to zero. This register number is used to read or write
|
||||
the register; e.g.@: it is used in the remote @code{p} and @code{P}
|
||||
packets, and registers appear in the @code{g} and @code{G} packets
|
||||
in order of increasing register number.
|
||||
|
||||
@item save-restore
|
||||
Whether the register should be preserved across inferior function
|
||||
calls; this must be either @code{yes} or @code{no}. The default is
|
||||
@code{yes}, which is appropriate for most registers except for
|
||||
some system control registers; this is not related to the target's
|
||||
ABI.
|
||||
|
||||
@item type
|
||||
The type of the register. @var{type} may be a predefined type, a type
|
||||
defined in the current feature, or one of the special types @code{int}
|
||||
and @code{float}. @code{int} is an integer type of the correct size
|
||||
for @var{bitsize}, and @code{float} is a floating point type (in the
|
||||
architecture's normal floating point format) of the correct size for
|
||||
@var{bitsize}. The default is @code{int}.
|
||||
|
||||
@item group
|
||||
The register group to which this register belongs. @var{group} must
|
||||
be either @code{general}, @code{float}, or @code{vector}. If no
|
||||
@var{group} is specified, @value{GDBN} will not display the register
|
||||
in @code{info registers}.
|
||||
|
||||
@end table
|
||||
|
||||
@node Predefined Target Types
|
||||
@section Predefined Target Types
|
||||
@cindex target descriptions, predefined types
|
||||
|
||||
Type definitions in the self-description can build up composite types
|
||||
from basic building blocks, but can not define fundamental types. Instead,
|
||||
standard identifiers are provided by @value{GDBN} for the fundamental
|
||||
types. The currently supported types are:
|
||||
|
||||
@table @code
|
||||
|
||||
@item int8
|
||||
@itemx int16
|
||||
@itemx int32
|
||||
@itemx int64
|
||||
Signed integer types holding the specified number of bits.
|
||||
|
||||
@item uint8
|
||||
@itemx uint16
|
||||
@itemx uint32
|
||||
@itemx uint64
|
||||
Unsigned integer types holding the specified number of bits.
|
||||
|
||||
@item code_ptr
|
||||
@itemx data_ptr
|
||||
Pointers to unspecified code and data. The program counter and
|
||||
any dedicated return address register may be marked as code
|
||||
pointers; printing a code pointer converts it into a symbolic
|
||||
address. The stack pointer and any dedicated address registers
|
||||
may be marked as data pointers.
|
||||
|
||||
@item arm_fpa_ext
|
||||
The 12-byte extended precision format used by ARM FPA registers.
|
||||
|
||||
@end table
|
||||
|
||||
@node Standard Target Features
|
||||
@section Standard Target Features
|
||||
@cindex target descriptions, standard features
|
||||
|
||||
A target description must contain either no registers or all the
|
||||
target's registers. If the description contains no registers, then
|
||||
@value{GDBN} will assume a default register layout, selected based on
|
||||
the architecture. If the description contains any registers, the
|
||||
default layout will not be used; the standard registers must be
|
||||
described in the target description, in such a way that @value{GDBN}
|
||||
can recognize them.
|
||||
|
||||
This is accomplished by giving specific names to feature elements
|
||||
which contain standard registers. @value{GDBN} will look for features
|
||||
with those names and verify that they contain the expected registers;
|
||||
if any known feature is missing required registers, or if any required
|
||||
feature is missing, @value{GDBN} will reject the target
|
||||
description. You can add additional registers to any of the
|
||||
standard features --- @value{GDBN} will display them just as if
|
||||
they were added to an unrecognized feature.
|
||||
|
||||
This section lists the known features and their expected contents.
|
||||
Sample XML documents for these features are included in the
|
||||
@value{GDBN} source tree, in the directory @file{gdb/features}.
|
||||
|
||||
Names recognized by @value{GDBN} should include the name of the
|
||||
company or organization which selected the name, and the overall
|
||||
architecture to which the feature applies; so e.g.@: the feature
|
||||
containing ARM core registers is named @samp{org.gnu.gdb.arm.core}.
|
||||
|
||||
@subsection ARM Features
|
||||
@cindex target descriptions, ARM features
|
||||
|
||||
The @samp{org.gnu.gdb.arm.core} feature is required for ARM targets.
|
||||
It should contain registers @samp{r0} through @samp{r13}, @samp{sp},
|
||||
@samp{lr}, @samp{pc}, and @samp{cpsr}.
|
||||
|
||||
The @samp{org.gnu.gdb.arm.fpa} feature is optional. If present, it
|
||||
should contain registers @samp{f0} through @samp{f7} and @samp{fps}.
|
||||
|
||||
|
||||
@include gpl.texi
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets.
|
|||
* Language Support::
|
||||
* Host Definition::
|
||||
* Target Architecture Definition::
|
||||
* Target Descriptions::
|
||||
* Target Vector Definition::
|
||||
* Native Debugging::
|
||||
* Support Libraries::
|
||||
|
@ -4512,6 +4513,135 @@ The @file{tm-@var{arch}.h} can be deleted. @file{@var{arch}.mt} and
|
|||
@file{configure.in} updated.
|
||||
|
||||
|
||||
@node Target Descriptions
|
||||
@chapter Target Descriptions
|
||||
@cindex target descriptions
|
||||
|
||||
The target architecture definition (@pxref{Target Architecture Definition})
|
||||
contains @value{GDBN}'s hard-coded knowledge about an architecture. For
|
||||
some platforms, it is handy to have more flexible knowledge about a specific
|
||||
instance of the architecture---for instance, a processor or development board.
|
||||
@dfn{Target descriptions} provide a mechanism for the user to tell @value{GDBN}
|
||||
more about what their target supports, or for the target to tell @value{GDBN}
|
||||
directly.
|
||||
|
||||
For details on writing, automatically supplying, and manually selecting
|
||||
target descriptions, see @ref{Target Descriptions, , , gdb,
|
||||
Debugging with @value{GDBN}}. This section will cover some related
|
||||
topics about the @value{GDBN} internals.
|
||||
|
||||
@menu
|
||||
* Target Descriptions Implementation::
|
||||
* Adding Target Described Register Support::
|
||||
@end menu
|
||||
|
||||
@node Target Descriptions Implementation
|
||||
@section Target Descriptions Implementation
|
||||
@cindex target descriptions, implementation
|
||||
|
||||
Before @value{GDBN} connects to a new target, or runs a new program on
|
||||
an existing target, it discards any existing target description and
|
||||
reverts to a default gdbarch. Then, after connecting, it looks for a
|
||||
new target description by calling @code{target_find_description}.
|
||||
|
||||
A description may come from a user specified file (XML), the remote
|
||||
@samp{qXfer:features:read} packet (also XML), or from any custom
|
||||
@code{to_read_description} routine in the target vector. For instance,
|
||||
the remote target supports guessing whether a MIPS target is 32-bit or
|
||||
64-bit based on the size of the @samp{g} packet.
|
||||
|
||||
If any target description is found, @value{GDBN} creates a new gdbarch
|
||||
incorporating the description by calling @code{gdbarch_update_p}. Any
|
||||
@samp{<architecture>} element is handled first, to determine which
|
||||
architecture's gdbarch initialization routine is called to create the
|
||||
new architecture. Then the initialization routine is called, and has
|
||||
a chance to adjust the constructed architecture based on the contents
|
||||
of the target description. For instance, it can recognize any
|
||||
properties set by a @code{to_read_description} routine. Also
|
||||
see @ref{Adding Target Described Register Support}.
|
||||
|
||||
@node Adding Target Described Register Support
|
||||
@section Adding Target Described Register Support
|
||||
@cindex target descriptions, adding register support
|
||||
|
||||
Target descriptions can report additional registers specific to an
|
||||
instance of the target. But it takes a little work in the architecture
|
||||
specific routines to support this.
|
||||
|
||||
A target description must either have no registers or a complete
|
||||
set---this avoids complexity in trying to merge standard registers
|
||||
with the target defined registers. It is the architecture's
|
||||
responsibility to validate that a description with registers has
|
||||
everything it needs. To keep architecture code simple, the same
|
||||
mechanism is used to assign fixed internal register numbers to
|
||||
standard registers.
|
||||
|
||||
If @code{tdesc_has_registers} returns 1, the description contains
|
||||
registers. The architecture's @code{gdbarch_init} routine should:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item
|
||||
Call @code{tdesc_data_alloc} to allocate storage, early, before
|
||||
searching for a matching gdbarch or allocating a new one.
|
||||
|
||||
@item
|
||||
Use @code{tdesc_find_feature} to locate standard features by name.
|
||||
|
||||
@item
|
||||
Use @code{tdesc_numbered_register} and @code{tdesc_numbered_register_choices}
|
||||
to locate the expected registers in the standard features.
|
||||
|
||||
@item
|
||||
Return @code{NULL} if a required feature is missing, or if any standard
|
||||
feature is missing expected registers. This will produce a warning that
|
||||
the description was incomplete.
|
||||
|
||||
@item
|
||||
Free the allocated data before returning, unless @code{tdesc_use_registers}
|
||||
is called.
|
||||
|
||||
@item
|
||||
Call @code{set_gdbarch_num_regs} as usual, with a number higher than any
|
||||
fixed number passed to @code{tdesc_numbered_register}.
|
||||
|
||||
@item
|
||||
Call @code{tdesc_use_registers} after creating a new gdbarch, before
|
||||
returning it.
|
||||
|
||||
@end itemize
|
||||
|
||||
After @code{tdesc_use_registers} has been called, the architecture's
|
||||
@code{register_name}, @code{register_type}, and @code{register_reggroup_p}
|
||||
routines will not be called; that information will be taken from
|
||||
the target description. @code{num_regs} may be increased to account
|
||||
for any additional registers in the description.
|
||||
|
||||
Pseudo-registers require some extra care:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item
|
||||
Using @code{tdesc_numbered_register} allows the architecture to give
|
||||
constant register numbers to standard architectural registers, e.g.@:
|
||||
as an @code{enum} in @file{@var{arch}-tdep.h}. But because
|
||||
pseudo-registers are always numbered above @code{num_regs},
|
||||
which may be increased by the description, constant numbers
|
||||
can not be used for pseudos. They must be numbered relative to
|
||||
@code{num_regs} instead.
|
||||
|
||||
@item
|
||||
The description will not describe pseudo-registers, so the
|
||||
architecture must call @code{set_tdesc_pseudo_register_name},
|
||||
@code{set_tdesc_pseudo_register_type}, and
|
||||
@code{set_tdesc_pseudo_register_reggroup_p} to supply routines
|
||||
describing pseudo registers. These routines will be passed
|
||||
internal register numbers, so the same routines used for the
|
||||
gdbarch equivalents are usually suitable.
|
||||
|
||||
@end itemize
|
||||
|
||||
|
||||
@node Target Vector Definition
|
||||
|
||||
@chapter Target Vector Definition
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "cp-support.h"
|
||||
#include "ui-out.h"
|
||||
#include "exceptions.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
|
@ -500,8 +501,12 @@ evaluate_subexp_standard (struct type *expect_type,
|
|||
case OP_REGISTER:
|
||||
{
|
||||
int regno = longest_to_int (exp->elts[pc + 1].longconst);
|
||||
struct value *val = value_of_register (regno, get_selected_frame (NULL));
|
||||
struct value *val;
|
||||
(*pos) += 2;
|
||||
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
||||
val = value_zero (register_type (current_gdbarch, regno), not_lval);
|
||||
else
|
||||
val = value_of_register (regno, get_selected_frame (NULL));
|
||||
if (val == NULL)
|
||||
error (_("Value of register %s not available."),
|
||||
frame_map_regnum_to_name (get_selected_frame (NULL), regno));
|
||||
|
|
31
gdb/features/arm-core.xml
Normal file
31
gdb/features/arm-core.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.arm.core">
|
||||
<reg name="r0" bitsize="32"/>
|
||||
<reg name="r1" bitsize="32"/>
|
||||
<reg name="r2" bitsize="32"/>
|
||||
<reg name="r3" bitsize="32"/>
|
||||
<reg name="r4" bitsize="32"/>
|
||||
<reg name="r5" bitsize="32"/>
|
||||
<reg name="r6" bitsize="32"/>
|
||||
<reg name="r7" bitsize="32"/>
|
||||
<reg name="r8" bitsize="32"/>
|
||||
<reg name="r9" bitsize="32"/>
|
||||
<reg name="r10" bitsize="32"/>
|
||||
<reg name="r11" bitsize="32"/>
|
||||
<reg name="r12" bitsize="32"/>
|
||||
<reg name="sp" bitsize="32"/>
|
||||
<reg name="lr" bitsize="32"/>
|
||||
<reg name="pc" bitsize="32"/>
|
||||
|
||||
<!-- The CPSR is register 25, rather than register 16, because
|
||||
the FPA registers historically were placed between the PC
|
||||
and the CPSR in the "g" packet. -->
|
||||
<reg name="cpsr" bitsize="32" regnum="25"/>
|
||||
</feature>
|
23
gdb/features/arm-fpa.xml
Normal file
23
gdb/features/arm-fpa.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.arm.fpa">
|
||||
<!-- f0's regnum is set explicitly, because the FPA registers
|
||||
historically were placed between the PC and the CPSR in the "g"
|
||||
packet - in the middle of org.gnu.gdb.arm.core. -->
|
||||
<reg name="f0" bitsize="96" type="arm_fpa_ext" regnum="16"/>
|
||||
<reg name="f1" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f2" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f3" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f4" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f5" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f6" bitsize="96" type="arm_fpa_ext"/>
|
||||
<reg name="f7" bitsize="96" type="arm_fpa_ext"/>
|
||||
|
||||
<reg name="fps" bitsize="32"/>
|
||||
</feature>
|
|
@ -6,9 +6,38 @@
|
|||
|
||||
<!-- The root element of a GDB target description is <target>. -->
|
||||
|
||||
<!ELEMENT target (architecture?)>
|
||||
<!ELEMENT target (architecture?, feature*)>
|
||||
|
||||
<!ELEMENT architecture (#PCDATA)>
|
||||
|
||||
<!ELEMENT feature ((vector | union)*, reg*)>
|
||||
<!ATTLIST feature
|
||||
name ID #REQUIRED>
|
||||
|
||||
<!ELEMENT reg (description*)>
|
||||
<!ATTLIST reg
|
||||
name CDATA #REQUIRED
|
||||
bitsize CDATA #REQUIRED
|
||||
regnum CDATA #IMPLIED
|
||||
save-restore (yes | no) 'yes'
|
||||
type CDATA 'int'
|
||||
group CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT vector EMPTY>
|
||||
<!ATTLIST vector
|
||||
id CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
count CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT union (field+)>
|
||||
<!ATTLIST union
|
||||
id CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT field EMPTY>
|
||||
<!ATTLIST field
|
||||
name CDATA #REQUIRED
|
||||
type CDATA #REQUIRED>
|
||||
|
||||
<!ENTITY % xinclude SYSTEM "xinclude.dtd">
|
||||
%xinclude;
|
||||
|
|
|
@ -203,6 +203,7 @@ struct gdbarch
|
|||
CORE_ADDR decr_pc_after_break;
|
||||
CORE_ADDR deprecated_function_start_offset;
|
||||
gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address;
|
||||
gdbarch_remote_register_number_ftype *remote_register_number;
|
||||
gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address;
|
||||
CORE_ADDR frame_args_skip;
|
||||
gdbarch_unwind_pc_ftype *unwind_pc;
|
||||
|
@ -330,6 +331,7 @@ struct gdbarch startup_gdbarch =
|
|||
0, /* decr_pc_after_break */
|
||||
0, /* deprecated_function_start_offset */
|
||||
generic_remote_translate_xfer_address, /* remote_translate_xfer_address */
|
||||
default_remote_register_number, /* remote_register_number */
|
||||
0, /* fetch_tls_load_module_address */
|
||||
0, /* frame_args_skip */
|
||||
0, /* unwind_pc */
|
||||
|
@ -440,6 +442,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
|
|||
current_gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
|
||||
current_gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
|
||||
current_gdbarch->remote_translate_xfer_address = generic_remote_translate_xfer_address;
|
||||
current_gdbarch->remote_register_number = default_remote_register_number;
|
||||
current_gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
|
||||
current_gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
|
||||
current_gdbarch->addr_bits_remove = core_addr_identity;
|
||||
|
@ -584,6 +587,7 @@ verify_gdbarch (struct gdbarch *current_gdbarch)
|
|||
/* Skip verify of decr_pc_after_break, invalid_p == 0 */
|
||||
/* Skip verify of deprecated_function_start_offset, invalid_p == 0 */
|
||||
/* Skip verify of remote_translate_xfer_address, invalid_p == 0 */
|
||||
/* Skip verify of remote_register_number, invalid_p == 0 */
|
||||
/* Skip verify of fetch_tls_load_module_address, has predicate */
|
||||
/* Skip verify of frame_args_skip, invalid_p == 0 */
|
||||
/* Skip verify of unwind_pc, has predicate */
|
||||
|
@ -1441,6 +1445,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
|
|||
fprintf_unfiltered (file,
|
||||
"gdbarch_dump: regset_from_core_section = <0x%lx>\n",
|
||||
(long) current_gdbarch->regset_from_core_section);
|
||||
fprintf_unfiltered (file,
|
||||
"gdbarch_dump: remote_register_number = <0x%lx>\n",
|
||||
(long) current_gdbarch->remote_register_number);
|
||||
fprintf_unfiltered (file,
|
||||
"gdbarch_dump: remote_translate_xfer_address = <0x%lx>\n",
|
||||
(long) current_gdbarch->remote_translate_xfer_address);
|
||||
|
@ -2989,6 +2996,23 @@ set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch,
|
|||
gdbarch->remote_translate_xfer_address = remote_translate_xfer_address;
|
||||
}
|
||||
|
||||
int
|
||||
gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno)
|
||||
{
|
||||
gdb_assert (gdbarch != NULL);
|
||||
gdb_assert (gdbarch->remote_register_number != NULL);
|
||||
if (gdbarch_debug >= 2)
|
||||
fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_register_number called\n");
|
||||
return gdbarch->remote_register_number (gdbarch, regno);
|
||||
}
|
||||
|
||||
void
|
||||
set_gdbarch_remote_register_number (struct gdbarch *gdbarch,
|
||||
gdbarch_remote_register_number_ftype remote_register_number)
|
||||
{
|
||||
gdbarch->remote_register_number = remote_register_number;
|
||||
}
|
||||
|
||||
int
|
||||
gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
|
||||
{
|
||||
|
|
|
@ -947,6 +947,13 @@ typedef void (gdbarch_remote_translate_xfer_address_ftype) (struct gdbarch *gdba
|
|||
extern void gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len);
|
||||
extern void set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address);
|
||||
|
||||
/* Return the remote protocol register number associated with this
|
||||
register. Normally the identity mapping. */
|
||||
|
||||
typedef int (gdbarch_remote_register_number_ftype) (struct gdbarch *gdbarch, int regno);
|
||||
extern int gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno);
|
||||
extern void set_gdbarch_remote_register_number (struct gdbarch *gdbarch, gdbarch_remote_register_number_ftype *remote_register_number);
|
||||
|
||||
/* Fetch the target specific address used to represent a load module. */
|
||||
|
||||
#if defined (FETCH_TLS_LOAD_MODULE_ADDRESS)
|
||||
|
|
|
@ -574,6 +574,10 @@ v:=:CORE_ADDR:deprecated_function_start_offset:::0:::0
|
|||
|
||||
m::void:remote_translate_xfer_address:struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len:regcache, gdb_addr, gdb_len, rem_addr, rem_len::generic_remote_translate_xfer_address::0
|
||||
|
||||
# Return the remote protocol register number associated with this
|
||||
# register. Normally the identity mapping.
|
||||
m::int:remote_register_number:int regno:regno::default_remote_register_number::0
|
||||
|
||||
# Fetch the target specific address used to represent a load module.
|
||||
F:=:CORE_ADDR:fetch_tls_load_module_address:struct objfile *objfile:objfile
|
||||
#
|
||||
|
|
|
@ -334,12 +334,13 @@ init_remote_state (struct gdbarch *gdbarch)
|
|||
|
||||
rsa = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_arch_state);
|
||||
|
||||
/* Assume a 1:1 regnum<->pnum table. */
|
||||
/* Use the architecture to build a regnum<->pnum table, which will be
|
||||
1:1 unless a feature set specifies otherwise. */
|
||||
rsa->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS, struct packet_reg);
|
||||
for (regnum = 0; regnum < NUM_REGS; regnum++)
|
||||
{
|
||||
struct packet_reg *r = &rsa->regs[regnum];
|
||||
r->pnum = regnum;
|
||||
r->pnum = gdbarch_remote_register_number (gdbarch, regnum);
|
||||
r->regnum = regnum;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ build_builtin_type_frame_reg (void)
|
|||
}
|
||||
|
||||
static struct value *
|
||||
value_of_builtin_frame_reg (struct frame_info *frame)
|
||||
value_of_builtin_frame_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
struct value *val;
|
||||
gdb_byte *buf;
|
||||
|
@ -72,7 +72,7 @@ value_of_builtin_frame_reg (struct frame_info *frame)
|
|||
}
|
||||
|
||||
static struct value *
|
||||
value_of_builtin_frame_fp_reg (struct frame_info *frame)
|
||||
value_of_builtin_frame_fp_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
if (DEPRECATED_FP_REGNUM >= 0)
|
||||
/* NOTE: cagney/2003-04-24: Since the mere presence of "fp" in the
|
||||
|
@ -96,7 +96,7 @@ value_of_builtin_frame_fp_reg (struct frame_info *frame)
|
|||
}
|
||||
|
||||
static struct value *
|
||||
value_of_builtin_frame_pc_reg (struct frame_info *frame)
|
||||
value_of_builtin_frame_pc_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
if (PC_REGNUM >= 0)
|
||||
return value_of_register (PC_REGNUM, frame);
|
||||
|
@ -114,7 +114,7 @@ value_of_builtin_frame_pc_reg (struct frame_info *frame)
|
|||
}
|
||||
|
||||
static struct value *
|
||||
value_of_builtin_frame_sp_reg (struct frame_info *frame)
|
||||
value_of_builtin_frame_sp_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
#ifdef SP_REGNUM
|
||||
if (SP_REGNUM >= 0)
|
||||
|
@ -124,7 +124,7 @@ value_of_builtin_frame_sp_reg (struct frame_info *frame)
|
|||
}
|
||||
|
||||
static struct value *
|
||||
value_of_builtin_frame_ps_reg (struct frame_info *frame)
|
||||
value_of_builtin_frame_ps_reg (struct frame_info *frame, const void *baton)
|
||||
{
|
||||
#ifdef PS_REGNUM
|
||||
if (PS_REGNUM >= 0)
|
||||
|
@ -147,14 +147,14 @@ _initialize_frame_reg (void)
|
|||
/* Frame based $fp, $pc, $sp and $ps. These only come into play
|
||||
when the target does not define its own version of these
|
||||
registers. */
|
||||
user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg);
|
||||
user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg);
|
||||
user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg);
|
||||
user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg);
|
||||
user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg, NULL);
|
||||
user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg, NULL);
|
||||
user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg, NULL);
|
||||
user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg, NULL);
|
||||
|
||||
/* NOTE: cagney/2002-04-05: For moment leave the $frame / $gdbframe
|
||||
/ $gdb.frame disabled. It isn't yet clear which of the many
|
||||
options is the best. */
|
||||
if (0)
|
||||
user_reg_add_builtin ("frame", value_of_builtin_frame_reg);
|
||||
user_reg_add_builtin ("frame", value_of_builtin_frame_reg, NULL);
|
||||
}
|
||||
|
|
|
@ -24,12 +24,17 @@
|
|||
#include "defs.h"
|
||||
#include "arch-utils.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "reggroups.h"
|
||||
#include "target.h"
|
||||
#include "target-descriptions.h"
|
||||
#include "vec.h"
|
||||
#include "xml-support.h"
|
||||
#include "xml-tdesc.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
/* Types. */
|
||||
|
||||
|
@ -40,6 +45,69 @@ typedef struct property
|
|||
} property_s;
|
||||
DEF_VEC_O(property_s);
|
||||
|
||||
/* An individual register from a target description. */
|
||||
|
||||
typedef struct tdesc_reg
|
||||
{
|
||||
/* The name of this register. In standard features, it may be
|
||||
recognized by the architecture support code, or it may be purely
|
||||
for the user. */
|
||||
char *name;
|
||||
|
||||
/* The register number used by this target to refer to this
|
||||
register. This is used for remote p/P packets and to determine
|
||||
the ordering of registers in the remote g/G packets. */
|
||||
long target_regnum;
|
||||
|
||||
/* If this flag is set, GDB should save and restore this register
|
||||
around calls to an inferior function. */
|
||||
int save_restore;
|
||||
|
||||
/* The name of the register group containing this register, or NULL
|
||||
if the group should be automatically determined from the
|
||||
register's type. If this is "general", "float", or "vector", the
|
||||
corresponding "info" command should display this register's
|
||||
value. It can be an arbitrary string, but should be limited to
|
||||
alphanumeric characters and internal hyphens. Currently other
|
||||
strings are ignored (treated as NULL). */
|
||||
char *group;
|
||||
|
||||
/* The size of the register, in bits. */
|
||||
int bitsize;
|
||||
|
||||
/* The type of the register. This string corresponds to either
|
||||
a named type from the target description or a predefined
|
||||
type from GDB. */
|
||||
char *type;
|
||||
|
||||
/* The target-described type corresponding to TYPE, if found. */
|
||||
struct type *gdb_type;
|
||||
} *tdesc_reg_p;
|
||||
DEF_VEC_P(tdesc_reg_p);
|
||||
|
||||
/* A named type from a target description. */
|
||||
typedef struct type *type_p;
|
||||
DEF_VEC_P(type_p);
|
||||
|
||||
/* A feature from a target description. Each feature is a collection
|
||||
of other elements, e.g. registers and types. */
|
||||
|
||||
typedef struct tdesc_feature
|
||||
{
|
||||
/* The name of this feature. It may be recognized by the architecture
|
||||
support code. */
|
||||
char *name;
|
||||
|
||||
/* The registers associated with this feature. */
|
||||
VEC(tdesc_reg_p) *registers;
|
||||
|
||||
/* The types associated with this feature. */
|
||||
VEC(type_p) *types;
|
||||
} *tdesc_feature_p;
|
||||
DEF_VEC_P(tdesc_feature_p);
|
||||
|
||||
/* A target description. */
|
||||
|
||||
struct target_desc
|
||||
{
|
||||
/* The architecture reported by the target, if any. */
|
||||
|
@ -47,6 +115,30 @@ struct target_desc
|
|||
|
||||
/* Any architecture-specific properties specified by the target. */
|
||||
VEC(property_s) *properties;
|
||||
|
||||
/* The features associated with this target. */
|
||||
VEC(tdesc_feature_p) *features;
|
||||
};
|
||||
|
||||
/* Per-architecture data associated with a target description. The
|
||||
target description may be shared by multiple architectures, but
|
||||
this data is private to one gdbarch. */
|
||||
|
||||
struct tdesc_arch_data
|
||||
{
|
||||
/* A list of registers, indexed by GDB's internal register number.
|
||||
During initialization of the gdbarch this list is used to store
|
||||
registers which the architecture assigns a fixed register number.
|
||||
Registers which are NULL in this array, or off the end, are
|
||||
treated as zero-sized and nameless (i.e. placeholders in the
|
||||
numbering). */
|
||||
VEC(tdesc_reg_p) *registers;
|
||||
|
||||
/* Functions which report the register name, type, and reggroups for
|
||||
pseudo-registers. */
|
||||
gdbarch_register_name_ftype *pseudo_register_name;
|
||||
gdbarch_register_type_ftype *pseudo_register_type;
|
||||
gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p;
|
||||
};
|
||||
|
||||
/* Global state. These variables are associated with the current
|
||||
|
@ -72,6 +164,11 @@ static const struct target_desc *current_target_desc;
|
|||
|
||||
static char *target_description_filename;
|
||||
|
||||
/* A handle for architecture-specific data associated with the
|
||||
target description (see struct tdesc_arch_data). */
|
||||
|
||||
static struct gdbarch_data *tdesc_data;
|
||||
|
||||
/* Fetch the current target's description, and switch the current
|
||||
architecture to one which incorporates that description. */
|
||||
|
||||
|
@ -116,7 +213,17 @@ target_find_description (void)
|
|||
gdbarch_info_init (&info);
|
||||
info.target_desc = current_target_desc;
|
||||
if (!gdbarch_update_p (info))
|
||||
warning (_("Could not use target-supplied description"));
|
||||
warning (_("Architecture rejected target-supplied description"));
|
||||
else
|
||||
{
|
||||
struct tdesc_arch_data *data;
|
||||
|
||||
data = gdbarch_data (current_gdbarch, tdesc_data);
|
||||
if (tdesc_has_registers (current_target_desc)
|
||||
&& data->registers == NULL)
|
||||
warning (_("Target-supplied registers are not supported "
|
||||
"by the current architecture"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we know this description is usable, record that we
|
||||
|
@ -158,7 +265,7 @@ target_current_description (void)
|
|||
}
|
||||
|
||||
|
||||
/* Direct accessors for feature sets. */
|
||||
/* Direct accessors for target descriptions. */
|
||||
|
||||
/* Return the string value of a property named KEY, or NULL if the
|
||||
property was not specified. */
|
||||
|
@ -187,8 +294,529 @@ tdesc_architecture (const struct target_desc *target_desc)
|
|||
}
|
||||
|
||||
|
||||
/* Return 1 if this target description includes any registers. */
|
||||
|
||||
int
|
||||
tdesc_has_registers (const struct target_desc *target_desc)
|
||||
{
|
||||
int ix;
|
||||
struct tdesc_feature *feature;
|
||||
|
||||
if (target_desc == NULL)
|
||||
return 0;
|
||||
|
||||
for (ix = 0;
|
||||
VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
|
||||
ix++)
|
||||
if (! VEC_empty (tdesc_reg_p, feature->registers))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the feature with the given name, if present, or NULL if
|
||||
the named feature is not found. */
|
||||
|
||||
const struct tdesc_feature *
|
||||
tdesc_find_feature (const struct target_desc *target_desc,
|
||||
const char *name)
|
||||
{
|
||||
int ix;
|
||||
struct tdesc_feature *feature;
|
||||
|
||||
for (ix = 0;
|
||||
VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
|
||||
ix++)
|
||||
if (strcmp (feature->name, name) == 0)
|
||||
return feature;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the name of FEATURE. */
|
||||
|
||||
const char *
|
||||
tdesc_feature_name (const struct tdesc_feature *feature)
|
||||
{
|
||||
return feature->name;
|
||||
}
|
||||
|
||||
/* Return the type associated with ID in the context of FEATURE, or
|
||||
NULL if none. */
|
||||
|
||||
struct type *
|
||||
tdesc_named_type (const struct tdesc_feature *feature, const char *id)
|
||||
{
|
||||
int ix;
|
||||
struct type *gdb_type;
|
||||
|
||||
/* First try target-defined types. */
|
||||
for (ix = 0; VEC_iterate (type_p, feature->types, ix, gdb_type); ix++)
|
||||
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;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Support for registers from target descriptions. */
|
||||
|
||||
/* Construct the per-gdbarch data. */
|
||||
|
||||
static void *
|
||||
tdesc_data_init (struct obstack *obstack)
|
||||
{
|
||||
struct tdesc_arch_data *data;
|
||||
|
||||
data = OBSTACK_ZALLOC (obstack, struct tdesc_arch_data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Similar, but for the temporary copy used during architecture
|
||||
initialization. */
|
||||
|
||||
struct tdesc_arch_data *
|
||||
tdesc_data_alloc (void)
|
||||
{
|
||||
return XZALLOC (struct tdesc_arch_data);
|
||||
}
|
||||
|
||||
/* Free something allocated by tdesc_data_alloc, if it is not going
|
||||
to be used (for instance if it was unsuitable for the
|
||||
architecture). */
|
||||
|
||||
void
|
||||
tdesc_data_cleanup (void *data_untyped)
|
||||
{
|
||||
struct tdesc_arch_data *data = data_untyped;
|
||||
|
||||
VEC_free (tdesc_reg_p, data->registers);
|
||||
xfree (data);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int ixr;
|
||||
struct tdesc_reg *reg;
|
||||
|
||||
for (ixr = 0;
|
||||
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 0;
|
||||
}
|
||||
|
||||
/* Search FEATURE for a register whose name is in NAMES. */
|
||||
|
||||
int
|
||||
tdesc_numbered_register_choices (const struct tdesc_feature *feature,
|
||||
struct tdesc_arch_data *data,
|
||||
int regno, const char *const names[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
if (tdesc_numbered_register (feature, data, regno, names[i]))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look up a register by its GDB internal register number. */
|
||||
|
||||
static struct tdesc_reg *
|
||||
tdesc_find_register (struct gdbarch *gdbarch, int regno)
|
||||
{
|
||||
struct tdesc_reg *reg;
|
||||
struct tdesc_arch_data *data;
|
||||
|
||||
data = gdbarch_data (gdbarch, tdesc_data);
|
||||
if (regno < VEC_length (tdesc_reg_p, data->registers))
|
||||
return VEC_index (tdesc_reg_p, data->registers, regno);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
tdesc_register_name (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);
|
||||
|
||||
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);
|
||||
gdb_assert (data->pseudo_register_name != NULL);
|
||||
return data->pseudo_register_name (regno);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static struct type *
|
||||
tdesc_register_type (struct gdbarch *gdbarch, int regno)
|
||||
{
|
||||
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 && regno >= num_regs && regno < num_regs + num_pseudo_regs)
|
||||
{
|
||||
struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
|
||||
gdb_assert (data->pseudo_register_type != NULL);
|
||||
return data->pseudo_register_type (gdbarch, regno);
|
||||
}
|
||||
|
||||
if (reg == NULL)
|
||||
/* Return "int0_t", since "void" has a misleading size of one. */
|
||||
return builtin_type_int0;
|
||||
|
||||
/* First check for a predefined or target defined type. */
|
||||
if (reg->gdb_type)
|
||||
return reg->gdb_type;
|
||||
|
||||
/* Next try size-sensitive type shortcuts. */
|
||||
if (strcmp (reg->type, "float") == 0)
|
||||
{
|
||||
if (reg->bitsize == gdbarch_float_bit (gdbarch))
|
||||
return builtin_type_float;
|
||||
else if (reg->bitsize == gdbarch_double_bit (gdbarch))
|
||||
return builtin_type_double;
|
||||
else if (reg->bitsize == gdbarch_long_double_bit (gdbarch))
|
||||
return builtin_type_long_double;
|
||||
}
|
||||
else if (strcmp (reg->type, "int") == 0)
|
||||
{
|
||||
if (reg->bitsize == gdbarch_long_bit (gdbarch))
|
||||
return builtin_type_long;
|
||||
else if (reg->bitsize == TARGET_CHAR_BIT)
|
||||
return builtin_type_char;
|
||||
else if (reg->bitsize == gdbarch_short_bit (gdbarch))
|
||||
return builtin_type_short;
|
||||
else if (reg->bitsize == gdbarch_int_bit (gdbarch))
|
||||
return builtin_type_int;
|
||||
else if (reg->bitsize == gdbarch_long_long_bit (gdbarch))
|
||||
return builtin_type_long_long;
|
||||
else if (reg->bitsize == gdbarch_ptr_bit (gdbarch))
|
||||
/* A bit desperate by this point... */
|
||||
return builtin_type_void_data_ptr;
|
||||
}
|
||||
else
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"Register \"%s\" has an unknown type \"%s\"",
|
||||
reg->name, reg->type);
|
||||
|
||||
warning (_("Register \"%s\" has an unsupported size (%d bits)"),
|
||||
reg->name, reg->bitsize);
|
||||
return builtin_type_long;
|
||||
}
|
||||
|
||||
static int
|
||||
tdesc_remote_register_number (struct gdbarch *gdbarch, int regno)
|
||||
{
|
||||
struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
|
||||
|
||||
if (reg != NULL)
|
||||
return reg->target_regnum;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
|
||||
Arbitrary strings (other than "general", "float", and "vector")
|
||||
from the description are not used; they cause the register to be
|
||||
displayed in "info all-registers" but excluded from "info
|
||||
registers" et al. The names of containing features are also not
|
||||
used. This might be extended to display registers in some more
|
||||
useful groupings.
|
||||
|
||||
The save-restore flag is also implemented here. */
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
if (strcmp (reg->group, "general") == 0)
|
||||
general_p = 1;
|
||||
else if (strcmp (reg->group, "float") == 0)
|
||||
float_p = 1;
|
||||
else if (strcmp (reg->group, "vector") == 0)
|
||||
vector_p = 1;
|
||||
|
||||
if (reggroup == float_reggroup)
|
||||
return float_p;
|
||||
|
||||
if (reggroup == vector_reggroup)
|
||||
return vector_p;
|
||||
|
||||
if (reggroup == general_reggroup)
|
||||
return general_p;
|
||||
}
|
||||
|
||||
if (reg != NULL
|
||||
&& (reggroup == save_reggroup || reggroup == restore_reggroup))
|
||||
return reg->save_restore;
|
||||
|
||||
return default_register_reggroup_p (gdbarch, regno, reggroup);
|
||||
}
|
||||
|
||||
/* Record architecture-specific functions to call for pseudo-register
|
||||
support. */
|
||||
|
||||
void
|
||||
set_tdesc_pseudo_register_name (struct gdbarch *gdbarch,
|
||||
gdbarch_register_name_ftype *pseudo_name)
|
||||
{
|
||||
struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
|
||||
|
||||
data->pseudo_register_name = pseudo_name;
|
||||
}
|
||||
|
||||
void
|
||||
set_tdesc_pseudo_register_type (struct gdbarch *gdbarch,
|
||||
gdbarch_register_type_ftype *pseudo_type)
|
||||
{
|
||||
struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
|
||||
|
||||
data->pseudo_register_type = pseudo_type;
|
||||
}
|
||||
|
||||
void
|
||||
set_tdesc_pseudo_register_reggroup_p
|
||||
(struct gdbarch *gdbarch,
|
||||
gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p)
|
||||
{
|
||||
struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
|
||||
|
||||
data->pseudo_register_reggroup_p = pseudo_reggroup_p;
|
||||
}
|
||||
|
||||
/* Update GDBARCH to use the target description for registers. */
|
||||
|
||||
void
|
||||
tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
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
|
||||
included. */
|
||||
gdb_assert (tdesc_has_registers (target_desc));
|
||||
|
||||
data = gdbarch_data (gdbarch, tdesc_data);
|
||||
data->registers = early_data->registers;
|
||||
xfree (early_data);
|
||||
|
||||
/* Build up a set of all registers, so that we can assign register
|
||||
numbers where needed. The hash table expands as necessary, so
|
||||
the initial size is arbitrary. */
|
||||
reg_hash = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
|
||||
for (ixf = 0;
|
||||
VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature);
|
||||
ixf++)
|
||||
for (ixr = 0;
|
||||
VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
|
||||
ixr++)
|
||||
{
|
||||
void **slot = htab_find_slot (reg_hash, reg, INSERT);
|
||||
|
||||
*slot = reg;
|
||||
}
|
||||
|
||||
/* Remove any registers which were assigned numbers by the
|
||||
architecture. */
|
||||
for (ixr = 0; VEC_iterate (tdesc_reg_p, data->registers, ixr, reg); ixr++)
|
||||
if (reg)
|
||||
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.
|
||||
Iterate over the features, not the hash table, so that the order
|
||||
matches that in the target description. */
|
||||
|
||||
gdb_assert (VEC_length (tdesc_reg_p, data->registers) <= num_regs);
|
||||
while (VEC_length (tdesc_reg_p, data->registers) < num_regs)
|
||||
VEC_safe_push (tdesc_reg_p, data->registers, NULL);
|
||||
for (ixf = 0;
|
||||
VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature);
|
||||
ixf++)
|
||||
for (ixr = 0;
|
||||
VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg);
|
||||
ixr++)
|
||||
if (htab_find (reg_hash, reg) != NULL)
|
||||
{
|
||||
VEC_safe_push (tdesc_reg_p, data->registers, reg);
|
||||
num_regs++;
|
||||
}
|
||||
|
||||
htab_delete (reg_hash);
|
||||
|
||||
/* Update the architecture. */
|
||||
set_gdbarch_num_regs (gdbarch, num_regs);
|
||||
set_gdbarch_register_name (gdbarch, tdesc_register_name);
|
||||
set_gdbarch_register_type (gdbarch, tdesc_register_type);
|
||||
set_gdbarch_remote_register_number (gdbarch,
|
||||
tdesc_remote_register_number);
|
||||
set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p);
|
||||
}
|
||||
|
||||
|
||||
/* Methods for constructing a target description. */
|
||||
|
||||
static void
|
||||
tdesc_free_reg (struct tdesc_reg *reg)
|
||||
{
|
||||
xfree (reg->name);
|
||||
xfree (reg->type);
|
||||
xfree (reg->group);
|
||||
xfree (reg);
|
||||
}
|
||||
|
||||
void
|
||||
tdesc_create_reg (struct tdesc_feature *feature, const char *name,
|
||||
int regnum, int save_restore, const char *group,
|
||||
int bitsize, const char *type)
|
||||
{
|
||||
struct tdesc_reg *reg = XZALLOC (struct tdesc_reg);
|
||||
|
||||
reg->name = xstrdup (name);
|
||||
reg->target_regnum = regnum;
|
||||
reg->save_restore = save_restore;
|
||||
reg->group = group ? xstrdup (group) : NULL;
|
||||
reg->bitsize = bitsize;
|
||||
reg->type = type ? xstrdup (type) : NULL;
|
||||
|
||||
/* 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. */
|
||||
reg->gdb_type = tdesc_named_type (feature, reg->type);
|
||||
|
||||
VEC_safe_push (tdesc_reg_p, feature->registers, reg);
|
||||
}
|
||||
|
||||
static void
|
||||
tdesc_free_feature (struct tdesc_feature *feature)
|
||||
{
|
||||
struct tdesc_reg *reg;
|
||||
int ix;
|
||||
|
||||
for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++)
|
||||
tdesc_free_reg (reg);
|
||||
VEC_free (tdesc_reg_p, feature->registers);
|
||||
|
||||
/* There is no easy way to free xmalloc-allocated types, nor is
|
||||
there a way to allocate types on an obstack not associated with
|
||||
an objfile. Therefore we never free types. Since we only ever
|
||||
parse an identical XML document once, this memory leak is mostly
|
||||
contained. */
|
||||
VEC_free (type_p, feature->types);
|
||||
|
||||
xfree (feature->name);
|
||||
xfree (feature);
|
||||
}
|
||||
|
||||
struct tdesc_feature *
|
||||
tdesc_create_feature (struct target_desc *tdesc, const char *name)
|
||||
{
|
||||
struct tdesc_feature *new_feature = XZALLOC (struct tdesc_feature);
|
||||
|
||||
new_feature->name = xstrdup (name);
|
||||
|
||||
VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature);
|
||||
return new_feature;
|
||||
}
|
||||
|
||||
void
|
||||
tdesc_record_type (struct tdesc_feature *feature, struct type *type)
|
||||
{
|
||||
/* The type's ID should be used as its TYPE_NAME. */
|
||||
gdb_assert (TYPE_NAME (type) != NULL);
|
||||
|
||||
VEC_safe_push (type_p, feature->types, type);
|
||||
}
|
||||
|
||||
struct target_desc *
|
||||
allocate_target_description (void)
|
||||
{
|
||||
|
@ -199,9 +827,16 @@ static void
|
|||
free_target_description (void *arg)
|
||||
{
|
||||
struct target_desc *target_desc = arg;
|
||||
struct tdesc_feature *feature;
|
||||
struct property *prop;
|
||||
int ix;
|
||||
|
||||
for (ix = 0;
|
||||
VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature);
|
||||
ix++)
|
||||
tdesc_free_feature (feature);
|
||||
VEC_free (tdesc_feature_p, target_desc->features);
|
||||
|
||||
for (ix = 0;
|
||||
VEC_iterate (property_s, target_desc->properties, ix, prop);
|
||||
ix++)
|
||||
|
@ -305,6 +940,8 @@ unset_tdesc_filename_cmd (char *args, int from_tty)
|
|||
void
|
||||
_initialize_target_descriptions (void)
|
||||
{
|
||||
tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init);
|
||||
|
||||
add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\
|
||||
Set target description specific variables."),
|
||||
&tdesc_set_cmdlist, "set tdesc ",
|
||||
|
|
|
@ -24,7 +24,12 @@
|
|||
#ifndef TARGET_DESCRIPTIONS_H
|
||||
#define TARGET_DESCRIPTIONS_H 1
|
||||
|
||||
struct tdesc_feature;
|
||||
struct tdesc_arch_data;
|
||||
struct tdesc_reg;
|
||||
struct target_desc;
|
||||
struct target_ops;
|
||||
struct type;
|
||||
|
||||
/* Fetch the current target's description, and switch the current
|
||||
architecture to one which incorporates that description. */
|
||||
|
@ -42,6 +47,65 @@ void target_clear_description (void);
|
|||
|
||||
const struct target_desc *target_current_description (void);
|
||||
|
||||
/* Record architecture-specific functions to call for pseudo-register
|
||||
support. If tdesc_use_registers is called and NUM_PSEUDO_REGS
|
||||
is greater than zero, then these should be called as well.
|
||||
They are equivalent to the gdbarch methods with similar names,
|
||||
except that they will only be called for pseudo registers. */
|
||||
|
||||
void set_tdesc_pseudo_register_name
|
||||
(struct gdbarch *gdbarch, gdbarch_register_name_ftype *pseudo_name);
|
||||
|
||||
void set_tdesc_pseudo_register_type
|
||||
(struct gdbarch *gdbarch, gdbarch_register_type_ftype *pseudo_type);
|
||||
|
||||
void set_tdesc_pseudo_register_reggroup_p
|
||||
(struct gdbarch *gdbarch,
|
||||
gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p);
|
||||
|
||||
/* Update GDBARCH to use the target description for registers. Fixed
|
||||
register assignments are taken from EARLY_DATA, which is freed.
|
||||
All registers which have not been assigned fixed numbers are given
|
||||
numbers above the current value of NUM_REGS. NUM_REGS and various
|
||||
register-related predicates are updated to refer to the target
|
||||
description. This function should only be called from the
|
||||
architecture's gdbarch initialization routine, and only after
|
||||
successfully validating the required registers. */
|
||||
|
||||
void tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
struct tdesc_arch_data *early_data);
|
||||
|
||||
/* Allocate initial data for validation of a target description during
|
||||
gdbarch initialization. */
|
||||
|
||||
struct tdesc_arch_data *tdesc_data_alloc (void);
|
||||
|
||||
/* Clean up data allocated by tdesc_data_alloc. This should only
|
||||
be called to discard the data; tdesc_use_registers takes ownership
|
||||
of its EARLY_DATA argument. */
|
||||
|
||||
void tdesc_data_cleanup (void *data_untyped);
|
||||
|
||||
/* Search FEATURE for a register named NAME. Record REGNO and the
|
||||
register in DATA; when tdesc_use_registers is called, REGNO will be
|
||||
assigned to the register. 1 is returned if the register was found,
|
||||
0 if it was not. */
|
||||
|
||||
int tdesc_numbered_register (const struct tdesc_feature *feature,
|
||||
struct tdesc_arch_data *data,
|
||||
int regno, const char *name);
|
||||
|
||||
/* Search FEATURE for a register with any of the names from NAMES
|
||||
(NULL-terminated). Record REGNO and the register in DATA; when
|
||||
tdesc_use_registers is called, REGNO will be assigned to the
|
||||
register. 1 is returned if the register was found, 0 if it was
|
||||
not. */
|
||||
|
||||
int tdesc_numbered_register_choices (const struct tdesc_feature *feature,
|
||||
struct tdesc_arch_data *data,
|
||||
int regno, const char *const names[]);
|
||||
|
||||
|
||||
/* Accessors for target descriptions. */
|
||||
|
||||
/* Return the BFD architecture associated with this target
|
||||
|
@ -56,14 +120,41 @@ const struct bfd_arch_info *tdesc_architecture
|
|||
const char *tdesc_property (const struct target_desc *,
|
||||
const char *key);
|
||||
|
||||
/* Return 1 if this target description describes any registers. */
|
||||
|
||||
int tdesc_has_registers (const struct target_desc *);
|
||||
|
||||
/* Return the feature with the given name, if present, or NULL if
|
||||
the named feature is not found. */
|
||||
|
||||
const struct tdesc_feature *tdesc_find_feature (const struct target_desc *,
|
||||
const char *name);
|
||||
|
||||
/* Return the name of FEATURE. */
|
||||
|
||||
const char *tdesc_feature_name (const struct tdesc_feature *feature);
|
||||
|
||||
/* Return the type associated with ID in the context of FEATURE, or
|
||||
NULL if none. */
|
||||
|
||||
struct type *tdesc_named_type (const struct tdesc_feature *feature,
|
||||
const char *id);
|
||||
|
||||
/* Methods for constructing a target description. */
|
||||
|
||||
struct target_desc *allocate_target_description (void);
|
||||
struct cleanup *make_cleanup_free_target_description (struct target_desc *);
|
||||
void set_tdesc_architecture (struct target_desc *,
|
||||
const struct bfd_arch_info *);
|
||||
|
||||
void set_tdesc_property (struct target_desc *,
|
||||
const char *key, const char *value);
|
||||
|
||||
struct tdesc_feature *tdesc_create_feature (struct target_desc *tdesc,
|
||||
const char *name);
|
||||
void tdesc_record_type (struct tdesc_feature *feature, struct type *type);
|
||||
|
||||
void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
|
||||
int regnum, int save_restore, const char *group,
|
||||
int bitsize, const char *type);
|
||||
|
||||
#endif /* TARGET_DESCRIPTIONS_H */
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2007-02-08 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp,
|
||||
gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files.
|
||||
|
||||
2007-02-08 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* gdb.mi/mi-var-block.exp, gdb.mi/mi2-var-block.exp
|
||||
|
|
3
gdb/testsuite/gdb.xml/core-only.xml
Normal file
3
gdb/testsuite/gdb.xml/core-only.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<target>
|
||||
<xi:include href="core-regs.xml"/>
|
||||
</target>
|
16
gdb/testsuite/gdb.xml/extra-regs.xml
Normal file
16
gdb/testsuite/gdb.xml/extra-regs.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<target>
|
||||
<xi:include href="core-regs.xml"/>
|
||||
<feature name="extra">
|
||||
<vector id="v4int8" type="int8" count="4"/>
|
||||
<vector id="v2int16" type="int16" count="2"/>
|
||||
<union id="vecint">
|
||||
<field name="v4" type="v4int8"/>
|
||||
<field name="v2" type="v2int16"/>
|
||||
</union>
|
||||
|
||||
<reg name="extrareg" bitsize="32"/>
|
||||
<reg name="uintreg" bitsize="32" type="uint32"/>
|
||||
<reg name="vecreg" bitsize="32" type="v4int8"/>
|
||||
<reg name="unionreg" bitsize="32" type="vecint"/>
|
||||
</feature>
|
||||
</target>
|
5
gdb/testsuite/gdb.xml/single-reg.xml
Normal file
5
gdb/testsuite/gdb.xml/single-reg.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<target>
|
||||
<feature name="single">
|
||||
<reg name="one" bitsize="32"/>
|
||||
</feature>
|
||||
</target>
|
95
gdb/testsuite/gdb.xml/tdesc-regs.exp
Normal file
95
gdb/testsuite/gdb.xml/tdesc-regs.exp
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Copyright 2007 Free Software Foundation, Inc.
|
||||
|
||||
# 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
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
if {[gdb_skip_xml_test]} {
|
||||
unsupported "tdesc-regs.exp"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_start
|
||||
|
||||
# To test adding registers, we need a core set of registers for this
|
||||
# architecture, or the description will be rejected.
|
||||
|
||||
set core-regs ""
|
||||
switch -glob -- [istarget] {
|
||||
"*arm-*-*" {
|
||||
set core-regs arm-core
|
||||
}
|
||||
"xscale-*-*" {
|
||||
set core-regs arm-core
|
||||
}
|
||||
}
|
||||
|
||||
# If no core registers were specified, assume this target does not
|
||||
# support target-defined registers. Verify that we get a warning if
|
||||
# we try to use them. This not only tests the warning, but also
|
||||
# reminds maintainers to add test support when they add the feature.
|
||||
if {[string equal ${core-regs} ""]} {
|
||||
gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \
|
||||
"warning: Target-supplied registers are not supported.*" \
|
||||
"set tdesc file single-reg.xml"
|
||||
unsupported "register tests"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Otherwise, we support both XML and target defined registers.
|
||||
|
||||
# Make sure we reject a description missing standard registers,
|
||||
# like the PC.
|
||||
gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \
|
||||
"warning: Architecture rejected target-supplied description" \
|
||||
"set tdesc file single-reg.xml"
|
||||
|
||||
# Copy the core registers into the objdir if necessary, so that they
|
||||
# will be found by <xi:include>.
|
||||
file delete "core-regs.xml"
|
||||
file copy "$srcdir/../features/${core-regs}.xml" "core-regs.xml"
|
||||
|
||||
# Similarly, we need to copy files under test into the objdir.
|
||||
proc load_description { file errmsg } {
|
||||
global srcdir
|
||||
global subdir
|
||||
global gdb_prompt
|
||||
|
||||
file delete "regs.xml"
|
||||
file copy "$srcdir/$subdir/$file" "regs.xml"
|
||||
|
||||
# Anchor the test output, so that error messages are detected.
|
||||
set cmd "set tdesc filename regs.xml"
|
||||
set msg "set tdesc filename $file"
|
||||
set cmd_regex [string_to_regexp $cmd]
|
||||
gdb_test_multiple $cmd $msg {
|
||||
-re "^$cmd_regex\r\n$errmsg$gdb_prompt $" {
|
||||
pass $msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load_description "extra-regs.xml" ""
|
||||
gdb_test "ptype \$extrareg" "type = (int|long|long long)"
|
||||
gdb_test "ptype \$uintreg" "type = uint32_t"
|
||||
gdb_test "ptype \$vecreg" "type = int8_t \\\[4\\\]"
|
||||
gdb_test "ptype \$unionreg" \
|
||||
"type = union {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
|
||||
gdb_test "ptype \$unionreg.v4" "type = int8_t \\\[4\\\]"
|
||||
|
||||
load_description "core-only.xml" ""
|
||||
# The extra register from the previous description should be gone.
|
||||
gdb_test "ptype \$extrareg" "type = void"
|
||||
|
||||
file delete "core-regs.xml"
|
||||
file delete "regs.xml"
|
|
@ -41,7 +41,8 @@
|
|||
struct user_reg
|
||||
{
|
||||
const char *name;
|
||||
struct value *(*read) (struct frame_info * frame);
|
||||
struct value *(*read) (struct frame_info * frame, const void *baton);
|
||||
const void *baton;
|
||||
struct user_reg *next;
|
||||
};
|
||||
|
||||
|
@ -59,7 +60,8 @@ struct gdb_user_regs
|
|||
|
||||
static void
|
||||
append_user_reg (struct gdb_user_regs *regs, const char *name,
|
||||
user_reg_read_ftype *read, struct user_reg *reg)
|
||||
user_reg_read_ftype *read, const void *baton,
|
||||
struct user_reg *reg)
|
||||
{
|
||||
/* The caller is responsible for allocating memory needed to store
|
||||
the register. By doing this, the function can operate on a
|
||||
|
@ -67,6 +69,7 @@ append_user_reg (struct gdb_user_regs *regs, const char *name,
|
|||
gdb_assert (reg != NULL);
|
||||
reg->name = name;
|
||||
reg->read = read;
|
||||
reg->baton = baton;
|
||||
reg->next = NULL;
|
||||
(*regs->last) = reg;
|
||||
regs->last = &(*regs->last)->next;
|
||||
|
@ -77,9 +80,10 @@ append_user_reg (struct gdb_user_regs *regs, const char *name,
|
|||
static struct gdb_user_regs builtin_user_regs = { NULL, &builtin_user_regs.first };
|
||||
|
||||
void
|
||||
user_reg_add_builtin (const char *name, user_reg_read_ftype *read)
|
||||
user_reg_add_builtin (const char *name, user_reg_read_ftype *read,
|
||||
const void *baton)
|
||||
{
|
||||
append_user_reg (&builtin_user_regs, name, read,
|
||||
append_user_reg (&builtin_user_regs, name, read, baton,
|
||||
XMALLOC (struct user_reg));
|
||||
}
|
||||
|
||||
|
@ -95,14 +99,14 @@ user_regs_init (struct gdbarch *gdbarch)
|
|||
struct gdb_user_regs *regs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct gdb_user_regs);
|
||||
regs->last = ®s->first;
|
||||
for (reg = builtin_user_regs.first; reg != NULL; reg = reg->next)
|
||||
append_user_reg (regs, reg->name, reg->read,
|
||||
append_user_reg (regs, reg->name, reg->read, reg->baton,
|
||||
GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
|
||||
return regs;
|
||||
}
|
||||
|
||||
void
|
||||
user_reg_add (struct gdbarch *gdbarch, const char *name,
|
||||
user_reg_read_ftype *read)
|
||||
user_reg_read_ftype *read, const void *baton)
|
||||
{
|
||||
struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data);
|
||||
if (regs == NULL)
|
||||
|
@ -112,7 +116,7 @@ user_reg_add (struct gdbarch *gdbarch, const char *name,
|
|||
regs = user_regs_init (gdbarch);
|
||||
deprecated_set_gdbarch_data (gdbarch, user_regs_data, regs);
|
||||
}
|
||||
append_user_reg (regs, name, read,
|
||||
append_user_reg (regs, name, read, baton,
|
||||
GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg));
|
||||
}
|
||||
|
||||
|
@ -199,7 +203,7 @@ value_of_user_reg (int regnum, struct frame_info *frame)
|
|||
+ gdbarch_num_pseudo_regs (gdbarch));
|
||||
struct user_reg *reg = usernum_to_user_reg (gdbarch, regnum - maxregs);
|
||||
gdb_assert (reg != NULL);
|
||||
return reg->read (frame);
|
||||
return reg->read (frame, reg->baton);
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_user_regs; /* -Wmissing-prototypes */
|
||||
|
|
|
@ -57,15 +57,16 @@ extern const char *user_reg_map_regnum_to_name (struct gdbarch *gdbarch,
|
|||
bytes as, at the time the register is being added, the type needed
|
||||
to describe the register has not bee initialized. */
|
||||
|
||||
typedef struct value *(user_reg_read_ftype) (struct frame_info *frame);
|
||||
typedef struct value *(user_reg_read_ftype) (struct frame_info *frame,
|
||||
const void *baton);
|
||||
extern struct value *value_of_user_reg (int regnum, struct frame_info *frame);
|
||||
|
||||
/* Add a builtin register (present in all architectures). */
|
||||
extern void user_reg_add_builtin (const char *name,
|
||||
user_reg_read_ftype *read);
|
||||
user_reg_read_ftype *read, const void *baton);
|
||||
|
||||
/* Add a per-architecture frame register. */
|
||||
extern void user_reg_add (struct gdbarch *gdbarch, const char *name,
|
||||
user_reg_read_ftype *read);
|
||||
user_reg_read_ftype *read, const void *baton);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,6 +40,8 @@ static int debug_xml;
|
|||
we just want to avoid running out of stack on loops. */
|
||||
#define MAX_XINCLUDE_DEPTH 30
|
||||
|
||||
/* Simplified XML parser infrastructure. */
|
||||
|
||||
/* A parsing level -- used to keep track of the current element
|
||||
nesting. */
|
||||
struct scope_level
|
||||
|
@ -631,6 +633,14 @@ gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* A handler_data for yes/no boolean values. */
|
||||
|
||||
const struct gdb_xml_enum gdb_xml_enums_boolean[] = {
|
||||
{ "yes", 1 },
|
||||
{ "no", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* Map NAME to VALUE. A struct gdb_xml_enum * should be saved as the
|
||||
value of handler_data when using gdb_xml_parse_attr_enum to parse a
|
||||
fixed list of possible strings. The list is terminated by an entry
|
||||
|
@ -645,7 +655,7 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser,
|
|||
void *ret;
|
||||
|
||||
for (enums = attribute->handler_data; enums->name != NULL; enums++)
|
||||
if (strcmp (enums->name, value) == 0)
|
||||
if (strcasecmp (enums->name, value) == 0)
|
||||
break;
|
||||
|
||||
if (enums->name == NULL)
|
||||
|
|
|
@ -209,6 +209,9 @@ struct gdb_xml_enum
|
|||
ULONGEST value;
|
||||
};
|
||||
|
||||
/* A handler_data for yes/no boolean values. */
|
||||
extern const struct gdb_xml_enum gdb_xml_enums_boolean[];
|
||||
|
||||
extern gdb_xml_attribute_handler gdb_xml_parse_attr_enum;
|
||||
|
||||
/* Parse an integer string into a ULONGEST and return it, or call
|
||||
|
|
237
gdb/xml-tdesc.c
237
gdb/xml-tdesc.c
|
@ -23,6 +23,7 @@
|
|||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "target.h"
|
||||
#include "target-descriptions.h"
|
||||
#include "xml-support.h"
|
||||
|
@ -79,6 +80,16 @@ struct tdesc_parsing_data
|
|||
{
|
||||
/* The target description we are building. */
|
||||
struct target_desc *tdesc;
|
||||
|
||||
/* The target feature we are currently parsing, or last parsed. */
|
||||
struct tdesc_feature *current_feature;
|
||||
|
||||
/* The register number to use for the next register we see, if
|
||||
it does not have its own. This starts at zero. */
|
||||
int next_regnum;
|
||||
|
||||
/* The union we are currently parsing, or last parsed. */
|
||||
struct type *current_union;
|
||||
};
|
||||
|
||||
/* Handle the end of an <architecture> element and its value. */
|
||||
|
@ -98,15 +109,233 @@ tdesc_end_arch (struct gdb_xml_parser *parser,
|
|||
set_tdesc_architecture (data->tdesc, arch);
|
||||
}
|
||||
|
||||
/* Handle the start of a <feature> element. */
|
||||
|
||||
static void
|
||||
tdesc_start_feature (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
|
||||
data->current_feature = tdesc_create_feature (data->tdesc, name);
|
||||
}
|
||||
|
||||
/* Handle the start of a <reg> element. Fill in the optional
|
||||
attributes and attach it to the containing feature. */
|
||||
|
||||
static void
|
||||
tdesc_start_reg (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
|
||||
int ix = 0, length;
|
||||
char *name, *group, *type;
|
||||
int bitsize, regnum, save_restore;
|
||||
|
||||
length = VEC_length (gdb_xml_value_s, attributes);
|
||||
|
||||
name = attrs[ix++].value;
|
||||
bitsize = * (ULONGEST *) attrs[ix++].value;
|
||||
|
||||
if (ix < length && strcmp (attrs[ix].name, "regnum") == 0)
|
||||
regnum = * (ULONGEST *) attrs[ix++].value;
|
||||
else
|
||||
regnum = data->next_regnum;
|
||||
|
||||
if (ix < length && strcmp (attrs[ix].name, "type") == 0)
|
||||
type = attrs[ix++].value;
|
||||
else
|
||||
type = "int";
|
||||
|
||||
if (ix < length && strcmp (attrs[ix].name, "group") == 0)
|
||||
group = attrs[ix++].value;
|
||||
else
|
||||
group = NULL;
|
||||
|
||||
if (ix < length && strcmp (attrs[ix].name, "save-restore") == 0)
|
||||
save_restore = * (ULONGEST *) attrs[ix++].value;
|
||||
else
|
||||
save_restore = 1;
|
||||
|
||||
if (strcmp (type, "int") != 0
|
||||
&& strcmp (type, "float") != 0
|
||||
&& tdesc_named_type (data->current_feature, type) == NULL)
|
||||
gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""),
|
||||
name, type);
|
||||
|
||||
tdesc_create_reg (data->current_feature, name, regnum, save_restore, group,
|
||||
bitsize, type);
|
||||
|
||||
data->next_regnum = regnum + 1;
|
||||
}
|
||||
|
||||
/* Handle the start of a <union> element. Initialize the type and
|
||||
record it with the current feature. */
|
||||
|
||||
static void
|
||||
tdesc_start_union (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
struct type *type;
|
||||
|
||||
type = init_composite_type (NULL, TYPE_CODE_UNION);
|
||||
TYPE_NAME (type) = xstrdup (id);
|
||||
tdesc_record_type (data->current_feature, type);
|
||||
data->current_union = type;
|
||||
}
|
||||
|
||||
/* Handle the end of a <union> element. */
|
||||
|
||||
static void
|
||||
tdesc_end_union (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, const char *body_text)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
int i;
|
||||
|
||||
/* If any of the children of this union are vectors, flag the union
|
||||
as a vector also. This allows e.g. a union of two vector types
|
||||
to show up automatically in "info vector". */
|
||||
for (i = 0; i < TYPE_NFIELDS (data->current_union); i++)
|
||||
if (TYPE_VECTOR (TYPE_FIELD_TYPE (data->current_union, i)))
|
||||
{
|
||||
TYPE_FLAGS (data->current_union) |= TYPE_FLAG_VECTOR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the start of a <field> element. Attach the field to the
|
||||
current union. */
|
||||
|
||||
static void
|
||||
tdesc_start_field (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
|
||||
struct type *type, *field_type;
|
||||
char *field_name, *field_type_id;
|
||||
|
||||
field_name = attrs[0].value;
|
||||
field_type_id = attrs[1].value;
|
||||
|
||||
field_type = tdesc_named_type (data->current_feature, field_type_id);
|
||||
if (field_type == NULL)
|
||||
gdb_xml_error (parser, _("Union field \"%s\" references undefined "
|
||||
"type \"%s\""),
|
||||
field_name, field_type_id);
|
||||
|
||||
append_composite_type_field (data->current_union, xstrdup (field_name),
|
||||
field_type);
|
||||
}
|
||||
|
||||
/* Handle the start of a <vector> element. Initialize the type and
|
||||
record it with the current feature. */
|
||||
|
||||
static void
|
||||
tdesc_start_vector (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct tdesc_parsing_data *data = user_data;
|
||||
struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
|
||||
struct type *type, *field_type, *range_type;
|
||||
char *id, *field_type_id;
|
||||
int count;
|
||||
|
||||
id = attrs[0].value;
|
||||
field_type_id = attrs[1].value;
|
||||
count = * (ULONGEST *) attrs[2].value;
|
||||
|
||||
field_type = tdesc_named_type (data->current_feature, field_type_id);
|
||||
if (field_type == NULL)
|
||||
gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""),
|
||||
id, field_type_id);
|
||||
|
||||
/* A vector is just an array plus a special flag. */
|
||||
range_type = create_range_type (NULL, builtin_type_int, 0, count - 1);
|
||||
type = create_array_type (NULL, field_type, range_type);
|
||||
TYPE_NAME (type) = xstrdup (id);
|
||||
|
||||
TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
|
||||
|
||||
tdesc_record_type (data->current_feature, type);
|
||||
}
|
||||
|
||||
/* The elements and attributes of an XML target description. */
|
||||
|
||||
const struct gdb_xml_element target_children[] = {
|
||||
{ "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
|
||||
NULL, tdesc_end_arch },
|
||||
static const struct gdb_xml_attribute field_attributes[] = {
|
||||
{ "name", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "type", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element union_children[] = {
|
||||
{ "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE,
|
||||
tdesc_start_field, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element tdesc_elements[] = {
|
||||
static const struct gdb_xml_attribute reg_attributes[] = {
|
||||
{ "name", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "regnum", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "type", GDB_XML_AF_OPTIONAL, NULL, NULL },
|
||||
{ "group", GDB_XML_AF_OPTIONAL, NULL, NULL },
|
||||
{ "save-restore", GDB_XML_AF_OPTIONAL,
|
||||
gdb_xml_parse_attr_enum, gdb_xml_enums_boolean },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_attribute union_attributes[] = {
|
||||
{ "id", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_attribute vector_attributes[] = {
|
||||
{ "id", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "type", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_attribute feature_attributes[] = {
|
||||
{ "name", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element feature_children[] = {
|
||||
{ "reg", reg_attributes, NULL,
|
||||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||||
tdesc_start_reg, NULL },
|
||||
{ "union", union_attributes, union_children,
|
||||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||||
tdesc_start_union, tdesc_end_union },
|
||||
{ "vector", vector_attributes, NULL,
|
||||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||||
tdesc_start_vector, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element target_children[] = {
|
||||
{ "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
|
||||
NULL, tdesc_end_arch },
|
||||
{ "feature", feature_attributes, feature_children,
|
||||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||||
tdesc_start_feature, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element tdesc_elements[] = {
|
||||
{ "target", NULL, target_children, GDB_XML_EF_NONE,
|
||||
NULL, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
|
|
Loading…
Reference in a new issue