diff options
author | Daniel Jacobowitz <dan@debian.org> | 2006-04-02 02:35:32 +0000 |
---|---|---|
committer | Daniel Jacobowitz <dan@debian.org> | 2006-04-02 02:35:32 +0000 |
commit | 1984a159542a732023494000e0b8dce3dae0cc73 (patch) | |
tree | 478bf67ddf7149759cc7139a3eeda68206cdf458 | |
parent | 4b0adf2ebdb12f6e04c8cb975f21891709c035f4 (diff) | |
download | gdb-1984a159542a732023494000e0b8dce3dae0cc73.tar.gz |
Add support for VFP DWARF information and VFP single-precision
pseudo-registers.
-rw-r--r-- | gdb/Makefile.in | 2 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 142 | ||||
-rw-r--r-- | gdb/arm-tdep.h | 3 | ||||
-rw-r--r-- | gdb/available.c | 7 | ||||
-rw-r--r-- | gdb/available.h | 4 | ||||
-rw-r--r-- | gdb/frame.c | 10 |
6 files changed, 162 insertions, 6 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 27debb668c1..93d0856a68e 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1806,7 +1806,7 @@ 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) $(available_h) + $(dwarf2_frame_h) $(available_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) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index cf8bbff3e4a..b34200c1a0d 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -41,6 +41,7 @@ #include "objfiles.h" #include "dwarf2-frame.h" #include "available.h" +#include "user-regs.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" @@ -1352,6 +1353,10 @@ arm_register_type (struct gdbarch *gdbarch, int regnum) if (avail_type) return avail_type; + if (gdbarch_tdep (current_gdbarch)->have_vfp_pseudos + && regnum >= NUM_REGS && regnum < NUM_REGS + 32) + return builtin_type_float; + if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) { if (!gdbarch_tdep (gdbarch)->have_fpa_registers) @@ -1366,6 +1371,56 @@ arm_register_type (struct gdbarch *gdbarch, int regnum) return builtin_type_int32; } +/* Map DWARF register numbers onto internal GDB register numbers. */ +static int +arm_dwarf_reg_to_regnum (int reg) +{ + /* Core integer regs. */ + if (reg >= 0 && reg <= 15) + return reg; + + /* Legacy FPA encoding. These were once used in a way which + overlapped with VFP register numbering, so their use is + discouraged, but GDB doesn't support the ARM toolchain + which did that. */ + if (reg >= 16 && reg <= 23) + return ARM_F0_REGNUM + reg - 16; + + /* New assignments for the FPA registers. */ + if (reg >= 96 && reg <= 103) + return ARM_F0_REGNUM + reg - 96; + + /* VFP v2 registers. A double precision value is actually + in d1 rather than s2, but the ABI only defines numbering + for the single precision registers. This will "just work" + in GDB for little endian targets (we'll read eight bytes, + starting in s0 and then progressing to s1), but will be + reversed on big endian targets with VFP. This won't + be a problem for the new Neon quad registers; you're supposed + to use DW_OP_piece for those. */ + if (reg >= 64 && reg <= 95) + { + char name_buf[4]; + + sprintf (name_buf, "s%d", reg - 64); + return user_reg_map_name_to_regnum (current_gdbarch, name_buf, + strlen (name_buf)); + } + + /* VFP v3 / Neon registers. This range is also used for VFP v2 + registers, except that it now describes d0 instead of s0. */ + if (reg >= 256 && reg <= 287) + { + char name_buf[4]; + + sprintf (name_buf, "d%d", reg - 256); + return user_reg_map_name_to_regnum (current_gdbarch, name_buf, + strlen (name_buf)); + } + + return -1; +} + /* Map GDB internal REGNUM onto the Arm simulator register numbers. */ static int arm_register_sim_regno (int regnum) @@ -2475,6 +2530,19 @@ arm_register_name (int i) return ""; } + if (gdbarch_tdep (current_gdbarch)->have_vfp_pseudos + && i >= NUM_REGS && i < NUM_REGS + 32) + { + static const char *const vfp_pseudo_names[] = { + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + }; + + return vfp_pseudo_names[i - NUM_REGS]; + } + /* Check for target-supplied register numbers. */ return available_register_name (current_gdbarch, i); } @@ -2565,6 +2633,57 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid) write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid); } } + +static void +arm_pseudo_vfp_read (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, gdb_byte *buf) +{ + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + gdb_assert (regnum >= NUM_REGS && regnum <= NUM_REGS + 32); + regnum -= NUM_REGS; + + /* s0 is always the least significant half of d0. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + offset = (regnum & 1) ? 0 : 4; + else + offset = (regnum & 1) ? 4 : 0; + + sprintf (name_buf, "d%d", regnum >> 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + regcache_raw_read (regcache, double_regnum, reg_buf); + memcpy (buf, reg_buf + offset, 4); +} + +static void +arm_pseudo_vfp_write (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, const gdb_byte *buf) +{ + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + gdb_assert (regnum >= NUM_REGS && regnum <= NUM_REGS + 32); + regnum -= NUM_REGS; + + /* s0 is always the least significant half of d0. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + offset = (regnum & 1) ? 0 : 4; + else + offset = (regnum & 1) ? 4 : 0; + + sprintf (name_buf, "d%d", regnum >> 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + regcache_raw_read (regcache, double_regnum, reg_buf); + memcpy (reg_buf + offset, buf, 4); + regcache_raw_write (regcache, double_regnum, reg_buf); +} static enum gdb_osabi arm_elf_osabi_sniffer (bfd *abfd) @@ -2628,6 +2747,27 @@ arm_check_feature_set (struct gdbarch *gdbarch, } else gdbarch_tdep (gdbarch)->have_fpa_registers = 0; + + /* If we have a VFP unit, check whether the single precision registers + are present. If not, then we will synthesize them as pseudo + registers. */ + + if (available_find_named_feature (feature_set, "org.gnu.gdb.arm.vfp")) + { + if (available_find_named_register (feature_set, "d0", -1) + && !available_find_named_register (feature_set, "s0", -1)) + { + /* NOTE: This is the only set of pseudo registers used by + the ARM target at the moment. If more are added, a + little more care in numbering will be needed. */ + + set_gdbarch_num_pseudo_regs (gdbarch, 32); + set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_vfp_read); + set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_vfp_write); + gdbarch_tdep (gdbarch)->have_vfp_pseudos = 1; + } + gdbarch_tdep (gdbarch)->have_vfp_registers = 1; + } } @@ -2843,6 +2983,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_print_float_info (gdbarch, arm_print_float_info); /* Internal <-> external register number maps. */ + set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum); set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno); /* Integer registers are 4 bytes. */ diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index f02eeb1eeed..33e9b6cfec7 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -132,6 +132,9 @@ struct gdbarch_tdep enum arm_float_model fp_model; /* Floating point calling conventions. */ int have_fpa_registers; /* Does the target report the FPA registers? */ + int have_vfp_registers; /* Does the target report the VFP registers? */ + int have_vfp_pseudos; /* Are we synthesizing the single precision + VFP registers? */ CORE_ADDR lowest_pc; /* Lowest address at which instructions will appear. */ diff --git a/gdb/available.c b/gdb/available.c index 488984ca04f..d6ccbc18f4e 100644 --- a/gdb/available.c +++ b/gdb/available.c @@ -546,9 +546,10 @@ find_register (const struct gdb_feature_set *features, int regnum) return NULL; } -/* Search FEATURES for a register with target-specified name NAME, - and set its GDB register number to REGNUM. Return 1 if the - register was found, and 0 if it was not. This function should +/* Search FEATURES for a register with target-specified name NAME, and + set its GDB register number to REGNUM. Pass REGNUM == -1 if you do + not need to fix a register number for this register. Return 1 if + the register was found, and 0 if it was not. This function should only be used while initializing a gdbarch. */ int diff --git a/gdb/available.h b/gdb/available.h index ad756b5af4f..0008e5a24a2 100644 --- a/gdb/available.h +++ b/gdb/available.h @@ -145,8 +145,8 @@ int features_same_p (const struct gdb_feature_set *, void record_available_features (struct gdbarch *, struct gdb_feature_set *); -/* Find a register with the given name, and set its internal register - number. */ +/* Find a register with the given name, and optionally set its + internal register number. */ int available_find_named_register (struct gdb_feature_set *, const char *, int); diff --git a/gdb/frame.c b/gdb/frame.c index 64e1baff1eb..80814fbf35e 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -395,16 +395,26 @@ frame_find_by_id (struct frame_id id) { struct frame_info *frame; +#if 0 /* ZERO denotes the null frame, let the caller decide what to do about it. Should it instead return get_current_frame()? */ if (!frame_id_p (id)) return NULL; +#endif for (frame = get_current_frame (); frame != NULL; frame = get_prev_frame (frame)) { struct frame_id this = get_frame_id (frame); +#if 1 + /* We use an invalid frame id to mean "could not unwind from + here"! This hack fixes the "value being assigned to is + no longer active" problem. This strongly suggests that + we need to change the representation. */ + if (!frame_id_p (id) && !frame_id_p (this)) + return frame; +#endif if (frame_id_eq (id, this)) /* An exact match. */ return frame; |