Index: devel/gdb/Makefile =================================================================== --- devel/gdb/Makefile +++ devel/gdb/Makefile @@ -1,7 +1,7 @@ # Created by: Steven Kreuzer PORTNAME= gdb -DISTVERSION= 11.2 +DISTVERSION= 12.1 PORTREVISION= 0 CATEGORIES= devel MASTER_SITES= GNU @@ -38,6 +38,34 @@ CFLAGS+= -DRL_NO_COMPAT EXCLUDE= dejagnu expect sim texinfo intl EXTRACT_AFTER_ARGS= ${EXCLUDE:S/^/--exclude /} +EXTRA_PATCHES= ${FILESDIR}/commit-711b0b6698f \ + ${FILESDIR}/commit-922c2fc18e4 \ + ${FILESDIR}/commit-b1babce7c31 \ + ${FILESDIR}/commit-a49ce729c80 \ + ${FILESDIR}/commit-c77282d8ba9 \ + ${FILESDIR}/commit-041a4212d37 \ + ${FILESDIR}/commit-4bd817e71ee \ + ${FILESDIR}/commit-1570c37c340 \ + ${FILESDIR}/commit-6719bc690e2 \ + ${FILESDIR}/commit-983b1119bc3 \ + ${FILESDIR}/commit-a3627b54280 \ + ${FILESDIR}/commit-065a00b3a46 \ + ${FILESDIR}/commit-e330d4c033e \ + ${FILESDIR}/commit-a171378aa47 \ + ${FILESDIR}/commit-b5c2367c3ac \ + ${FILESDIR}/commit-f3215e1526d \ + ${FILESDIR}/commit-c13566fdd57 \ + ${FILESDIR}/commit-3181aed81c9 \ + ${FILESDIR}/commit-8e6afe4013f \ + ${FILESDIR}/commit-40c23d88038 \ + ${FILESDIR}/commit-92d48a1e4ea \ + ${FILESDIR}/commit-099fbce0acc \ + ${FILESDIR}/commit-2e686a74dc4 \ + ${FILESDIR}/commit-684943d213b \ + ${FILESDIR}/commit-414d5848bb2 \ + ${FILESDIR}/commit-0a765c1a8e9 \ + ${FILESDIR}/commit-f9fbb7636a5 \ + ${FILESDIR}/commit-b7fe5463cf0 LIB_DEPENDS+= libexpat.so:textproc/expat2 VER= ${DISTVERSION:S/.//g} @@ -123,10 +151,6 @@ CONFIGURE_TARGET= x86_64-portbld-freebsd${OSREL} .endif -.if ${CHOSEN_COMPILER_TYPE} == clang -CFLAGS+= -Wno-extended-offsetof -.endif - post-patch: @${REINPLACE_CMD} -e 's|$$| [GDB v${DISTVERSION} for FreeBSD]|' \ ${WRKSRC}/gdb/version.in Index: devel/gdb/distinfo =================================================================== --- devel/gdb/distinfo +++ devel/gdb/distinfo @@ -1,5 +1,5 @@ -TIMESTAMP = 1642410957 -SHA256 (gdb-11.2.tar.xz) = 1497c36a71881b8671a9a84a0ee40faab788ca30d7ba19d8463c3cc787152e32 -SIZE (gdb-11.2.tar.xz) = 22039420 +TIMESTAMP = 1651512279 +SHA256 (gdb-12.1.tar.xz) = 0e1793bf8f2b54d53f46dea84ccfd446f48f81b297b28c4f7fc017b818d69fed +SIZE (gdb-12.1.tar.xz) = 22470332 SHA256 (bsdjhb-libcxx-gdbpy-03d0d9b_GH0.tar.gz) = 2c1563f361d4fb59b54b1b39bff5cdf609d73962758eb05a8cdfe2c22551b259 SIZE (bsdjhb-libcxx-gdbpy-03d0d9b_GH0.tar.gz) = 6052 Index: devel/gdb/files/commit-041a4212d37 =================================================================== --- /dev/null +++ devel/gdb/files/commit-041a4212d37 @@ -0,0 +1,97 @@ +commit 7d06796cbc1e5f5a9ca03a5214934a849bd519b1 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + x86-fbsd-nat: Copy debug register state on fork. + + Use the FreeBSD native target low_new_fork hook to copy the + per-process debug state from the parent to the child on fork. + + (cherry picked from commit 041a4212d37de6172b3428613c9f9f52ab950c6c) + +diff --git a/gdb/configure.nat b/gdb/configure.nat +index b45519fd116..92ad4a6522b 100644 +--- gdb/configure.nat ++++ gdb/configure.nat +@@ -165,7 +165,7 @@ case ${gdb_host} in + i386) + # Host: FreeBSD/i386 + NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \ +- x86-bsd-nat.o i386-fbsd-nat.o bsd-kvm.o" ++ x86-bsd-nat.o x86-fbsd-nat.o i386-fbsd-nat.o bsd-kvm.o" + ;; + mips) + # Host: FreeBSD/mips +@@ -194,7 +194,7 @@ case ${gdb_host} in + # Host: FreeBSD/amd64 + NATDEPFILES="${NATDEPFILES} amd64-nat.o \ + amd64-fbsd-nat.o bsd-kvm.o x86-nat.o nat/x86-dregs.o \ +- x86-bsd-nat.o" ++ x86-bsd-nat.o x86-fbsd-nat.o" + ;; + esac + ;; +diff --git a/gdb/x86-fbsd-nat.c b/gdb/x86-fbsd-nat.c +new file mode 100644 +index 00000000000..ad8c693b68e +--- /dev/null ++++ gdb/x86-fbsd-nat.c +@@ -0,0 +1,45 @@ ++/* Native-dependent code for FreeBSD x86. ++ ++ Copyright (C) 2022 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 "x86-fbsd-nat.h" ++ ++/* Implement the virtual fbsd_nat_target::low_new_fork method. */ ++ ++void ++x86_fbsd_nat_target::low_new_fork (ptid_t parent, pid_t child) ++{ ++ struct x86_debug_reg_state *parent_state, *child_state; ++ ++ /* If there is no parent state, no watchpoints nor breakpoints have ++ been set, so there is nothing to do. */ ++ parent_state = x86_lookup_debug_reg_state (parent.pid ()); ++ if (parent_state == nullptr) ++ return; ++ ++ /* The kernel clears debug registers in the new child process after ++ fork, but GDB core assumes the child inherits the watchpoints/hw ++ breakpoints of the parent, and will remove them all from the ++ forked off process. Copy the debug registers mirrors into the ++ new process so that all breakpoints and watchpoints can be ++ removed together. */ ++ ++ child_state = x86_debug_reg_state (child); ++ *child_state = *parent_state; ++} +diff --git a/gdb/x86-fbsd-nat.h b/gdb/x86-fbsd-nat.h +index f9d3514aab4..cdb8cd36a4c 100644 +--- gdb/x86-fbsd-nat.h ++++ gdb/x86-fbsd-nat.h +@@ -29,6 +29,8 @@ class x86_fbsd_nat_target : public x86bsd_nat_target + { + bool supports_stopped_by_hw_breakpoint () override + { return true; } ++ ++ void low_new_fork (ptid_t parent, pid_t child) override; + }; + + #endif /* x86-bsd-nat.h */ Index: devel/gdb/files/commit-065a00b3a46 =================================================================== --- /dev/null +++ devel/gdb/files/commit-065a00b3a46 @@ -0,0 +1,338 @@ +commit 194342a42538301d9ef47d4be6efd74ddfb8fac2 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + Add support for hardware breakpoints/watchpoints on FreeBSD/Aarch64. + + This shares aarch64-nat.c and nat/aarch64-hw-point.c with the Linux + native target. Since FreeBSD writes all of the debug registers in one + ptrace op, use an unordered_set<> to track the "dirty" state for + threads rather than bitmasks of modified registers. + + (cherry picked from commit 065a00b3a461463cca766ac6bb33e3be436397bd) + +diff --git a/gdb/NEWS b/gdb/NEWS +index 501ace1872e..0320bf8ea1e 100644 +--- gdb/NEWS ++++ gdb/NEWS +@@ -3,6 +3,8 @@ + + *** Changes in GDB 12 + ++* GDB now supports hardware watchpoints on FreeBSD/Aarch64. ++ + * DBX mode is deprecated, and will be removed in GDB 13 + + * GDB 12 is the last release of GDB that will support building against +diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c +index e6ca1196139..99e2bf35276 100644 +--- gdb/aarch64-fbsd-nat.c ++++ gdb/aarch64-fbsd-nat.c +@@ -18,24 +18,60 @@ + along with this program. If not, see . */ + + #include "defs.h" ++#include "arch-utils.h" ++#include "inferior.h" + #include "regcache.h" + #include "target.h" ++#include "nat/aarch64-hw-point.h" + +-#include ++#include + #include ++#include + #include + + #include "fbsd-nat.h" + #include "aarch64-fbsd-tdep.h" ++#include "aarch64-nat.h" + #include "inf-ptrace.h" + ++#if __FreeBSD_version >= 1400005 ++#define HAVE_DBREG ++ ++#include ++#endif ++ ++#ifdef HAVE_DBREG ++struct aarch64_fbsd_nat_target final ++ : public aarch64_nat_target ++#else + struct aarch64_fbsd_nat_target final : public fbsd_nat_target ++#endif + { + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; ++ ++#ifdef HAVE_DBREG ++ /* Hardware breakpoints and watchpoints. */ ++ bool stopped_by_watchpoint () override; ++ bool stopped_data_address (CORE_ADDR *) override; ++ bool stopped_by_hw_breakpoint () override; ++ bool supports_stopped_by_hw_breakpoint () override; ++ ++ void post_startup_inferior (ptid_t) override; ++ void post_attach (int pid) override; ++ ++ void low_new_fork (ptid_t parent, pid_t child) override; ++ void low_delete_thread (thread_info *) override; ++ void low_prepare_to_resume (thread_info *) override; ++ ++private: ++ void probe_debug_regs (int pid); ++ static bool debug_regs_probed; ++#endif + }; + + static aarch64_fbsd_nat_target the_aarch64_fbsd_nat_target; ++bool aarch64_fbsd_nat_target::debug_regs_probed; + + /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this + for all registers. */ +@@ -63,9 +99,231 @@ aarch64_fbsd_nat_target::store_registers (struct regcache *regcache, + PT_SETFPREGS, &aarch64_fbsd_fpregset); + } + ++#ifdef HAVE_DBREG ++/* Set of threads which need to update debug registers on next resume. */ ++ ++static std::unordered_set aarch64_debug_pending_threads; ++ ++/* Implement the "stopped_data_address" target_ops method. */ ++ ++bool ++aarch64_fbsd_nat_target::stopped_data_address (CORE_ADDR *addr_p) ++{ ++ siginfo_t siginfo; ++ struct aarch64_debug_reg_state *state; ++ ++ if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo)) ++ return false; ++ ++ /* This must be a hardware breakpoint. */ ++ if (siginfo.si_signo != SIGTRAP ++ || siginfo.si_code != TRAP_TRACE ++ || siginfo.si_trapno != EXCP_WATCHPT_EL0) ++ return false; ++ ++ const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr; ++ ++ /* Check if the address matches any watched address. */ ++ state = aarch64_get_debug_reg_state (inferior_ptid.pid ()); ++ return aarch64_stopped_data_address (state, addr_trap, addr_p); ++} ++ ++/* Implement the "stopped_by_watchpoint" target_ops method. */ ++ ++bool ++aarch64_fbsd_nat_target::stopped_by_watchpoint () ++{ ++ CORE_ADDR addr; ++ ++ return stopped_data_address (&addr); ++} ++ ++/* Implement the "stopped_by_hw_breakpoint" target_ops method. */ ++ ++bool ++aarch64_fbsd_nat_target::stopped_by_hw_breakpoint () ++{ ++ siginfo_t siginfo; ++ struct aarch64_debug_reg_state *state; ++ ++ if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo)) ++ return false; ++ ++ /* This must be a hardware breakpoint. */ ++ if (siginfo.si_signo != SIGTRAP ++ || siginfo.si_code != TRAP_TRACE ++ || siginfo.si_trapno != EXCP_WATCHPT_EL0) ++ return false; ++ ++ return !stopped_by_watchpoint(); ++} ++ ++/* Implement the "supports_stopped_by_hw_breakpoint" target_ops method. */ ++ ++bool ++aarch64_fbsd_nat_target::supports_stopped_by_hw_breakpoint () ++{ ++ return true; ++} ++ ++/* Fetch the hardware debug register capability information. */ ++ ++void ++aarch64_fbsd_nat_target::probe_debug_regs (int pid) ++{ ++ if (!debug_regs_probed) ++ { ++ struct dbreg reg; ++ ++ debug_regs_probed = true; ++ aarch64_num_bp_regs = 0; ++ aarch64_num_wp_regs = 0; ++ ++ if (ptrace(PT_GETDBREGS, pid, (PTRACE_TYPE_ARG3) ®, 0) == 0) ++ { ++ switch (reg.db_debug_ver) ++ { ++ case AARCH64_DEBUG_ARCH_V8: ++ case AARCH64_DEBUG_ARCH_V8_1: ++ case AARCH64_DEBUG_ARCH_V8_2: ++ case AARCH64_DEBUG_ARCH_V8_4: ++ break; ++ default: ++ return; ++ } ++ ++ aarch64_num_bp_regs = reg.db_nbkpts; ++ if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM) ++ { ++ warning (_("Unexpected number of hardware breakpoint registers" ++ " reported by ptrace, got %d, expected %d."), ++ aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM); ++ aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM; ++ } ++ aarch64_num_wp_regs = reg.db_nwtpts; ++ if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM) ++ { ++ warning (_("Unexpected number of hardware watchpoint registers" ++ " reported by ptrace, got %d, expected %d."), ++ aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM); ++ aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM; ++ } ++ } ++ } ++} ++ ++/* Implement the virtual inf_ptrace_target::post_startup_inferior method. */ ++ ++void ++aarch64_fbsd_nat_target::post_startup_inferior (ptid_t ptid) ++{ ++ aarch64_remove_debug_reg_state (ptid.pid ()); ++ probe_debug_regs (ptid.pid ()); ++ fbsd_nat_target::post_startup_inferior (ptid); ++} ++ ++/* Implement the "post_attach" target_ops method. */ ++ ++void ++aarch64_fbsd_nat_target::post_attach (int pid) ++{ ++ aarch64_remove_debug_reg_state (pid); ++ probe_debug_regs (pid); ++ fbsd_nat_target::post_attach (pid); ++} ++ ++/* Implement the virtual fbsd_nat_target::low_new_fork method. */ ++ ++void ++aarch64_fbsd_nat_target::low_new_fork (ptid_t parent, pid_t child) ++{ ++ struct aarch64_debug_reg_state *parent_state, *child_state; ++ ++ /* If there is no parent state, no watchpoints nor breakpoints have ++ been set, so there is nothing to do. */ ++ parent_state = aarch64_lookup_debug_reg_state (parent.pid ()); ++ if (parent_state == nullptr) ++ return; ++ ++ /* The kernel clears debug registers in the new child process after ++ fork, but GDB core assumes the child inherits the watchpoints/hw ++ breakpoints of the parent, and will remove them all from the ++ forked off process. Copy the debug registers mirrors into the ++ new process so that all breakpoints and watchpoints can be ++ removed together. */ ++ ++ child_state = aarch64_get_debug_reg_state (child); ++ *child_state = *parent_state; ++} ++ ++/* Mark debug register state "dirty" for all threads belonging to the ++ current inferior. */ ++ ++void ++aarch64_notify_debug_reg_change (ptid_t ptid, ++ int is_watchpoint, unsigned int idx) ++{ ++ for (thread_info *tp : current_inferior ()->non_exited_threads ()) ++ { ++ if (tp->ptid.lwp_p ()) ++ aarch64_debug_pending_threads.emplace (tp->ptid.lwp ()); ++ } ++} ++ ++/* Implement the virtual fbsd_nat_target::low_delete_thread method. */ ++ ++void ++aarch64_fbsd_nat_target::low_delete_thread (thread_info *tp) ++{ ++ gdb_assert(tp->ptid.lwp_p ()); ++ aarch64_debug_pending_threads.erase (tp->ptid.lwp ()); ++} ++ ++/* Implement the virtual fbsd_nat_target::low_prepare_to_resume method. */ ++ ++void ++aarch64_fbsd_nat_target::low_prepare_to_resume (thread_info *tp) ++{ ++ gdb_assert(tp->ptid.lwp_p ()); ++ ++ if (aarch64_debug_pending_threads.erase (tp->ptid.lwp ()) == 0) ++ return; ++ ++ struct aarch64_debug_reg_state *state = ++ aarch64_lookup_debug_reg_state (tp->ptid.pid ()); ++ gdb_assert(state != nullptr); ++ ++ struct dbreg reg; ++ memset (®, 0, sizeof(reg)); ++ for (int i = 0; i < aarch64_num_bp_regs; i++) ++ { ++ reg.db_breakregs[i].dbr_addr = state->dr_addr_bp[i]; ++ reg.db_breakregs[i].dbr_ctrl = state->dr_ctrl_bp[i]; ++ } ++ for (int i = 0; i < aarch64_num_wp_regs; i++) ++ { ++ reg.db_watchregs[i].dbw_addr = state->dr_addr_wp[i]; ++ reg.db_watchregs[i].dbw_ctrl = state->dr_ctrl_wp[i]; ++ } ++ if (ptrace(PT_SETDBREGS, tp->ptid.lwp (), (PTRACE_TYPE_ARG3) ®, 0) != 0) ++ error (_("Failed to set hardware debug registers")); ++} ++#else ++/* A stub that should never be called. */ ++void ++aarch64_notify_debug_reg_change (ptid_t ptid, ++ int is_watchpoint, unsigned int idx) ++{ ++ gdb_assert (true); ++} ++#endif ++ + void _initialize_aarch64_fbsd_nat (); + void + _initialize_aarch64_fbsd_nat () + { ++#ifdef HAVE_DBREG ++ aarch64_initialize_hw_point (); ++#endif + add_inf_child_target (&the_aarch64_fbsd_nat_target); + } +diff --git a/gdb/configure.nat b/gdb/configure.nat +index 4f5850dd595..d219d6a960c 100644 +--- gdb/configure.nat ++++ gdb/configure.nat +@@ -154,7 +154,8 @@ case ${gdb_host} in + case ${gdb_host_cpu} in + aarch64) + # Host: FreeBSD/aarch64 +- NATDEPFILES="${NATDEPFILES} aarch64-fbsd-nat.o" ++ NATDEPFILES="${NATDEPFILES} aarch64-nat.o \ ++ nat/aarch64-hw-point.o aarch64-fbsd-nat.o" + LOADLIBES= + ;; + arm) Index: devel/gdb/files/commit-099fbce0acc =================================================================== --- /dev/null +++ devel/gdb/files/commit-099fbce0acc @@ -0,0 +1,114 @@ +commit 82d5c31c4fe5bb67386dc568893dc23c899ff303 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Read the tpidruro register from NT_ARM_TLS core dump notes on FreeBSD/arm. + + (cherry picked from commit 099fbce0accf209677e041fd9dc10bcb4a5eb578) + +diff --git gdb/arm-fbsd-nat.c gdb/arm-fbsd-nat.c +index 3106d73cc3a..c32924de735 100644 +--- gdb/arm-fbsd-nat.c ++++ gdb/arm-fbsd-nat.c +@@ -72,7 +72,7 @@ arm_fbsd_nat_target::read_description () + { + const struct target_desc *desc; + +- desc = arm_fbsd_read_description_auxv (this); ++ desc = arm_fbsd_read_description_auxv (this, false); + if (desc == NULL) + desc = this->beneath ()->read_description (); + return desc; +diff --git gdb/arm-fbsd-tdep.c gdb/arm-fbsd-tdep.c +index 06745a36186..a27dfb2fb4a 100644 +--- gdb/arm-fbsd-tdep.c ++++ gdb/arm-fbsd-tdep.c +@@ -163,6 +163,24 @@ arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + cb (".reg", ARM_FBSD_SIZEOF_GREGSET, ARM_FBSD_SIZEOF_GREGSET, + &arm_fbsd_gregset, NULL, cb_data); + ++ if (tdep->tls_regnum > 0) ++ { ++ const struct regcache_map_entry arm_fbsd_tlsregmap[] = ++ { ++ { 1, tdep->tls_regnum, 4 }, ++ { 0 } ++ }; ++ ++ const struct regset arm_fbsd_tlsregset = ++ { ++ arm_fbsd_tlsregmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ cb (".reg-aarch-tls", ARM_FBSD_SIZEOF_TLSREGSET, ARM_FBSD_SIZEOF_TLSREGSET, ++ &arm_fbsd_tlsregset, NULL, cb_data); ++ } ++ + /* While FreeBSD/arm cores do contain a NT_FPREGSET / ".reg2" + register set, it is not populated with register values by the + kernel but just contains all zeroes. */ +@@ -175,12 +193,12 @@ arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + vector. */ + + const struct target_desc * +-arm_fbsd_read_description_auxv (struct target_ops *target) ++arm_fbsd_read_description_auxv (struct target_ops *target, bool tls) + { + CORE_ADDR arm_hwcap = 0; + + if (target_auxv_search (target, AT_FREEBSD_HWCAP, &arm_hwcap) != 1) +- return nullptr; ++ return arm_read_description (ARM_FP_TYPE_NONE, tls); + + if (arm_hwcap & HWCAP_VFP) + { +@@ -188,12 +206,12 @@ arm_fbsd_read_description_auxv (struct target_ops *target) + return aarch32_read_description (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPD32)) + == (HWCAP_VFPv3 | HWCAP_VFPD32)) +- return arm_read_description (ARM_FP_TYPE_VFPV3, false); ++ return arm_read_description (ARM_FP_TYPE_VFPV3, tls); + else +- return arm_read_description (ARM_FP_TYPE_VFPV2, false); ++ return arm_read_description (ARM_FP_TYPE_VFPV2, tls); + } + +- return nullptr; ++ return arm_read_description (ARM_FP_TYPE_NONE, tls); + } + + /* Implement the "core_read_description" gdbarch method. */ +@@ -203,7 +221,9 @@ arm_fbsd_core_read_description (struct gdbarch *gdbarch, + struct target_ops *target, + bfd *abfd) + { +- return arm_fbsd_read_description_auxv (target); ++ asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls"); ++ ++ return arm_fbsd_read_description_auxv (target, tls != nullptr); + } + + /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ +diff --git gdb/arm-fbsd-tdep.h gdb/arm-fbsd-tdep.h +index 633dafad75d..193eb76df3c 100644 +--- gdb/arm-fbsd-tdep.h ++++ gdb/arm-fbsd-tdep.h +@@ -26,6 +26,9 @@ + PC, and CPSR registers. */ + #define ARM_FBSD_SIZEOF_GREGSET (17 * 4) + ++/* The TLS regset consists of a single register. */ ++#define ARM_FBSD_SIZEOF_TLSREGSET (4) ++ + /* The VFP regset consists of 32 D registers plus FPSCR, and the whole + structure is padded to 64-bit alignment. */ + #define ARM_FBSD_SIZEOF_VFPREGSET (33 * 8) +@@ -40,6 +43,6 @@ extern const struct regset arm_fbsd_vfpregset; + #define HWCAP_VFPD32 0x00080000 + + extern const struct target_desc * +-arm_fbsd_read_description_auxv (struct target_ops *target); ++arm_fbsd_read_description_auxv (struct target_ops *target, bool tls); + + #endif /* ARM_FBSD_TDEP_H */ Index: devel/gdb/files/commit-0a765c1a8e9 =================================================================== --- /dev/null +++ devel/gdb/files/commit-0a765c1a8e9 @@ -0,0 +1,78 @@ +commit 25dc6de9343ae320e37a6b9daaf5c5fc398debae +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Read the tpidr register from NT_ARM_TLS core dump notes on FreeBSD/Aarch64. + + (cherry picked from commit 0a765c1a8e9c59f4cd0cdaf986291f957fe6ee90) + +diff --git gdb/aarch64-fbsd-tdep.c gdb/aarch64-fbsd-tdep.c +index 32f441892a8..ed1b84387f0 100644 +--- gdb/aarch64-fbsd-tdep.c ++++ gdb/aarch64-fbsd-tdep.c +@@ -142,10 +142,42 @@ aarch64_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + void *cb_data, + const struct regcache *regcache) + { ++ aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ + cb (".reg", AARCH64_FBSD_SIZEOF_GREGSET, AARCH64_FBSD_SIZEOF_GREGSET, + &aarch64_fbsd_gregset, NULL, cb_data); + cb (".reg2", AARCH64_FBSD_SIZEOF_FPREGSET, AARCH64_FBSD_SIZEOF_FPREGSET, + &aarch64_fbsd_fpregset, NULL, cb_data); ++ ++ if (tdep->has_tls ()) ++ { ++ const struct regcache_map_entry aarch64_fbsd_tls_regmap[] = ++ { ++ { 1, tdep->tls_regnum, 8 }, ++ { 0 } ++ }; ++ ++ const struct regset aarch64_fbsd_tls_regset = ++ { ++ aarch64_fbsd_tls_regmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ cb (".reg-aarch-tls", AARCH64_FBSD_SIZEOF_TLSREGSET, ++ AARCH64_FBSD_SIZEOF_TLSREGSET, &aarch64_fbsd_tls_regset, ++ "TLS register", cb_data); ++ } ++} ++ ++/* Implement the "core_read_description" gdbarch method. */ ++ ++static const struct target_desc * ++aarch64_fbsd_core_read_description (struct gdbarch *gdbarch, ++ struct target_ops *target, bfd *abfd) ++{ ++ asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls"); ++ ++ return aarch64_read_description (0, false, false, tls != nullptr); + } + + /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ +@@ -168,6 +200,8 @@ aarch64_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + + set_gdbarch_iterate_over_regset_sections + (gdbarch, aarch64_fbsd_iterate_over_regset_sections); ++ set_gdbarch_core_read_description (gdbarch, ++ aarch64_fbsd_core_read_description); + } + + void _initialize_aarch64_fbsd_tdep (); +diff --git gdb/aarch64-fbsd-tdep.h gdb/aarch64-fbsd-tdep.h +index fc8fbee8843..7419ea6be03 100644 +--- gdb/aarch64-fbsd-tdep.h ++++ gdb/aarch64-fbsd-tdep.h +@@ -32,6 +32,9 @@ + alignment. */ + #define AARCH64_FBSD_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE) + ++/* The TLS regset consists of a single register. */ ++#define AARCH64_FBSD_SIZEOF_TLSREGSET (X_REGISTER_SIZE) ++ + extern const struct regset aarch64_fbsd_gregset; + extern const struct regset aarch64_fbsd_fpregset; + Index: devel/gdb/files/commit-1570c37c340 =================================================================== --- /dev/null +++ devel/gdb/files/commit-1570c37c340 @@ -0,0 +1,892 @@ +commit ae520e967e0ccde249b47b7cea1c557299afd7ab +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + aarch64: Add an aarch64_nat_target mixin class. + + This class includes platform-independent target methods for hardware + breakpoints and watchpoints using routines from + nat/aarch64-hw-point.c. + + stopped_data_address is not platform-independent since the FAR + register holding the address for a breakpoint hit must be fetched in a + platform-specific manner. However, aarch64_stopped_data_address is + provided as a helper routine which performs platform-independent + validation given the value of the FAR register. + + For tracking the per-process debug register mirror state, use an + unordered_map indexed by pid as recently adopted in x86-nat.c rather + than a manual linked-list. + + (cherry picked from commit 1570c37c340bb9df2db2c30b437d6c30e1d75459) + +diff --git gdb/aarch64-linux-nat.c gdb/aarch64-linux-nat.c +index dd072d9315e..7bb82d17cc8 100644 +--- gdb/aarch64-linux-nat.c ++++ gdb/aarch64-linux-nat.c +@@ -27,6 +27,7 @@ + #include "target-descriptions.h" + #include "auxv.h" + #include "gdbcmd.h" ++#include "aarch64-nat.h" + #include "aarch64-tdep.h" + #include "aarch64-linux-tdep.h" + #include "aarch32-linux-nat.h" +@@ -58,7 +59,8 @@ + #define TRAP_HWBKPT 0x0004 + #endif + +-class aarch64_linux_nat_target final : public linux_nat_target ++class aarch64_linux_nat_target final ++ : public aarch64_nat_target + { + public: + /* Add our register access methods. */ +@@ -68,17 +70,8 @@ class aarch64_linux_nat_target final : public linux_nat_target + const struct target_desc *read_description () override; + + /* Add our hardware breakpoint and watchpoint implementation. */ +- int can_use_hw_breakpoint (enum bptype, int, int) override; +- int insert_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override; +- int remove_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override; +- int region_ok_for_hw_watchpoint (CORE_ADDR, int) override; +- int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type, +- struct expression *) override; +- int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type, +- struct expression *) override; + bool stopped_by_watchpoint () override; + bool stopped_data_address (CORE_ADDR *) override; +- bool watchpoint_addr_within_range (CORE_ADDR, CORE_ADDR, int) override; + + int can_do_single_step () override; + +@@ -118,103 +111,13 @@ class aarch64_linux_nat_target final : public linux_nat_target + + static aarch64_linux_nat_target the_aarch64_linux_nat_target; + +-/* Per-process data. We don't bind this to a per-inferior registry +- because of targets like x86 GNU/Linux that need to keep track of +- processes that aren't bound to any inferior (e.g., fork children, +- checkpoints). */ +- +-struct aarch64_process_info +-{ +- /* Linked list. */ +- struct aarch64_process_info *next; +- +- /* The process identifier. */ +- pid_t pid; +- +- /* Copy of aarch64 hardware debug registers. */ +- struct aarch64_debug_reg_state state; +-}; +- +-static struct aarch64_process_info *aarch64_process_list = NULL; +- +-/* Find process data for process PID. */ +- +-static struct aarch64_process_info * +-aarch64_find_process_pid (pid_t pid) +-{ +- struct aarch64_process_info *proc; +- +- for (proc = aarch64_process_list; proc; proc = proc->next) +- if (proc->pid == pid) +- return proc; +- +- return NULL; +-} +- +-/* Add process data for process PID. Returns newly allocated info +- object. */ +- +-static struct aarch64_process_info * +-aarch64_add_process (pid_t pid) +-{ +- struct aarch64_process_info *proc; +- +- proc = XCNEW (struct aarch64_process_info); +- proc->pid = pid; +- +- proc->next = aarch64_process_list; +- aarch64_process_list = proc; +- +- return proc; +-} +- +-/* Get data specific info for process PID, creating it if necessary. +- Never returns NULL. */ +- +-static struct aarch64_process_info * +-aarch64_process_info_get (pid_t pid) +-{ +- struct aarch64_process_info *proc; +- +- proc = aarch64_find_process_pid (pid); +- if (proc == NULL) +- proc = aarch64_add_process (pid); +- +- return proc; +-} +- + /* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of debug register state. */ + + void + aarch64_linux_nat_target::low_forget_process (pid_t pid) + { +- struct aarch64_process_info *proc, **proc_link; +- +- proc = aarch64_process_list; +- proc_link = &aarch64_process_list; +- +- while (proc != NULL) +- { +- if (proc->pid == pid) +- { +- *proc_link = proc->next; +- +- xfree (proc); +- return; +- } +- +- proc_link = &proc->next; +- proc = *proc_link; +- } +-} +- +-/* Get debug registers state for process PID. */ +- +-struct aarch64_debug_reg_state * +-aarch64_get_debug_reg_state (pid_t pid) +-{ +- return &aarch64_process_info_get (pid)->state; ++ aarch64_remove_debug_reg_state (pid); + } + + /* Fill GDB's register array with the general-purpose register values +@@ -775,192 +678,12 @@ aarch64_linux_nat_target::low_siginfo_fixup (siginfo_t *native, gdb_byte *inf, + return false; + } + +-/* Returns the number of hardware watchpoints of type TYPE that we can +- set. Value is positive if we can set CNT watchpoints, zero if +- setting watchpoints of type TYPE is not supported, and negative if +- CNT is more than the maximum number of watchpoints of type TYPE +- that we can support. TYPE is one of bp_hardware_watchpoint, +- bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint. +- CNT is the number of such watchpoints used so far (including this +- one). OTHERTYPE is non-zero if other types of watchpoints are +- currently enabled. */ +- +-int +-aarch64_linux_nat_target::can_use_hw_breakpoint (enum bptype type, +- int cnt, int othertype) +-{ +- if (type == bp_hardware_watchpoint || type == bp_read_watchpoint +- || type == bp_access_watchpoint || type == bp_watchpoint) +- { +- if (aarch64_num_wp_regs == 0) +- return 0; +- } +- else if (type == bp_hardware_breakpoint) +- { +- if (aarch64_num_bp_regs == 0) +- return 0; +- } +- else +- gdb_assert_not_reached ("unexpected breakpoint type"); +- +- /* We always return 1 here because we don't have enough information +- about possible overlap of addresses that they want to watch. As an +- extreme example, consider the case where all the watchpoints watch +- the same address and the same region length: then we can handle a +- virtually unlimited number of watchpoints, due to debug register +- sharing implemented via reference counts. */ +- return 1; +-} +- +-/* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address. +- Return 0 on success, -1 on failure. */ +- +-int +-aarch64_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch, +- struct bp_target_info *bp_tgt) +-{ +- int ret; +- CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address; +- int len; +- const enum target_hw_bp_type type = hw_execute; +- struct aarch64_debug_reg_state *state +- = aarch64_get_debug_reg_state (inferior_ptid.pid ()); +- +- gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); +- +- if (show_debug_regs) +- fprintf_unfiltered +- (gdb_stdlog, +- "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", +- (unsigned long) addr, len); +- +- ret = aarch64_handle_breakpoint (type, addr, len, 1 /* is_insert */, +- inferior_ptid, state); +- +- if (show_debug_regs) +- { +- aarch64_show_debug_reg_state (state, +- "insert_hw_breakpoint", addr, len, type); +- } +- +- return ret; +-} +- +-/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address. +- Return 0 on success, -1 on failure. */ +- +-int +-aarch64_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch, +- struct bp_target_info *bp_tgt) +-{ +- int ret; +- CORE_ADDR addr = bp_tgt->placed_address; +- int len = 4; +- const enum target_hw_bp_type type = hw_execute; +- struct aarch64_debug_reg_state *state +- = aarch64_get_debug_reg_state (inferior_ptid.pid ()); +- +- gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); +- +- if (show_debug_regs) +- fprintf_unfiltered +- (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", +- (unsigned long) addr, len); +- +- ret = aarch64_handle_breakpoint (type, addr, len, 0 /* is_insert */, +- inferior_ptid, state); +- +- if (show_debug_regs) +- { +- aarch64_show_debug_reg_state (state, +- "remove_hw_watchpoint", addr, len, type); +- } +- +- return ret; +-} +- +-/* Implement the "insert_watchpoint" target_ops method. +- +- Insert a watchpoint to watch a memory region which starts at +- address ADDR and whose length is LEN bytes. Watch memory accesses +- of the type TYPE. Return 0 on success, -1 on failure. */ +- +-int +-aarch64_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len, +- enum target_hw_bp_type type, +- struct expression *cond) +-{ +- int ret; +- struct aarch64_debug_reg_state *state +- = aarch64_get_debug_reg_state (inferior_ptid.pid ()); +- +- if (show_debug_regs) +- fprintf_unfiltered (gdb_stdlog, +- "insert_watchpoint on entry (addr=0x%08lx, len=%d)\n", +- (unsigned long) addr, len); +- +- gdb_assert (type != hw_execute); +- +- ret = aarch64_handle_watchpoint (type, addr, len, 1 /* is_insert */, +- inferior_ptid, state); +- +- if (show_debug_regs) +- { +- aarch64_show_debug_reg_state (state, +- "insert_watchpoint", addr, len, type); +- } +- +- return ret; +-} +- +-/* Implement the "remove_watchpoint" target_ops method. +- Remove a watchpoint that watched the memory region which starts at +- address ADDR, whose length is LEN bytes, and for accesses of the +- type TYPE. Return 0 on success, -1 on failure. */ +- +-int +-aarch64_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len, +- enum target_hw_bp_type type, +- struct expression *cond) +-{ +- int ret; +- struct aarch64_debug_reg_state *state +- = aarch64_get_debug_reg_state (inferior_ptid.pid ()); +- +- if (show_debug_regs) +- fprintf_unfiltered (gdb_stdlog, +- "remove_watchpoint on entry (addr=0x%08lx, len=%d)\n", +- (unsigned long) addr, len); +- +- gdb_assert (type != hw_execute); +- +- ret = aarch64_handle_watchpoint (type, addr, len, 0 /* is_insert */, +- inferior_ptid, state); +- +- if (show_debug_regs) +- { +- aarch64_show_debug_reg_state (state, +- "remove_watchpoint", addr, len, type); +- } +- +- return ret; +-} +- +-/* Implement the "region_ok_for_hw_watchpoint" target_ops method. */ +- +-int +-aarch64_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +-{ +- return aarch64_region_ok_for_watchpoint (addr, len); +-} +- + /* Implement the "stopped_data_address" target_ops method. */ + + bool + aarch64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p) + { + siginfo_t siginfo; +- int i; + struct aarch64_debug_reg_state *state; + + if (!linux_nat_get_siginfo (inferior_ptid, &siginfo)) +@@ -980,44 +703,7 @@ aarch64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p) + + /* Check if the address matches any watched address. */ + state = aarch64_get_debug_reg_state (inferior_ptid.pid ()); +- for (i = aarch64_num_wp_regs - 1; i >= 0; --i) +- { +- const unsigned int offset +- = aarch64_watchpoint_offset (state->dr_ctrl_wp[i]); +- const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); +- const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset; +- const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); +- const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i]; +- +- if (state->dr_ref_count_wp[i] +- && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i]) +- && addr_trap >= addr_watch_aligned +- && addr_trap < addr_watch + len) +- { +- /* ADDR_TRAP reports the first address of the memory range +- accessed by the CPU, regardless of what was the memory +- range watched. Thus, a large CPU access that straddles +- the ADDR_WATCH..ADDR_WATCH+LEN range may result in an +- ADDR_TRAP that is lower than the +- ADDR_WATCH..ADDR_WATCH+LEN range. E.g.: +- +- addr: | 4 | 5 | 6 | 7 | 8 | +- |---- range watched ----| +- |----------- range accessed ------------| +- +- In this case, ADDR_TRAP will be 4. +- +- To match a watchpoint known to GDB core, we must never +- report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN +- range. ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false +- positive on kernels older than 4.10. See PR +- external/20207. */ +- *addr_p = addr_orig; +- return true; +- } +- } +- +- return false; ++ return aarch64_stopped_data_address (state, addr_trap, addr_p); + } + + /* Implement the "stopped_by_watchpoint" target_ops method. */ +@@ -1030,15 +716,6 @@ aarch64_linux_nat_target::stopped_by_watchpoint () + return stopped_data_address (&addr); + } + +-/* Implement the "watchpoint_addr_within_range" target_ops method. */ +- +-bool +-aarch64_linux_nat_target::watchpoint_addr_within_range (CORE_ADDR addr, +- CORE_ADDR start, int length) +-{ +- return start <= addr && start + length - 1 >= addr; +-} +- + /* Implement the "can_do_single_step" target_ops method. */ + + int +@@ -1114,32 +791,11 @@ aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len, + return false; + } + +-/* Define AArch64 maintenance commands. */ +- +-static void +-add_show_debug_regs_command (void) +-{ +- /* A maintenance command to enable printing the internal DRi mirror +- variables. */ +- add_setshow_boolean_cmd ("show-debug-regs", class_maintenance, +- &show_debug_regs, _("\ +-Set whether to show variables that mirror the AArch64 debug registers."), _("\ +-Show whether to show variables that mirror the AArch64 debug registers."), _("\ +-Use \"on\" to enable, \"off\" to disable.\n\ +-If enabled, the debug registers values are shown when GDB inserts\n\ +-or removes a hardware breakpoint or watchpoint, and when the inferior\n\ +-triggers a breakpoint or watchpoint."), +- NULL, +- NULL, +- &maintenance_set_cmdlist, +- &maintenance_show_cmdlist); +-} +- + void _initialize_aarch64_linux_nat (); + void + _initialize_aarch64_linux_nat () + { +- add_show_debug_regs_command (); ++ aarch64_initialize_hw_point (); + + /* Register the target. */ + linux_target = &the_aarch64_linux_nat_target; +diff --git gdb/aarch64-nat.c gdb/aarch64-nat.c +new file mode 100644 +index 00000000000..85cf7f2011a +--- /dev/null ++++ gdb/aarch64-nat.c +@@ -0,0 +1,302 @@ ++/* Native-dependent code for AArch64. ++ ++ Copyright (C) 2011-2022 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 "inferior.h" ++#include "cli/cli-cmds.h" ++#include "aarch64-nat.h" ++ ++#include ++ ++/* Hash table storing per-process data. We don't bind this to a ++ per-inferior registry because of targets like x86 GNU/Linux that ++ need to keep track of processes that aren't bound to any inferior ++ (e.g., fork children, checkpoints). */ ++ ++static std::unordered_map ++aarch64_debug_process_state; ++ ++/* See aarch64-nat.h. */ ++ ++struct aarch64_debug_reg_state * ++aarch64_lookup_debug_reg_state (pid_t pid) ++{ ++ auto it = aarch64_debug_process_state.find (pid); ++ if (it != aarch64_debug_process_state.end ()) ++ return &it->second; ++ ++ return nullptr; ++} ++ ++/* See aarch64-nat.h. */ ++ ++struct aarch64_debug_reg_state * ++aarch64_get_debug_reg_state (pid_t pid) ++{ ++ return &aarch64_debug_process_state[pid]; ++} ++ ++/* See aarch64-nat.h. */ ++ ++void ++aarch64_remove_debug_reg_state (pid_t pid) ++{ ++ aarch64_debug_process_state.erase (pid); ++} ++ ++/* Returns the number of hardware watchpoints of type TYPE that we can ++ set. Value is positive if we can set CNT watchpoints, zero if ++ setting watchpoints of type TYPE is not supported, and negative if ++ CNT is more than the maximum number of watchpoints of type TYPE ++ that we can support. TYPE is one of bp_hardware_watchpoint, ++ bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint. ++ CNT is the number of such watchpoints used so far (including this ++ one). OTHERTYPE is non-zero if other types of watchpoints are ++ currently enabled. */ ++ ++int ++aarch64_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype) ++{ ++ if (type == bp_hardware_watchpoint || type == bp_read_watchpoint ++ || type == bp_access_watchpoint || type == bp_watchpoint) ++ { ++ if (aarch64_num_wp_regs == 0) ++ return 0; ++ } ++ else if (type == bp_hardware_breakpoint) ++ { ++ if (aarch64_num_bp_regs == 0) ++ return 0; ++ } ++ else ++ gdb_assert_not_reached ("unexpected breakpoint type"); ++ ++ /* We always return 1 here because we don't have enough information ++ about possible overlap of addresses that they want to watch. As an ++ extreme example, consider the case where all the watchpoints watch ++ the same address and the same region length: then we can handle a ++ virtually unlimited number of watchpoints, due to debug register ++ sharing implemented via reference counts. */ ++ return 1; ++} ++ ++/* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address. ++ Return 0 on success, -1 on failure. */ ++ ++int ++aarch64_insert_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt) ++{ ++ int ret; ++ CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address; ++ int len; ++ const enum target_hw_bp_type type = hw_execute; ++ struct aarch64_debug_reg_state *state ++ = aarch64_get_debug_reg_state (inferior_ptid.pid ()); ++ ++ gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); ++ ++ if (show_debug_regs) ++ fprintf_unfiltered ++ (gdb_stdlog, ++ "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", ++ (unsigned long) addr, len); ++ ++ ret = aarch64_handle_breakpoint (type, addr, len, 1 /* is_insert */, ++ inferior_ptid, state); ++ ++ if (show_debug_regs) ++ { ++ aarch64_show_debug_reg_state (state, ++ "insert_hw_breakpoint", addr, len, type); ++ } ++ ++ return ret; ++} ++ ++/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address. ++ Return 0 on success, -1 on failure. */ ++ ++int ++aarch64_remove_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt) ++{ ++ int ret; ++ CORE_ADDR addr = bp_tgt->placed_address; ++ int len = 4; ++ const enum target_hw_bp_type type = hw_execute; ++ struct aarch64_debug_reg_state *state ++ = aarch64_get_debug_reg_state (inferior_ptid.pid ()); ++ ++ gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); ++ ++ if (show_debug_regs) ++ fprintf_unfiltered ++ (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", ++ (unsigned long) addr, len); ++ ++ ret = aarch64_handle_breakpoint (type, addr, len, 0 /* is_insert */, ++ inferior_ptid, state); ++ ++ if (show_debug_regs) ++ { ++ aarch64_show_debug_reg_state (state, ++ "remove_hw_watchpoint", addr, len, type); ++ } ++ ++ return ret; ++} ++ ++/* Insert a watchpoint to watch a memory region which starts at ++ address ADDR and whose length is LEN bytes. Watch memory accesses ++ of the type TYPE. Return 0 on success, -1 on failure. */ ++ ++int ++aarch64_insert_watchpoint (CORE_ADDR addr, int len, enum target_hw_bp_type type, ++ struct expression *cond) ++{ ++ int ret; ++ struct aarch64_debug_reg_state *state ++ = aarch64_get_debug_reg_state (inferior_ptid.pid ()); ++ ++ if (show_debug_regs) ++ fprintf_unfiltered (gdb_stdlog, ++ "insert_watchpoint on entry (addr=0x%08lx, len=%d)\n", ++ (unsigned long) addr, len); ++ ++ gdb_assert (type != hw_execute); ++ ++ ret = aarch64_handle_watchpoint (type, addr, len, 1 /* is_insert */, ++ inferior_ptid, state); ++ ++ if (show_debug_regs) ++ { ++ aarch64_show_debug_reg_state (state, ++ "insert_watchpoint", addr, len, type); ++ } ++ ++ return ret; ++} ++ ++/* Remove a watchpoint that watched the memory region which starts at ++ address ADDR, whose length is LEN bytes, and for accesses of the ++ type TYPE. Return 0 on success, -1 on failure. */ ++ ++int ++aarch64_remove_watchpoint (CORE_ADDR addr, int len, enum target_hw_bp_type type, ++ struct expression *cond) ++{ ++ int ret; ++ struct aarch64_debug_reg_state *state ++ = aarch64_get_debug_reg_state (inferior_ptid.pid ()); ++ ++ if (show_debug_regs) ++ fprintf_unfiltered (gdb_stdlog, ++ "remove_watchpoint on entry (addr=0x%08lx, len=%d)\n", ++ (unsigned long) addr, len); ++ ++ gdb_assert (type != hw_execute); ++ ++ ret = aarch64_handle_watchpoint (type, addr, len, 0 /* is_insert */, ++ inferior_ptid, state); ++ ++ if (show_debug_regs) ++ { ++ aarch64_show_debug_reg_state (state, ++ "remove_watchpoint", addr, len, type); ++ } ++ ++ return ret; ++} ++ ++/* See aarch64-nat.h. */ ++ ++bool ++aarch64_stopped_data_address (const struct aarch64_debug_reg_state *state, ++ CORE_ADDR addr_trap, CORE_ADDR *addr_p) ++{ ++ int i; ++ ++ for (i = aarch64_num_wp_regs - 1; i >= 0; --i) ++ { ++ const unsigned int offset ++ = aarch64_watchpoint_offset (state->dr_ctrl_wp[i]); ++ const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); ++ const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset; ++ const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); ++ const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i]; ++ ++ if (state->dr_ref_count_wp[i] ++ && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i]) ++ && addr_trap >= addr_watch_aligned ++ && addr_trap < addr_watch + len) ++ { ++ /* ADDR_TRAP reports the first address of the memory range ++ accessed by the CPU, regardless of what was the memory ++ range watched. Thus, a large CPU access that straddles ++ the ADDR_WATCH..ADDR_WATCH+LEN range may result in an ++ ADDR_TRAP that is lower than the ++ ADDR_WATCH..ADDR_WATCH+LEN range. E.g.: ++ ++ addr: | 4 | 5 | 6 | 7 | 8 | ++ |---- range watched ----| ++ |----------- range accessed ------------| ++ ++ In this case, ADDR_TRAP will be 4. ++ ++ To match a watchpoint known to GDB core, we must never ++ report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN ++ range. ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false ++ positive on kernels older than 4.10. See PR ++ external/20207. */ ++ *addr_p = addr_orig; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* Define AArch64 maintenance commands. */ ++ ++static void ++add_show_debug_regs_command (void) ++{ ++ /* A maintenance command to enable printing the internal DRi mirror ++ variables. */ ++ add_setshow_boolean_cmd ("show-debug-regs", class_maintenance, ++ &show_debug_regs, _("\ ++Set whether to show variables that mirror the AArch64 debug registers."), _("\ ++Show whether to show variables that mirror the AArch64 debug registers."), _("\ ++Use \"on\" to enable, \"off\" to disable.\n\ ++If enabled, the debug registers values are shown when GDB inserts\n\ ++or removes a hardware breakpoint or watchpoint, and when the inferior\n\ ++triggers a breakpoint or watchpoint."), ++ NULL, ++ NULL, ++ &maintenance_set_cmdlist, ++ &maintenance_show_cmdlist); ++} ++ ++void ++aarch64_initialize_hw_point () ++{ ++ add_show_debug_regs_command (); ++} +diff --git gdb/aarch64-nat.h gdb/aarch64-nat.h +new file mode 100644 +index 00000000000..56e720f02ee +--- /dev/null ++++ gdb/aarch64-nat.h +@@ -0,0 +1,109 @@ ++/* Native-dependent code for AArch64. ++ ++ Copyright (C) 2011-2022 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 . */ ++ ++#ifndef AARCH64_NAT_H ++#define AARCH64_NAT_H ++ ++#include "breakpoint.h" ++#include "nat/aarch64-hw-point.h" ++#include "target.h" ++ ++/* Hardware-assisted breakpoints and watchpoints. */ ++ ++/* Initialize platform-independent state for hardware-assisted ++ breakpoints and watchpoints. */ ++ ++void aarch64_initialize_hw_point (); ++ ++/* Return the debug register state for process PID. If no existing ++ state is found for this process, return nullptr. */ ++ ++struct aarch64_debug_reg_state *aarch64_lookup_debug_reg_state (pid_t pid); ++ ++/* Return the debug register state for process PID. If no existing ++ state is found for this process, create new state. */ ++ ++struct aarch64_debug_reg_state *aarch64_get_debug_reg_state (pid_t pid); ++ ++/* Remove any existing per-process debug state for process PID. */ ++ ++void aarch64_remove_debug_reg_state (pid_t pid); ++ ++/* Helper for the "stopped_data_address" target method. Returns TRUE ++ if a hardware watchpoint trap at ADDR_TRAP matches a set ++ watchpoint. The address of the matched watchpoint is returned in ++ *ADDR_P. */ ++ ++bool aarch64_stopped_data_address (const struct aarch64_debug_reg_state *state, ++ CORE_ADDR addr_trap, CORE_ADDR *addr_p); ++ ++/* Helper functions used by aarch64_nat_target below. See their ++ definitions. */ ++ ++int aarch64_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype); ++int aarch64_insert_watchpoint (CORE_ADDR addr, int len, ++ enum target_hw_bp_type type, ++ struct expression *cond); ++int aarch64_remove_watchpoint (CORE_ADDR addr, int len, ++ enum target_hw_bp_type type, ++ struct expression *cond); ++int aarch64_insert_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt); ++int aarch64_remove_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt); ++int aarch64_stopped_by_hw_breakpoint (); ++ ++/* Convenience template mixin used to add aarch64 watchpoints support to a ++ target. */ ++ ++template ++struct aarch64_nat_target : public BaseTarget ++{ ++ /* Hook in common aarch64 hardware watchpoints/breakpoints support. */ ++ ++ int can_use_hw_breakpoint (enum bptype type, int cnt, int othertype) override ++ { return aarch64_can_use_hw_breakpoint (type, cnt, othertype); } ++ ++ int region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) override ++ { return aarch64_region_ok_for_watchpoint (addr, len); } ++ ++ int insert_watchpoint (CORE_ADDR addr, int len, ++ enum target_hw_bp_type type, ++ struct expression *cond) override ++ { return aarch64_insert_watchpoint (addr, len, type, cond); } ++ ++ int remove_watchpoint (CORE_ADDR addr, int len, ++ enum target_hw_bp_type type, ++ struct expression *cond) override ++ { return aarch64_remove_watchpoint (addr, len, type, cond); } ++ ++ int insert_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt) override ++ { return aarch64_insert_hw_breakpoint (gdbarch, bp_tgt); } ++ ++ int remove_hw_breakpoint (struct gdbarch *gdbarch, ++ struct bp_target_info *bp_tgt) override ++ { return aarch64_remove_hw_breakpoint (gdbarch, bp_tgt); } ++ ++ bool watchpoint_addr_within_range (CORE_ADDR addr, CORE_ADDR start, ++ int length) override ++ { return start <= addr && start + length - 1 >= addr; } ++}; ++ ++#endif /* AARCH64_NAT_H */ +diff --git gdb/configure.nat gdb/configure.nat +index ad6d35babc2..4f5850dd595 100644 +--- gdb/configure.nat ++++ gdb/configure.nat +@@ -233,7 +233,7 @@ case ${gdb_host} in + case ${gdb_host_cpu} in + aarch64) + # Host: AArch64 based machine running GNU/Linux +- NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \ ++ NATDEPFILES="${NATDEPFILES} aarch64-nat.o aarch64-linux-nat.o \ + aarch32-linux-nat.o nat/aarch64-hw-point.o \ + nat/aarch64-linux-hw-point.o \ + nat/aarch64-linux.o \ Index: devel/gdb/files/commit-2e686a74dc4 =================================================================== --- /dev/null +++ devel/gdb/files/commit-2e686a74dc4 @@ -0,0 +1,68 @@ +commit a2915c914b21b07ab7916da71fc69297168d6878 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Support TLS variables on FreeBSD/arm. + + Derive the pointer to the DTV array from the tpidruro register. + + (cherry picked from commit 2e686a74dc4782caeef75f76174909ab7ad358f8) + +diff --git gdb/arm-fbsd-tdep.c gdb/arm-fbsd-tdep.c +index a27dfb2fb4a..483820c1092 100644 +--- gdb/arm-fbsd-tdep.c ++++ gdb/arm-fbsd-tdep.c +@@ -27,6 +27,7 @@ + #include "auxv.h" + #include "fbsd-tdep.h" + #include "gdbcore.h" ++#include "inferior.h" + #include "osabi.h" + #include "solib-svr4.h" + #include "trad-frame.h" +@@ -226,6 +227,30 @@ arm_fbsd_core_read_description (struct gdbarch *gdbarch, + return arm_fbsd_read_description_auxv (target, tls != nullptr); + } + ++/* Implement the get_thread_local_address gdbarch method. */ ++ ++static CORE_ADDR ++arm_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ struct regcache *regcache; ++ ++ regcache = get_thread_arch_regcache (current_inferior ()->process_target (), ++ ptid, gdbarch); ++ ++ target_fetch_registers (regcache, tdep->tls_regnum); ++ ++ ULONGEST tpidruro; ++ if (regcache->cooked_read (tdep->tls_regnum, &tpidruro) != REG_VALID) ++ error (_("Unable to fetch %%tpidruro")); ++ ++ /* %tpidruro points to the TCB whose first member is the dtv ++ pointer. */ ++ CORE_ADDR dtv_addr = tpidruro; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} ++ + /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + + static void +@@ -251,6 +276,14 @@ arm_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + (gdbarch, arm_fbsd_iterate_over_regset_sections); + set_gdbarch_core_read_description (gdbarch, arm_fbsd_core_read_description); + ++ if (tdep->tls_regnum > 0) ++ { ++ set_gdbarch_fetch_tls_load_module_address (gdbarch, ++ svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address (gdbarch, ++ arm_fbsd_get_thread_local_address); ++ } ++ + /* Single stepping. */ + set_gdbarch_software_single_step (gdbarch, arm_software_single_step); + } Index: devel/gdb/files/commit-3181aed81c9 =================================================================== --- /dev/null +++ devel/gdb/files/commit-3181aed81c9 @@ -0,0 +1,20 @@ +commit e5cfae026a00128719b409beeb03fb58c105fdae +Author: John Baldwin +Date: Fri Apr 1 15:21:09 2022 -0700 + + Remove unused variable. + + (cherry picked from commit 3181aed81c92d091f5313df5dee27a9376dc1cce) + +diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c +index d50f35707ee..d68498cd5e9 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -347,7 +347,6 @@ static CORE_ADDR + i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, + CORE_ADDR lm_addr, CORE_ADDR offset) + { +- i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); + struct regcache *regcache; + + regcache = get_thread_arch_regcache (current_inferior ()->process_target (), Index: devel/gdb/files/commit-40c23d88038 =================================================================== --- /dev/null +++ devel/gdb/files/commit-40c23d88038 @@ -0,0 +1,163 @@ +commit e4b141663b47f26ef84a6716e53731bb0debfdf4 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + fbsd-nat: Add helper routines for register sets using PT_[G]SETREGSET. + + FreeBSD's kernel has recently added PT_GETREGSET and PT_SETREGSET + operations to fetch a register set named by an ELF note type. These + helper routines provide helpers to check for a register set's + existence, fetch registers for a register set, and store registers to + a register set. + + (cherry picked from commit 40c23d880386d6e8202567eaa2a6b041feb1a652) + +diff --git gdb/fbsd-nat.c gdb/fbsd-nat.c +index 934fdbad6ef..9dfbd599c92 100644 +--- gdb/fbsd-nat.c ++++ gdb/fbsd-nat.c +@@ -49,6 +49,11 @@ + + #include + ++#ifndef PT_GETREGSET ++#define PT_GETREGSET 42 /* Get a target register set */ ++#define PT_SETREGSET 43 /* Set a target register set */ ++#endif ++ + /* Return the name of a file that can be opened to get the symbols for + the child process identified by PID. */ + +@@ -1774,6 +1779,76 @@ fbsd_nat_target::store_register_set (struct regcache *regcache, int regnum, + + /* See fbsd-nat.h. */ + ++bool ++fbsd_nat_target::have_regset (ptid_t ptid, int note) ++{ ++ pid_t pid = get_ptrace_pid (ptid); ++ struct iovec iov; ++ ++ iov.iov_base = nullptr; ++ iov.iov_len = 0; ++ if (ptrace (PT_GETREGSET, pid, (PTRACE_TYPE_ARG3) &iov, note) == -1) ++ return 0; ++ return iov.iov_len; ++} ++ ++/* See fbsd-nat.h. */ ++ ++bool ++fbsd_nat_target::fetch_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset, void *regs, ++ size_t size) ++{ ++ const struct regcache_map_entry *map ++ = (const struct regcache_map_entry *) regset->regmap; ++ pid_t pid = get_ptrace_pid (regcache->ptid ()); ++ ++ if (regnum == -1 || regcache_map_supplies (map, regnum, regcache->arch(), ++ size)) ++ { ++ struct iovec iov; ++ ++ iov.iov_base = regs; ++ iov.iov_len = size; ++ if (ptrace (PT_GETREGSET, pid, (PTRACE_TYPE_ARG3) &iov, note) == -1) ++ perror_with_name (_("Couldn't get registers")); ++ ++ regcache->supply_regset (regset, regnum, regs, size); ++ return true; ++ } ++ return false; ++} ++ ++bool ++fbsd_nat_target::store_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset, void *regs, ++ size_t size) ++{ ++ const struct regcache_map_entry *map ++ = (const struct regcache_map_entry *) regset->regmap; ++ pid_t pid = get_ptrace_pid (regcache->ptid ()); ++ ++ if (regnum == -1 || regcache_map_supplies (map, regnum, regcache->arch(), ++ size)) ++ { ++ struct iovec iov; ++ ++ iov.iov_base = regs; ++ iov.iov_len = size; ++ if (ptrace (PT_GETREGSET, pid, (PTRACE_TYPE_ARG3) &iov, note) == -1) ++ perror_with_name (_("Couldn't get registers")); ++ ++ regcache->collect_regset (regset, regnum, regs, size); ++ ++ if (ptrace (PT_SETREGSET, pid, (PTRACE_TYPE_ARG3) &iov, note) == -1) ++ perror_with_name (_("Couldn't write registers")); ++ return true; ++ } ++ return false; ++} ++ ++/* See fbsd-nat.h. */ ++ + bool + fbsd_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo) + { +diff --git gdb/fbsd-nat.h gdb/fbsd-nat.h +index 82f7ee47949..ba359c62314 100644 +--- gdb/fbsd-nat.h ++++ gdb/fbsd-nat.h +@@ -151,6 +151,17 @@ class fbsd_nat_target : public inf_ptrace_target + bool store_register_set (struct regcache *regcache, int regnum, int fetch_op, + int store_op, const struct regset *regset, + void *regs, size_t size); ++ ++ /* Helper routines which use PT_GETREGSET and PT_SETREGSET for the ++ specified NOTE instead of regset-specific fetch and store ++ ops. */ ++ ++ bool fetch_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset, void *regs, size_t size); ++ ++ bool store_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset, void *regs, size_t size); ++ + protected: + /* Wrapper versions of the above helpers which accept a register set + type such as 'struct reg' or 'struct fpreg'. */ +@@ -172,6 +183,33 @@ class fbsd_nat_target : public inf_ptrace_target + return store_register_set (regcache, regnum, fetch_op, store_op, regset, + ®s, sizeof (regs)); + } ++ ++ /* Helper routine for use in read_description in subclasses. This ++ routine checks if the register set for the specified NOTE is ++ present for a given PTID. If the register set is present, the ++ the size of the register set is returned. If the register set is ++ not present, zero is returned. */ ++ ++ bool have_regset (ptid_t ptid, int note); ++ ++ /* Wrapper versions of the PT_GETREGSET and PT_REGSET helpers which ++ accept a register set type. */ ++ ++ template ++ bool fetch_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset) ++ { ++ Regset regs; ++ return fetch_regset (regcache, regnum, note, regset, ®s, sizeof (regs)); ++ } ++ ++ template ++ bool store_regset (struct regcache *regcache, int regnum, int note, ++ const struct regset *regset) ++ { ++ Regset regs; ++ return store_regset (regcache, regnum, note, regset, ®s, sizeof (regs)); ++ } + }; + + /* Fetch the signal information for PTID and store it in *SIGINFO. Index: devel/gdb/files/commit-414d5848bb2 =================================================================== --- /dev/null +++ devel/gdb/files/commit-414d5848bb2 @@ -0,0 +1,293 @@ +commit 697c5583d89eacc2d61648549df4276ad34f4ec1 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Add an aarch64-tls feature which includes the tpidr register. + + (cherry picked from commit 414d5848bb2766ea7cef162c6ef5862ddb4dfe0f) + +diff --git gdb/aarch64-linux-nat.c gdb/aarch64-linux-nat.c +index 7bb82d17cc8..4da274c285a 100644 +--- gdb/aarch64-linux-nat.c ++++ gdb/aarch64-linux-nat.c +@@ -646,7 +646,8 @@ aarch64_linux_nat_target::read_description () + bool pauth_p = hwcap & AARCH64_HWCAP_PACA; + bool mte_p = hwcap2 & HWCAP2_MTE; + +- return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, mte_p); ++ return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, mte_p, ++ false); + } + + /* Convert a native/host siginfo object, into/from the siginfo in the +diff --git gdb/aarch64-linux-tdep.c gdb/aarch64-linux-tdep.c +index cb132d5a540..f5aac7bc0b4 100644 +--- gdb/aarch64-linux-tdep.c ++++ gdb/aarch64-linux-tdep.c +@@ -763,7 +763,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, + bool pauth_p = hwcap & AARCH64_HWCAP_PACA; + bool mte_p = hwcap2 & HWCAP2_MTE; + return aarch64_read_description (aarch64_linux_core_read_vq (gdbarch, abfd), +- pauth_p, mte_p); ++ pauth_p, mte_p, false); + } + + /* Implementation of `gdbarch_stap_is_single_operand', as defined in +diff --git gdb/aarch64-tdep.c gdb/aarch64-tdep.c +index b714f6194b6..c193234eb91 100644 +--- gdb/aarch64-tdep.c ++++ gdb/aarch64-tdep.c +@@ -58,7 +58,7 @@ + #define HA_MAX_NUM_FLDS 4 + + /* All possible aarch64 target descriptors. */ +-static target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/][2 /* mte */]; ++static target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/][2 /* mte */][2 /* tls */]; + + /* The standard register names, and all the valid aliases for them. */ + static const struct +@@ -3327,21 +3327,23 @@ aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch) + If VQ is zero then it is assumed SVE is not supported. + (It is not possible to set VQ to zero on an SVE system). + +- MTE_P indicates the presence of the Memory Tagging Extension feature. */ ++ MTE_P indicates the presence of the Memory Tagging Extension feature. ++ ++ TLS_P indicates the presence of the Thread Local Storage feature. */ + + const target_desc * +-aarch64_read_description (uint64_t vq, bool pauth_p, bool mte_p) ++aarch64_read_description (uint64_t vq, bool pauth_p, bool mte_p, bool tls_p) + { + if (vq > AARCH64_MAX_SVE_VQ) + error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq, + AARCH64_MAX_SVE_VQ); + +- struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p][mte_p]; ++ struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p][mte_p][tls_p]; + + if (tdesc == NULL) + { +- tdesc = aarch64_create_target_description (vq, pauth_p, mte_p); +- tdesc_aarch64_list[vq][pauth_p][mte_p] = tdesc; ++ tdesc = aarch64_create_target_description (vq, pauth_p, mte_p, tls_p); ++ tdesc_aarch64_list[vq][pauth_p][mte_p][tls_p] = tdesc; + } + + return tdesc; +@@ -3430,7 +3432,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + bool valid_p = true; + int i, num_regs = 0, num_pseudo_regs = 0; + int first_pauth_regnum = -1, pauth_ra_state_offset = -1; +- int first_mte_regnum = -1; ++ int first_mte_regnum = -1, tls_regnum = -1; + + /* Use the vector length passed via the target info. Here -1 is used for no + SVE, and 0 is unset. If unset then use the vector length from the existing +@@ -3462,7 +3464,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + value. */ + const struct target_desc *tdesc = info.target_desc; + if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc)) +- tdesc = aarch64_read_description (vq, false, false); ++ tdesc = aarch64_read_description (vq, false, false, false); + gdb_assert (tdesc); + + feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core"); +@@ -3471,6 +3473,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth"); + const struct tdesc_feature *feature_mte + = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte"); ++ const struct tdesc_feature *feature_tls ++ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls"); + + if (feature_core == nullptr) + return nullptr; +@@ -3525,6 +3529,18 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + num_pseudo_regs += 32; /* add the Bn scalar register pseudos */ + } + ++ /* Add the TLS register. */ ++ if (feature_tls != nullptr) ++ { ++ tls_regnum = num_regs; ++ /* Validate the descriptor provides the mandatory TLS register ++ and allocate its number. */ ++ valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (), ++ tls_regnum, "tpidr"); ++ ++ num_regs++; ++ } ++ + /* Add the pauth registers. */ + if (feature_pauth != NULL) + { +@@ -3573,6 +3589,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1 + : pauth_ra_state_offset + num_regs; + tdep->mte_reg_base = first_mte_regnum; ++ tdep->tls_regnum = tls_regnum; + + set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call); + set_gdbarch_frame_align (gdbarch, aarch64_frame_align); +diff --git gdb/aarch64-tdep.h gdb/aarch64-tdep.h +index 60a9d5a29c2..e4cdebb6311 100644 +--- gdb/aarch64-tdep.h ++++ gdb/aarch64-tdep.h +@@ -111,10 +111,18 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep + { + return mte_reg_base != -1; + } ++ ++ /* TLS register. This is -1 if the TLS register is not available. */ ++ int tls_regnum = 0; ++ ++ bool has_tls() const ++ { ++ return tls_regnum != -1; ++ } + }; + + const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p, +- bool mte_p); ++ bool mte_p, bool tls_p); + + extern int aarch64_process_record (struct gdbarch *gdbarch, + struct regcache *regcache, CORE_ADDR addr); +diff --git gdb/arch/aarch64.c gdb/arch/aarch64.c +index 485d667ccde..733a3fd6d2a 100644 +--- gdb/arch/aarch64.c ++++ gdb/arch/aarch64.c +@@ -24,11 +24,13 @@ + #include "../features/aarch64-sve.c" + #include "../features/aarch64-pauth.c" + #include "../features/aarch64-mte.c" ++#include "../features/aarch64-tls.c" + + /* See arch/aarch64.h. */ + + target_desc * +-aarch64_create_target_description (uint64_t vq, bool pauth_p, bool mte_p) ++aarch64_create_target_description (uint64_t vq, bool pauth_p, bool mte_p, ++ bool tls_p) + { + target_desc_up tdesc = allocate_target_description (); + +@@ -52,5 +54,8 @@ aarch64_create_target_description (uint64_t vq, bool pauth_p, bool mte_p) + if (mte_p) + regnum = create_feature_aarch64_mte (tdesc.get (), regnum); + ++ if (tls_p) ++ regnum = create_feature_aarch64_tls (tdesc.get (), regnum); ++ + return tdesc.release (); + } +diff --git gdb/arch/aarch64.h gdb/arch/aarch64.h +index e416e346e9a..8496a0341f7 100644 +--- gdb/arch/aarch64.h ++++ gdb/arch/aarch64.h +@@ -29,6 +29,7 @@ struct aarch64_features + bool sve = false; + bool pauth = false; + bool mte = false; ++ bool tls = false; + }; + + /* Create the aarch64 target description. A non zero VQ value indicates both +@@ -36,10 +37,12 @@ struct aarch64_features + an SVE Z register. HAS_PAUTH_P indicates the presence of the PAUTH + feature. + +- MTE_P indicates the presence of the Memory Tagging Extension feature. */ ++ MTE_P indicates the presence of the Memory Tagging Extension feature. ++ ++ TLS_P indicates the presence of the Thread Local Storage feature. */ + + target_desc *aarch64_create_target_description (uint64_t vq, bool has_pauth_p, +- bool mte_p); ++ bool mte_p, bool tls_p); + + /* Register numbers of various important registers. + Note that on SVE, the Z registers reuse the V register numbers and the V +@@ -91,6 +94,7 @@ enum aarch64_regnum + #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1 + #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1 + ++#define AARCH64_TLS_REGS_SIZE (8) + + /* There are a number of ways of expressing the current SVE vector size: + +diff --git gdb/features/Makefile gdb/features/Makefile +index 4b09819389a..946ec983df5 100644 +--- gdb/features/Makefile ++++ gdb/features/Makefile +@@ -198,6 +198,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ + aarch64-fpu.xml \ + aarch64-pauth.xml \ + aarch64-mte.xml \ ++ aarch64-tls.xml \ + arc/v1-core.xml \ + arc/v1-aux.xml \ + arc/v2-core.xml \ +diff --git gdb/features/aarch64-tls.c gdb/features/aarch64-tls.c +new file mode 100644 +index 00000000000..30d730dffba +--- /dev/null ++++ gdb/features/aarch64-tls.c +@@ -0,0 +1,14 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: aarch64-tls.xml */ ++ ++#include "gdbsupport/tdesc.h" ++ ++static int ++create_feature_aarch64_tls (struct target_desc *result, long regnum) ++{ ++ struct tdesc_feature *feature; ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls"); ++ tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr"); ++ return regnum; ++} +diff --git gdb/features/aarch64-tls.xml gdb/features/aarch64-tls.xml +new file mode 100644 +index 00000000000..f6437785f71 +--- /dev/null ++++ gdb/features/aarch64-tls.xml +@@ -0,0 +1,11 @@ ++ ++ ++ ++ ++ ++ ++ +diff --git gdbserver/linux-aarch64-tdesc.cc gdbserver/linux-aarch64-tdesc.cc +index e982ab85067..14d6a4f80eb 100644 +--- gdbserver/linux-aarch64-tdesc.cc ++++ gdbserver/linux-aarch64-tdesc.cc +@@ -42,7 +42,7 @@ aarch64_linux_read_description (uint64_t vq, bool pauth_p, bool mte_p) + + if (tdesc == NULL) + { +- tdesc = aarch64_create_target_description (vq, pauth_p, mte_p); ++ tdesc = aarch64_create_target_description (vq, pauth_p, mte_p, false); + + static const char *expedite_regs_aarch64[] = { "x29", "sp", "pc", NULL }; + static const char *expedite_regs_aarch64_sve[] = { "x29", "sp", "pc", +diff --git gdbserver/netbsd-aarch64-low.cc gdbserver/netbsd-aarch64-low.cc +index 202bf1cdac6..b371e599232 100644 +--- gdbserver/netbsd-aarch64-low.cc ++++ gdbserver/netbsd-aarch64-low.cc +@@ -96,7 +96,7 @@ void + netbsd_aarch64_target::low_arch_setup () + { + target_desc *tdesc +- = aarch64_create_target_description (0, false); ++ = aarch64_create_target_description (0, false, false, false); + + static const char *expedite_regs_aarch64[] = { "x29", "sp", "pc", NULL }; + init_target_desc (tdesc, expedite_regs_aarch64); Index: devel/gdb/files/commit-4bd817e71ee =================================================================== --- /dev/null +++ devel/gdb/files/commit-4bd817e71ee @@ -0,0 +1,1726 @@ +commit 9ea194902df6599ae8f4096fe0426feae12cd7ab +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + nat: Split out platform-independent aarch64 debug register support. + + Move non-Linux-specific support for hardware break/watchpoints from + nat/aarch64-linux-hw-point.c to nat/aarch64-hw-point.c. Changes + beyond a simple split of the code are: + + - aarch64_linux_region_ok_for_watchpoint and + aarch64_linux_any_set_debug_regs_state renamed to drop linux_ as + they are not platform specific. + + - Platforms must implement the aarch64_notify_debug_reg_change + function which is invoked from the platform-independent code when a + debug register changes for a given debug register state. This does + not use the indirection of a 'low' structure as is done for x86. + + - The handling for kernel_supports_any_contiguous_range is not + pristine. For non-Linux it is simply defined to true. Some uses of + this could perhaps be implemented as new 'low' routines for the + various places that check it instead? + + - Pass down ptid into aarch64_handle_breakpoint and + aarch64_handle_watchpoint rather than using current_lwp_ptid which + is only defined on Linux. In addition, pass the ptid on to + aarch64_notify_debug_reg_change instead of the unused state + argument. + + (cherry picked from commit 4bd817e71eefd659f51ec75bfb13109c486e8311) + +diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c +index db764975207..dd072d9315e 100644 +--- gdb/aarch64-linux-nat.c ++++ gdb/aarch64-linux-nat.c +@@ -834,7 +834,8 @@ aarch64_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch, + "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", + (unsigned long) addr, len); + +- ret = aarch64_handle_breakpoint (type, addr, len, 1 /* is_insert */, state); ++ ret = aarch64_handle_breakpoint (type, addr, len, 1 /* is_insert */, ++ inferior_ptid, state); + + if (show_debug_regs) + { +@@ -866,7 +867,8 @@ aarch64_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch, + (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", + (unsigned long) addr, len); + +- ret = aarch64_handle_breakpoint (type, addr, len, 0 /* is_insert */, state); ++ ret = aarch64_handle_breakpoint (type, addr, len, 0 /* is_insert */, ++ inferior_ptid, state); + + if (show_debug_regs) + { +@@ -899,7 +901,8 @@ aarch64_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len, + + gdb_assert (type != hw_execute); + +- ret = aarch64_handle_watchpoint (type, addr, len, 1 /* is_insert */, state); ++ ret = aarch64_handle_watchpoint (type, addr, len, 1 /* is_insert */, ++ inferior_ptid, state); + + if (show_debug_regs) + { +@@ -931,7 +934,8 @@ aarch64_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len, + + gdb_assert (type != hw_execute); + +- ret = aarch64_handle_watchpoint (type, addr, len, 0 /* is_insert */, state); ++ ret = aarch64_handle_watchpoint (type, addr, len, 0 /* is_insert */, ++ inferior_ptid, state); + + if (show_debug_regs) + { +@@ -947,7 +951,7 @@ aarch64_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len, + int + aarch64_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) + { +- return aarch64_linux_region_ok_for_watchpoint (addr, len); ++ return aarch64_region_ok_for_watchpoint (addr, len); + } + + /* Implement the "stopped_data_address" target_ops method. */ +diff --git a/gdb/configure.nat b/gdb/configure.nat +index 92ad4a6522b..ad6d35babc2 100644 +--- gdb/configure.nat ++++ gdb/configure.nat +@@ -234,7 +234,8 @@ case ${gdb_host} in + aarch64) + # Host: AArch64 based machine running GNU/Linux + NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \ +- aarch32-linux-nat.o nat/aarch64-linux-hw-point.o \ ++ aarch32-linux-nat.o nat/aarch64-hw-point.o \ ++ nat/aarch64-linux-hw-point.o \ + nat/aarch64-linux.o \ + nat/aarch64-sve-linux-ptrace.o \ + nat/aarch64-mte-linux-ptrace.o" +diff --git a/gdb/nat/aarch64-hw-point.c b/gdb/nat/aarch64-hw-point.c +new file mode 100644 +index 00000000000..f0418f7eef8 +--- /dev/null ++++ gdb/nat/aarch64-hw-point.c +@@ -0,0 +1,624 @@ ++/* Copyright (C) 2009-2022 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 "gdbsupport/common-defs.h" ++#include "gdbsupport/break-common.h" ++#include "gdbsupport/common-regcache.h" ++#include "aarch64-hw-point.h" ++ ++#ifdef __linux__ ++/* For kernel_supports_any_contiguous_range. */ ++#include "aarch64-linux-hw-point.h" ++#else ++#define kernel_supports_any_contiguous_range true ++#endif ++ ++/* Number of hardware breakpoints/watchpoints the target supports. ++ They are initialized with values obtained via ptrace. */ ++ ++int aarch64_num_bp_regs; ++int aarch64_num_wp_regs; ++ ++/* Return starting byte 0..7 incl. of a watchpoint encoded by CTRL. */ ++ ++unsigned int ++aarch64_watchpoint_offset (unsigned int ctrl) ++{ ++ uint8_t mask = DR_CONTROL_MASK (ctrl); ++ unsigned retval; ++ ++ /* Shift out bottom zeros. */ ++ for (retval = 0; mask && (mask & 1) == 0; ++retval) ++ mask >>= 1; ++ ++ return retval; ++} ++ ++/* Utility function that returns the length in bytes of a watchpoint ++ according to the content of a hardware debug control register CTRL. ++ Any contiguous range of bytes in CTRL is supported. The returned ++ value can be between 0..8 (inclusive). */ ++ ++unsigned int ++aarch64_watchpoint_length (unsigned int ctrl) ++{ ++ uint8_t mask = DR_CONTROL_MASK (ctrl); ++ unsigned retval; ++ ++ /* Shift out bottom zeros. */ ++ mask >>= aarch64_watchpoint_offset (ctrl); ++ ++ /* Count bottom ones. */ ++ for (retval = 0; (mask & 1) != 0; ++retval) ++ mask >>= 1; ++ ++ if (mask != 0) ++ error (_("Unexpected hardware watchpoint length register value 0x%x"), ++ DR_CONTROL_MASK (ctrl)); ++ ++ return retval; ++} ++ ++/* Given the hardware breakpoint or watchpoint type TYPE and its ++ length LEN, return the expected encoding for a hardware ++ breakpoint/watchpoint control register. */ ++ ++static unsigned int ++aarch64_point_encode_ctrl_reg (enum target_hw_bp_type type, int offset, int len) ++{ ++ unsigned int ctrl, ttype; ++ ++ gdb_assert (offset == 0 || kernel_supports_any_contiguous_range); ++ gdb_assert (offset + len <= AARCH64_HWP_MAX_LEN_PER_REG); ++ ++ /* type */ ++ switch (type) ++ { ++ case hw_write: ++ ttype = 2; ++ break; ++ case hw_read: ++ ttype = 1; ++ break; ++ case hw_access: ++ ttype = 3; ++ break; ++ case hw_execute: ++ ttype = 0; ++ break; ++ default: ++ perror_with_name (_("Unrecognized breakpoint/watchpoint type")); ++ } ++ ++ ctrl = ttype << 3; ++ ++ /* offset and length bitmask */ ++ ctrl |= ((1 << len) - 1) << (5 + offset); ++ /* enabled at el0 */ ++ ctrl |= (2 << 1) | 1; ++ ++ return ctrl; ++} ++ ++/* Addresses to be written to the hardware breakpoint and watchpoint ++ value registers need to be aligned; the alignment is 4-byte and ++ 8-type respectively. Linux kernel rejects any non-aligned address ++ it receives from the related ptrace call. Furthermore, the kernel ++ currently only supports the following Byte Address Select (BAS) ++ values: 0x1, 0x3, 0xf and 0xff, which means that for a hardware ++ watchpoint to be accepted by the kernel (via ptrace call), its ++ valid length can only be 1 byte, 2 bytes, 4 bytes or 8 bytes. ++ Despite these limitations, the unaligned watchpoint is supported in ++ this port. ++ ++ Return 0 for any non-compliant ADDR and/or LEN; return 1 otherwise. */ ++ ++static int ++aarch64_point_is_aligned (ptid_t ptid, int is_watchpoint, CORE_ADDR addr, ++ int len) ++{ ++ unsigned int alignment = 0; ++ ++ if (is_watchpoint) ++ alignment = AARCH64_HWP_ALIGNMENT; ++ else ++ { ++ struct regcache *regcache ++ = get_thread_regcache_for_ptid (ptid); ++ ++ /* Set alignment to 2 only if the current process is 32-bit, ++ since thumb instruction can be 2-byte aligned. Otherwise, set ++ alignment to AARCH64_HBP_ALIGNMENT. */ ++ if (regcache_register_size (regcache, 0) == 8) ++ alignment = AARCH64_HBP_ALIGNMENT; ++ else ++ alignment = 2; ++ } ++ ++ if (addr & (alignment - 1)) ++ return 0; ++ ++ if ((!kernel_supports_any_contiguous_range ++ && len != 8 && len != 4 && len != 2 && len != 1) ++ || (kernel_supports_any_contiguous_range ++ && (len < 1 || len > 8))) ++ return 0; ++ ++ return 1; ++} ++ ++/* Given the (potentially unaligned) watchpoint address in ADDR and ++ length in LEN, return the aligned address, offset from that base ++ address, and aligned length in *ALIGNED_ADDR_P, *ALIGNED_OFFSET_P ++ and *ALIGNED_LEN_P, respectively. The returned values will be ++ valid values to write to the hardware watchpoint value and control ++ registers. ++ ++ The given watchpoint may get truncated if more than one hardware ++ register is needed to cover the watched region. *NEXT_ADDR_P ++ and *NEXT_LEN_P, if non-NULL, will return the address and length ++ of the remaining part of the watchpoint (which can be processed ++ by calling this routine again to generate another aligned address, ++ offset and length tuple. ++ ++ Essentially, unaligned watchpoint is achieved by minimally ++ enlarging the watched area to meet the alignment requirement, and ++ if necessary, splitting the watchpoint over several hardware ++ watchpoint registers. ++ ++ On kernels that predate the support for Byte Address Select (BAS) ++ in the hardware watchpoint control register, the offset from the ++ base address is always zero, and so in that case the trade-off is ++ that there will be false-positive hits for the read-type or the ++ access-type hardware watchpoints; for the write type, which is more ++ commonly used, there will be no such issues, as the higher-level ++ breakpoint management in gdb always examines the exact watched ++ region for any content change, and transparently resumes a thread ++ from a watchpoint trap if there is no change to the watched region. ++ ++ Another limitation is that because the watched region is enlarged, ++ the watchpoint fault address discovered by ++ aarch64_stopped_data_address may be outside of the original watched ++ region, especially when the triggering instruction is accessing a ++ larger region. When the fault address is not within any known ++ range, watchpoints_triggered in gdb will get confused, as the ++ higher-level watchpoint management is only aware of original ++ watched regions, and will think that some unknown watchpoint has ++ been triggered. To prevent such a case, ++ aarch64_stopped_data_address implementations in gdb and gdbserver ++ try to match the trapped address with a watched region, and return ++ an address within the latter. */ ++ ++static void ++aarch64_align_watchpoint (CORE_ADDR addr, int len, CORE_ADDR *aligned_addr_p, ++ int *aligned_offset_p, int *aligned_len_p, ++ CORE_ADDR *next_addr_p, int *next_len_p, ++ CORE_ADDR *next_addr_orig_p) ++{ ++ int aligned_len; ++ unsigned int offset, aligned_offset; ++ CORE_ADDR aligned_addr; ++ const unsigned int alignment = AARCH64_HWP_ALIGNMENT; ++ const unsigned int max_wp_len = AARCH64_HWP_MAX_LEN_PER_REG; ++ ++ /* As assumed by the algorithm. */ ++ gdb_assert (alignment == max_wp_len); ++ ++ if (len <= 0) ++ return; ++ ++ /* The address put into the hardware watchpoint value register must ++ be aligned. */ ++ offset = addr & (alignment - 1); ++ aligned_addr = addr - offset; ++ aligned_offset ++ = kernel_supports_any_contiguous_range ? addr & (alignment - 1) : 0; ++ ++ gdb_assert (offset >= 0 && offset < alignment); ++ gdb_assert (aligned_addr >= 0 && aligned_addr <= addr); ++ gdb_assert (offset + len > 0); ++ ++ if (offset + len >= max_wp_len) ++ { ++ /* Need more than one watchpoint register; truncate at the ++ alignment boundary. */ ++ aligned_len ++ = max_wp_len - (kernel_supports_any_contiguous_range ? offset : 0); ++ len -= (max_wp_len - offset); ++ addr += (max_wp_len - offset); ++ gdb_assert ((addr & (alignment - 1)) == 0); ++ } ++ else ++ { ++ /* Find the smallest valid length that is large enough to ++ accommodate this watchpoint. */ ++ static const unsigned char ++ aligned_len_array[AARCH64_HWP_MAX_LEN_PER_REG] = ++ { 1, 2, 4, 4, 8, 8, 8, 8 }; ++ ++ aligned_len = (kernel_supports_any_contiguous_range ++ ? len : aligned_len_array[offset + len - 1]); ++ addr += len; ++ len = 0; ++ } ++ ++ if (aligned_addr_p) ++ *aligned_addr_p = aligned_addr; ++ if (aligned_offset_p) ++ *aligned_offset_p = aligned_offset; ++ if (aligned_len_p) ++ *aligned_len_p = aligned_len; ++ if (next_addr_p) ++ *next_addr_p = addr; ++ if (next_len_p) ++ *next_len_p = len; ++ if (next_addr_orig_p) ++ *next_addr_orig_p = align_down (*next_addr_orig_p + alignment, alignment); ++} ++ ++/* Record the insertion of one breakpoint/watchpoint, as represented ++ by ADDR and CTRL, in the process' arch-specific data area *STATE. */ ++ ++static int ++aarch64_dr_state_insert_one_point (ptid_t ptid, ++ struct aarch64_debug_reg_state *state, ++ enum target_hw_bp_type type, ++ CORE_ADDR addr, int offset, int len, ++ CORE_ADDR addr_orig) ++{ ++ int i, idx, num_regs, is_watchpoint; ++ unsigned int ctrl, *dr_ctrl_p, *dr_ref_count; ++ CORE_ADDR *dr_addr_p, *dr_addr_orig_p; ++ ++ /* Set up state pointers. */ ++ is_watchpoint = (type != hw_execute); ++ gdb_assert (aarch64_point_is_aligned (ptid, is_watchpoint, addr, len)); ++ if (is_watchpoint) ++ { ++ num_regs = aarch64_num_wp_regs; ++ dr_addr_p = state->dr_addr_wp; ++ dr_addr_orig_p = state->dr_addr_orig_wp; ++ dr_ctrl_p = state->dr_ctrl_wp; ++ dr_ref_count = state->dr_ref_count_wp; ++ } ++ else ++ { ++ num_regs = aarch64_num_bp_regs; ++ dr_addr_p = state->dr_addr_bp; ++ dr_addr_orig_p = nullptr; ++ dr_ctrl_p = state->dr_ctrl_bp; ++ dr_ref_count = state->dr_ref_count_bp; ++ } ++ ++ ctrl = aarch64_point_encode_ctrl_reg (type, offset, len); ++ ++ /* Find an existing or free register in our cache. */ ++ idx = -1; ++ for (i = 0; i < num_regs; ++i) ++ { ++ if ((dr_ctrl_p[i] & 1) == 0) ++ { ++ gdb_assert (dr_ref_count[i] == 0); ++ idx = i; ++ /* no break; continue hunting for an exising one. */ ++ } ++ else if (dr_addr_p[i] == addr ++ && (dr_addr_orig_p == nullptr || dr_addr_orig_p[i] == addr_orig) ++ && dr_ctrl_p[i] == ctrl) ++ { ++ gdb_assert (dr_ref_count[i] != 0); ++ idx = i; ++ break; ++ } ++ } ++ ++ /* No space. */ ++ if (idx == -1) ++ return -1; ++ ++ /* Update our cache. */ ++ if ((dr_ctrl_p[idx] & 1) == 0) ++ { ++ /* new entry */ ++ dr_addr_p[idx] = addr; ++ if (dr_addr_orig_p != nullptr) ++ dr_addr_orig_p[idx] = addr_orig; ++ dr_ctrl_p[idx] = ctrl; ++ dr_ref_count[idx] = 1; ++ /* Notify the change. */ ++ aarch64_notify_debug_reg_change (ptid, is_watchpoint, idx); ++ } ++ else ++ { ++ /* existing entry */ ++ dr_ref_count[idx]++; ++ } ++ ++ return 0; ++} ++ ++/* Record the removal of one breakpoint/watchpoint, as represented by ++ ADDR and CTRL, in the process' arch-specific data area *STATE. */ ++ ++static int ++aarch64_dr_state_remove_one_point (ptid_t ptid, ++ struct aarch64_debug_reg_state *state, ++ enum target_hw_bp_type type, ++ CORE_ADDR addr, int offset, int len, ++ CORE_ADDR addr_orig) ++{ ++ int i, num_regs, is_watchpoint; ++ unsigned int ctrl, *dr_ctrl_p, *dr_ref_count; ++ CORE_ADDR *dr_addr_p, *dr_addr_orig_p; ++ ++ /* Set up state pointers. */ ++ is_watchpoint = (type != hw_execute); ++ if (is_watchpoint) ++ { ++ num_regs = aarch64_num_wp_regs; ++ dr_addr_p = state->dr_addr_wp; ++ dr_addr_orig_p = state->dr_addr_orig_wp; ++ dr_ctrl_p = state->dr_ctrl_wp; ++ dr_ref_count = state->dr_ref_count_wp; ++ } ++ else ++ { ++ num_regs = aarch64_num_bp_regs; ++ dr_addr_p = state->dr_addr_bp; ++ dr_addr_orig_p = nullptr; ++ dr_ctrl_p = state->dr_ctrl_bp; ++ dr_ref_count = state->dr_ref_count_bp; ++ } ++ ++ ctrl = aarch64_point_encode_ctrl_reg (type, offset, len); ++ ++ /* Find the entry that matches the ADDR and CTRL. */ ++ for (i = 0; i < num_regs; ++i) ++ if (dr_addr_p[i] == addr ++ && (dr_addr_orig_p == nullptr || dr_addr_orig_p[i] == addr_orig) ++ && dr_ctrl_p[i] == ctrl) ++ { ++ gdb_assert (dr_ref_count[i] != 0); ++ break; ++ } ++ ++ /* Not found. */ ++ if (i == num_regs) ++ return -1; ++ ++ /* Clear our cache. */ ++ if (--dr_ref_count[i] == 0) ++ { ++ /* Clear the enable bit. */ ++ ctrl &= ~1; ++ dr_addr_p[i] = 0; ++ if (dr_addr_orig_p != nullptr) ++ dr_addr_orig_p[i] = 0; ++ dr_ctrl_p[i] = ctrl; ++ /* Notify the change. */ ++ aarch64_notify_debug_reg_change (ptid, is_watchpoint, i); ++ } ++ ++ return 0; ++} ++ ++int ++aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr, ++ int len, int is_insert, ptid_t ptid, ++ struct aarch64_debug_reg_state *state) ++{ ++ if (is_insert) ++ { ++ /* The hardware breakpoint on AArch64 should always be 4-byte ++ aligned, but on AArch32, it can be 2-byte aligned. Note that ++ we only check the alignment on inserting breakpoint because ++ aarch64_point_is_aligned needs the inferior_ptid inferior's ++ regcache to decide whether the inferior is 32-bit or 64-bit. ++ However when GDB follows the parent process and detach breakpoints ++ from child process, inferior_ptid is the child ptid, but the ++ child inferior doesn't exist in GDB's view yet. */ ++ if (!aarch64_point_is_aligned (ptid, 0 /* is_watchpoint */ , addr, len)) ++ return -1; ++ ++ return aarch64_dr_state_insert_one_point (ptid, state, type, addr, 0, len, ++ -1); ++ } ++ else ++ return aarch64_dr_state_remove_one_point (ptid, state, type, addr, 0, len, ++ -1); ++} ++ ++/* This is essentially the same as aarch64_handle_breakpoint, apart ++ from that it is an aligned watchpoint to be handled. */ ++ ++static int ++aarch64_handle_aligned_watchpoint (enum target_hw_bp_type type, ++ CORE_ADDR addr, int len, int is_insert, ++ ptid_t ptid, ++ struct aarch64_debug_reg_state *state) ++{ ++ if (is_insert) ++ return aarch64_dr_state_insert_one_point (ptid, state, type, addr, 0, len, ++ addr); ++ else ++ return aarch64_dr_state_remove_one_point (ptid, state, type, addr, 0, len, ++ addr); ++} ++ ++/* Insert/remove unaligned watchpoint by calling ++ aarch64_align_watchpoint repeatedly until the whole watched region, ++ as represented by ADDR and LEN, has been properly aligned and ready ++ to be written to one or more hardware watchpoint registers. ++ IS_INSERT indicates whether this is an insertion or a deletion. ++ Return 0 if succeed. */ ++ ++static int ++aarch64_handle_unaligned_watchpoint (enum target_hw_bp_type type, ++ CORE_ADDR addr, int len, int is_insert, ++ ptid_t ptid, ++ struct aarch64_debug_reg_state *state) ++{ ++ CORE_ADDR addr_orig = addr; ++ ++ while (len > 0) ++ { ++ CORE_ADDR aligned_addr; ++ int aligned_offset, aligned_len, ret; ++ CORE_ADDR addr_orig_next = addr_orig; ++ ++ aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_offset, ++ &aligned_len, &addr, &len, &addr_orig_next); ++ ++ if (is_insert) ++ ret = aarch64_dr_state_insert_one_point (ptid, state, type, ++ aligned_addr, aligned_offset, ++ aligned_len, addr_orig); ++ else ++ ret = aarch64_dr_state_remove_one_point (ptid, state, type, ++ aligned_addr, aligned_offset, ++ aligned_len, addr_orig); ++ ++ if (show_debug_regs) ++ debug_printf ("handle_unaligned_watchpoint: is_insert: %d\n" ++ " " ++ "aligned_addr: %s, aligned_len: %d\n" ++ " " ++ "addr_orig: %s\n" ++ " " ++ "next_addr: %s, next_len: %d\n" ++ " " ++ "addr_orig_next: %s\n", ++ is_insert, core_addr_to_string_nz (aligned_addr), ++ aligned_len, core_addr_to_string_nz (addr_orig), ++ core_addr_to_string_nz (addr), len, ++ core_addr_to_string_nz (addr_orig_next)); ++ ++ addr_orig = addr_orig_next; ++ ++ if (ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ++aarch64_handle_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, ++ int len, int is_insert, ptid_t ptid, ++ struct aarch64_debug_reg_state *state) ++{ ++ if (aarch64_point_is_aligned (ptid, 1 /* is_watchpoint */ , addr, len)) ++ return aarch64_handle_aligned_watchpoint (type, addr, len, is_insert, ptid, ++ state); ++ else ++ return aarch64_handle_unaligned_watchpoint (type, addr, len, is_insert, ++ ptid, state); ++} ++ ++/* See nat/aarch64-hw-point.h. */ ++ ++bool ++aarch64_any_set_debug_regs_state (aarch64_debug_reg_state *state, ++ bool watchpoint) ++{ ++ int count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs; ++ if (count == 0) ++ return false; ++ ++ const CORE_ADDR *addr = watchpoint ? state->dr_addr_wp : state->dr_addr_bp; ++ const unsigned int *ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp; ++ ++ for (int i = 0; i < count; i++) ++ if (addr[i] != 0 || ctrl[i] != 0) ++ return true; ++ ++ return false; ++} ++ ++/* Print the values of the cached breakpoint/watchpoint registers. */ ++ ++void ++aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state, ++ const char *func, CORE_ADDR addr, ++ int len, enum target_hw_bp_type type) ++{ ++ int i; ++ ++ debug_printf ("%s", func); ++ if (addr || len) ++ debug_printf (" (addr=0x%08lx, len=%d, type=%s)", ++ (unsigned long) addr, len, ++ type == hw_write ? "hw-write-watchpoint" ++ : (type == hw_read ? "hw-read-watchpoint" ++ : (type == hw_access ? "hw-access-watchpoint" ++ : (type == hw_execute ? "hw-breakpoint" ++ : "??unknown??")))); ++ debug_printf (":\n"); ++ ++ debug_printf ("\tBREAKPOINTs:\n"); ++ for (i = 0; i < aarch64_num_bp_regs; i++) ++ debug_printf ("\tBP%d: addr=%s, ctrl=0x%08x, ref.count=%d\n", ++ i, core_addr_to_string_nz (state->dr_addr_bp[i]), ++ state->dr_ctrl_bp[i], state->dr_ref_count_bp[i]); ++ ++ debug_printf ("\tWATCHPOINTs:\n"); ++ for (i = 0; i < aarch64_num_wp_regs; i++) ++ debug_printf ("\tWP%d: addr=%s (orig=%s), ctrl=0x%08x, ref.count=%d\n", ++ i, core_addr_to_string_nz (state->dr_addr_wp[i]), ++ core_addr_to_string_nz (state->dr_addr_orig_wp[i]), ++ state->dr_ctrl_wp[i], state->dr_ref_count_wp[i]); ++} ++ ++/* Return true if we can watch a memory region that starts address ++ ADDR and whose length is LEN in bytes. */ ++ ++int ++aarch64_region_ok_for_watchpoint (CORE_ADDR addr, int len) ++{ ++ CORE_ADDR aligned_addr; ++ ++ /* Can not set watchpoints for zero or negative lengths. */ ++ if (len <= 0) ++ return 0; ++ ++ /* Must have hardware watchpoint debug register(s). */ ++ if (aarch64_num_wp_regs == 0) ++ return 0; ++ ++ /* We support unaligned watchpoint address and arbitrary length, ++ as long as the size of the whole watched area after alignment ++ doesn't exceed size of the total area that all watchpoint debug ++ registers can watch cooperatively. ++ ++ This is a very relaxed rule, but unfortunately there are ++ limitations, e.g. false-positive hits, due to limited support of ++ hardware debug registers in the kernel. See comment above ++ aarch64_align_watchpoint for more information. */ ++ ++ aligned_addr = addr & ~(AARCH64_HWP_MAX_LEN_PER_REG - 1); ++ if (aligned_addr + aarch64_num_wp_regs * AARCH64_HWP_MAX_LEN_PER_REG ++ < addr + len) ++ return 0; ++ ++ /* All tests passed so we are likely to be able to set the watchpoint. ++ The reason that it is 'likely' rather than 'must' is because ++ we don't check the current usage of the watchpoint registers, and ++ there may not be enough registers available for this watchpoint. ++ Ideally we should check the cached debug register state, however ++ the checking is costly. */ ++ return 1; ++} +diff --git a/gdb/nat/aarch64-hw-point.h b/gdb/nat/aarch64-hw-point.h +new file mode 100644 +index 00000000000..97b37d537c2 +--- /dev/null ++++ gdb/nat/aarch64-hw-point.h +@@ -0,0 +1,126 @@ ++/* Copyright (C) 2009-2022 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 . */ ++ ++#ifndef NAT_AARCH64_HW_POINT_H ++#define NAT_AARCH64_HW_POINT_H ++ ++/* Macro definitions, data structures, and code for the hardware ++ breakpoint and hardware watchpoint support follow. We use the ++ following abbreviations throughout the code: ++ ++ hw - hardware ++ bp - breakpoint ++ wp - watchpoint */ ++ ++/* Maximum number of hardware breakpoint and watchpoint registers. ++ Neither of these values may exceed the width of dr_changed_t ++ measured in bits. */ ++ ++#define AARCH64_HBP_MAX_NUM 16 ++#define AARCH64_HWP_MAX_NUM 16 ++ ++/* Alignment requirement in bytes for addresses written to ++ hardware breakpoint and watchpoint value registers. ++ ++ A ptrace call attempting to set an address that does not meet the ++ alignment criteria will fail. Limited support has been provided in ++ this port for unaligned watchpoints, such that from a GDB user ++ perspective, an unaligned watchpoint may be requested. ++ ++ This is achieved by minimally enlarging the watched area to meet the ++ alignment requirement, and if necessary, splitting the watchpoint ++ over several hardware watchpoint registers. */ ++ ++#define AARCH64_HBP_ALIGNMENT 4 ++#define AARCH64_HWP_ALIGNMENT 8 ++ ++/* The maximum length of a memory region that can be watched by one ++ hardware watchpoint register. */ ++ ++#define AARCH64_HWP_MAX_LEN_PER_REG 8 ++ ++/* Macro for the expected version of the ARMv8-A debug architecture. */ ++#define AARCH64_DEBUG_ARCH_V8 0x6 ++#define AARCH64_DEBUG_ARCH_V8_1 0x7 ++#define AARCH64_DEBUG_ARCH_V8_2 0x8 ++#define AARCH64_DEBUG_ARCH_V8_4 0x9 ++ ++/* ptrace expects control registers to be formatted as follows: ++ ++ 31 13 5 3 1 0 ++ +--------------------------------+----------+------+------+----+ ++ | RESERVED (SBZ) | MASK | TYPE | PRIV | EN | ++ +--------------------------------+----------+------+------+----+ ++ ++ The TYPE field is ignored for breakpoints. */ ++ ++#define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1) ++#define DR_CONTROL_MASK(ctrl) (((ctrl) >> 5) & 0xff) ++ ++/* Structure for managing the hardware breakpoint/watchpoint resources. ++ DR_ADDR_* stores the address, DR_CTRL_* stores the control register ++ content, and DR_REF_COUNT_* counts the numbers of references to the ++ corresponding bp/wp, by which way the limited hardware resources ++ are not wasted on duplicated bp/wp settings (though so far gdb has ++ done a good job by not sending duplicated bp/wp requests). */ ++ ++struct aarch64_debug_reg_state ++{ ++ /* hardware breakpoint */ ++ CORE_ADDR dr_addr_bp[AARCH64_HBP_MAX_NUM]; ++ unsigned int dr_ctrl_bp[AARCH64_HBP_MAX_NUM]; ++ unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM]; ++ ++ /* hardware watchpoint */ ++ /* Address aligned down to AARCH64_HWP_ALIGNMENT. */ ++ CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM]; ++ /* Address as entered by user without any forced alignment. */ ++ CORE_ADDR dr_addr_orig_wp[AARCH64_HWP_MAX_NUM]; ++ unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM]; ++ unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM]; ++}; ++ ++extern int aarch64_num_bp_regs; ++extern int aarch64_num_wp_regs; ++ ++/* Invoked when IDXth breakpoint/watchpoint register pair needs to be ++ updated. */ ++void aarch64_notify_debug_reg_change (ptid_t ptid, int is_watchpoint, ++ unsigned int idx); ++ ++unsigned int aarch64_watchpoint_offset (unsigned int ctrl); ++unsigned int aarch64_watchpoint_length (unsigned int ctrl); ++ ++int aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr, ++ int len, int is_insert, ptid_t ptid, ++ struct aarch64_debug_reg_state *state); ++int aarch64_handle_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, ++ int len, int is_insert, ptid_t ptid, ++ struct aarch64_debug_reg_state *state); ++ ++/* Return TRUE if there are any hardware breakpoints. If WATCHPOINT is TRUE, ++ check hardware watchpoints instead. */ ++bool aarch64_any_set_debug_regs_state (aarch64_debug_reg_state *state, ++ bool watchpoint); ++ ++void aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state, ++ const char *func, CORE_ADDR addr, ++ int len, enum target_hw_bp_type type); ++ ++int aarch64_region_ok_for_watchpoint (CORE_ADDR addr, int len); ++ ++#endif /* NAT_AARCH64_HW_POINT_H */ +diff --git a/gdb/nat/aarch64-linux-hw-point.c b/gdb/nat/aarch64-linux-hw-point.c +index f5dd3b2be2c..a6d91a367b7 100644 +--- gdb/nat/aarch64-linux-hw-point.c ++++ gdb/nat/aarch64-linux-hw-point.c +@@ -34,256 +34,9 @@ + + #include + +-/* Number of hardware breakpoints/watchpoints the target supports. +- They are initialized with values obtained via the ptrace calls +- with NT_ARM_HW_BREAK and NT_ARM_HW_WATCH respectively. */ ++/* See aarch64-linux-hw-point.h */ + +-int aarch64_num_bp_regs; +-int aarch64_num_wp_regs; +- +-/* True if this kernel does not have the bug described by PR +- external/20207 (Linux >= 4.10). A fixed kernel supports any +- contiguous range of bits in 8-bit byte DR_CONTROL_MASK. A buggy +- kernel supports only 0x01, 0x03, 0x0f and 0xff. We start by +- assuming the bug is fixed, and then detect the bug at +- PTRACE_SETREGSET time. */ +-static bool kernel_supports_any_contiguous_range = true; +- +-/* Return starting byte 0..7 incl. of a watchpoint encoded by CTRL. */ +- +-unsigned int +-aarch64_watchpoint_offset (unsigned int ctrl) +-{ +- uint8_t mask = DR_CONTROL_MASK (ctrl); +- unsigned retval; +- +- /* Shift out bottom zeros. */ +- for (retval = 0; mask && (mask & 1) == 0; ++retval) +- mask >>= 1; +- +- return retval; +-} +- +-/* Utility function that returns the length in bytes of a watchpoint +- according to the content of a hardware debug control register CTRL. +- Any contiguous range of bytes in CTRL is supported. The returned +- value can be between 0..8 (inclusive). */ +- +-unsigned int +-aarch64_watchpoint_length (unsigned int ctrl) +-{ +- uint8_t mask = DR_CONTROL_MASK (ctrl); +- unsigned retval; +- +- /* Shift out bottom zeros. */ +- mask >>= aarch64_watchpoint_offset (ctrl); +- +- /* Count bottom ones. */ +- for (retval = 0; (mask & 1) != 0; ++retval) +- mask >>= 1; +- +- if (mask != 0) +- error (_("Unexpected hardware watchpoint length register value 0x%x"), +- DR_CONTROL_MASK (ctrl)); +- +- return retval; +-} +- +-/* Given the hardware breakpoint or watchpoint type TYPE and its +- length LEN, return the expected encoding for a hardware +- breakpoint/watchpoint control register. */ +- +-static unsigned int +-aarch64_point_encode_ctrl_reg (enum target_hw_bp_type type, int offset, int len) +-{ +- unsigned int ctrl, ttype; +- +- gdb_assert (offset == 0 || kernel_supports_any_contiguous_range); +- gdb_assert (offset + len <= AARCH64_HWP_MAX_LEN_PER_REG); +- +- /* type */ +- switch (type) +- { +- case hw_write: +- ttype = 2; +- break; +- case hw_read: +- ttype = 1; +- break; +- case hw_access: +- ttype = 3; +- break; +- case hw_execute: +- ttype = 0; +- break; +- default: +- perror_with_name (_("Unrecognized breakpoint/watchpoint type")); +- } +- +- ctrl = ttype << 3; +- +- /* offset and length bitmask */ +- ctrl |= ((1 << len) - 1) << (5 + offset); +- /* enabled at el0 */ +- ctrl |= (2 << 1) | 1; +- +- return ctrl; +-} +- +-/* Addresses to be written to the hardware breakpoint and watchpoint +- value registers need to be aligned; the alignment is 4-byte and +- 8-type respectively. Linux kernel rejects any non-aligned address +- it receives from the related ptrace call. Furthermore, the kernel +- currently only supports the following Byte Address Select (BAS) +- values: 0x1, 0x3, 0xf and 0xff, which means that for a hardware +- watchpoint to be accepted by the kernel (via ptrace call), its +- valid length can only be 1 byte, 2 bytes, 4 bytes or 8 bytes. +- Despite these limitations, the unaligned watchpoint is supported in +- this port. +- +- Return 0 for any non-compliant ADDR and/or LEN; return 1 otherwise. */ +- +-static int +-aarch64_point_is_aligned (int is_watchpoint, CORE_ADDR addr, int len) +-{ +- unsigned int alignment = 0; +- +- if (is_watchpoint) +- alignment = AARCH64_HWP_ALIGNMENT; +- else +- { +- struct regcache *regcache +- = get_thread_regcache_for_ptid (current_lwp_ptid ()); +- +- /* Set alignment to 2 only if the current process is 32-bit, +- since thumb instruction can be 2-byte aligned. Otherwise, set +- alignment to AARCH64_HBP_ALIGNMENT. */ +- if (regcache_register_size (regcache, 0) == 8) +- alignment = AARCH64_HBP_ALIGNMENT; +- else +- alignment = 2; +- } +- +- if (addr & (alignment - 1)) +- return 0; +- +- if ((!kernel_supports_any_contiguous_range +- && len != 8 && len != 4 && len != 2 && len != 1) +- || (kernel_supports_any_contiguous_range +- && (len < 1 || len > 8))) +- return 0; +- +- return 1; +-} +- +-/* Given the (potentially unaligned) watchpoint address in ADDR and +- length in LEN, return the aligned address, offset from that base +- address, and aligned length in *ALIGNED_ADDR_P, *ALIGNED_OFFSET_P +- and *ALIGNED_LEN_P, respectively. The returned values will be +- valid values to write to the hardware watchpoint value and control +- registers. +- +- The given watchpoint may get truncated if more than one hardware +- register is needed to cover the watched region. *NEXT_ADDR_P +- and *NEXT_LEN_P, if non-NULL, will return the address and length +- of the remaining part of the watchpoint (which can be processed +- by calling this routine again to generate another aligned address, +- offset and length tuple. +- +- Essentially, unaligned watchpoint is achieved by minimally +- enlarging the watched area to meet the alignment requirement, and +- if necessary, splitting the watchpoint over several hardware +- watchpoint registers. +- +- On kernels that predate the support for Byte Address Select (BAS) +- in the hardware watchpoint control register, the offset from the +- base address is always zero, and so in that case the trade-off is +- that there will be false-positive hits for the read-type or the +- access-type hardware watchpoints; for the write type, which is more +- commonly used, there will be no such issues, as the higher-level +- breakpoint management in gdb always examines the exact watched +- region for any content change, and transparently resumes a thread +- from a watchpoint trap if there is no change to the watched region. +- +- Another limitation is that because the watched region is enlarged, +- the watchpoint fault address discovered by +- aarch64_stopped_data_address may be outside of the original watched +- region, especially when the triggering instruction is accessing a +- larger region. When the fault address is not within any known +- range, watchpoints_triggered in gdb will get confused, as the +- higher-level watchpoint management is only aware of original +- watched regions, and will think that some unknown watchpoint has +- been triggered. To prevent such a case, +- aarch64_stopped_data_address implementations in gdb and gdbserver +- try to match the trapped address with a watched region, and return +- an address within the latter. */ +- +-static void +-aarch64_align_watchpoint (CORE_ADDR addr, int len, CORE_ADDR *aligned_addr_p, +- int *aligned_offset_p, int *aligned_len_p, +- CORE_ADDR *next_addr_p, int *next_len_p, +- CORE_ADDR *next_addr_orig_p) +-{ +- int aligned_len; +- unsigned int offset, aligned_offset; +- CORE_ADDR aligned_addr; +- const unsigned int alignment = AARCH64_HWP_ALIGNMENT; +- const unsigned int max_wp_len = AARCH64_HWP_MAX_LEN_PER_REG; +- +- /* As assumed by the algorithm. */ +- gdb_assert (alignment == max_wp_len); +- +- if (len <= 0) +- return; +- +- /* The address put into the hardware watchpoint value register must +- be aligned. */ +- offset = addr & (alignment - 1); +- aligned_addr = addr - offset; +- aligned_offset +- = kernel_supports_any_contiguous_range ? addr & (alignment - 1) : 0; +- +- gdb_assert (offset >= 0 && offset < alignment); +- gdb_assert (aligned_addr >= 0 && aligned_addr <= addr); +- gdb_assert (offset + len > 0); +- +- if (offset + len >= max_wp_len) +- { +- /* Need more than one watchpoint register; truncate at the +- alignment boundary. */ +- aligned_len +- = max_wp_len - (kernel_supports_any_contiguous_range ? offset : 0); +- len -= (max_wp_len - offset); +- addr += (max_wp_len - offset); +- gdb_assert ((addr & (alignment - 1)) == 0); +- } +- else +- { +- /* Find the smallest valid length that is large enough to +- accommodate this watchpoint. */ +- static const unsigned char +- aligned_len_array[AARCH64_HWP_MAX_LEN_PER_REG] = +- { 1, 2, 4, 4, 8, 8, 8, 8 }; +- +- aligned_len = (kernel_supports_any_contiguous_range +- ? len : aligned_len_array[offset + len - 1]); +- addr += len; +- len = 0; +- } +- +- if (aligned_addr_p) +- *aligned_addr_p = aligned_addr; +- if (aligned_offset_p) +- *aligned_offset_p = aligned_offset; +- if (aligned_len_p) +- *aligned_len_p = aligned_len; +- if (next_addr_p) +- *next_addr_p = addr; +- if (next_len_p) +- *next_len_p = len; +- if (next_addr_orig_p) +- *next_addr_orig_p = align_down (*next_addr_orig_p + alignment, alignment); +-} ++bool kernel_supports_any_contiguous_range = true; + + /* Helper for aarch64_notify_debug_reg_change. Records the + information about the change of one hardware breakpoint/watchpoint +@@ -349,11 +102,11 @@ debug_reg_change_callback (struct lwp_info *lwp, int is_watchpoint, + thread's arch-specific data area, the actual updating will be done + when the thread is resumed. */ + +-static void +-aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state, ++void ++aarch64_notify_debug_reg_change (ptid_t ptid, + int is_watchpoint, unsigned int idx) + { +- ptid_t pid_ptid = ptid_t (current_lwp_ptid ().pid ()); ++ ptid_t pid_ptid = ptid_t (ptid.pid ()); + + iterate_over_lwps (pid_ptid, [=] (struct lwp_info *info) + { +@@ -414,261 +167,11 @@ aarch64_downgrade_regs (struct aarch64_debug_reg_state *state) + break; + } + +- aarch64_notify_debug_reg_change (state, 1 /* is_watchpoint */, i); ++ aarch64_notify_debug_reg_change (current_lwp_ptid (), ++ 1 /* is_watchpoint */, i); + } + } + +-/* Record the insertion of one breakpoint/watchpoint, as represented +- by ADDR and CTRL, in the process' arch-specific data area *STATE. */ +- +-static int +-aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state, +- enum target_hw_bp_type type, +- CORE_ADDR addr, int offset, int len, +- CORE_ADDR addr_orig) +-{ +- int i, idx, num_regs, is_watchpoint; +- unsigned int ctrl, *dr_ctrl_p, *dr_ref_count; +- CORE_ADDR *dr_addr_p, *dr_addr_orig_p; +- +- /* Set up state pointers. */ +- is_watchpoint = (type != hw_execute); +- gdb_assert (aarch64_point_is_aligned (is_watchpoint, addr, len)); +- if (is_watchpoint) +- { +- num_regs = aarch64_num_wp_regs; +- dr_addr_p = state->dr_addr_wp; +- dr_addr_orig_p = state->dr_addr_orig_wp; +- dr_ctrl_p = state->dr_ctrl_wp; +- dr_ref_count = state->dr_ref_count_wp; +- } +- else +- { +- num_regs = aarch64_num_bp_regs; +- dr_addr_p = state->dr_addr_bp; +- dr_addr_orig_p = nullptr; +- dr_ctrl_p = state->dr_ctrl_bp; +- dr_ref_count = state->dr_ref_count_bp; +- } +- +- ctrl = aarch64_point_encode_ctrl_reg (type, offset, len); +- +- /* Find an existing or free register in our cache. */ +- idx = -1; +- for (i = 0; i < num_regs; ++i) +- { +- if ((dr_ctrl_p[i] & 1) == 0) +- { +- gdb_assert (dr_ref_count[i] == 0); +- idx = i; +- /* no break; continue hunting for an exising one. */ +- } +- else if (dr_addr_p[i] == addr +- && (dr_addr_orig_p == nullptr || dr_addr_orig_p[i] == addr_orig) +- && dr_ctrl_p[i] == ctrl) +- { +- gdb_assert (dr_ref_count[i] != 0); +- idx = i; +- break; +- } +- } +- +- /* No space. */ +- if (idx == -1) +- return -1; +- +- /* Update our cache. */ +- if ((dr_ctrl_p[idx] & 1) == 0) +- { +- /* new entry */ +- dr_addr_p[idx] = addr; +- if (dr_addr_orig_p != nullptr) +- dr_addr_orig_p[idx] = addr_orig; +- dr_ctrl_p[idx] = ctrl; +- dr_ref_count[idx] = 1; +- /* Notify the change. */ +- aarch64_notify_debug_reg_change (state, is_watchpoint, idx); +- } +- else +- { +- /* existing entry */ +- dr_ref_count[idx]++; +- } +- +- return 0; +-} +- +-/* Record the removal of one breakpoint/watchpoint, as represented by +- ADDR and CTRL, in the process' arch-specific data area *STATE. */ +- +-static int +-aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state, +- enum target_hw_bp_type type, +- CORE_ADDR addr, int offset, int len, +- CORE_ADDR addr_orig) +-{ +- int i, num_regs, is_watchpoint; +- unsigned int ctrl, *dr_ctrl_p, *dr_ref_count; +- CORE_ADDR *dr_addr_p, *dr_addr_orig_p; +- +- /* Set up state pointers. */ +- is_watchpoint = (type != hw_execute); +- if (is_watchpoint) +- { +- num_regs = aarch64_num_wp_regs; +- dr_addr_p = state->dr_addr_wp; +- dr_addr_orig_p = state->dr_addr_orig_wp; +- dr_ctrl_p = state->dr_ctrl_wp; +- dr_ref_count = state->dr_ref_count_wp; +- } +- else +- { +- num_regs = aarch64_num_bp_regs; +- dr_addr_p = state->dr_addr_bp; +- dr_addr_orig_p = nullptr; +- dr_ctrl_p = state->dr_ctrl_bp; +- dr_ref_count = state->dr_ref_count_bp; +- } +- +- ctrl = aarch64_point_encode_ctrl_reg (type, offset, len); +- +- /* Find the entry that matches the ADDR and CTRL. */ +- for (i = 0; i < num_regs; ++i) +- if (dr_addr_p[i] == addr +- && (dr_addr_orig_p == nullptr || dr_addr_orig_p[i] == addr_orig) +- && dr_ctrl_p[i] == ctrl) +- { +- gdb_assert (dr_ref_count[i] != 0); +- break; +- } +- +- /* Not found. */ +- if (i == num_regs) +- return -1; +- +- /* Clear our cache. */ +- if (--dr_ref_count[i] == 0) +- { +- /* Clear the enable bit. */ +- ctrl &= ~1; +- dr_addr_p[i] = 0; +- if (dr_addr_orig_p != nullptr) +- dr_addr_orig_p[i] = 0; +- dr_ctrl_p[i] = ctrl; +- /* Notify the change. */ +- aarch64_notify_debug_reg_change (state, is_watchpoint, i); +- } +- +- return 0; +-} +- +-int +-aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr, +- int len, int is_insert, +- struct aarch64_debug_reg_state *state) +-{ +- if (is_insert) +- { +- /* The hardware breakpoint on AArch64 should always be 4-byte +- aligned, but on AArch32, it can be 2-byte aligned. Note that +- we only check the alignment on inserting breakpoint because +- aarch64_point_is_aligned needs the inferior_ptid inferior's +- regcache to decide whether the inferior is 32-bit or 64-bit. +- However when GDB follows the parent process and detach breakpoints +- from child process, inferior_ptid is the child ptid, but the +- child inferior doesn't exist in GDB's view yet. */ +- if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len)) +- return -1; +- +- return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, -1); +- } +- else +- return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, -1); +-} +- +-/* This is essentially the same as aarch64_handle_breakpoint, apart +- from that it is an aligned watchpoint to be handled. */ +- +-static int +-aarch64_handle_aligned_watchpoint (enum target_hw_bp_type type, +- CORE_ADDR addr, int len, int is_insert, +- struct aarch64_debug_reg_state *state) +-{ +- if (is_insert) +- return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, addr); +- else +- return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, addr); +-} +- +-/* Insert/remove unaligned watchpoint by calling +- aarch64_align_watchpoint repeatedly until the whole watched region, +- as represented by ADDR and LEN, has been properly aligned and ready +- to be written to one or more hardware watchpoint registers. +- IS_INSERT indicates whether this is an insertion or a deletion. +- Return 0 if succeed. */ +- +-static int +-aarch64_handle_unaligned_watchpoint (enum target_hw_bp_type type, +- CORE_ADDR addr, int len, int is_insert, +- struct aarch64_debug_reg_state *state) +-{ +- CORE_ADDR addr_orig = addr; +- +- while (len > 0) +- { +- CORE_ADDR aligned_addr; +- int aligned_offset, aligned_len, ret; +- CORE_ADDR addr_orig_next = addr_orig; +- +- aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_offset, +- &aligned_len, &addr, &len, &addr_orig_next); +- +- if (is_insert) +- ret = aarch64_dr_state_insert_one_point (state, type, aligned_addr, +- aligned_offset, +- aligned_len, addr_orig); +- else +- ret = aarch64_dr_state_remove_one_point (state, type, aligned_addr, +- aligned_offset, +- aligned_len, addr_orig); +- +- if (show_debug_regs) +- debug_printf ("handle_unaligned_watchpoint: is_insert: %d\n" +- " " +- "aligned_addr: %s, aligned_len: %d\n" +- " " +- "addr_orig: %s\n" +- " " +- "next_addr: %s, next_len: %d\n" +- " " +- "addr_orig_next: %s\n", +- is_insert, core_addr_to_string_nz (aligned_addr), +- aligned_len, core_addr_to_string_nz (addr_orig), +- core_addr_to_string_nz (addr), len, +- core_addr_to_string_nz (addr_orig_next)); +- +- addr_orig = addr_orig_next; +- +- if (ret != 0) +- return ret; +- } +- +- return 0; +-} +- +-int +-aarch64_handle_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, +- int len, int is_insert, +- struct aarch64_debug_reg_state *state) +-{ +- if (aarch64_point_is_aligned (1 /* is_watchpoint */ , addr, len)) +- return aarch64_handle_aligned_watchpoint (type, addr, len, is_insert, +- state); +- else +- return aarch64_handle_unaligned_watchpoint (type, addr, len, is_insert, +- state); +-} +- + /* Call ptrace to set the thread TID's hardware breakpoint/watchpoint + registers with data from *STATE. */ + +@@ -715,60 +218,6 @@ aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state *state, + } + } + +-/* See nat/aarch64-linux-hw-point.h. */ +- +-bool +-aarch64_linux_any_set_debug_regs_state (aarch64_debug_reg_state *state, +- bool watchpoint) +-{ +- int count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs; +- if (count == 0) +- return false; +- +- const CORE_ADDR *addr = watchpoint ? state->dr_addr_wp : state->dr_addr_bp; +- const unsigned int *ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp; +- +- for (int i = 0; i < count; i++) +- if (addr[i] != 0 || ctrl[i] != 0) +- return true; +- +- return false; +-} +- +-/* Print the values of the cached breakpoint/watchpoint registers. */ +- +-void +-aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state, +- const char *func, CORE_ADDR addr, +- int len, enum target_hw_bp_type type) +-{ +- int i; +- +- debug_printf ("%s", func); +- if (addr || len) +- debug_printf (" (addr=0x%08lx, len=%d, type=%s)", +- (unsigned long) addr, len, +- type == hw_write ? "hw-write-watchpoint" +- : (type == hw_read ? "hw-read-watchpoint" +- : (type == hw_access ? "hw-access-watchpoint" +- : (type == hw_execute ? "hw-breakpoint" +- : "??unknown??")))); +- debug_printf (":\n"); +- +- debug_printf ("\tBREAKPOINTs:\n"); +- for (i = 0; i < aarch64_num_bp_regs; i++) +- debug_printf ("\tBP%d: addr=%s, ctrl=0x%08x, ref.count=%d\n", +- i, core_addr_to_string_nz (state->dr_addr_bp[i]), +- state->dr_ctrl_bp[i], state->dr_ref_count_bp[i]); +- +- debug_printf ("\tWATCHPOINTs:\n"); +- for (i = 0; i < aarch64_num_wp_regs; i++) +- debug_printf ("\tWP%d: addr=%s (orig=%s), ctrl=0x%08x, ref.count=%d\n", +- i, core_addr_to_string_nz (state->dr_addr_wp[i]), +- core_addr_to_string_nz (state->dr_addr_orig_wp[i]), +- state->dr_ctrl_wp[i], state->dr_ref_count_wp[i]); +-} +- + /* Return true if debug arch level is compatible for hw watchpoints + and breakpoints. */ + +@@ -839,43 +288,3 @@ aarch64_linux_get_debug_reg_capacity (int tid) + aarch64_num_bp_regs = 0; + } + } +- +-/* Return true if we can watch a memory region that starts address +- ADDR and whose length is LEN in bytes. */ +- +-int +-aarch64_linux_region_ok_for_watchpoint (CORE_ADDR addr, int len) +-{ +- CORE_ADDR aligned_addr; +- +- /* Can not set watchpoints for zero or negative lengths. */ +- if (len <= 0) +- return 0; +- +- /* Must have hardware watchpoint debug register(s). */ +- if (aarch64_num_wp_regs == 0) +- return 0; +- +- /* We support unaligned watchpoint address and arbitrary length, +- as long as the size of the whole watched area after alignment +- doesn't exceed size of the total area that all watchpoint debug +- registers can watch cooperatively. +- +- This is a very relaxed rule, but unfortunately there are +- limitations, e.g. false-positive hits, due to limited support of +- hardware debug registers in the kernel. See comment above +- aarch64_align_watchpoint for more information. */ +- +- aligned_addr = addr & ~(AARCH64_HWP_MAX_LEN_PER_REG - 1); +- if (aligned_addr + aarch64_num_wp_regs * AARCH64_HWP_MAX_LEN_PER_REG +- < addr + len) +- return 0; +- +- /* All tests passed so we are likely to be able to set the watchpoint. +- The reason that it is 'likely' rather than 'must' is because +- we don't check the current usage of the watchpoint registers, and +- there may not be enough registers available for this watchpoint. +- Ideally we should check the cached debug register state, however +- the checking is costly. */ +- return 1; +-} +diff --git a/gdb/nat/aarch64-linux-hw-point.h b/gdb/nat/aarch64-linux-hw-point.h +index c746a7622a0..7c694ff0882 100644 +--- gdb/nat/aarch64-linux-hw-point.h ++++ gdb/nat/aarch64-linux-hw-point.h +@@ -21,40 +21,7 @@ + + #include "gdbsupport/break-common.h" /* For enum target_hw_bp_type. */ + +-/* Macro definitions, data structures, and code for the hardware +- breakpoint and hardware watchpoint support follow. We use the +- following abbreviations throughout the code: +- +- hw - hardware +- bp - breakpoint +- wp - watchpoint */ +- +-/* Maximum number of hardware breakpoint and watchpoint registers. +- Neither of these values may exceed the width of dr_changed_t +- measured in bits. */ +- +-#define AARCH64_HBP_MAX_NUM 16 +-#define AARCH64_HWP_MAX_NUM 16 +- +-/* Alignment requirement in bytes for addresses written to +- hardware breakpoint and watchpoint value registers. +- +- A ptrace call attempting to set an address that does not meet the +- alignment criteria will fail. Limited support has been provided in +- this port for unaligned watchpoints, such that from a GDB user +- perspective, an unaligned watchpoint may be requested. +- +- This is achieved by minimally enlarging the watched area to meet the +- alignment requirement, and if necessary, splitting the watchpoint +- over several hardware watchpoint registers. */ +- +-#define AARCH64_HBP_ALIGNMENT 4 +-#define AARCH64_HWP_ALIGNMENT 8 +- +-/* The maximum length of a memory region that can be watched by one +- hardware watchpoint register. */ +- +-#define AARCH64_HWP_MAX_LEN_PER_REG 8 ++#include "nat/aarch64-hw-point.h" + + /* ptrace hardware breakpoint resource info is formatted as follows: + +@@ -68,24 +35,6 @@ + #define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff) + #define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff) + +-/* Macro for the expected version of the ARMv8-A debug architecture. */ +-#define AARCH64_DEBUG_ARCH_V8 0x6 +-#define AARCH64_DEBUG_ARCH_V8_1 0x7 +-#define AARCH64_DEBUG_ARCH_V8_2 0x8 +-#define AARCH64_DEBUG_ARCH_V8_4 0x9 +- +-/* ptrace expects control registers to be formatted as follows: +- +- 31 13 5 3 1 0 +- +--------------------------------+----------+------+------+----+ +- | RESERVED (SBZ) | MASK | TYPE | PRIV | EN | +- +--------------------------------+----------+------+------+----+ +- +- The TYPE field is ignored for breakpoints. */ +- +-#define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1) +-#define DR_CONTROL_MASK(ctrl) (((ctrl) >> 5) & 0xff) +- + /* Each bit of a variable of this type is used to indicate whether a + hardware breakpoint or watchpoint setting has been changed since + the last update. +@@ -133,29 +82,6 @@ typedef ULONGEST dr_changed_t; + #define DR_HAS_CHANGED(x) ((x) != 0) + #define DR_N_HAS_CHANGED(x, n) ((x) & ((dr_changed_t)1 << (n))) + +-/* Structure for managing the hardware breakpoint/watchpoint resources. +- DR_ADDR_* stores the address, DR_CTRL_* stores the control register +- content, and DR_REF_COUNT_* counts the numbers of references to the +- corresponding bp/wp, by which way the limited hardware resources +- are not wasted on duplicated bp/wp settings (though so far gdb has +- done a good job by not sending duplicated bp/wp requests). */ +- +-struct aarch64_debug_reg_state +-{ +- /* hardware breakpoint */ +- CORE_ADDR dr_addr_bp[AARCH64_HBP_MAX_NUM]; +- unsigned int dr_ctrl_bp[AARCH64_HBP_MAX_NUM]; +- unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM]; +- +- /* hardware watchpoint */ +- /* Address aligned down to AARCH64_HWP_ALIGNMENT. */ +- CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM]; +- /* Address as entered by user without any forced alignment. */ +- CORE_ADDR dr_addr_orig_wp[AARCH64_HWP_MAX_NUM]; +- unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM]; +- unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM]; +-}; +- + /* Per-thread arch-specific data we want to keep. */ + + struct arch_lwp_info +@@ -167,35 +93,20 @@ struct arch_lwp_info + dr_changed_t dr_changed_wp; + }; + +-extern int aarch64_num_bp_regs; +-extern int aarch64_num_wp_regs; ++/* True if this kernel does not have the bug described by PR ++ external/20207 (Linux >= 4.10). A fixed kernel supports any ++ contiguous range of bits in 8-bit byte DR_CONTROL_MASK. A buggy ++ kernel supports only 0x01, 0x03, 0x0f and 0xff. We start by ++ assuming the bug is fixed, and then detect the bug at ++ PTRACE_SETREGSET time. */ + +-unsigned int aarch64_watchpoint_offset (unsigned int ctrl); +-unsigned int aarch64_watchpoint_length (unsigned int ctrl); +- +-int aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr, +- int len, int is_insert, +- struct aarch64_debug_reg_state *state); +-int aarch64_handle_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, +- int len, int is_insert, +- struct aarch64_debug_reg_state *state); ++extern bool kernel_supports_any_contiguous_range; + + void aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state *state, + int tid, int watchpoint); + +-/* Return TRUE if there are any hardware breakpoints. If WATCHPOINT is TRUE, +- check hardware watchpoints instead. */ +-bool aarch64_linux_any_set_debug_regs_state (aarch64_debug_reg_state *state, +- bool watchpoint); +- +-void aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state, +- const char *func, CORE_ADDR addr, +- int len, enum target_hw_bp_type type); +- + void aarch64_linux_get_debug_reg_capacity (int tid); + + struct aarch64_debug_reg_state *aarch64_get_debug_reg_state (pid_t pid); + +-int aarch64_linux_region_ok_for_watchpoint (CORE_ADDR addr, int len); +- + #endif /* NAT_AARCH64_LINUX_HW_POINT_H */ +diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c +index b2ed8f9a2a5..421d1ecb53c 100644 +--- gdb/nat/aarch64-linux.c ++++ gdb/nat/aarch64-linux.c +@@ -81,9 +81,9 @@ aarch64_linux_new_thread (struct lwp_info *lwp) + /* If there are hardware breakpoints/watchpoints in the process then mark that + all the hardware breakpoint/watchpoint register pairs for this thread need + to be initialized (with data from aarch_process_info.debug_reg_state). */ +- if (aarch64_linux_any_set_debug_regs_state (state, false)) ++ if (aarch64_any_set_debug_regs_state (state, false)) + DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs); +- if (aarch64_linux_any_set_debug_regs_state (state, true)) ++ if (aarch64_any_set_debug_regs_state (state, true)) + DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs); + + lwp_set_arch_private_info (lwp, info); +diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv +index 6e09b0eeb79..d37053628fc 100644 +--- gdbserver/configure.srv ++++ gdbserver/configure.srv +@@ -39,6 +39,7 @@ fi + + case "${gdbserver_host}" in + aarch64*-*-linux*) srv_tgtobj="linux-aarch64-low.o" ++ srv_tgtobj="$srv_tgtobj nat/aarch64-hw-point.o" + srv_tgtobj="$srv_tgtobj nat/aarch64-linux-hw-point.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o" +diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc +index aef69b34525..0091f998c63 100644 +--- gdbserver/linux-aarch64-low.cc ++++ gdbserver/linux-aarch64-low.cc +@@ -413,9 +413,10 @@ aarch64_target::low_insert_point (raw_bkpt_type type, CORE_ADDR addr, + + if (targ_type != hw_execute) + { +- if (aarch64_linux_region_ok_for_watchpoint (addr, len)) ++ if (aarch64_region_ok_for_watchpoint (addr, len)) + ret = aarch64_handle_watchpoint (targ_type, addr, len, +- 1 /* is_insert */, state); ++ 1 /* is_insert */, ++ current_lwp_ptid (), state); + else + ret = -1; + } +@@ -429,7 +430,8 @@ aarch64_target::low_insert_point (raw_bkpt_type type, CORE_ADDR addr, + len = 2; + } + ret = aarch64_handle_breakpoint (targ_type, addr, len, +- 1 /* is_insert */, state); ++ 1 /* is_insert */, current_lwp_ptid (), ++ state); + } + + if (show_debug_regs) +@@ -464,7 +466,7 @@ aarch64_target::low_remove_point (raw_bkpt_type type, CORE_ADDR addr, + if (targ_type != hw_execute) + ret = + aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */, +- state); ++ current_lwp_ptid (), state); + else + { + if (len == 3) +@@ -475,7 +477,8 @@ aarch64_target::low_remove_point (raw_bkpt_type type, CORE_ADDR addr, + len = 2; + } + ret = aarch64_handle_breakpoint (targ_type, addr, len, +- 0 /* is_insert */, state); ++ 0 /* is_insert */, current_lwp_ptid (), ++ state); + } + + if (show_debug_regs) Index: devel/gdb/files/commit-6719bc690e2 =================================================================== --- /dev/null +++ devel/gdb/files/commit-6719bc690e2 @@ -0,0 +1,48 @@ +commit 20c8aa681d97f5ab8a8f374b23339777b1dc4353 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + fbsd-nat: Add helper routine to fetch siginfo_t for a ptid. + + (cherry picked from commit 6719bc690e2829c50d3d3bb22ede1324e5baa12a) + +diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c +index 6d76c8234d5..51234eaa6c9 100644 +--- gdb/fbsd-nat.c ++++ gdb/fbsd-nat.c +@@ -1766,6 +1766,22 @@ fbsd_nat_target::store_register_set (struct regcache *regcache, int regnum, + return false; + } + ++/* See fbsd-nat.h. */ ++ ++bool ++fbsd_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo) ++{ ++ struct ptrace_lwpinfo pl; ++ pid_t pid = get_ptrace_pid (ptid); ++ ++ if (ptrace (PT_LWPINFO, pid, (caddr_t) &pl, sizeof pl) == -1) ++ return false; ++ if (!(pl.pl_flags & PL_FLAG_SI)) ++ return false;; ++ *siginfo = pl.pl_siginfo; ++ return (true); ++} ++ + void _initialize_fbsd_nat (); + void + _initialize_fbsd_nat () +diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h +index 2f17be5a8f0..d7c8eb81e96 100644 +--- gdb/fbsd-nat.h ++++ gdb/fbsd-nat.h +@@ -166,4 +166,8 @@ class fbsd_nat_target : public inf_ptrace_target + } + }; + ++/* Fetch the signal information for PTID and store it in *SIGINFO. ++ Return true if successful. */ ++bool fbsd_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo); ++ + #endif /* fbsd-nat.h */ Index: devel/gdb/files/commit-684943d213b =================================================================== --- /dev/null +++ devel/gdb/files/commit-684943d213b @@ -0,0 +1,102 @@ +commit 1264775133315cab3598b3bceea4aa969e49715c +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Fetch the NT_ARM_TLS register set for native FreeBSD/arm processes. + + This permits resolving TLS variables. + + (cherry picked from commit 684943d213b461a6a84ae67a9b8fcae5a28f007d) + +diff --git gdb/arm-fbsd-nat.c gdb/arm-fbsd-nat.c +index c32924de735..a306e1e2ee0 100644 +--- gdb/arm-fbsd-nat.c ++++ gdb/arm-fbsd-nat.c +@@ -18,13 +18,17 @@ + along with this program. If not, see . */ + + #include "defs.h" ++#include "inferior.h" + #include "target.h" + ++#include "elf/common.h" ++ + #include + #include + #include + + #include "fbsd-nat.h" ++#include "arm-tdep.h" + #include "arm-fbsd-tdep.h" + #include "inf-ptrace.h" + +@@ -49,6 +53,27 @@ arm_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) + fetch_register_set (regcache, regnum, PT_GETVFPREGS, + &arm_fbsd_vfpregset); + #endif ++#ifdef PT_GETREGSET ++ gdbarch *gdbarch = regcache->arch (); ++ arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ ++ if (tdep->tls_regnum > 0) ++ { ++ const struct regcache_map_entry arm_fbsd_tlsregmap[] = ++ { ++ { 1, tdep->tls_regnum, 4 }, ++ { 0 } ++ }; ++ ++ const struct regset arm_fbsd_tlsregset = ++ { ++ arm_fbsd_tlsregmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ fetch_regset (regcache, regnum, NT_ARM_TLS, &arm_fbsd_tlsregset); ++ } ++#endif + } + + /* Store register REGNUM back into the inferior. If REGNUM is -1, do +@@ -63,6 +88,27 @@ arm_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum) + store_register_set (regcache, regnum, PT_GETVFPREGS, + PT_SETVFPREGS, &arm_fbsd_vfpregset); + #endif ++#ifdef PT_GETREGSET ++ gdbarch *gdbarch = regcache->arch (); ++ arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ ++ if (tdep->tls_regnum > 0) ++ { ++ const struct regcache_map_entry arm_fbsd_tlsregmap[] = ++ { ++ { 1, tdep->tls_regnum, 4 }, ++ { 0 } ++ }; ++ ++ const struct regset arm_fbsd_tlsregset = ++ { ++ arm_fbsd_tlsregmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ store_regset (regcache, regnum, NT_ARM_TLS, &arm_fbsd_tlsregset); ++ } ++#endif + } + + /* Implement the to_read_description method. */ +@@ -71,8 +117,12 @@ const struct target_desc * + arm_fbsd_nat_target::read_description () + { + const struct target_desc *desc; ++ bool tls = false; + +- desc = arm_fbsd_read_description_auxv (this, false); ++#ifdef PT_GETREGSET ++ tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0; ++#endif ++ desc = arm_fbsd_read_description_auxv (this, tls); + if (desc == NULL) + desc = this->beneath ()->read_description (); + return desc; Index: devel/gdb/files/commit-711b0b6698f =================================================================== --- /dev/null +++ devel/gdb/files/commit-711b0b6698f @@ -0,0 +1,55 @@ +commit 8a8b3a6ad25f6bd379f7cbd6cc1f9edcf076d940 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + Remove USE_SIGTRAP_SIGINFO condition for FreeBSD/x86 debug regs support. + + For BSD x86 targets, stopped_by_hw_breakpoint doesn't check siginfo_t + but inspects the DR6 register directly via PT_GETDBREGS. + + (cherry picked from commit 711b0b6698ff6350b7c61710491c76c749945d4a) + +diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c +index 98a1af03a66..368f4c10786 100644 +--- gdb/amd64-fbsd-nat.c ++++ gdb/amd64-fbsd-nat.c +@@ -46,7 +46,7 @@ class amd64_fbsd_nat_target final + + const struct target_desc *read_description () override; + +-#if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) ++#if defined(HAVE_PT_GETDBREGS) + bool supports_stopped_by_hw_breakpoint () override; + #endif + }; +@@ -348,7 +348,7 @@ amd64_fbsd_nat_target::read_description () + return i386_target_description (X86_XSTATE_SSE_MASK, true); + } + +-#if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) ++#if defined(HAVE_PT_GETDBREGS) + /* Implement the supports_stopped_by_hw_breakpoints method. */ + + bool +diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c +index a6ced66250c..023f24bab37 100644 +--- gdb/i386-fbsd-nat.c ++++ gdb/i386-fbsd-nat.c +@@ -46,7 +46,7 @@ class i386_fbsd_nat_target final + + void resume (ptid_t, int, enum gdb_signal) override; + +-#if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) ++#if defined(HAVE_PT_GETDBREGS) + bool supports_stopped_by_hw_breakpoint () override; + #endif + }; +@@ -361,7 +361,7 @@ i386_fbsd_nat_target::read_description () + return i386_target_description (X86_XSTATE_X87_MASK, true); + } + +-#if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) ++#if defined(HAVE_PT_GETDBREGS) + /* Implement the supports_stopped_by_hw_breakpoints method. */ + + bool Index: devel/gdb/files/commit-8e6afe4013f =================================================================== --- /dev/null +++ devel/gdb/files/commit-8e6afe4013f @@ -0,0 +1,38 @@ +commit 8e1e09542c37a8937af47fd740806ea71ff260e9 +Author: John Baldwin +Date: Wed Apr 27 08:06:39 2022 -0700 + + Create pseudo sections for NT_ARM_TLS notes on FreeBSD. + + bfd/ChangeLog: + + * elf.c (elfcore_grok_freebsd_note): Handle NT_ARM_TLS notes. + + (cherry picked from commit 8e6afe4013fd57f92eec4659439bc6e44b0446f8) + +diff --git a/bfd/ChangeLog b/bfd/ChangeLog +index 10098014297..197bfd425a7 100644 +--- bfd/ChangeLog ++++ bfd/ChangeLog +@@ -1,3 +1,7 @@ ++2022-04-27 John Baldwin ++ ++ * elf.c (elfcore_grok_freebsd_note): Handle NT_ARM_TLS notes. ++ + 2022-04-01 John Baldwin + + * elf-bfd.h (elfcore_write_x86_segbases): New. +diff --git a/bfd/elf.c b/bfd/elf.c +index 37c53cfdf32..e9148dbecab 100644 +--- bfd/elf.c ++++ bfd/elf.c +@@ -11037,6 +11037,9 @@ elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note) + return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.lwpinfo", + note); + ++ case NT_ARM_TLS: ++ return elfcore_grok_aarch_tls (abfd, note); ++ + case NT_ARM_VFP: + return elfcore_grok_arm_vfp (abfd, note); + Index: devel/gdb/files/commit-922c2fc18e4 =================================================================== --- /dev/null +++ devel/gdb/files/commit-922c2fc18e4 @@ -0,0 +1,132 @@ +commit 0167735706a3328fb8d2206e6eae472e231e8695 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + x86-nat: Use an unordered_map to store per-pid debug reg state. + + This replaces a manual linked list which used O(n) lookup and removal. + + (cherry picked from commit 922c2fc18e4de33d24b6ba3b7b6e8732209a5e69) + +diff --git a/gdb/x86-nat.c b/gdb/x86-nat.c +index d0d52a00265..c1e892bf564 100644 +--- gdb/x86-nat.c ++++ gdb/x86-nat.c +@@ -22,6 +22,8 @@ + #include "gdbcmd.h" + #include "inferior.h" + ++#include ++ + /* Support for hardware watchpoints and breakpoints using the x86 + debug registers. + +@@ -36,75 +38,20 @@ + /* Low-level function vector. */ + struct x86_dr_low_type x86_dr_low; + +-/* Per-process data. We don't bind this to a per-inferior registry +- because of targets like x86 GNU/Linux that need to keep track of +- processes that aren't bound to any inferior (e.g., fork children, +- checkpoints). */ ++/* Hash table storing per-process data. We don't bind this to a ++ per-inferior registry because of targets like x86 GNU/Linux that ++ need to keep track of processes that aren't bound to any inferior ++ (e.g., fork children, checkpoints). */ + +-struct x86_process_info +-{ +- /* Linked list. */ +- struct x86_process_info *next; +- +- /* The process identifier. */ +- pid_t pid; +- +- /* Copy of x86 hardware debug registers. */ +- struct x86_debug_reg_state state; +-}; +- +-static struct x86_process_info *x86_process_list = NULL; +- +-/* Find process data for process PID. */ +- +-static struct x86_process_info * +-x86_find_process_pid (pid_t pid) +-{ +- struct x86_process_info *proc; +- +- for (proc = x86_process_list; proc; proc = proc->next) +- if (proc->pid == pid) +- return proc; +- +- return NULL; +-} +- +-/* Add process data for process PID. Returns newly allocated info +- object. */ +- +-static struct x86_process_info * +-x86_add_process (pid_t pid) +-{ +- struct x86_process_info *proc = XCNEW (struct x86_process_info); +- +- proc->pid = pid; +- proc->next = x86_process_list; +- x86_process_list = proc; +- +- return proc; +-} +- +-/* Get data specific info for process PID, creating it if necessary. +- Never returns NULL. */ +- +-static struct x86_process_info * +-x86_process_info_get (pid_t pid) +-{ +- struct x86_process_info *proc; +- +- proc = x86_find_process_pid (pid); +- if (proc == NULL) +- proc = x86_add_process (pid); +- +- return proc; +-} ++static std::unordered_map x86_debug_process_state; + + /* Get debug registers state for process PID. */ + + struct x86_debug_reg_state * + x86_debug_reg_state (pid_t pid) + { +- return &x86_process_info_get (pid)->state; ++ return &x86_debug_process_state[pid]; + } + + /* See declaration in x86-nat.h. */ +@@ -112,24 +59,7 @@ x86_debug_reg_state (pid_t pid) + void + x86_forget_process (pid_t pid) + { +- struct x86_process_info *proc, **proc_link; +- +- proc = x86_process_list; +- proc_link = &x86_process_list; +- +- while (proc != NULL) +- { +- if (proc->pid == pid) +- { +- *proc_link = proc->next; +- +- xfree (proc); +- return; +- } +- +- proc_link = &proc->next; +- proc = *proc_link; +- } ++ x86_debug_process_state.erase (pid); + } + + /* Clear the reference counts and forget everything we knew about the Index: devel/gdb/files/commit-92d48a1e4ea =================================================================== --- /dev/null +++ devel/gdb/files/commit-92d48a1e4ea @@ -0,0 +1,288 @@ +commit 1a0c401bbc882307404666733808666715f93dd7 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Add an arm-tls feature which includes the tpidruro register from CP15. + + (cherry picked from commit 92d48a1e4eac54db11f1a110328672394fce2853) + +diff --git gdb/arch/aarch32.c gdb/arch/aarch32.c +index 0c544d381f1..4d6ffb44a15 100644 +--- gdb/arch/aarch32.c ++++ gdb/arch/aarch32.c +@@ -19,6 +19,7 @@ + #include "aarch32.h" + + #include "../features/arm/arm-core.c" ++#include "../features/arm/arm-tls.c" + #include "../features/arm/arm-vfpv3.c" + + /* See aarch32.h. */ +@@ -38,6 +39,7 @@ aarch32_create_target_description () + /* Create a vfpv3 feature, then a blank NEON feature. */ + regnum = create_feature_arm_arm_vfpv3 (tdesc.get (), regnum); + tdesc_create_feature (tdesc.get (), "org.gnu.gdb.arm.neon"); ++ regnum = create_feature_arm_arm_tls (tdesc.get (), regnum); + + return tdesc.release (); + } +diff --git gdb/arch/arm.c gdb/arch/arm.c +index 126e46a950a..15b600e22f4 100644 +--- gdb/arch/arm.c ++++ gdb/arch/arm.c +@@ -22,6 +22,7 @@ + #include "arm.h" + + #include "../features/arm/arm-core.c" ++#include "../features/arm/arm-tls.c" + #include "../features/arm/arm-vfpv2.c" + #include "../features/arm/arm-vfpv3.c" + #include "../features/arm/xscale-iwmmxt.c" +@@ -373,7 +374,7 @@ shifted_reg_val (struct regcache *regcache, unsigned long inst, + /* See arch/arm.h. */ + + target_desc * +-arm_create_target_description (arm_fp_type fp_type) ++arm_create_target_description (arm_fp_type fp_type, bool tls) + { + target_desc_up tdesc = allocate_target_description (); + +@@ -409,6 +410,9 @@ arm_create_target_description (arm_fp_type fp_type) + error (_("Invalid Arm FP type: %d"), fp_type); + } + ++ if (tls) ++ regnum = create_feature_arm_arm_tls (tdesc.get (), regnum); ++ + return tdesc.release (); + } + +diff --git gdb/arch/arm.h gdb/arch/arm.h +index f75470e7572..2873effae8b 100644 +--- gdb/arch/arm.h ++++ gdb/arch/arm.h +@@ -193,7 +193,7 @@ unsigned long shifted_reg_val (struct regcache *regcache, + + /* Create an Arm target description with the given FP hardware type. */ + +-target_desc *arm_create_target_description (arm_fp_type fp_type); ++target_desc *arm_create_target_description (arm_fp_type fp_type, bool tls); + + /* Create an Arm M-profile target description with the given hardware type. */ + +diff --git gdb/arm-fbsd-tdep.c gdb/arm-fbsd-tdep.c +index bf337b13f98..06745a36186 100644 +--- gdb/arm-fbsd-tdep.c ++++ gdb/arm-fbsd-tdep.c +@@ -188,9 +188,9 @@ arm_fbsd_read_description_auxv (struct target_ops *target) + return aarch32_read_description (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPD32)) + == (HWCAP_VFPv3 | HWCAP_VFPD32)) +- return arm_read_description (ARM_FP_TYPE_VFPV3); ++ return arm_read_description (ARM_FP_TYPE_VFPV3, false); + else +- return arm_read_description (ARM_FP_TYPE_VFPV2); ++ return arm_read_description (ARM_FP_TYPE_VFPV2, false); + } + + return nullptr; +diff --git gdb/arm-linux-nat.c gdb/arm-linux-nat.c +index f0f09acf2f9..2abaf5a675d 100644 +--- gdb/arm-linux-nat.c ++++ gdb/arm-linux-nat.c +@@ -550,7 +550,7 @@ arm_linux_nat_target::read_description () + } + + if (arm_hwcap & HWCAP_IWMMXT) +- return arm_read_description (ARM_FP_TYPE_IWMMXT); ++ return arm_read_description (ARM_FP_TYPE_IWMMXT, false); + + if (arm_hwcap & HWCAP_VFP) + { +@@ -567,9 +567,9 @@ arm_linux_nat_target::read_description () + if (arm_hwcap & HWCAP_NEON) + return aarch32_read_description (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) +- return arm_read_description (ARM_FP_TYPE_VFPV3); ++ return arm_read_description (ARM_FP_TYPE_VFPV3, false); + +- return arm_read_description (ARM_FP_TYPE_VFPV2); ++ return arm_read_description (ARM_FP_TYPE_VFPV2, false); + } + + return this->beneath ()->read_description (); +diff --git gdb/arm-linux-tdep.c gdb/arm-linux-tdep.c +index 6aac016afb9..805c6ac0459 100644 +--- gdb/arm-linux-tdep.c ++++ gdb/arm-linux-tdep.c +@@ -741,9 +741,9 @@ arm_linux_core_read_description (struct gdbarch *gdbarch, + if (arm_hwcap & HWCAP_NEON) + return aarch32_read_description (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) +- return arm_read_description (ARM_FP_TYPE_VFPV3); ++ return arm_read_description (ARM_FP_TYPE_VFPV3, false); + +- return arm_read_description (ARM_FP_TYPE_VFPV2); ++ return arm_read_description (ARM_FP_TYPE_VFPV2, false); + } + + return nullptr; +diff --git gdb/arm-netbsd-nat.c gdb/arm-netbsd-nat.c +index 591a0ab1d54..764bbe8cd3d 100644 +--- gdb/arm-netbsd-nat.c ++++ gdb/arm-netbsd-nat.c +@@ -346,13 +346,13 @@ arm_netbsd_nat_target::read_description () + + if (sysctlbyname("machdep.fpu_present", &flag, &len, NULL, 0) != 0 + || !flag) +- return arm_read_description (ARM_FP_TYPE_NONE); ++ return arm_read_description (ARM_FP_TYPE_NONE, false); + + len = sizeof(flag); + if (sysctlbyname("machdep.neon_present", &flag, &len, NULL, 0) == 0 && flag) + return aarch32_read_description (); + +- return arm_read_description (ARM_FP_TYPE_VFPV3); ++ return arm_read_description (ARM_FP_TYPE_VFPV3, false); + } + + void _initialize_arm_netbsd_nat (); +diff --git gdb/arm-tdep.c gdb/arm-tdep.c +index 8e245648f23..0c87388bc11 100644 +--- gdb/arm-tdep.c ++++ gdb/arm-tdep.c +@@ -239,7 +239,7 @@ static const char **valid_disassembly_styles; + static const char *disassembly_style; + + /* All possible arm target descriptors. */ +-static struct target_desc *tdesc_arm_list[ARM_FP_TYPE_INVALID]; ++static struct target_desc *tdesc_arm_list[ARM_FP_TYPE_INVALID][2]; + static struct target_desc *tdesc_arm_mprofile_list[ARM_M_TYPE_INVALID]; + + /* This is used to keep the bfd arch_info in sync with the disassembly +@@ -9100,6 +9100,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + bool have_mve = false; + int mve_vpr_regnum = -1; + int register_count = ARM_NUM_REGS; ++ int tls_regnum = 0; + + /* If we have an object to base this architecture on, try to determine + its ABI. */ +@@ -9410,6 +9411,19 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + } + } + ++ /* Check for the TLS register feature. */ ++ feature = tdesc_find_feature (tdesc, "org.gnu.gdb.arm.tls"); ++ if (feature != nullptr) ++ { ++ valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), ++ register_count, "tpidruro"); ++ if (!valid_p) ++ return nullptr; ++ ++ tls_regnum = register_count; ++ register_count++; ++ } ++ + /* Check for MVE after all the checks for GPR's, VFP and Neon. + MVE (Helium) is an M-profile extension. */ + if (is_m) +@@ -9493,6 +9507,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + tdep->have_s_pseudos = have_s_pseudos; + tdep->have_q_pseudos = have_q_pseudos; + tdep->have_neon = have_neon; ++ tdep->tls_regnum = tls_regnum; + + /* Adjust the MVE feature settings. */ + if (have_mve) +@@ -13725,14 +13740,14 @@ arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache, + /* See arm-tdep.h. */ + + const target_desc * +-arm_read_description (arm_fp_type fp_type) ++arm_read_description (arm_fp_type fp_type, bool tls) + { +- struct target_desc *tdesc = tdesc_arm_list[fp_type]; ++ struct target_desc *tdesc = tdesc_arm_list[fp_type][tls]; + + if (tdesc == nullptr) + { +- tdesc = arm_create_target_description (fp_type); +- tdesc_arm_list[fp_type] = tdesc; ++ tdesc = arm_create_target_description (fp_type, tls); ++ tdesc_arm_list[fp_type][tls] = tdesc; + } + + return tdesc; +diff --git gdb/arm-tdep.h gdb/arm-tdep.h +index 8a9f618539f..ddcd08a4dc9 100644 +--- gdb/arm-tdep.h ++++ gdb/arm-tdep.h +@@ -119,6 +119,8 @@ struct arm_gdbarch_tdep : gdbarch_tdep + int mve_pseudo_base = 0; /* Number of the first MVE pseudo register. */ + int mve_pseudo_count = 0; /* Total number of MVE pseudo registers. */ + ++ int tls_regnum = 0; /* Number of the tpidruro register. */ ++ + bool is_m = false; /* Does the target follow the "M" profile. */ + CORE_ADDR lowest_pc = 0; /* Lowest address at which instructions + will appear. */ +@@ -301,7 +303,7 @@ extern void + const struct regcache *regcache); + + /* Get the correct Arm target description with given FP hardware type. */ +-const target_desc *arm_read_description (arm_fp_type fp_type); ++const target_desc *arm_read_description (arm_fp_type fp_type, bool tls); + + /* Get the correct Arm M-Profile target description with given hardware + type. */ +diff --git gdb/features/Makefile gdb/features/Makefile +index 68e17d0085d..4b09819389a 100644 +--- gdb/features/Makefile ++++ gdb/features/Makefile +@@ -207,6 +207,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ + arm/arm-m-profile.xml \ + arm/arm-m-profile-mve.xml \ + arm/arm-m-profile-with-fpa.xml \ ++ arm/arm-tls.xml \ + arm/arm-vfpv2.xml \ + arm/arm-vfpv3.xml \ + arm/xscale-iwmmxt.xml \ +diff --git gdb/features/arm/arm-tls.c gdb/features/arm/arm-tls.c +new file mode 100644 +index 00000000000..d1214dda8ec +--- /dev/null ++++ gdb/features/arm/arm-tls.c +@@ -0,0 +1,14 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: arm-tls.xml */ ++ ++#include "gdbsupport/tdesc.h" ++ ++static int ++create_feature_arm_arm_tls (struct target_desc *result, long regnum) ++{ ++ struct tdesc_feature *feature; ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.tls"); ++ tdesc_create_reg (feature, "tpidruro", regnum++, 1, NULL, 32, "data_ptr"); ++ return regnum; ++} +diff --git gdb/features/arm/arm-tls.xml gdb/features/arm/arm-tls.xml +new file mode 100644 +index 00000000000..3cdf73e776f +--- /dev/null ++++ gdb/features/arm/arm-tls.xml +@@ -0,0 +1,11 @@ ++ ++ ++ ++ ++ ++ ++ Index: devel/gdb/files/commit-983b1119bc3 =================================================================== --- /dev/null +++ devel/gdb/files/commit-983b1119bc3 @@ -0,0 +1,42 @@ +commit 1371da3a2d71dbd58f5ba3dd3c39841f0182556d +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + fbsd-nat: Add a low_delete_thread virtual method. + + This method can be overridden by architecture-specific targets to + perform additional work when a thread is deleted. + + Note that this method is only invoked on systems supporting LWP + events, but the pending use case (aarch64 debug registers) is not + supported on older kernels that do not support LWP events. + + (cherry picked from commit 983b1119bc315c9182e3aba898ca8099e54da49e) + +diff --git gdb/fbsd-nat.c gdb/fbsd-nat.c +index 51234eaa6c9..2bc7937a38b 100644 +--- gdb/fbsd-nat.c ++++ gdb/fbsd-nat.c +@@ -1293,6 +1293,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, + if (print_thread_events) + printf_unfiltered (_("[%s exited]\n"), + target_pid_to_str (wptid).c_str ()); ++ low_delete_thread (thr); + delete_thread (thr); + } + if (ptrace (PT_CONTINUE, pid, (caddr_t) 1, 0) == -1) +diff --git gdb/fbsd-nat.h gdb/fbsd-nat.h +index d7c8eb81e96..6028aebfccc 100644 +--- gdb/fbsd-nat.h ++++ gdb/fbsd-nat.h +@@ -115,6 +115,10 @@ class fbsd_nat_target : public inf_ptrace_target + virtual void low_new_fork (ptid_t parent, pid_t child) + {} + ++ /* The method to call, if any, when a thread is destroyed. */ ++ virtual void low_delete_thread (thread_info *) ++ {} ++ + protected: + + void post_startup_inferior (ptid_t) override; Index: devel/gdb/files/commit-a171378aa47 =================================================================== --- /dev/null +++ devel/gdb/files/commit-a171378aa47 @@ -0,0 +1,45 @@ +commit 9f5989ef192efab3d477fd6cc8712a8fd53e1856 +Author: John Baldwin +Date: Fri Apr 1 13:16:46 2022 -0700 + + Recognize FreeBSD core dump note for x86 segment base registers. + + This core dump note contains the value of the base address of the %fs + and %gs segments for both i386 and amd64 core dumps. It is primarily + useful in resolving the address of TLS variables in core dumps. + + binutils/ChangeLog: + + * readelf.c (get_freebsd_elfcore_note_type): Handle + NT_FREEBSD_X86_SEGBASES. + + include/ChangeLog: + + * elf/common.h (NT_FREEBSD_X86_SEGBASES): Define. + + (cherry picked from commit a171378aa472fab0407dc1f99e8e7782286719ed) + +diff --git a/include/ChangeLog b/include/ChangeLog +index 82194629c97..502fc47c148 100644 +--- include/ChangeLog ++++ include/ChangeLog +@@ -1,3 +1,7 @@ ++2022-04-01 John Baldwin ++ ++ * elf/common.h (NT_FREEBSD_X86_SEGBASES): Define. ++ + 2022-03-16 Simon Marchi + + * elf/amdgpu.h: Add relocation values. +diff --git a/include/elf/common.h b/include/elf/common.h +index 70d63e3299c..ad62a7d8523 100644 +--- include/elf/common.h ++++ include/elf/common.h +@@ -738,6 +738,7 @@ + #define NT_FREEBSD_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ + #define NT_FREEBSD_PROCSTAT_AUXV 16 /* Procstat auxv data. */ + #define NT_FREEBSD_PTLWPINFO 17 /* Thread ptrace miscellaneous info. */ ++#define NT_FREEBSD_X86_SEGBASES 0x200 /* x86 segment base registers */ + + /* Note segments for core files on NetBSD systems. Note name + must start with "NetBSD-CORE". */ Index: devel/gdb/files/commit-a3627b54280 =================================================================== --- /dev/null +++ devel/gdb/files/commit-a3627b54280 @@ -0,0 +1,53 @@ +commit 28207615d3f3d639a71df51be9ceed3033bb17c6 +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + fbsd-nat: Add a low_prepare_to_resume virtual method. + + This method can be overridden by architecture-specific targets to + perform additional work before a thread is resumed. + + (cherry picked from commit a3627b54280ba306766f2689fb35442f24c4c313) + +diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c +index 2bc7937a38b..934fdbad6ef 100644 +--- gdb/fbsd-nat.c ++++ gdb/fbsd-nat.c +@@ -1138,6 +1138,8 @@ fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo) + perror_with_name (request == PT_RESUME ? + ("ptrace (PT_RESUME)") : + ("ptrace (PT_SUSPEND)")); ++ if (request == PT_RESUME) ++ low_prepare_to_resume (tp); + } + } + else +@@ -1145,8 +1147,11 @@ fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo) + /* If ptid is a wildcard, resume all matching threads (they won't run + until the process is continued however). */ + for (thread_info *tp : all_non_exited_threads (this, ptid)) +- if (ptrace (PT_RESUME, tp->ptid.lwp (), NULL, 0) == -1) +- perror_with_name (("ptrace (PT_RESUME)")); ++ { ++ if (ptrace (PT_RESUME, tp->ptid.lwp (), NULL, 0) == -1) ++ perror_with_name (("ptrace (PT_RESUME)")); ++ low_prepare_to_resume (tp); ++ } + ptid = inferior_ptid; + } + +diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h +index 6028aebfccc..82f7ee47949 100644 +--- gdb/fbsd-nat.h ++++ gdb/fbsd-nat.h +@@ -119,6 +119,10 @@ class fbsd_nat_target : public inf_ptrace_target + virtual void low_delete_thread (thread_info *) + {} + ++ /* Hook to call prior to resuming a thread. */ ++ virtual void low_prepare_to_resume (thread_info *) ++ {} ++ + protected: + + void post_startup_inferior (ptid_t) override; Index: devel/gdb/files/commit-a49ce729c80 =================================================================== --- /dev/null +++ devel/gdb/files/commit-a49ce729c80 @@ -0,0 +1,157 @@ +commit 6f5759385274e15c5ef1a7d879ce7324ab0605ab +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + Add an x86_fbsd_nat_target mixin class for FreeBSD x86 native targets. + + This class implements debug register support common between the i386 + and amd64 native targets. + + While here, remove #ifdef's for HAVE_PT_GETDBREGS in FreeBSD-specific + code. The ptrace request has been present on FreeBSD x86 + architectures since 4.0 (released in March 2000). The last FreeBSD + release without this support is 3.5 released in June 2000. + + (cherry picked from commit a49ce729c808b5762faf948a34e6159a6d8874de) + +diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c +index 368f4c10786..d125d582a21 100644 +--- gdb/amd64-fbsd-nat.c ++++ gdb/amd64-fbsd-nat.c +@@ -29,26 +29,20 @@ + #include + #include + +-#include "fbsd-nat.h" + #include "amd64-tdep.h" + #include "amd64-fbsd-tdep.h" + #include "amd64-nat.h" + #include "x86-nat.h" + #include "gdbsupport/x86-xstate.h" +-#include "x86-bsd-nat.h" ++#include "x86-fbsd-nat.h" + +-class amd64_fbsd_nat_target final +- : public x86bsd_nat_target ++class amd64_fbsd_nat_target final : public x86_fbsd_nat_target + { + public: + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; + + const struct target_desc *read_description () override; +- +-#if defined(HAVE_PT_GETDBREGS) +- bool supports_stopped_by_hw_breakpoint () override; +-#endif + }; + + static amd64_fbsd_nat_target the_amd64_fbsd_nat_target; +@@ -348,16 +342,6 @@ amd64_fbsd_nat_target::read_description () + return i386_target_description (X86_XSTATE_SSE_MASK, true); + } + +-#if defined(HAVE_PT_GETDBREGS) +-/* Implement the supports_stopped_by_hw_breakpoints method. */ +- +-bool +-amd64_fbsd_nat_target::supports_stopped_by_hw_breakpoint () +-{ +- return true; +-} +-#endif +- + void _initialize_amd64fbsd_nat (); + void + _initialize_amd64fbsd_nat () +diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c +index 023f24bab37..4b8ba8b598f 100644 +--- gdb/i386-fbsd-nat.c ++++ gdb/i386-fbsd-nat.c +@@ -27,16 +27,14 @@ + #include + #include + +-#include "fbsd-nat.h" + #include "i386-tdep.h" + #include "i386-fbsd-tdep.h" + #include "i387-tdep.h" + #include "x86-nat.h" + #include "gdbsupport/x86-xstate.h" +-#include "x86-bsd-nat.h" ++#include "x86-fbsd-nat.h" + +-class i386_fbsd_nat_target final +- : public x86bsd_nat_target ++class i386_fbsd_nat_target final : public x86_fbsd_nat_target + { + public: + void fetch_registers (struct regcache *, int) override; +@@ -45,10 +43,6 @@ class i386_fbsd_nat_target final + const struct target_desc *read_description () override; + + void resume (ptid_t, int, enum gdb_signal) override; +- +-#if defined(HAVE_PT_GETDBREGS) +- bool supports_stopped_by_hw_breakpoint () override; +-#endif + }; + + static i386_fbsd_nat_target the_i386_fbsd_nat_target; +@@ -361,16 +355,6 @@ i386_fbsd_nat_target::read_description () + return i386_target_description (X86_XSTATE_X87_MASK, true); + } + +-#if defined(HAVE_PT_GETDBREGS) +-/* Implement the supports_stopped_by_hw_breakpoints method. */ +- +-bool +-i386_fbsd_nat_target::supports_stopped_by_hw_breakpoint () +-{ +- return true; +-} +-#endif +- + void _initialize_i386fbsd_nat (); + void + _initialize_i386fbsd_nat () +diff --git a/gdb/x86-fbsd-nat.h b/gdb/x86-fbsd-nat.h +new file mode 100644 +index 00000000000..f9d3514aab4 +--- /dev/null ++++ gdb/x86-fbsd-nat.h +@@ -0,0 +1,34 @@ ++/* Native-dependent code for FreeBSD x86. ++ ++ Copyright (C) 2022 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 . */ ++ ++#ifndef X86_FBSD_NAT_H ++#define X86_FBSD_NAT_H ++ ++#include "fbsd-nat.h" ++#include "x86-bsd-nat.h" ++ ++/* A prototype FreeBSD/x86 target. */ ++ ++class x86_fbsd_nat_target : public x86bsd_nat_target ++{ ++ bool supports_stopped_by_hw_breakpoint () override ++ { return true; } ++}; ++ ++#endif /* x86-bsd-nat.h */ Index: devel/gdb/files/commit-b1babce7c31 =================================================================== --- /dev/null +++ devel/gdb/files/commit-b1babce7c31 @@ -0,0 +1,50 @@ +commit 8a528699fdc82963d528bbbbd3f3509e1472a64b +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + x86-nat: Add x86_lookup_debug_reg_state. + + This function returns nullptr if debug register state does not yet + exist for a given process rather than creating new state. + + (cherry picked from commit b1babce7c31def7fb894875136788490b167f989) + +diff --git a/gdb/x86-nat.c b/gdb/x86-nat.c +index c1e892bf564..36513dd8cfb 100644 +--- gdb/x86-nat.c ++++ gdb/x86-nat.c +@@ -46,6 +46,18 @@ struct x86_dr_low_type x86_dr_low; + static std::unordered_map x86_debug_process_state; + ++/* See x86-nat.h. */ ++ ++struct x86_debug_reg_state * ++x86_lookup_debug_reg_state (pid_t pid) ++{ ++ auto it = x86_debug_process_state.find (pid); ++ if (it != x86_debug_process_state.end ()) ++ return &it->second; ++ ++ return nullptr; ++} ++ + /* Get debug registers state for process PID. */ + + struct x86_debug_reg_state * +diff --git a/gdb/x86-nat.h b/gdb/x86-nat.h +index 913291a2305..d9c2a3f6e14 100644 +--- gdb/x86-nat.h ++++ gdb/x86-nat.h +@@ -40,6 +40,11 @@ extern void x86_set_debug_register_length (int len); + + extern void x86_cleanup_dregs (void); + ++/* Return the debug register state for process PID. If no existing ++ state is found for this process, return nullptr. */ ++ ++struct x86_debug_reg_state *x86_lookup_debug_reg_state (pid_t pid); ++ + /* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of debug register state. */ + Index: devel/gdb/files/commit-b5c2367c3ac =================================================================== --- /dev/null +++ devel/gdb/files/commit-b5c2367c3ac @@ -0,0 +1,89 @@ +commit f5bae6f6cb45860d63ebc6d309404cf5d7d29052 +Author: John Baldwin +Date: Fri Apr 1 13:16:46 2022 -0700 + + Use pseudosections for NT_FREEBSD_X86_SEGBASES core dump notes. + + This includes adding pseudosections when reading a core dump as well + as support for writing out a core dump note from a pseudosection. + + bfd/ChangeLog: + + * elf-bfd.h (elfcore_write_x86_segbases): New. + * elf.c (elfcore_grok_freebsd_note): Add pseudosections for + NT_FREEBSD_X86_SEGBASES register notes. + (elfcore_write_x86_segbases): New. + (elfcore_write_register_note): Write NT_FREEBSD_X86_SEGBASES + register notes. + + (cherry picked from commit b5c2367c3ac5f696221d9c24f470498abdb83257) + +diff --git a/bfd/ChangeLog b/bfd/ChangeLog +index ae8b25faae4..10098014297 100644 +--- bfd/ChangeLog ++++ bfd/ChangeLog +@@ -1,3 +1,12 @@ ++2022-04-01 John Baldwin ++ ++ * elf-bfd.h (elfcore_write_x86_segbases): New. ++ * elf.c (elfcore_grok_freebsd_note): Add pseudosections for ++ NT_FREEBSD_X86_SEGBASES register notes. ++ (elfcore_write_x86_segbases): New. ++ (elfcore_write_register_note): Write NT_FREEBSD_X86_SEGBASES ++ register notes. ++ + 2022-04-01 John Baldwin + + * elf.c (elfcore_grok_freebsd_note): Remove checks for namesz. +diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h +index 5c3985f6e57..c7c0a793b15 100644 +--- bfd/elf-bfd.h ++++ bfd/elf-bfd.h +@@ -2786,6 +2786,8 @@ extern char *elfcore_write_prxfpreg + (bfd *, char *, int *, const void *, int); + extern char *elfcore_write_xstatereg + (bfd *, char *, int *, const void *, int); ++extern char *elfcore_write_x86_segbases ++ (bfd *, char *, int *, const void *, int); + extern char *elfcore_write_ppc_vmx + (bfd *, char *, int *, const void *, int); + extern char *elfcore_write_ppc_vsx +diff --git a/bfd/elf.c b/bfd/elf.c +index a99149e50b3..37c53cfdf32 100644 +--- bfd/elf.c ++++ bfd/elf.c +@@ -11027,6 +11027,9 @@ elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note) + case NT_FREEBSD_PROCSTAT_AUXV: + return elfcore_make_auxv_note_section (abfd, note, 4); + ++ case NT_FREEBSD_X86_SEGBASES: ++ return elfcore_make_note_pseudosection (abfd, ".reg-x86-segbases", note); ++ + case NT_X86_XSTATE: + return elfcore_grok_xstatereg (abfd, note); + +@@ -11904,6 +11907,15 @@ elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz, + note_name, NT_X86_XSTATE, xfpregs, size); + } + ++char * ++elfcore_write_x86_segbases (bfd *abfd, char *buf, int *bufsiz, ++ const void *regs, int size) ++{ ++ char *note_name = "FreeBSD"; ++ return elfcore_write_note (abfd, buf, bufsiz, ++ note_name, NT_FREEBSD_X86_SEGBASES, regs, size); ++} ++ + char * + elfcore_write_ppc_vmx (bfd *abfd, + char *buf, +@@ -12441,6 +12453,8 @@ elfcore_write_register_note (bfd *abfd, + return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-xstate") == 0) + return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size); ++ if (strcmp (section, ".reg-x86-segbases") == 0) ++ return elfcore_write_x86_segbases (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-ppc-vmx") == 0) + return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-ppc-vsx") == 0) Index: devel/gdb/files/commit-b7fe5463cf0 =================================================================== --- /dev/null +++ devel/gdb/files/commit-b7fe5463cf0 @@ -0,0 +1,102 @@ +commit 0e67403c6b094d638a4ca130ff6dcd6a153f3eb2 +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Fetch the NT_ARM_TLS register set for native FreeBSD/Aarch64 processes. + + This permits resolving TLS variables. + + (cherry picked from commit b7fe5463cf0dd6d7701d0be5ae129a9d4ecd28bc) + +diff --git gdb/aarch64-fbsd-nat.c gdb/aarch64-fbsd-nat.c +index 99e2bf35276..910bf5bb190 100644 +--- gdb/aarch64-fbsd-nat.c ++++ gdb/aarch64-fbsd-nat.c +@@ -24,12 +24,15 @@ + #include "target.h" + #include "nat/aarch64-hw-point.h" + ++#include "elf/common.h" ++ + #include + #include + #include + #include + + #include "fbsd-nat.h" ++#include "aarch64-tdep.h" + #include "aarch64-fbsd-tdep.h" + #include "aarch64-nat.h" + #include "inf-ptrace.h" +@@ -50,6 +53,8 @@ struct aarch64_fbsd_nat_target final : public fbsd_nat_target + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; + ++ const struct target_desc *read_description () override; ++ + #ifdef HAVE_DBREG + /* Hardware breakpoints and watchpoints. */ + bool stopped_by_watchpoint () override; +@@ -84,6 +89,26 @@ aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache, + &aarch64_fbsd_gregset); + fetch_register_set (regcache, regnum, PT_GETFPREGS, + &aarch64_fbsd_fpregset); ++ ++ gdbarch *gdbarch = regcache->arch (); ++ aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ if (tdep->has_tls ()) ++ { ++ const struct regcache_map_entry aarch64_fbsd_tls_regmap[] = ++ { ++ { 1, tdep->tls_regnum, 8 }, ++ { 0 } ++ }; ++ ++ const struct regset aarch64_fbsd_tls_regset = ++ { ++ aarch64_fbsd_tls_regmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ fetch_regset (regcache, regnum, NT_ARM_TLS, ++ &aarch64_fbsd_tls_regset); ++ } + } + + /* Store register REGNUM back into the inferior. If REGNUM is -1, do +@@ -97,6 +122,35 @@ aarch64_fbsd_nat_target::store_registers (struct regcache *regcache, + &aarch64_fbsd_gregset); + store_register_set (regcache, regnum, PT_GETFPREGS, + PT_SETFPREGS, &aarch64_fbsd_fpregset); ++ ++ gdbarch *gdbarch = regcache->arch (); ++ aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ if (tdep->has_tls ()) ++ { ++ const struct regcache_map_entry aarch64_fbsd_tls_regmap[] = ++ { ++ { 1, tdep->tls_regnum, 8 }, ++ { 0 } ++ }; ++ ++ const struct regset aarch64_fbsd_tls_regset = ++ { ++ aarch64_fbsd_tls_regmap, ++ regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ store_regset (regcache, regnum, NT_ARM_TLS, ++ &aarch64_fbsd_tls_regset); ++ } ++} ++ ++/* Implement the target read_description method. */ ++ ++const struct target_desc * ++aarch64_fbsd_nat_target::read_description () ++{ ++ bool tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0; ++ return aarch64_read_description (0, false, false, tls); + } + + #ifdef HAVE_DBREG Index: devel/gdb/files/commit-c13566fdd57 =================================================================== --- /dev/null +++ devel/gdb/files/commit-c13566fdd57 @@ -0,0 +1,35 @@ +commit 7995cf839e5c608372e78f8bd5f6d120803a4e63 +Author: John Baldwin +Date: Fri Apr 1 13:16:46 2022 -0700 + + Use I386_GSBASE_REGNUM in i386fbsd_get_thread_local_address. + + 32-bit x86 arches always the I386_*BASE_REGNUM values. Only code that + needs to support both 64-bit and 32-bit arches needs to use + tdep->fsbase_regnum to compute a segment base register number. + + (cherry picked from commit c13566fdd5725d4c337a2741be02c12c4f430022) + +diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c +index fad091f8472..d50f35707ee 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -350,16 +350,13 @@ i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, + i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); + struct regcache *regcache; + +- if (tdep->fsbase_regnum == -1) +- error (_("Unable to fetch %%gsbase")); +- + regcache = get_thread_arch_regcache (current_inferior ()->process_target (), + ptid, gdbarch); + +- target_fetch_registers (regcache, tdep->fsbase_regnum + 1); ++ target_fetch_registers (regcache, I386_GSBASE_REGNUM); + + ULONGEST gsbase; +- if (regcache->cooked_read (tdep->fsbase_regnum + 1, &gsbase) != REG_VALID) ++ if (regcache->cooked_read (I386_GSBASE_REGNUM, &gsbase) != REG_VALID) + error (_("Unable to fetch %%gsbase")); + + CORE_ADDR dtv_addr = gsbase + gdbarch_ptr_bit (gdbarch) / 8; Index: devel/gdb/files/commit-c77282d8ba9 =================================================================== --- /dev/null +++ devel/gdb/files/commit-c77282d8ba9 @@ -0,0 +1,41 @@ +commit 066ae99a326d77966288c59066018ca6f3f1d22d +Author: John Baldwin +Date: Tue Mar 22 12:05:43 2022 -0700 + + fbsd-nat: Add a low_new_fork virtual method. + + This method can be overridden by architecture-specific targets to + perform additional work when a new child process is forked. + + (cherry picked from commit c77282d8ba91cf25cf2f08b76702c447e2e74575) + +diff --git gdb/fbsd-nat.c gdb/fbsd-nat.c +index ba84265dd58..6d76c8234d5 100644 +--- gdb/fbsd-nat.c ++++ gdb/fbsd-nat.c +@@ -1380,6 +1380,8 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, + warning (_("Failed to fetch process information")); + #endif + ++ low_new_fork (wptid, child); ++ + if (is_vfork) + ourstatus->set_vforked (child_ptid); + else +diff --git gdb/fbsd-nat.h gdb/fbsd-nat.h +index 2d9c6e19a2c..2f17be5a8f0 100644 +--- gdb/fbsd-nat.h ++++ gdb/fbsd-nat.h +@@ -109,6 +109,12 @@ class fbsd_nat_target : public inf_ptrace_target + + bool supports_disable_randomization () override; + ++ /* Methods meant to be overridden by arch-specific target ++ classes. */ ++ ++ virtual void low_new_fork (ptid_t parent, pid_t child) ++ {} ++ + protected: + + void post_startup_inferior (ptid_t) override; Index: devel/gdb/files/commit-e330d4c033e =================================================================== --- /dev/null +++ devel/gdb/files/commit-e330d4c033e @@ -0,0 +1,55 @@ +commit 1ec77d89016f9b26dde3de6cdc4f4eaa44bbff13 +Author: John Baldwin +Date: Fri Apr 1 13:16:46 2022 -0700 + + elfcore_grok_freebsd_note: Remove checks of note->namesz. + + This function is only called if the note name is "FreeBSD", so + checking the name size is unnecessary. + + bfd/ChangeLog: + + * elf.c (elfcore_grok_freebsd_note): Remove checks for namesz. + + (cherry picked from commit e330d4c033eab2e0e7206a29d6c11a9a59fd205b) + +diff --git a/bfd/ChangeLog b/bfd/ChangeLog +index 6ac8b96c57a..ae8b25faae4 100644 +--- bfd/ChangeLog ++++ bfd/ChangeLog +@@ -1,3 +1,7 @@ ++2022-04-01 John Baldwin ++ ++ * elf.c (elfcore_grok_freebsd_note): Remove checks for namesz. ++ + 2022-03-18 Viorel Preoteasa + + PR 28924 +diff --git a/bfd/elf.c b/bfd/elf.c +index 82b53be99f9..a99149e50b3 100644 +--- bfd/elf.c ++++ bfd/elf.c +@@ -11010,10 +11010,7 @@ elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note) + return elfcore_grok_freebsd_psinfo (abfd, note); + + case NT_FREEBSD_THRMISC: +- if (note->namesz == 8) +- return elfcore_make_note_pseudosection (abfd, ".thrmisc", note); +- else +- return true; ++ return elfcore_make_note_pseudosection (abfd, ".thrmisc", note); + + case NT_FREEBSD_PROCSTAT_PROC: + return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.proc", +@@ -11031,10 +11028,7 @@ elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note) + return elfcore_make_auxv_note_section (abfd, note, 4); + + case NT_X86_XSTATE: +- if (note->namesz == 8) +- return elfcore_grok_xstatereg (abfd, note); +- else +- return true; ++ return elfcore_grok_xstatereg (abfd, note); + + case NT_FREEBSD_PTLWPINFO: + return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.lwpinfo", Index: devel/gdb/files/commit-f3215e1526d =================================================================== --- /dev/null +++ devel/gdb/files/commit-f3215e1526d @@ -0,0 +1,114 @@ +commit 87716bf398bfa17f73de9d6ac4a8573e520985e5 +Author: John Baldwin +Date: Fri Apr 1 13:16:46 2022 -0700 + + FreeBSD/x86: Read segment base registers from NT_X86_SEGBASES. + + FreeBSD kernels recently grew a new register core dump note containing + the base addresses of the %fs and %gs segments (corresponding to the + %fsbase and %gsbase registers). Parse this note to permit inspecting + TLS variables in core dumps. Native processes already supported TLS + via older ptrace() operations. + + (cherry picked from commit f3215e1526d762f005fdf86abac81da514c74e50) + +diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c +index da5c297902d..55764beaad2 100644 +--- gdb/amd64-fbsd-tdep.c ++++ gdb/amd64-fbsd-tdep.c +@@ -37,6 +37,9 @@ + 16-bit segment registers. */ + #define AMD64_FBSD_SIZEOF_GREGSET (22 * 8) + ++/* The segment base register set consists of 2 64-bit registers. */ ++#define AMD64_FBSD_SIZEOF_SEGBASES_REGSET (2 * 8) ++ + /* Register maps. */ + + static const struct regcache_map_entry amd64_fbsd_gregmap[] = +@@ -70,6 +73,13 @@ static const struct regcache_map_entry amd64_fbsd_gregmap[] = + { 0 } + }; + ++static const struct regcache_map_entry amd64_fbsd_segbases_regmap[] = ++{ ++ { 1, AMD64_FSBASE_REGNUM, 0 }, ++ { 1, AMD64_GSBASE_REGNUM, 0 }, ++ { 0 } ++}; ++ + /* This layout including fsbase and gsbase was adopted in FreeBSD + 8.0. */ + +@@ -120,6 +130,11 @@ const struct regset amd64_fbsd_gregset = + amd64_fbsd_gregmap, regcache_supply_regset, regcache_collect_regset + }; + ++const struct regset amd64_fbsd_segbases_regset = ++{ ++ amd64_fbsd_segbases_regmap, regcache_supply_regset, regcache_collect_regset ++}; ++ + /* Support for signal handlers. */ + + /* In a signal frame, rsp points to a 'struct sigframe' which is +@@ -253,6 +268,9 @@ amd64fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + &amd64_fbsd_gregset, NULL, cb_data); + cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &amd64_fpregset, + NULL, cb_data); ++ cb (".reg-x86-segbases", AMD64_FBSD_SIZEOF_SEGBASES_REGSET, ++ AMD64_FBSD_SIZEOF_SEGBASES_REGSET, &amd64_fbsd_segbases_regset, ++ "segment bases", cb_data); + cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0), X86_XSTATE_SIZE (tdep->xcr0), + &amd64fbsd_xstateregset, "XSAVE extended state", cb_data); + } +diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c +index 16ffd576323..fad091f8472 100644 +--- gdb/i386-fbsd-tdep.c ++++ gdb/i386-fbsd-tdep.c +@@ -35,6 +35,9 @@ + /* The general-purpose regset consists of 19 32-bit slots. */ + #define I386_FBSD_SIZEOF_GREGSET (19 * 4) + ++/* The segment base register set consists of 2 32-bit registers. */ ++#define I386_FBSD_SIZEOF_SEGBASES_REGSET (2 * 4) ++ + /* Register maps. */ + + static const struct regcache_map_entry i386_fbsd_gregmap[] = +@@ -61,6 +64,13 @@ static const struct regcache_map_entry i386_fbsd_gregmap[] = + { 0 } + }; + ++static const struct regcache_map_entry i386_fbsd_segbases_regmap[] = ++{ ++ { 1, I386_FSBASE_REGNUM, 0 }, ++ { 1, I386_GSBASE_REGNUM, 0 }, ++ { 0 } ++}; ++ + /* This layout including fsbase and gsbase was adopted in FreeBSD + 8.0. */ + +@@ -103,6 +113,11 @@ const struct regset i386_fbsd_gregset = + i386_fbsd_gregmap, regcache_supply_regset, regcache_collect_regset + }; + ++const struct regset i386_fbsd_segbases_regset = ++{ ++ i386_fbsd_segbases_regmap, regcache_supply_regset, regcache_collect_regset ++}; ++ + /* Support for signal handlers. */ + + /* In a signal frame, esp points to a 'struct sigframe' which is +@@ -316,6 +331,9 @@ i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + &i386_fbsd_gregset, NULL, cb_data); + cb (".reg2", tdep->sizeof_fpregset, tdep->sizeof_fpregset, &i386_fpregset, + NULL, cb_data); ++ cb (".reg-x86-segbases", I386_FBSD_SIZEOF_SEGBASES_REGSET, ++ I386_FBSD_SIZEOF_SEGBASES_REGSET, &i386_fbsd_segbases_regset, ++ "segment bases", cb_data); + + if (tdep->xcr0 & X86_XSTATE_AVX) + cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0), Index: devel/gdb/files/commit-f9fbb7636a5 =================================================================== --- /dev/null +++ devel/gdb/files/commit-f9fbb7636a5 @@ -0,0 +1,68 @@ +commit e6107bf932b37ae7e30a5fffe93f9998c4b9c20a +Author: John Baldwin +Date: Tue May 3 16:05:10 2022 -0700 + + Support TLS variables on FreeBSD/Aarch64. + + Derive the pointer to the DTV array from the tpidr register. + + (cherry picked from commit f9fbb7636a5b67abae41a35f02ae70f58523d375) + +diff --git gdb/aarch64-fbsd-tdep.c gdb/aarch64-fbsd-tdep.c +index ed1b84387f0..fdf0795b9bf 100644 +--- gdb/aarch64-fbsd-tdep.c ++++ gdb/aarch64-fbsd-tdep.c +@@ -23,6 +23,7 @@ + #include "fbsd-tdep.h" + #include "aarch64-tdep.h" + #include "aarch64-fbsd-tdep.h" ++#include "inferior.h" + #include "osabi.h" + #include "solib-svr4.h" + #include "target.h" +@@ -180,6 +181,30 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch, + return aarch64_read_description (0, false, false, tls != nullptr); + } + ++/* Implement the get_thread_local_address gdbarch method. */ ++ ++static CORE_ADDR ++aarch64_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, ++ CORE_ADDR lm_addr, CORE_ADDR offset) ++{ ++ aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); ++ struct regcache *regcache; ++ ++ regcache = get_thread_arch_regcache (current_inferior ()->process_target (), ++ ptid, gdbarch); ++ ++ target_fetch_registers (regcache, tdep->tls_regnum); ++ ++ ULONGEST tpidr; ++ if (regcache->cooked_read (tdep->tls_regnum, &tpidr) != REG_VALID) ++ error (_("Unable to fetch %%tpidr")); ++ ++ /* %tpidr points to the TCB whose first member is the dtv ++ pointer. */ ++ CORE_ADDR dtv_addr = tpidr; ++ return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); ++} ++ + /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + + static void +@@ -202,6 +227,14 @@ aarch64_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + (gdbarch, aarch64_fbsd_iterate_over_regset_sections); + set_gdbarch_core_read_description (gdbarch, + aarch64_fbsd_core_read_description); ++ ++ if (tdep->has_tls ()) ++ { ++ set_gdbarch_fetch_tls_load_module_address (gdbarch, ++ svr4_fetch_objfile_link_map); ++ set_gdbarch_get_thread_local_address ++ (gdbarch, aarch64_fbsd_get_thread_local_address); ++ } + } + + void _initialize_aarch64_fbsd_tdep (); Index: devel/gdb/files/extrapatch-kgdb =================================================================== --- devel/gdb/files/extrapatch-kgdb +++ devel/gdb/files/extrapatch-kgdb @@ -1,8 +1,8 @@ diff --git gdb/Makefile.in gdb/Makefile.in -index b8729ed7b2e..660476c11e2 100644 +index aecab41eeb8..45aa63c31f4 100644 --- gdb/Makefile.in +++ gdb/Makefile.in -@@ -677,6 +677,7 @@ TARGET_OBS = @TARGET_OBS@ +@@ -688,6 +688,7 @@ TARGET_OBS = @TARGET_OBS@ # All target-dependent objects files that require 64-bit CORE_ADDR # (used with --enable-targets=all --enable-64-bit-bfd). ALL_64_TARGET_OBS = \ @@ -10,7 +10,7 @@ aarch64-fbsd-tdep.o \ aarch64-linux-tdep.o \ aarch64-newlib-tdep.o \ -@@ -691,6 +692,7 @@ ALL_64_TARGET_OBS = \ +@@ -702,6 +703,7 @@ ALL_64_TARGET_OBS = \ amd64-darwin-tdep.o \ amd64-dicos-tdep.o \ amd64-fbsd-tdep.o \ @@ -18,23 +18,37 @@ amd64-linux-tdep.o \ amd64-netbsd-tdep.o \ amd64-obsd-tdep.o \ -@@ -707,6 +709,7 @@ ALL_64_TARGET_OBS = \ +@@ -717,18 +719,21 @@ ALL_64_TARGET_OBS = \ + ia64-linux-tdep.o \ + ia64-tdep.o \ ia64-vms-tdep.o \ ++ mipsfbsd-kern.o \ + mips-fbsd-tdep.o \ + mips-linux-tdep.o \ + mips-netbsd-tdep.o \ + mips-sde-tdep.o \ + mips-tdep.o \ mips64-obsd-tdep.o \ ++ riscv-fbsd-kern.o \ + riscv-fbsd-tdep.o \ + riscv-linux-tdep.o \ + riscv-none-tdep.o \ + riscv-ravenscar-thread.o \ + riscv-tdep.o \ sparc64-fbsd-tdep.o \ + sparc64fbsd-kern.o \ sparc64-linux-tdep.o \ sparc64-netbsd-tdep.o \ sparc64-obsd-tdep.o \ -@@ -727,6 +730,7 @@ ALL_TARGET_OBS = \ +@@ -750,6 +755,7 @@ ALL_TARGET_OBS = \ + arch/loongarch.o \ arch/ppc-linux-common.o \ - arch/riscv.o \ arm-bsd-tdep.o \ + arm-fbsd-kern.o \ arm-fbsd-tdep.o \ arm-linux-tdep.o \ arm-netbsd-tdep.o \ -@@ -745,6 +749,8 @@ ALL_TARGET_OBS = \ +@@ -768,6 +774,8 @@ ALL_TARGET_OBS = \ csky-linux-tdep.o \ csky-tdep.o \ dicos-tdep.o \ @@ -43,7 +57,7 @@ fbsd-tdep.o \ frv-linux-tdep.o \ frv-tdep.o \ -@@ -760,6 +766,7 @@ ALL_TARGET_OBS = \ +@@ -783,6 +791,7 @@ ALL_TARGET_OBS = \ i386-darwin-tdep.o \ i386-dicos-tdep.o \ i386-fbsd-tdep.o \ @@ -51,15 +65,7 @@ i386-gnu-tdep.o \ i386-go32-tdep.o \ i386-linux-tdep.o \ -@@ -784,6 +791,7 @@ ALL_TARGET_OBS = \ - mep-tdep.o \ - microblaze-linux-tdep.o \ - microblaze-tdep.o \ -+ mipsfbsd-kern.o \ - mips-fbsd-tdep.o \ - mips-linux-tdep.o \ - mips-netbsd-tdep.o \ -@@ -802,6 +810,7 @@ ALL_TARGET_OBS = \ +@@ -822,6 +831,7 @@ ALL_TARGET_OBS = \ or1k-linux-tdep.o \ or1k-tdep.o \ ppc-fbsd-tdep.o \ @@ -67,15 +73,7 @@ ppc-linux-tdep.o \ ppc-netbsd-tdep.o \ ppc-obsd-tdep.o \ -@@ -809,6 +818,7 @@ ALL_TARGET_OBS = \ - ppc-sysv-tdep.o \ - ppc64-tdep.o \ - ravenscar-thread.o \ -+ riscv-fbsd-kern.o \ - riscv-fbsd-tdep.o \ - riscv-linux-tdep.o \ - riscv-none-tdep.o \ -@@ -1633,7 +1643,7 @@ generated_files = \ +@@ -1647,7 +1657,7 @@ generated_files = \ # Flags needed to compile Python code PYTHON_CFLAGS = @PYTHON_CFLAGS@ @@ -84,7 +82,7 @@ @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=$(SUBDIRS)" subdir_do # Rule for compiling .c files in the top-level gdb directory. -@@ -1887,6 +1897,12 @@ ifneq ($(CODESIGN_CERT),) +@@ -1909,6 +1919,12 @@ ifneq ($(CODESIGN_CERT),) $(ECHO_SIGN) $(CODESIGN) -s $(CODESIGN_CERT) gdb$(EXEEXT) endif @@ -97,7 +95,7 @@ # This is useful when debugging GDB, because some Unix's don't let you run GDB # on itself without copying the executable. So "make gdb1" will make # gdb and put a copy in gdb1, and you can run it with "gdb gdb1". -@@ -1922,6 +1938,7 @@ clean mostlyclean: $(CONFIG_CLEAN) +@@ -1944,6 +1960,7 @@ clean mostlyclean: $(CONFIG_CLEAN) rm -f init.c stamp-init version.c stamp-version rm -f gdb$(EXEEXT) core make.log rm -f gdb[0-9]$(EXEEXT) @@ -105,7 +103,7 @@ rm -f test-cp-name-parser$(EXEEXT) rm -f xml-builtin.c stamp-xml rm -f $(DEPDIR)/* -@@ -2114,6 +2131,7 @@ MAKEOVERRIDES = +@@ -2136,6 +2153,7 @@ MAKEOVERRIDES = ALLDEPFILES = \ aarch32-tdep.c \ @@ -113,7 +111,7 @@ aarch64-fbsd-nat.c \ aarch64-fbsd-tdep.c \ aarch64-linux-nat.c \ -@@ -2133,6 +2151,7 @@ ALLDEPFILES = \ +@@ -2155,6 +2173,7 @@ ALLDEPFILES = \ amd64-bsd-nat.c \ amd64-darwin-tdep.c \ amd64-dicos-tdep.c \ @@ -121,7 +119,7 @@ amd64-fbsd-nat.c \ amd64-fbsd-tdep.c \ amd64-linux-nat.c \ -@@ -2149,6 +2168,7 @@ ALLDEPFILES = \ +@@ -2171,6 +2190,7 @@ ALLDEPFILES = \ arc-tdep.c \ arm.c \ arm-bsd-tdep.c \ @@ -129,7 +127,7 @@ arm-fbsd-nat.c \ arm-fbsd-tdep.c \ arm-get-next-pcs.c \ -@@ -2170,6 +2190,9 @@ ALLDEPFILES = \ +@@ -2192,6 +2212,9 @@ ALLDEPFILES = \ csky-tdep.c \ darwin-nat.c \ dicos-tdep.c \ @@ -139,7 +137,7 @@ fbsd-nat.c \ fbsd-tdep.c \ fork-child.c \ -@@ -2190,6 +2213,7 @@ ALLDEPFILES = \ +@@ -2212,6 +2235,7 @@ ALLDEPFILES = \ i386-darwin-nat.c \ i386-darwin-tdep.c \ i386-dicos-tdep.c \ @@ -147,7 +145,7 @@ i386-fbsd-nat.c \ i386-fbsd-tdep.c \ i386-gnu-nat.c \ -@@ -2227,6 +2251,7 @@ ALLDEPFILES = \ +@@ -2252,6 +2276,7 @@ ALLDEPFILES = \ microblaze-linux-tdep.c \ microblaze-tdep.c \ mingw-hdep.c \ @@ -155,15 +153,15 @@ mips-fbsd-nat.c \ mips-fbsd-tdep.c \ mips-linux-nat.c \ -@@ -2246,6 +2271,7 @@ ALLDEPFILES = \ - obsd-nat.c \ +@@ -2272,6 +2297,7 @@ ALLDEPFILES = \ obsd-tdep.c \ + or1k-linux-nat.c \ posix-hdep.c \ + ppcfbsd-kern.c \ ppc-fbsd-nat.c \ ppc-fbsd-tdep.c \ ppc-linux-nat.c \ -@@ -2260,6 +2286,7 @@ ALLDEPFILES = \ +@@ -2286,6 +2312,7 @@ ALLDEPFILES = \ procfs.c \ ravenscar-thread.c \ remote-sim.c \ @@ -171,7 +169,7 @@ riscv-fbsd-nat.c \ riscv-fbsd-tdep.c \ riscv-linux-nat.c \ -@@ -2297,6 +2324,7 @@ ALLDEPFILES = \ +@@ -2322,6 +2349,7 @@ ALLDEPFILES = \ sparc-sol2-nat.c \ sparc-sol2-tdep.c \ sparc-tdep.c \ @@ -179,7 +177,7 @@ sparc64-fbsd-nat.c \ sparc64-fbsd-tdep.c \ sparc64-linux-nat.c \ -@@ -2555,7 +2583,7 @@ endif +@@ -2579,7 +2607,7 @@ endif # A list of all the objects we might care about in this build, for # dependency tracking. @@ -189,10 +187,10 @@ # All the .deps files to include. diff --git gdb/config.in gdb/config.in -index 2c30504905b..edf57bf48a9 100644 +index cd9f252eba1..f2fea54353d 100644 --- gdb/config.in +++ gdb/config.in -@@ -213,6 +213,12 @@ +@@ -223,6 +223,12 @@ /* Define to 1 if you have the `kinfo_getfile' function. */ #undef HAVE_KINFO_GETFILE @@ -206,10 +204,10 @@ #undef HAVE_LANGINFO_CODESET diff --git gdb/configure gdb/configure -index 5d89635c043..2ab494696c6 100755 +index b34baff13be..16fafffb245 100755 --- gdb/configure +++ gdb/configure -@@ -8226,6 +8226,126 @@ fi +@@ -8249,6 +8249,126 @@ fi @@ -337,10 +335,10 @@ if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" diff --git gdb/configure.ac gdb/configure.ac -index b8c79bcac9a..9b73cb6018d 100644 +index bc8925ddd69..04540240760 100644 --- gdb/configure.ac +++ gdb/configure.ac -@@ -504,6 +504,16 @@ AC_SEARCH_LIBS(socketpair, socket) +@@ -481,6 +481,16 @@ AC_SEARCH_LIBS(socketpair, socket) # Link in zlib if we can. This allows us to read compressed debug sections. AM_ZLIB @@ -358,7 +356,7 @@ # GDB may fork/exec the iconv program to get the list of supported character diff --git gdb/configure.nat gdb/configure.nat -index e34cccffd98..d15a915d2c9 100644 +index b45519fd116..6443969f2f0 100644 --- gdb/configure.nat +++ gdb/configure.nat @@ -63,7 +63,8 @@ case ${gdb_host} in @@ -372,10 +370,10 @@ LOADLIBES='-lkvm' ;; diff --git gdb/configure.tgt gdb/configure.tgt -index 97a5a57c378..19ef5c7a48f 100644 +index 0705ccf32b8..babf4920139 100644 --- gdb/configure.tgt +++ gdb/configure.tgt -@@ -103,7 +103,7 @@ esac +@@ -114,7 +114,7 @@ esac case "${targ}" in *-*-freebsd* | *-*-kfreebsd*-gnu) @@ -384,7 +382,7 @@ *-*-netbsd* | *-*-knetbsd*-gnu) os_obs="netbsd-tdep.o solib-svr4.o";; *-*-openbsd*) -@@ -120,7 +120,7 @@ aarch64*-*-elf | aarch64*-*-rtems*) +@@ -131,7 +131,7 @@ aarch64*-*-elf | aarch64*-*-rtems*) aarch64*-*-freebsd*) # Target: FreeBSD/aarch64 @@ -393,7 +391,7 @@ ;; aarch64*-*-linux*) -@@ -176,7 +176,7 @@ arm*-*-linux*) +@@ -187,7 +187,7 @@ arm*-*-linux*) ;; arm*-*-freebsd*) # Target: FreeBSD/arm @@ -402,7 +400,7 @@ ;; arm*-*-netbsd* | arm*-*-knetbsd*-gnu) # Target: NetBSD/arm -@@ -276,7 +276,11 @@ i[34567]86-*-dicos*) +@@ -279,7 +279,11 @@ i[34567]86-*-dicos*) ;; i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu) # Target: FreeBSD/i386 @@ -415,16 +413,16 @@ ;; i[34567]86-*-netbsd* | i[34567]86-*-knetbsd*-gnu) # Target: NetBSD/i386 -@@ -422,7 +426,7 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu) +@@ -419,7 +423,7 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu) ;; mips*-*-freebsd*) # Target: MIPS running FreeBSD - gdb_target_obs="mips-tdep.o mips-fbsd-tdep.o" + gdb_target_obs="mips-tdep.o mips-fbsd-tdep.o mipsfbsd-kern.o" - gdb_sim=../sim/mips/libsim.a ;; mips64*-*-openbsd*) -@@ -488,7 +492,7 @@ or1k-*-* | or1knd-*-*) + # Target: OpenBSD/mips64 +@@ -477,7 +481,7 @@ or1k-*-* | or1knd-*-*) powerpc*-*-freebsd*) # Target: FreeBSD/powerpc gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \ @@ -433,7 +431,7 @@ ravenscar-thread.o ppc-ravenscar-thread.o" ;; -@@ -540,7 +544,7 @@ s390*-*-linux*) +@@ -526,7 +530,7 @@ s390*-*-linux*) riscv*-*-freebsd*) # Target: FreeBSD/riscv @@ -442,7 +440,7 @@ ;; riscv*-*-linux*) -@@ -616,6 +620,7 @@ sparc64-*-linux*) +@@ -591,6 +595,7 @@ sparc64-*-linux*) sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) # Target: FreeBSD/sparc64 gdb_target_obs="sparc-tdep.o sparc64-tdep.o sparc64-fbsd-tdep.o \ @@ -450,7 +448,7 @@ ravenscar-thread.o sparc-ravenscar-thread.o" ;; sparc-*-netbsd* | sparc-*-knetbsd*-gnu) -@@ -735,8 +740,8 @@ x86_64-*-linux*) +@@ -707,8 +712,8 @@ x86_64-*-linux*) ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) # Target: FreeBSD/amd64 @@ -462,7 +460,7 @@ x86_64-*-mingw* | x86_64-*-cygwin*) # Target: MingW/amd64 diff --git gdb/osabi.c gdb/osabi.c -index aabf895c045..5b5ef033f90 100644 +index d4a98061dbd..ff4117ca8a1 100644 --- gdb/osabi.c +++ gdb/osabi.c @@ -67,6 +67,7 @@ static const struct osabi_names gdb_osabi_names[] = @@ -474,7 +472,7 @@ { "OpenBSD", NULL }, { "WindowsCE", NULL }, diff --git gdb/osabi.h gdb/osabi.h -index 1ecbed4611d..9f701076063 100644 +index be016732cbc..866e764c220 100644 --- gdb/osabi.h +++ gdb/osabi.h @@ -31,6 +31,7 @@ enum gdb_osabi @@ -486,10 +484,10 @@ GDB_OSABI_OPENBSD, GDB_OSABI_WINCE, diff --git gdb/regcache.c gdb/regcache.c -index fde0c612975..818c62bbf31 100644 +index 00d7a10e289..7639d459286 100644 --- gdb/regcache.c +++ gdb/regcache.c -@@ -1112,6 +1112,22 @@ reg_buffer::raw_supply_zeroed (int regnum) +@@ -1107,6 +1107,22 @@ reg_buffer::raw_supply_zeroed (int regnum) m_register_status[regnum] = REG_VALID; } @@ -513,10 +511,10 @@ void diff --git gdb/regcache.h gdb/regcache.h -index ee254f381f4..63158dcdaf1 100644 +index 1dbba5ce9af..7d4e404a96c 100644 --- gdb/regcache.h +++ gdb/regcache.h -@@ -228,6 +228,8 @@ class reg_buffer : public reg_buffer_common +@@ -237,6 +237,8 @@ class reg_buffer : public reg_buffer_common only LEN, without editing the rest of the register. */ void raw_supply_part (int regnum, int offset, int len, const gdb_byte *in); Index: devel/gdb/files/kgdb/aarch64-fbsd-kern.c =================================================================== --- devel/gdb/files/kgdb/aarch64-fbsd-kern.c +++ devel/gdb/files/kgdb/aarch64-fbsd-kern.c @@ -169,7 +169,7 @@ static void aarch64_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); frame_unwind_prepend_unwinder (gdbarch, &aarch64_fbsd_trapframe_unwind); Index: devel/gdb/files/kgdb/arm-fbsd-kern.c =================================================================== --- devel/gdb/files/kgdb/arm-fbsd-kern.c +++ devel/gdb/files/kgdb/arm-fbsd-kern.c @@ -183,7 +183,7 @@ static void arm_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch); frame_unwind_prepend_unwinder (gdbarch, &arm_fbsd_trapframe_unwind); Index: devel/gdb/files/kgdb/fbsd-kld.c =================================================================== --- devel/gdb/files/kgdb/fbsd-kld.c +++ devel/gdb/files/kgdb/fbsd-kld.c @@ -377,17 +377,17 @@ "Unable to find struct linker_file symbol")); info->off_address = - lookup_struct_elt (SYMBOL_TYPE (linker_file_sym), + lookup_struct_elt (linker_file_sym->type (), "address", 0).offset / 8; info->off_filename = - lookup_struct_elt (SYMBOL_TYPE (linker_file_sym), + lookup_struct_elt (linker_file_sym->type (), "filename", 0).offset / 8; info->off_pathname = - lookup_struct_elt (SYMBOL_TYPE (linker_file_sym), + lookup_struct_elt (linker_file_sym->type (), "pathname", 0).offset / 8; struct type *link_type = - lookup_struct_elt_type (SYMBOL_TYPE (linker_file_sym), + lookup_struct_elt_type (linker_file_sym->type (), "link", 0); if (link_type == NULL) error (_("Unable to find link type")); Index: devel/gdb/files/kgdb/fbsd-kthr.c =================================================================== --- devel/gdb/files/kgdb/fbsd-kthr.c +++ devel/gdb/files/kgdb/fbsd-kthr.c @@ -254,16 +254,16 @@ error (_("Unable to find struct proc symbol")); proc_off_p_pid = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "p_pid", + lookup_struct_elt (proc_sym->type (), "p_pid", 0).offset / 8; proc_off_p_comm = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "p_comm", + lookup_struct_elt (proc_sym->type (), "p_comm", 0).offset / 8; proc_off_p_list = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "p_list", + lookup_struct_elt (proc_sym->type (), "p_list", 0).offset / 8; proc_off_p_threads = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), + lookup_struct_elt (proc_sym->type (), "p_threads", 0).offset / 8; struct symbol *thread_sym = @@ -273,20 +273,20 @@ error (_("Unable to find struct thread symbol")); thread_off_td_tid = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "td_tid", + lookup_struct_elt (proc_sym->type (), "td_tid", 0).offset / 8; thread_off_td_name = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "td_name", + lookup_struct_elt (proc_sym->type (), "td_name", 0).offset / 8; thread_off_td_pcb = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "td_pcb", + lookup_struct_elt (proc_sym->type (), "td_pcb", 0).offset / 8; thread_off_td_plist = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "td_plist", + lookup_struct_elt (proc_sym->type (), "td_plist", 0).offset / 8; struct_elt td_oncpu = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "td_oncpu", + lookup_struct_elt (proc_sym->type (), "td_oncpu", 0); thread_off_td_oncpu = td_oncpu.offset / 8; thread_oncpu_size = FIELD_BITSIZE(*td_oncpu.field) / 8; @@ -319,7 +319,7 @@ error (_("Unable to find struct proc symbol")); proc_off_p_hash = - lookup_struct_elt (SYMBOL_TYPE (proc_sym), "p_hash", + lookup_struct_elt (proc_sym->type (), "p_hash", 0).offset / 8; } catch (const gdb_exception_error &e2) { proc_off_p_hash = offsetof(struct proc, p_hash); Index: devel/gdb/files/kgdb/fbsd-kvm.c =================================================================== --- devel/gdb/files/kgdb/fbsd-kvm.c +++ devel/gdb/files/kgdb/fbsd-kvm.c @@ -30,7 +30,7 @@ #include "filenames.h" #include "gdbcore.h" #include "gdbthread.h" -#include "gdb_obstack.h" +#include "gdbsupport/gdb_obstack.h" #include "inferior.h" #include "objfiles.h" #include "osabi.h" @@ -39,6 +39,7 @@ #include "target.h" #include "value.h" #include "readline/tilde.h" +#include "gdbsupport/buildargv.h" #include "gdbsupport/pathstuff.h" #include @@ -479,7 +480,7 @@ { printf_filtered ("\t`%s', ", vmcore); - wrap_here (" "); + gdb_stdout->wrap_here (8); printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore"); } Index: devel/gdb/files/kgdb/ppcfbsd-kern.c =================================================================== --- devel/gdb/files/kgdb/ppcfbsd-kern.c +++ devel/gdb/files/kgdb/ppcfbsd-kern.c @@ -64,7 +64,7 @@ static void ppcfbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) { - struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); gdb_byte buf[24 * tdep->wordsize]; int i; @@ -121,7 +121,7 @@ ppcfbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); struct trad_frame_cache *cache; CORE_ADDR base; int i; @@ -211,7 +211,7 @@ static void ppcfbsd_kernel_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); frame_unwind_prepend_unwinder(gdbarch, &ppcfbsd_trapframe_unwind); Index: devel/gdb/files/patch-fixes =================================================================== --- devel/gdb/files/patch-fixes +++ /dev/null @@ -1,10 +0,0 @@ ---- gdb/compile/compile-loc2c.c.orig 2019-02-26 20:51:50.000000000 -0800 -+++ gdb/compile/compile-loc2c.c 2019-05-24 16:07:42.382379000 -0700 -@@ -657,6 +657,7 @@ do_compile_dwarf_expr_to_c (int indent, string_file *s - uint64_t uoffset, reg; - int64_t offset; - -+ uoffset = 0; - print_spaces (indent - 2, stream); - if (info[op_ptr - base].label) - { Index: devel/gdb/files/patch-gdb_amd64-bsd-nat.c =================================================================== --- devel/gdb/files/patch-gdb_amd64-bsd-nat.c +++ /dev/null @@ -1,30 +0,0 @@ ---- gdb/amd64-bsd-nat.c.orig 2021-07-03 10:41:09.000000000 -0700 -+++ gdb/amd64-bsd-nat.c 2021-09-16 13:59:34.240785000 -0700 -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - - #include "amd64-tdep.h" - #include "amd64-nat.h" -@@ -142,12 +143,19 @@ amd64bsd_store_inferior_registers (struct regcache *re - if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) - { - struct reg regs; -+ register_t old_rflags; - - if (gdb_ptrace (PT_GETREGS, ptid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) - perror_with_name (_("Couldn't get registers")); - -+ old_rflags = regs.r_rflags; - amd64_collect_native_gregset (regcache, ®s, regnum); - -+ /* This is a workaround about the PSL_USERCHANGE posix limitation. */ -+ if ((regs.r_rflags ^ old_rflags ) & ~PSL_USERCHANGE) -+ { -+ regs.r_rflags ^= (regs.r_rflags ^ old_rflags ) & ~PSL_USERCHANGE; -+ } - if (gdb_ptrace (PT_SETREGS, ptid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) - perror_with_name (_("Couldn't write registers")); - Index: devel/gdb/files/patch-gdb_i386-fbsd-nat.c =================================================================== --- devel/gdb/files/patch-gdb_i386-fbsd-nat.c +++ devel/gdb/files/patch-gdb_i386-fbsd-nat.c @@ -1,23 +1,23 @@ ---- gdb/i386-fbsd-nat.c 2017-09-14 09:28:17 UTC -+++ gdb/i386-fbsd-nat.c -@@ -43,8 +43,6 @@ public: +--- gdb/i386-fbsd-nat.c.orig 2022-05-02 12:03:48.925048000 -0700 ++++ gdb/i386-fbsd-nat.c 2022-05-02 12:04:43.474983000 -0700 +@@ -41,8 +41,6 @@ class i386_fbsd_nat_target final : public x86_fbsd_nat + void store_registers (struct regcache *, int) override; + const struct target_desc *read_description () override; - #endif - -- void resume (ptid_t, int, enum gdb_signal) override; - - #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) - bool supports_stopped_by_hw_breakpoint () override; - #endif -@@ -52,6 +50,7 @@ public: +- void resume (ptid_t, int, enum gdb_signal) override; + }; static i386_fbsd_nat_target the_i386_fbsd_nat_target; +@@ -227,6 +225,7 @@ i386_fbsd_nat_target::store_registers (struct regcache + perror_with_name (_("Couldn't write floating point status")); + } +#if 0 /* Resume execution of the inferior process. If STEP is nonzero, single-step it. If SIGNAL is nonzero, give it that signal. */ -@@ -98,6 +97,7 @@ i386_fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal) +@@ -273,6 +272,7 @@ i386_fbsd_nat_target::resume (ptid_t ptid, int step, e gdb_signal_to_host (signal)) == -1) perror_with_name (("ptrace")); } Index: devel/gdb/files/patch-include_libiberty.h =================================================================== --- devel/gdb/files/patch-include_libiberty.h +++ /dev/null @@ -1,11 +0,0 @@ ---- include/libiberty.h 2017-09-14 09:28:17 UTC -+++ include/libiberty.h -@@ -109,7 +109,7 @@ - || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) \ - || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) \ - || defined (__DragonFly__) || defined (HAVE_DECL_BASENAME) --extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); -+#include - #else - /* Do not allow basename to be used if there is no prototype seen. We - either need to use the above prototype or have one from Index: devel/gdb/files/patch-libiberty_configure =================================================================== --- devel/gdb/files/patch-libiberty_configure +++ /dev/null @@ -1,12 +0,0 @@ ---- libiberty/configure.orig 2017-09-12 12:10:11 UTC -+++ libiberty/configure -@@ -4398,8 +4398,7 @@ - ac_libiberty_warn_cflags= - save_CFLAGS="$CFLAGS" - for real_option in -W -Wall -Wwrite-strings -Wc++-compat \ -- -Wstrict-prototypes \ -- -Wshadow=local; do -+ -Wstrict-prototypes ; do - # Do the check with the no- prefix removed since gcc silently - # accepts any -Wno-* option on purpose - case $real_option in Index: devel/gdb/pkg-plist =================================================================== --- devel/gdb/pkg-plist +++ devel/gdb/pkg-plist @@ -21,6 +21,8 @@ %%PYTHON%%%%DATADIR%%/python/gdb/prompt.py %%PYTHON%%%%DATADIR%%/python/gdb/prompt.pyc %%PYTHON%%%%DATADIR%%/python/gdb/printing.pyc +%%PYTHON%%%%DATADIR%%/python/gdb/styling.py +%%PYTHON%%%%DATADIR%%/python/gdb/styling.pyc %%PYTHON%%%%DATADIR%%/python/gdb/types.py %%PYTHON%%%%DATADIR%%/python/gdb/types.pyc %%PYTHON%%%%DATADIR%%/python/gdb/unwinder.py