]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Support linkmap offsets for the AAPCS64-CAP ABI
authorLuis Machado <luis.machado@linaro.org>
Fri, 20 Aug 2021 11:19:04 +0000 (08:19 -0300)
committerLuis Machado <luis.machado@linaro.org>
Thu, 2 Sep 2021 18:56:22 +0000 (15:56 -0300)
With the AAPCS64-CAP ABI, any pointers in data structures become capabilities.
Capabilities for Morello are 128-bit in size, so the offsets of individual
fields within the structure might change.

One such structure that needs to be adjusted is the linkmap. The linkmap is
used by GDB to list shared libraries that get loaded/unloaded.

This patch enables AAPCS64-CAP linkmap offsets for both GDB and GDBserver,
allowing GDB/GDBserver to list the shared libraries correctly.

gdb/aarch64-linux-tdep.c
gdb/solib-svr4.c
gdb/solib-svr4.h
gdbserver/linux-aarch64-low.cc
gdbserver/linux-low.cc
gdbserver/linux-low.h

index ccb2d3cd173102139e87f211c71edc3e189ab7b4..d04fe8961edb12cec7960078086e22cd0bd2b876 100644 (file)
@@ -2066,6 +2066,11 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   if (tdep->has_capability ())
     {
+      /* Register CHERI-specific linkmap offsets for the AAPCS64_CAP ABI.  */
+      if (tdep->abi == AARCH64_ABI_AAPCS64_CAP)
+       set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                       svr4_lp64_cheri_fetch_link_map_offsets);
+
       /* Initialize the register numbers for the core file register set.
         Please note the PCC/CSP position in GDB's target description is
         the inverse of the position in the Linux Kernel's user_morello_state
index a780f8d34678e5e59ed77d9702062e572626b3e8..58cb2e2f15a86055c5ab9c3cc0d7ed3b9171f7e3 100644 (file)
@@ -3205,6 +3205,58 @@ svr4_lp64_fetch_link_map_offsets (void)
 
   return lmp;
 }
+
+/* Build an appropriate `struct link_map_offsets'
+   for a LP64 CHERI SVR4 system.
+
+   The structure, offsets and sizes for CHERI are the following:
+
+   struct link_map {          size 80
+     ElfW(Addr) l_addr;       offset 0 - size 8
+     char* l_name;            offset 16 - size 16
+     ElfW(Dyn)* l_ld;         offset 32 - size 16
+     struct link_map* l_next; offset 48 - size 16
+     struct link_map* l_prev; offset 64 - size 16
+   };
+
+   struct r_debug {          size 64
+     int32_t r_version;      offset 0 - size 4
+     struct link_map* r_map; offset 16 - size 16
+     ElfW(Addr) r_brk;       offset 32 - size 8
+     enum {                  offset 40 - size 4
+       RT_CONSISTENT,
+       RT_ADD,
+       RT_DELETE
+     } r_state;
+     ElfW(Addr) r_ldbase;    offset 48 - size 8
+   };  */
+
+struct link_map_offsets *
+svr4_lp64_cheri_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    {
+      lmp = &lmo;
+
+      lmo.r_version_offset = 0;
+      lmo.r_version_size = 4;
+      lmo.r_map_offset = 16;
+      lmo.r_brk_offset = 32;
+      lmo.r_ldsomap_offset = 48;
+
+      lmo.link_map_size = 80;
+      lmo.l_addr_offset = 0;
+      lmo.l_name_offset = 16;
+      lmo.l_ld_offset = 32;
+      lmo.l_next_offset = 48;
+      lmo.l_prev_offset = 64;
+    }
+
+  return lmp;
+}
 \f
 
 struct target_so_ops svr4_so_ops;
index 30dd6bc0b368d1643f8f78fa2e5bd4c3db998f14..e2dab3937616177e323f58b60e52f54134181e66 100644 (file)
@@ -102,6 +102,7 @@ extern CORE_ADDR svr4_fetch_objfile_link_map (struct objfile *objfile);
    for ILP32 and LP64 SVR4 systems.  */
 extern struct link_map_offsets *svr4_ilp32_fetch_link_map_offsets (void);
 extern struct link_map_offsets *svr4_lp64_fetch_link_map_offsets (void);
+extern struct link_map_offsets *svr4_lp64_cheri_fetch_link_map_offsets (void);
 
 /* Return 1 if PC lies in the dynamic symbol resolution code of the
    SVR4 run time loader.  */
index ce3fee522ce5f745809458a0081915dc4953e8a0..94f2fdaca0362a2fe4fb2aec0749b89a56f1da3b 100644 (file)
@@ -137,6 +137,8 @@ protected:
   bool low_supports_catch_syscall () override;
 
   void low_get_syscall_trapinfo (regcache *regcache, int *sysno) override;
+
+  const struct link_map_offsets *low_fetch_linkmap_offsets (int is_elf64) override;
 };
 
 /* The singleton target ops object.  */
@@ -875,6 +877,33 @@ aarch64_target::low_get_syscall_trapinfo (regcache *regcache, int *sysno)
     collect_register_by_name (regcache, "r7", sysno);
 }
 
+static const struct link_map_offsets lmo_64bit_morello_offsets =
+{
+  0,     /* r_version offset. */
+  16,     /* r_debug.r_map offset.  */
+  0,     /* l_addr offset in link_map.  */
+  16,     /* l_name offset in link_map.  */
+  32,    /* l_ld offset in link_map.  */
+  48,    /* l_next offset in link_map.  */
+  64     /* l_prev offset in link_map.  */
+};
+
+const struct link_map_offsets *
+aarch64_target::low_fetch_linkmap_offsets (int is_elf64)
+{
+  if (is_elf64)
+    {
+      CORE_ADDR entry_addr = linux_get_at_entry (8);
+
+      /* If the LSB of AT_ENTRY is 1, then we have a pure capability Morello
+        ELF.  */
+      if (entry_addr & 1)
+       return &lmo_64bit_morello_offsets;
+    }
+
+  return linux_process_target::low_fetch_linkmap_offsets (is_elf64);
+}
+
 /* List of condition codes that we need.  */
 
 enum aarch64_condition_codes
index 06ce2f090ab618397d20255815c45eee37ad0462..24509f173634bb01dbf86d76317d4bc64319d6a4 100644 (file)
@@ -6709,29 +6709,35 @@ linux_process_target::supports_qxfer_libraries_svr4 ()
   return true;
 }
 
-struct link_map_offsets
-  {
-    /* Offset and size of r_debug.r_version.  */
-    int r_version_offset;
-
-    /* Offset and size of r_debug.r_map.  */
-    int r_map_offset;
-
-    /* Offset to l_addr field in struct link_map.  */
-    int l_addr_offset;
+/* Generic Linux 32-bit/64-bit linkmap offsets.  */
 
-    /* Offset to l_name field in struct link_map.  */
-    int l_name_offset;
-
-    /* Offset to l_ld field in struct link_map.  */
-    int l_ld_offset;
+static const struct link_map_offsets lmo_32bit_offsets =
+{
+  0,     /* r_version offset. */
+  4,     /* r_debug.r_map offset.  */
+  0,     /* l_addr offset in link_map.  */
+  4,     /* l_name offset in link_map.  */
+  8,     /* l_ld offset in link_map.  */
+  12,    /* l_next offset in link_map.  */
+  16     /* l_prev offset in link_map.  */
+};
 
-    /* Offset to l_next field in struct link_map.  */
-    int l_next_offset;
+static const struct link_map_offsets lmo_64bit_offsets =
+{
+  0,     /* r_version offset. */
+  8,     /* r_debug.r_map offset.  */
+  0,     /* l_addr offset in link_map.  */
+  8,     /* l_name offset in link_map.  */
+  16,    /* l_ld offset in link_map.  */
+  24,    /* l_next offset in link_map.  */
+  32     /* l_prev offset in link_map.  */
+};
 
-    /* Offset to l_prev field in struct link_map.  */
-    int l_prev_offset;
-  };
+const struct link_map_offsets *
+linux_process_target::low_fetch_linkmap_offsets (int is_elf64)
+{
+  return is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+}
 
 /* Construct qXfer:libraries-svr4:read reply.  */
 
@@ -6745,27 +6751,6 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
   char filename[PATH_MAX];
   int pid, is_elf64;
 
-  static const struct link_map_offsets lmo_32bit_offsets =
-    {
-      0,     /* r_version offset. */
-      4,     /* r_debug.r_map offset.  */
-      0,     /* l_addr offset in link_map.  */
-      4,     /* l_name offset in link_map.  */
-      8,     /* l_ld offset in link_map.  */
-      12,    /* l_next offset in link_map.  */
-      16     /* l_prev offset in link_map.  */
-    };
-
-  static const struct link_map_offsets lmo_64bit_offsets =
-    {
-      0,     /* r_version offset. */
-      8,     /* r_debug.r_map offset.  */
-      0,     /* l_addr offset in link_map.  */
-      8,     /* l_name offset in link_map.  */
-      16,    /* l_ld offset in link_map.  */
-      24,    /* l_next offset in link_map.  */
-      32     /* l_prev offset in link_map.  */
-    };
   const struct link_map_offsets *lmo;
   unsigned int machine;
   int ptr_size;
@@ -6781,7 +6766,7 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
   pid = lwpid_of (current_thread);
   xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
   is_elf64 = elf_64_file_p (filename, &machine);
-  lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+  lmo = low_fetch_linkmap_offsets (is_elf64);
   ptr_size = is_elf64 ? 8 : 4;
 
   while (annex[0] != '\0')
@@ -7202,6 +7187,16 @@ linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
 
 /* See linux-low.h.  */
 
+CORE_ADDR
+linux_get_at_entry (int wordsize)
+{
+  CORE_ADDR entry = 0;
+  linux_get_auxv (wordsize, AT_ENTRY, &entry);
+  return entry;
+}
+
+/* See linux-low.h.  */
+
 CORE_ADDR
 linux_get_hwcap (int wordsize)
 {
index 56c353319c2cf6b9f9f226ccc3fd08596c4957d0..bd6f402afbf5b8cc22f13a289aeed0ec3b8e99d1 100644 (file)
@@ -131,6 +131,30 @@ struct process_info_private
 
 struct lwp_info;
 
+struct link_map_offsets
+{
+  /* Offset and size of r_debug.r_version.  */
+  int r_version_offset;
+
+  /* Offset and size of r_debug.r_map.  */
+  int r_map_offset;
+
+  /* Offset to l_addr field in struct link_map.  */
+  int l_addr_offset;
+
+  /* Offset to l_name field in struct link_map.  */
+  int l_name_offset;
+
+  /* Offset to l_ld field in struct link_map.  */
+  int l_ld_offset;
+
+  /* Offset to l_next field in struct link_map.  */
+  int l_next_offset;
+
+  /* Offset to l_prev field in struct link_map.  */
+  int l_prev_offset;
+};
+
 /* Target ops definitions for a Linux target.  */
 
 class linux_process_target : public process_stratum_target
@@ -690,6 +714,10 @@ protected:
 
   /* How many bytes the PC should be decremented after a break.  */
   virtual int low_decr_pc_after_break ();
+
+  /* Return the linkmap offsets based on IS_ELF64.  */
+  virtual const struct link_map_offsets *low_fetch_linkmap_offsets (int is_elf64);
+
 };
 
 extern linux_process_target *the_linux_target;
@@ -884,6 +912,11 @@ extern int have_ptrace_getregset;
 int linux_get_auxv (int wordsize, CORE_ADDR match,
                    CORE_ADDR *valp);
 
+/* Fetch the AT_ENTRY entry from the auxv vector, where entries are length
+   WORDSIZE.  If no entry was found, return zero.  */
+
+CORE_ADDR linux_get_at_entry (int wordsize);
+
 /* Fetch the AT_HWCAP entry from the auxv vector, where entries are length
    WORDSIZE.  If no entry was found, return zero.  */