From: Pascal Stumpf 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 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 . */ + +#include "defs.h" +#include "gdbarch.h" +#include "regcache.h" +#include "target.h" + +#include +#include +#include +#include + +#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 (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) ®s, 0) == -1) + perror_with_name (_("Couldn't get registers")); + + regcache->supply_regset (&aarch64_obsd_gregset, regnum, ®s, + 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) ®s, 0) == -1) + perror_with_name (_("Couldn't get registers")); + + regcache->collect_regset (&aarch64_obsd_gregset, regnum, ®s, + sizeof (regs)); + + if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 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 . */ + +#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 (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 (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 (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); +}