Improve devel/gdb aarch64 support

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Improve devel/gdb aarch64 support

Kurt Miller-3
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)&regs, 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)&regs, 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;