]> 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)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:59:24 +0000 (15:59 -0700)
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 07ea274f6bfedc7f374d7cc04f446ad797189a4d..d425b299560d71294fd503a9a8861b49f9c6e15c 100644 (file)
@@ -2471,6 +2471,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 f0f02cb37e19efe8f32650538a0a9134845a0cc4..a4fcb121486fb406ea1b1104099c46892ab2e6f5 100644 (file)
@@ -3125,6 +3125,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 8b4968509f2a56123bb86c5776763375cd998e07..aaf49ed66e51bc892e7a4883995066cc6996fffd 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 0213fce70228b8e23bde7dfef57a84b798e7d3a7..b8929ef4bab1a5bac53aec5b510e3562e656ac4d 100644 (file)
@@ -151,6 +151,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.  */
@@ -990,6 +992,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 7726a4a0c36c6bafea32fc929b954ed83fd80289..2ab3a8794c12259ed41924e68c8254b91e63fcb6 100644 (file)
@@ -6477,29 +6477,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.  */
 
@@ -6513,27 +6519,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;
@@ -6549,7 +6534,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')
@@ -6990,6 +6975,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 27cc9641f124a871c3290fd0426230fa706cd2e1..9edf446865039c87f7eee50813e27093fdb28174 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
@@ -693,6 +717,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;
@@ -941,6 +969,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.  */