Tidy dwarf1 cached section contents
[binutils-gdb.git] / gdb / arm-fbsd-tdep.c
index 6e1af9cda30ed0621f96ed705452283c6c117d27..acafc4a8bcd417f9d2e58e5d99bd827fa3793718 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for FreeBSD/arm.
 
-   Copyright (C) 2017-2019 Free Software Foundation, Inc.
+   Copyright (C) 2017-2023 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -27,6 +27,7 @@
 #include "auxv.h"
 #include "fbsd-tdep.h"
 #include "gdbcore.h"
+#include "inferior.h"
 #include "osabi.h"
 #include "solib-svr4.h"
 #include "trad-frame.h"
@@ -51,6 +52,14 @@ static const struct regcache_map_entry arm_fbsd_vfpregmap[] =
     { 0 }
   };
 
+/* Register numbers are relative to tdep->tls_regnum.  */
+
+static const struct regcache_map_entry arm_fbsd_tls_regmap[] =
+  {
+    { 1, 0, 4 },       /* tpidruro  */
+    { 0 }
+  };
+
 /* In a signal frame, sp points to a 'struct sigframe' which is
    defined as:
 
@@ -96,7 +105,7 @@ static const struct regcache_map_entry arm_fbsd_vfpregmap[] =
 
 static void
 arm_fbsd_sigframe_init (const struct tramp_frame *self,
-                       struct frame_info *this_frame,
+                       frame_info_ptr this_frame,
                        struct trad_frame_cache *this_cache,
                        CORE_ADDR func)
 {
@@ -150,7 +159,35 @@ const struct regset arm_fbsd_vfpregset =
     regcache_supply_regset, regcache_collect_regset
   };
 
-/* Implement the "regset_from_core_section" gdbarch method.  */
+static void
+arm_fbsd_supply_tls_regset (const struct regset *regset,
+                           struct regcache *regcache,
+                           int regnum, const void *buf, size_t size)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
+
+  regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size);
+}
+
+static void
+arm_fbsd_collect_tls_regset (const struct regset *regset,
+                            const struct regcache *regcache,
+                            int regnum, void *buf, size_t size)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
+
+  regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size);
+}
+
+const struct regset arm_fbsd_tls_regset =
+  {
+    arm_fbsd_tls_regmap,
+    arm_fbsd_supply_tls_regset, arm_fbsd_collect_tls_regset
+  };
+
+/* Implement the "iterate_over_regset_sections" gdbarch method.  */
 
 static void
 arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
@@ -158,11 +195,15 @@ arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
                                       void *cb_data,
                                       const struct regcache *regcache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
 
   cb (".reg", ARM_FBSD_SIZEOF_GREGSET, ARM_FBSD_SIZEOF_GREGSET,
       &arm_fbsd_gregset, NULL, cb_data);
 
+  if (tdep->tls_regnum > 0)
+    cb (".reg-aarch-tls", ARM_FBSD_SIZEOF_TLSREGSET, ARM_FBSD_SIZEOF_TLSREGSET,
+       &arm_fbsd_tls_regset, NULL, cb_data);
+
   /* While FreeBSD/arm cores do contain a NT_FPREGSET / ".reg2"
      register set, it is not populated with register values by the
      kernel but just contains all zeroes.  */
@@ -171,29 +212,43 @@ arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
        &arm_fbsd_vfpregset, "VFP floating-point", cb_data);
 }
 
-/* Lookup a target description from a target's AT_HWCAP auxiliary
-   vector.  */
+/* See arm-fbsd-tdep.h.  */
 
 const struct target_desc *
-arm_fbsd_read_description_auxv (struct target_ops *target)
+arm_fbsd_read_description_auxv (const gdb::optional<gdb::byte_vector> &auxv,
+                               target_ops *target, gdbarch *gdbarch, bool tls)
 {
   CORE_ADDR arm_hwcap = 0;
 
-  if (target_auxv_search (target, AT_FREEBSD_HWCAP, &arm_hwcap) != 1)
-    return nullptr;
+  if (!auxv.has_value ()
+      || target_auxv_search (*auxv, target, gdbarch, AT_FREEBSD_HWCAP,
+                            &arm_hwcap) != 1)
+    return arm_read_description (ARM_FP_TYPE_NONE, tls);
 
   if (arm_hwcap & HWCAP_VFP)
     {
       if (arm_hwcap & HWCAP_NEON)
        return aarch32_read_description ();
       else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPD32))
-         == (HWCAP_VFPv3 | HWCAP_VFPD32))
-       return arm_read_description (ARM_FP_TYPE_VFPV3);
+              == (HWCAP_VFPv3 | HWCAP_VFPD32))
+       return arm_read_description (ARM_FP_TYPE_VFPV3, tls);
       else
-      return arm_read_description (ARM_FP_TYPE_VFPV2);
+       return arm_read_description (ARM_FP_TYPE_VFPV2, tls);
     }
 
-  return nullptr;
+  return arm_read_description (ARM_FP_TYPE_NONE, tls);
+}
+
+/* See arm-fbsd-tdep.h.  */
+
+const struct target_desc *
+arm_fbsd_read_description_auxv (bool tls)
+{
+  gdb::optional<gdb::byte_vector> auxv = target_read_auxv ();
+  return arm_fbsd_read_description_auxv (auxv,
+                                        current_inferior ()->top_target (),
+                                        current_inferior ()->gdbarch,
+                                        tls);
 }
 
 /* Implement the "core_read_description" gdbarch method.  */
@@ -203,7 +258,34 @@ arm_fbsd_core_read_description (struct gdbarch *gdbarch,
                                struct target_ops *target,
                                bfd *abfd)
 {
-  return arm_fbsd_read_description_auxv (target);
+  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
+
+  gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
+  return arm_fbsd_read_description_auxv (auxv, target, gdbarch, tls != nullptr);
+}
+
+/* Implement the get_thread_local_address gdbarch method.  */
+
+static CORE_ADDR
+arm_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
+                                  CORE_ADDR lm_addr, CORE_ADDR offset)
+{
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
+  struct regcache *regcache;
+
+  regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
+                                      ptid, gdbarch);
+
+  target_fetch_registers (regcache, tdep->tls_regnum);
+
+  ULONGEST tpidruro;
+  if (regcache->cooked_read (tdep->tls_regnum, &tpidruro) != REG_VALID)
+    error (_("Unable to fetch %%tpidruro"));
+
+  /* %tpidruro points to the TCB whose first member is the dtv
+      pointer.  */
+  CORE_ADDR dtv_addr = tpidruro;
+  return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
 }
 
 /* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
@@ -211,7 +293,7 @@ arm_fbsd_core_read_description (struct gdbarch *gdbarch,
 static void
 arm_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
 
   /* Generic FreeBSD support.  */
   fbsd_init_abi (info, gdbarch);
@@ -231,12 +313,21 @@ arm_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
     (gdbarch, arm_fbsd_iterate_over_regset_sections);
   set_gdbarch_core_read_description (gdbarch, arm_fbsd_core_read_description);
 
+  if (tdep->tls_regnum > 0)
+    {
+      set_gdbarch_fetch_tls_load_module_address (gdbarch,
+                                                svr4_fetch_objfile_link_map);
+      set_gdbarch_get_thread_local_address (gdbarch,
+                                           arm_fbsd_get_thread_local_address);
+    }
+
   /* Single stepping.  */
   set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
 }
 
+void _initialize_arm_fbsd_tdep ();
 void
-_initialize_arm_fbsd_tdep (void)
+_initialize_arm_fbsd_tdep ()
 {
   gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD,
                          arm_fbsd_init_abi);