Index | Thread | Search

From:
Pascal Stumpf <pascal@stumpf.co>
Subject:
Re: Update to gdb-13.2 - tests wanted
To:
ports@openbsd.org, tb@openbsd.org, gkoehler@openbsd.org, kettenis@openbsd.org, miod@openbsd.org, visa@openbsd.org
Date:
Fri, 08 Nov 2024 07:59:43 +0100

Download raw body.

Thread
On Thu, 7 Nov 2024 17:28:50 +0100, Jeremie Courreges-Anglas wrote:
> 
> So pascal@ shared an update to gdb-13.2 some time ago.  At least tb@
> is using it because of better support for IBT/endbrxx.  Instead of
> backporting fixes to our gdb-9.2 port, it would be nice to move the
> port to gdb-13.2, but that requires some cross-platform efforts*.
> 
> The diff below seems to work for me on amd64, riscv64 and sparc64.
> There's a good chance that the blind fixes I have added for arm64 and
> powerpc64 are not enough.  Also, the NetBSD native support we've been
> using for arm has changed significantly so it's probably better to
> have a separate implementation.  For now, I have added the file but
> I have unhooked native support on that arch.
> 
> Build tests would be most welcome on: arm, arm64, i386, powerpc,
> powerpc64, mips64.  Bonus points for alpha or hppa, they were not
> tested during the upgrade to gdb-9.2.  If you hit an issue and produce
> build or runtime fixes, please share the resulting
> patches/patch-... file(s).
> 
> Runtime tests welcome on all platforms.  Among other things I'm
> curious about support for PAC-enabled platforms.  What's the status
> with the current package and with the updated port?
> 
> 
> * an alternative discussed with tb would be to have several versions
>   of gdb in the ports tree.  I'd slightly prefer that we work on
>   having a single one that works, even if updates are a bit painful.
>   Hopefully we can upstream support for some of our new architectures
>   at some point.  Thoughts?
> 

As gkoehler@ already said, the coff-rs6000.c patch needs to be removed
for powerpc.

Here are the updated patches for aarch64.  Single stepping in a simple
program works fine, I haven't tested much else yet.


Index: gdb/aarch64-obsd-nat.c
--- gdb/aarch64-obsd-nat.c.orig
+++ gdb/aarch64-obsd-nat.c
@@ -0,0 +1,170 @@
+/* Native-dependent code for OpenBSD/aarch64.
+
+   Copyright (C) 2017-2020 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 "gdbarch.h"
+#include "regcache.h"
+#include "target.h"
+
+#include <sys/types.h>
+#include <sys/auxv.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#include "aarch64-tdep.h"
+#include "aarch64-obsd-tdep.h"
+#include "inf-ptrace.h"
+#include "obsd-nat.h"
+
+struct aarch64_obsd_nat_target final : public obsd_nat_target
+{
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+  const struct target_desc *read_description () override;
+};
+
+static aarch64_obsd_nat_target the_aarch64_obsd_nat_target;
+
+/* Determine if PT_GETREGS fetches REGNUM.  */
+
+static bool
+getregs_supplies (int regnum)
+{
+  return (regnum >= AARCH64_X0_REGNUM && regnum <= AARCH64_CPSR_REGNUM);
+}
+
+/* Determine if PT_GETFPREGS fetches REGNUM.  */
+
+static bool
+getfpregs_supplies (int regnum)
+{
+  return (regnum >= AARCH64_V0_REGNUM && regnum <= AARCH64_FPCR_REGNUM);
+}
+
+/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
+   for all registers.  */
+
+void
+aarch64_obsd_nat_target::fetch_registers (struct regcache *regcache,
+					  int regnum)
+{
+#ifdef PT_PACMASK
+  gdbarch *gdbarch = regcache->arch ();
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep <aarch64_gdbarch_tdep> (gdbarch);
+#endif
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  if (regnum == -1 || getregs_supplies (regnum))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+	perror_with_name (_("Couldn't get registers"));
+
+      regcache->supply_regset (&aarch64_obsd_gregset, regnum, &regs,
+			       sizeof (regs));
+    }
+
+  if (regnum == -1 || getfpregs_supplies (regnum))
+    {
+      struct fpreg fpregs;
+
+      if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't get floating point status"));
+
+      regcache->supply_regset (&aarch64_obsd_fpregset, regnum, &fpregs,
+			       sizeof (fpregs));
+    }
+
+#ifdef PT_PACMASK
+  if (tdep->has_pauth())
+    {
+      int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base);
+      int dmask_num = AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base);
+      register_t pacmask[2];
+
+      if (regnum == -1 || regnum == cmask_num || regnum == dmask_num)
+	{
+	  if (ptrace (PT_PACMASK, pid, (PTRACE_TYPE_ARG3) &pacmask,
+		      sizeof (pacmask)) == -1)
+	    perror_with_name (_("Couldn't get PAC mask"));
+
+	  regcache->raw_supply (cmask_num, &pacmask[0]);
+	  regcache->raw_supply (dmask_num, &pacmask[1]);
+	}
+    }
+#endif
+}
+
+/* Store register REGNUM back into the inferior.  If REGNUM is -1, do
+   this for all registers.  */
+
+void
+aarch64_obsd_nat_target::store_registers (struct regcache *regcache,
+					  int regnum)
+{
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  if (regnum == -1 || getregs_supplies (regnum))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+	perror_with_name (_("Couldn't get registers"));
+
+      regcache->collect_regset (&aarch64_obsd_gregset, regnum, &regs,
+			       sizeof (regs));
+
+      if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+	perror_with_name (_("Couldn't write registers"));
+    }
+
+  if (regnum == -1 || getfpregs_supplies (regnum))
+    {
+      struct fpreg fpregs;
+
+      if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't get floating point status"));
+
+      regcache->collect_regset (&aarch64_obsd_fpregset, regnum, &fpregs,
+				sizeof (fpregs));
+
+      if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't write floating point status"));
+    }
+}
+
+const struct target_desc *
+aarch64_obsd_nat_target::read_description ()
+{
+  aarch64_features features;
+  unsigned long hwcap;
+
+  if (elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap) == 0)
+    features.pauth = hwcap & HWCAP_PACA;
+
+  return aarch64_read_description (features);
+}
+
+void
+_initialize_aarch64_obsd_nat ()
+{
+  add_inf_child_target (&the_aarch64_obsd_nat_target);
+}



Index: gdb/aarch64-obsd-tdep.c
--- gdb/aarch64-obsd-tdep.c.orig
+++ gdb/aarch64-obsd-tdep.c
@@ -0,0 +1,338 @@
+/* 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 "gdbarch.h"
+#include "frame-unwind.h"
+#include "osabi.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+
+#include "aarch64-tdep.h"
+#include "aarch64-obsd-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,
+				    frame_info_ptr 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))
+	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 (frame_info_ptr this_frame, void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_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))
+    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 (frame_info_ptr 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 (frame_info_ptr 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 = {
+  "aarch64 openbsd tramp",
+  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)
+
+/* The pauth regset consists of 2 64-bit masks.  */
+#define AARCH64_OBSD_SIZEOF_PAUTH (2 * X_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)
+{
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+  cb (".reg", AARCH64_OBSD_SIZEOF_GREGSET, AARCH64_OBSD_SIZEOF_GREGSET,
+      &aarch64_obsd_gregset, NULL, cb_data);
+  cb (".reg2", AARCH64_OBSD_SIZEOF_FPREGSET, AARCH64_OBSD_SIZEOF_FPREGSET,
+      &aarch64_obsd_fpregset, NULL, cb_data);
+
+  if (tdep->has_pauth ())
+    {
+      /* Create this on the fly in order to handle the variable location.  */
+      const struct regcache_map_entry pauth_regmap[] =
+	{
+	  { 2, AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base), 8},
+	  { 0 }
+	};
+
+      const struct regset aarch64_obsd_pauth_regset =
+	{
+	  pauth_regmap, regcache_supply_regset, regcache_collect_regset
+	};
+
+      cb (".reg-aarch-pauth", AARCH64_OBSD_SIZEOF_PAUTH,
+	  AARCH64_OBSD_SIZEOF_PAUTH, &aarch64_obsd_pauth_regset,
+	  NULL, cb_data);
+    }
+}
+
+static const struct target_desc *
+aarch64_obsd_core_read_description (struct gdbarch *gdbarch,
+				    struct target_ops *target, bfd *abfd)
+{
+  asection *pauth = bfd_get_section_by_name (abfd, ".reg-aarch-pauth");
+
+  aarch64_features features;
+  features.pauth = pauth != nullptr ? 1 : 0;
+
+  return aarch64_read_description (features);
+}
+␌
+
+static void
+aarch64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_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);
+  set_gdbarch_core_read_description
+    (gdbarch, aarch64_obsd_core_read_description);
+}
+␌
+
+void _initialize_aarch64_obsd_tdep ();
+
+void
+_initialize_aarch64_obsd_tdep ()
+{
+  gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_OPENBSD,
+			  aarch64obsd_init_abi);
+}