summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <dan@debian.org>2006-04-02 02:35:32 +0000
committerDaniel Jacobowitz <dan@debian.org>2006-04-02 02:35:32 +0000
commit1984a159542a732023494000e0b8dce3dae0cc73 (patch)
tree478bf67ddf7149759cc7139a3eeda68206cdf458
parent4b0adf2ebdb12f6e04c8cb975f21891709c035f4 (diff)
downloadgdb-1984a159542a732023494000e0b8dce3dae0cc73.tar.gz
Add support for VFP DWARF information and VFP single-precision
pseudo-registers.
-rw-r--r--gdb/Makefile.in2
-rw-r--r--gdb/arm-tdep.c142
-rw-r--r--gdb/arm-tdep.h3
-rw-r--r--gdb/available.c7
-rw-r--r--gdb/available.h4
-rw-r--r--gdb/frame.c10
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;