]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add support for VFP DWARF information and VFP single-precision
authorDaniel Jacobowitz <drow@false.org>
Sun, 2 Apr 2006 02:35:32 +0000 (02:35 +0000)
committerDaniel Jacobowitz <drow@false.org>
Sun, 2 Apr 2006 02:35:32 +0000 (02:35 +0000)
pseudo-registers.

gdb/Makefile.in
gdb/arm-tdep.c
gdb/arm-tdep.h
gdb/available.c
gdb/available.h
gdb/frame.c

index 27debb668c1ae82632570f784f72c0a11527c906..93d0856a68e6b3fa5330e8ee2249323ee64a2ef6 100644 (file)
@@ -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)
index cf8bbff3e4aa3cb6eb114c95449d212cd9c6c89e..b34200c1a0d268c1cfb2214ca7e8d0b4e41f43ac 100644 (file)
@@ -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);
+}
 \f
 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;
+    }
 }
 
 \f
@@ -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.  */
index f02eeb1eeed49171c5084d3056623f1393dbe26f..33e9b6cfec7859581c2624df8e1b3a5a719a4b6a 100644 (file)
@@ -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.  */
index 488984ca04f9a06f1f088e0c29d4cdb6bcdfad11..d6ccbc18f4e5f02441357bcc44ab78b4d58cbe92 100644 (file)
@@ -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
index ad756b5af4f9debfaf8a5b6db78a37e2ab9d4db5..0008e5a24a2234b1a4eb7eeba5bc21659260dc45 100644 (file)
@@ -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);
index 64e1baff1eb54e3430fb2c0844c430f90727ba0b..80814fbf35e1499b35b5d24647bc139618898516 100644 (file)
@@ -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;