Improve devel/gdb aarch64 support:
* Enable debugging on running threaded programs
* Provide sigtramp routine unwinding (support modeled after ppc)
okay?
Example of unwinding through signal trap page on running target:
(gdb) bt
#0 handler (sig=11, sip=0x16517e9238, ctx=0x16517e9118) at
pthread_attr_setguardsize_test.c:31
#1 <signal handler called>
#2 0x00000011f87d052c in check_bounds (bottom=0x16515e6000 <error: Cannot
access memory at address 0x16515e6000>,
top=0x16517ea000 <error: Cannot access memory at address 0x16517ea000>) at
pthread_attr_setguardsize_test.c:95
#3 0x00000011f87d05e8 in thread_start (arg=0x0) at
pthread_attr_setguardsize_test.c:111
#4 0x0000001647d772bc in _rthread_start (v=<optimized out>) at
/usr/src/lib/librthread/rthread.c:96
#5 0x000000164bf42afc in __tfork_thread () at
/usr/src/lib/libc/arch/aarch64/sys/tfork_thread.S:39
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Example of thread support on running target.
(gdb) info threads
Id Target Id Frame
1 thread 548780 futex () at -:4
* 2 thread 457261 handler (sig=11, sip=0x16517e9238, ctx=0x16517e9118)
at pthread_attr_setguardsize_test.c:31
(gdb) thread 1
[Switching to thread 1 (thread 548780)]
#0 futex () at -:4
4 -: No such file or directory.
(gdb) bt
#0 futex () at -:4
#1 0x0000001647d745c8 in _twait (p=0x167a2b9008, val=<error reading variable:
Cannot access memory at address 0x0>,
clockid=<error reading variable: Cannot access memory at address 0x0>,
abs=<optimized out>) at /usr/src/lib/librthread/synch.h:41
#2 _sem_wait (sem=<optimized out>, can_eintr=0, abstime=0x0,
delayed_cancel=0x164bfe3cc8 <_initial_thread+200>)
at /usr/src/lib/librthread/rthread_sem.c:77
#3 0x0000001647d76df8 in pthread_join (thread=0x167a2b9000,
retval=0x7ffffd6080) at /usr/src/lib/librthread/rthread.c:304
#4 0x00000011f87d0744 in main () at pthread_attr_setguardsize_test.c:139
Index: Makefile
===================================================================
RCS file: /cvs/ports/devel/gdb/Makefile,v
retrieving revision 1.61
diff -u -p -u -r1.61 Makefile
--- Makefile 16 Jul 2019 21:29:41 -0000 1.61
+++ Makefile 12 Oct 2019 22:49:59 -0000
@@ -4,7 +4,7 @@ COMMENT= GNU debugger
CATEGORIES= devel
DISTNAME= gdb-7.12.1
-REVISION= 7
+REVISION= 8
HOMEPAGE= https://www.gnu.org/software/gdb/
Index: patches/patch-gdb_aarch64obsd-nat_c
===================================================================
RCS file: /cvs/ports/devel/gdb/patches/patch-gdb_aarch64obsd-nat_c,v
retrieving revision 1.1
diff -u -p -u -r1.1 patch-gdb_aarch64obsd-nat_c
--- patches/patch-gdb_aarch64obsd-nat_c 10 Jul 2018 11:03:46 -0000 1.1
+++ patches/patch-gdb_aarch64obsd-nat_c 12 Oct 2019 22:49:59 -0000
@@ -2,7 +2,7 @@ $OpenBSD: patch-gdb_aarch64obsd-nat_c,v
Index: gdb/aarch64obsd-nat.c
--- gdb/aarch64obsd-nat.c.orig
+++ gdb/aarch64obsd-nat.c
-@@ -0,0 +1,205 @@
+@@ -0,0 +1,206 @@
+/* Native-dependent code for OpenBSD/arm64 (AArch64)
+
+ Copyright (C) 2011-2017 Free Software Foundation, Inc.
@@ -32,6 +32,7 @@ Index: gdb/aarch64obsd-nat.c
+
+#include "aarch64-tdep.h"
+#include "inf-ptrace.h"
++#include "obsd-nat.h"
+
+/* Fill GDB's register array with the general-purpose register values
+ from the current thread. */
@@ -44,7 +45,7 @@ Index: gdb/aarch64obsd-nat.c
+ int regno;
+ int ret;
+
-+ pid = ptid_get_pid (inferior_ptid);
++ pid = get_ptrace_pid (inferior_ptid);
+
+ ret = ptrace(PT_GETREGS, pid, (caddr_t)®s, 0);
+ if (ret < 0)
@@ -69,7 +70,7 @@ Index: gdb/aarch64obsd-nat.c
+ int regno;
+ int ret;
+
-+ pid = ptid_get_pid (inferior_ptid);
++ pid = get_ptrace_pid (inferior_ptid);
+
+ // fetch old values as only 'valid' entries will be replaced.
+ ret = ptrace(PT_GETREGS, pid, (caddr_t)®s, 0);
@@ -106,7 +107,7 @@ Index: gdb/aarch64obsd-nat.c
+ int regno;
+ struct fpreg fpregs;
+
-+ pid = ptid_get_pid (inferior_ptid);
++ pid = get_ptrace_pid (inferior_ptid);
+
+ ret = ptrace(PT_GETFPREGS, pid, (caddr_t)&fpregs, 0);
+ if (ret < 0) {
@@ -132,7 +133,7 @@ Index: gdb/aarch64obsd-nat.c
+ int regno;
+ struct fpreg fpregs;
+
-+ pid = ptid_get_pid (inferior_ptid);
++ pid = get_ptrace_pid (inferior_ptid);
+
+ ret = ptrace(PT_GETFPREGS, pid, (caddr_t)&fpregs, 0);
+ if (ret < 0) {
@@ -206,5 +207,5 @@ Index: gdb/aarch64obsd-nat.c
+ t->to_store_registers = aarch64_obsd_store_inferior_registers;
+
+ /* Register the target. */
-+ add_target (t);
++ obsd_add_target (t);
+}
Index: patches/patch-gdb_aarch64obsd-tdep_c
===================================================================
RCS file: /cvs/ports/devel/gdb/patches/patch-gdb_aarch64obsd-tdep_c,v
retrieving revision 1.1
diff -u -p -u -r1.1 patch-gdb_aarch64obsd-tdep_c
--- patches/patch-gdb_aarch64obsd-tdep_c 10 Jul 2018 11:03:46 -0000
1.1
+++ patches/patch-gdb_aarch64obsd-tdep_c 12 Oct 2019 22:49:59 -0000
@@ -2,7 +2,7 @@ $OpenBSD: patch-gdb_aarch64obsd-tdep_c,v
Index: gdb/aarch64obsd-tdep.c
--- gdb/aarch64obsd-tdep.c.orig
+++ gdb/aarch64obsd-tdep.c
-@@ -0,0 +1,111 @@
+@@ -0,0 +1,299 @@
+/* Target-dependent code for OpenBSD/aarch64.
+
+ Copyright (C) 2006-2017 Free Software Foundation, Inc.
@@ -23,6 +23,7 @@ Index: gdb/aarch64obsd-tdep.c
+ 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"
@@ -32,6 +33,189 @@ Index: gdb/aarch64obsd-tdep.c
+#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 a 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)
@@ -92,10 +276,14 @@ Index: gdb/aarch64obsd-tdep.c
+{
+ 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;