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.
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
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;
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. */
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. */
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
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. */
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;
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')
/* 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)
{
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
/* 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;
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. */