openbsd-ports/devel/gdb/patches/patch-gdb_aarch64obsd-tdep_c
kurt 5ad62a9825 Improve devel/gdb aarch64 support:
* Enable debugging on running threaded programs
* Provide sigtramp routine unwinding (support modeled after ppc)
okay pascal@ kettenis@
2019-10-17 17:10:26 +00:00

305 lines
9.4 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

$OpenBSD: patch-gdb_aarch64obsd-tdep_c,v 1.2 2019/10/17 17:10:26 kurt Exp $
Index: gdb/aarch64obsd-tdep.c
--- gdb/aarch64obsd-tdep.c.orig
+++ gdb/aarch64obsd-tdep.c
@@ -0,0 +1,299 @@
+/* Target-dependent code for OpenBSD/aarch64.
+
+ Copyright (C) 2006-2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "frame-unwind.h"
+#include "osabi.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+
+#include "aarch64-tdep.h"
+#include "obsd-tdep.h"
+#include "solib-svr4.h"
+
+/* Signal trampolines. */
+
+/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
+ in virtual memory. The randomness makes it somewhat tricky to
+ detect it, but fortunately we can rely on the fact that the start
+ of the sigtramp routine is page-aligned. We recognize the
+ trampoline by looking for the code that invokes the sigreturn
+ system call. The offset where we can find that code varies from
+ release to release.
+
+ By the way, the mapping mentioned above is read-only, so you cannot
+ place a breakpoint in the signal trampoline. */
+
+/* Default page size. */
+static const CORE_ADDR aarch64obsd_page_size = 4096;
+
+/* Offset for sigreturn(2). */
+static const int aarch64obsd_sigreturn_offset[] = {
+ 0xb4, /* OpenBSD 6.2 */
+ 0x08, /* OpenBSD 6.1 */
+ -1
+};
+
+static int
+aarch64obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR pc = get_frame_pc (this_frame);
+ CORE_ADDR start_pc = (pc & ~(aarch64obsd_page_size - 1));
+ const int *offset;
+ const char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (name)
+ return 0;
+
+ for (offset = aarch64obsd_sigreturn_offset; *offset != -1; offset++)
+ {
+ gdb_byte buf[8];
+ unsigned long insn;
+
+ if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
+ buf, sizeof buf))
+ continue;
+
+ /* Check for "mov x8, #SYS_sigreturn". */
+ insn = extract_unsigned_integer (buf, 4, byte_order);
+ if (insn != 0xd2800ce8)
+ continue;
+
+ /* Check for "svc 0". */
+ insn = extract_unsigned_integer (buf + 4, 4, byte_order);
+ if (insn != 0xd4000001)
+ continue;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ In 6.1 the sp points to the struct sigframe. Since 6.2 the
+ sigtramp routine saves floating point registers on the stack
+ before the struct sigframe so that needs to be skipped to look
+ at sigframe. A sigframe looks like this:
+
+ struct sigframe {
+ int sf_signum;
+ struct sigcontext sf_sc;
+ siginfo_t sf_si;
+ };
+
+ struct sigcontext {
+ int __sc_unused;
+ int sc_mask;
+
+ unsigned long sc_sp;
+ unsigned long sc_lr;
+ unsigned long sc_elr;
+ unsigned long sc_spsr;
+ unsigned long sc_x[30];
+
+ long sc_cookie;
+ };
+
+*/
+
+#define AARCH64_SIGCONTEXT_REG_SIZE 8
+#define AARCH64_SIGFRAME_SIGCONTEXT_OFFSET 8
+#define AARCH64_SIGCONTEXT_SP_OFFSET 8
+#define AARCH64_SIGCONTEXT_LR_OFFSET 16
+#define AARCH64_SIGCONTEXT_PC_OFFSET 24
+#define AARCH64_SIGCONTEXT_SPSR_OFFSET 32
+#define AARCH64_SIGCONTEXT_X0_OFFSET 40
+
+static struct trad_frame_cache *
+aarch64obsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct trad_frame_cache *cache;
+ CORE_ADDR sp, sigcontext_addr, x0_addr, func;
+ gdb_byte buf[4];
+ unsigned long insn, sigframe_offset = 0;
+ int i;
+
+ if (*this_cache)
+ return (struct trad_frame_cache *) *this_cache;
+
+ cache = trad_frame_cache_zalloc (this_frame);
+ *this_cache = cache;
+
+ func = get_frame_pc (this_frame);
+ func &= ~(aarch64obsd_page_size - 1);
+ if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
+ return cache;
+
+ /* Calculate the offset where we can find `struct sigframe'. In 6.1
+ no adjustment is needed so we look at the first instruction to see
+ if it matches 6.2+. If it is a 'sub sp, sp, #0xNNN' instruction,
+ use the amount of stack space to skip from it. */
+ insn = extract_unsigned_integer (buf, 4, byte_order);
+ if ((insn & 0xffc003ff) == 0xd10003ff)
+ sigframe_offset += ((insn & 0x003ffc00) >> 10);
+
+ sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
+ sigcontext_addr = sp + sigframe_offset + AARCH64_SIGFRAME_SIGCONTEXT_OFFSET;
+ x0_addr = sigcontext_addr + AARCH64_SIGCONTEXT_X0_OFFSET;
+
+ trad_frame_set_reg_addr (cache, AARCH64_SP_REGNUM,
+ sigcontext_addr + AARCH64_SIGCONTEXT_SP_OFFSET);
+ trad_frame_set_reg_addr (cache, AARCH64_LR_REGNUM,
+ sigcontext_addr + AARCH64_SIGCONTEXT_LR_OFFSET);
+ trad_frame_set_reg_addr (cache, AARCH64_PC_REGNUM,
+ sigcontext_addr + AARCH64_SIGCONTEXT_PC_OFFSET);
+ trad_frame_set_reg_addr (cache, AARCH64_CPSR_REGNUM,
+ sigcontext_addr + AARCH64_SIGCONTEXT_SPSR_OFFSET);
+ for (i = 0; i < 30; i++)
+ {
+ trad_frame_set_reg_addr (cache, AARCH64_X0_REGNUM + i,
+ x0_addr + i * AARCH64_SIGCONTEXT_REG_SIZE);
+ }
+
+ trad_frame_set_id (cache, frame_id_build (sp, func));
+
+ return cache;
+}
+
+static void
+aarch64obsd_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ aarch64obsd_sigtramp_frame_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+aarch64obsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ aarch64obsd_sigtramp_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static const struct frame_unwind aarch64obsd_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ aarch64obsd_sigtramp_frame_this_id,
+ aarch64obsd_sigtramp_frame_prev_register,
+ NULL,
+ aarch64obsd_sigtramp_frame_sniffer
+};
+
+/* The general-purpose regset consists of 31 X registers, plus SP, PC,
+ and SPSR and TPIDR registers. */
+#define AARCH64_OBSD_SIZEOF_GREGSET (35 * X_REGISTER_SIZE)
+
+/* The fp regset consists of 32 V registers, plus FPSR and FPCR which
+ are 4 bytes wide each, and the whole structure is padded to 128 bit
+ alignment. */
+#define AARCH64_OBSD_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE)
+
+/* Register maps. */
+
+static const struct regcache_map_entry aarch64_obsd_gregmap[] =
+ {
+ { 31, AARCH64_X0_REGNUM, 8 }, /* x0 ... x30 */
+ { 1, AARCH64_SP_REGNUM, 8 },
+ { 1, AARCH64_PC_REGNUM, 8 },
+ { 1, AARCH64_CPSR_REGNUM, 8 },
+ { 0 }
+ };
+
+static const struct regcache_map_entry aarch64_obsd_fpregmap[] =
+ {
+ { 32, AARCH64_V0_REGNUM, 16 }, /* v0 ... v31 */
+ { 1, AARCH64_FPSR_REGNUM, 4 },
+ { 1, AARCH64_FPCR_REGNUM, 4 },
+ { 0 }
+ };
+
+/* Register set definitions. */
+
+const struct regset aarch64_obsd_gregset =
+ {
+ aarch64_obsd_gregmap,
+ regcache_supply_regset, regcache_collect_regset
+ };
+
+const struct regset aarch64_obsd_fpregset =
+ {
+ aarch64_obsd_fpregmap,
+ regcache_supply_regset, regcache_collect_regset
+ };
+
+static void
+aarch64_obsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+ cb (".reg", AARCH64_OBSD_SIZEOF_GREGSET, &aarch64_obsd_gregset,
+ NULL, cb_data);
+ cb (".reg2", AARCH64_OBSD_SIZEOF_FPREGSET, &aarch64_obsd_fpregset,
+ NULL, cb_data);
+}
+
+
+static void
+aarch64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ obsd_init_abi (info, gdbarch);
+
+ /* OpenBSD/aarch64 uses SVR4-style shared libraries. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_lp64_fetch_link_map_offsets);
+ set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
+
+ frame_unwind_append_unwinder (gdbarch, &aarch64obsd_sigtramp_frame_unwind);
+
+ /* Enable longjmp. */
+ tdep->jb_pc = 13;
+
+ set_gdbarch_iterate_over_regset_sections
+ (gdbarch, aarch64_obsd_iterate_over_regset_sections);
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_aarch64obsd_tdep;
+
+void
+_initialize_aarch64obsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_OPENBSD_ELF,
+ aarch64obsd_init_abi);
+}