aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2022-05-10 17:41:13 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2022-05-10 17:41:13 +0000
commit1c25ded0af45ac5dc5817b4004f99ee288a2ce7a (patch)
tree04219d15d2eab94812968fdf4d40be56784a16a0
parent2241809cca1f4739e32d4c013e8c62ae832df8e6 (diff)
downloadports-1c25ded0af45ac5dc5817b4004f99ee288a2ce7a.tar.gz
ports-1c25ded0af45ac5dc5817b4004f99ee288a2ce7a.zip
-rw-r--r--devel/gdb/Makefile34
-rw-r--r--devel/gdb/distinfo6
-rw-r--r--devel/gdb/files/commit-041a4212d3797
-rw-r--r--devel/gdb/files/commit-065a00b3a46338
-rw-r--r--devel/gdb/files/commit-099fbce0acc114
-rw-r--r--devel/gdb/files/commit-0a765c1a8e978
-rw-r--r--devel/gdb/files/commit-1570c37c340892
-rw-r--r--devel/gdb/files/commit-2e686a74dc468
-rw-r--r--devel/gdb/files/commit-3181aed81c920
-rw-r--r--devel/gdb/files/commit-40c23d88038163
-rw-r--r--devel/gdb/files/commit-414d5848bb2293
-rw-r--r--devel/gdb/files/commit-4bd817e71ee1726
-rw-r--r--devel/gdb/files/commit-6719bc690e248
-rw-r--r--devel/gdb/files/commit-684943d213b102
-rw-r--r--devel/gdb/files/commit-711b0b6698f55
-rw-r--r--devel/gdb/files/commit-8e6afe4013f38
-rw-r--r--devel/gdb/files/commit-922c2fc18e4132
-rw-r--r--devel/gdb/files/commit-92d48a1e4ea288
-rw-r--r--devel/gdb/files/commit-983b1119bc342
-rw-r--r--devel/gdb/files/commit-a171378aa4745
-rw-r--r--devel/gdb/files/commit-a3627b5428053
-rw-r--r--devel/gdb/files/commit-a49ce729c80157
-rw-r--r--devel/gdb/files/commit-b1babce7c3150
-rw-r--r--devel/gdb/files/commit-b5c2367c3ac89
-rw-r--r--devel/gdb/files/commit-b7fe5463cf0102
-rw-r--r--devel/gdb/files/commit-c13566fdd5735
-rw-r--r--devel/gdb/files/commit-c77282d8ba941
-rw-r--r--devel/gdb/files/commit-e330d4c033e55
-rw-r--r--devel/gdb/files/commit-f3215e1526d114
-rw-r--r--devel/gdb/files/commit-f9fbb7636a568
-rw-r--r--devel/gdb/files/extrapatch-kgdb124
-rw-r--r--devel/gdb/files/kgdb/aarch64-fbsd-kern.c2
-rw-r--r--devel/gdb/files/kgdb/arm-fbsd-kern.c2
-rw-r--r--devel/gdb/files/kgdb/fbsd-kld.c8
-rw-r--r--devel/gdb/files/kgdb/fbsd-kthr.c20
-rw-r--r--devel/gdb/files/kgdb/fbsd-kvm.c5
-rw-r--r--devel/gdb/files/kgdb/ppcfbsd-kern.c6
-rw-r--r--devel/gdb/files/patch-fixes10
-rw-r--r--devel/gdb/files/patch-gdb_amd64-bsd-nat.c30
-rw-r--r--devel/gdb/files/patch-gdb_i386-fbsd-nat.c22
-rw-r--r--devel/gdb/files/patch-include_libiberty.h11
-rw-r--r--devel/gdb/files/patch-libiberty_configure12
-rw-r--r--devel/gdb/pkg-plist2
43 files changed, 5431 insertions, 166 deletions
diff --git a/devel/gdb/Makefile b/devel/gdb/Makefile
index 66ae1ce8316a..ec71f616457f 100644
--- a/devel/gdb/Makefile
+++ b/devel/gdb/Makefile
@@ -1,7 +1,7 @@
# Created by: Steven Kreuzer <skreuzer@FreeBSD.org>
PORTNAME= gdb
-DISTVERSION= 11.2
+DISTVERSION= 12.1
PORTREVISION= 0
CATEGORIES= devel
MASTER_SITES= GNU
@@ -38,6 +38,34 @@ CFLAGS:= ${CFLAGS:C/ +$//} # blanks at EOL creep in sometimes
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 @@ EXCLUDE+= zlib
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
diff --git a/devel/gdb/distinfo b/devel/gdb/distinfo
index 4004bd294123..41afd51e1aae 100644
--- a/devel/gdb/distinfo
+++ b/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
diff --git a/devel/gdb/files/commit-041a4212d37 b/devel/gdb/files/commit-041a4212d37
new file mode 100644
index 000000000000..8df89ea0cc7c
--- /dev/null
+++ b/devel/gdb/files/commit-041a4212d37
@@ -0,0 +1,97 @@
+commit 7d06796cbc1e5f5a9ca03a5214934a849bd519b1
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <http://www.gnu.org/licenses/>. */
++
++#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<fbsd_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 */
diff --git a/devel/gdb/files/commit-065a00b3a46 b/devel/gdb/files/commit-065a00b3a46
new file mode 100644
index 000000000000..a7725dc73827
--- /dev/null
+++ b/devel/gdb/files/commit-065a00b3a46
@@ -0,0 +1,338 @@
+commit 194342a42538301d9ef47d4be6efd74ddfb8fac2
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <http://www.gnu.org/licenses/>. */
+
+ #include "defs.h"
++#include "arch-utils.h"
++#include "inferior.h"
+ #include "regcache.h"
+ #include "target.h"
++#include "nat/aarch64-hw-point.h"
+
+-#include <sys/types.h>
++#include <sys/param.h>
+ #include <sys/ptrace.h>
++#include <machine/armreg.h>
+ #include <machine/reg.h>
+
+ #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 <unordered_set>
++#endif
++
++#ifdef HAVE_DBREG
++struct aarch64_fbsd_nat_target final
++ : public aarch64_nat_target<fbsd_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<lwpid_t> 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) &reg, 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 (&reg, 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) &reg, 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)
diff --git a/devel/gdb/files/commit-099fbce0acc b/devel/gdb/files/commit-099fbce0acc
new file mode 100644
index 000000000000..cdb75dee984d
--- /dev/null
+++ b/devel/gdb/files/commit-099fbce0acc
@@ -0,0 +1,114 @@
+commit 82d5c31c4fe5bb67386dc568893dc23c899ff303
+Author: John Baldwin <jhb@FreeBSD.org>
+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 */
diff --git a/devel/gdb/files/commit-0a765c1a8e9 b/devel/gdb/files/commit-0a765c1a8e9
new file mode 100644
index 000000000000..9e90fbe417da
--- /dev/null
+++ b/devel/gdb/files/commit-0a765c1a8e9
@@ -0,0 +1,78 @@
+commit 25dc6de9343ae320e37a6b9daaf5c5fc398debae
+Author: John Baldwin <jhb@FreeBSD.org>
+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;
+
diff --git a/devel/gdb/files/commit-1570c37c340 b/devel/gdb/files/commit-1570c37c340
new file mode 100644
index 000000000000..4457b360d751
--- /dev/null
+++ b/devel/gdb/files/commit-1570c37c340
@@ -0,0 +1,892 @@
+commit ae520e967e0ccde249b47b7cea1c557299afd7ab
+Author: John Baldwin <jhb@FreeBSD.org>
+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<linux_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 <http://www.gnu.org/licenses/>. */
++
++#include "defs.h"
++#include "gdbarch.h"
++#include "inferior.h"
++#include "cli/cli-cmds.h"
++#include "aarch64-nat.h"
++
++#include <unordered_map>
++
++/* 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<pid_t, aarch64_debug_reg_state>
++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 <http://www.gnu.org/licenses/>. */
++
++#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 <typename BaseTarget>
++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 \
diff --git a/devel/gdb/files/commit-2e686a74dc4 b/devel/gdb/files/commit-2e686a74dc4
new file mode 100644
index 000000000000..1c0c23fb9835
--- /dev/null
+++ b/devel/gdb/files/commit-2e686a74dc4
@@ -0,0 +1,68 @@
+commit a2915c914b21b07ab7916da71fc69297168d6878
+Author: John Baldwin <jhb@FreeBSD.org>
+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);
+ }
diff --git a/devel/gdb/files/commit-3181aed81c9 b/devel/gdb/files/commit-3181aed81c9
new file mode 100644
index 000000000000..3ac8102fd1dd
--- /dev/null
+++ b/devel/gdb/files/commit-3181aed81c9
@@ -0,0 +1,20 @@
+commit e5cfae026a00128719b409beeb03fb58c105fdae
+Author: John Baldwin <jhb@FreeBSD.org>
+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 (),
diff --git a/devel/gdb/files/commit-40c23d88038 b/devel/gdb/files/commit-40c23d88038
new file mode 100644
index 000000000000..553ba0626c6a
--- /dev/null
+++ b/devel/gdb/files/commit-40c23d88038
@@ -0,0 +1,163 @@
+commit e4b141663b47f26ef84a6716e53731bb0debfdf4
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <list>
+
++#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,
+ &regs, 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 <class Regset>
++ bool fetch_regset (struct regcache *regcache, int regnum, int note,
++ const struct regset *regset)
++ {
++ Regset regs;
++ return fetch_regset (regcache, regnum, note, regset, &regs, sizeof (regs));
++ }
++
++ template <class Regset>
++ bool store_regset (struct regcache *regcache, int regnum, int note,
++ const struct regset *regset)
++ {
++ Regset regs;
++ return store_regset (regcache, regnum, note, regset, &regs, sizeof (regs));
++ }
+ };
+
+ /* Fetch the signal information for PTID and store it in *SIGINFO.
diff --git a/devel/gdb/files/commit-414d5848bb2 b/devel/gdb/files/commit-414d5848bb2
new file mode 100644
index 000000000000..36695de8518b
--- /dev/null
+++ b/devel/gdb/files/commit-414d5848bb2
@@ -0,0 +1,293 @@
+commit 697c5583d89eacc2d61648549df4276ad34f4ec1
+Author: John Baldwin <jhb@FreeBSD.org>
+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 @@
++<?xml version="1.0"?>
++<!-- Copyright (C) 2022 Free Software Foundation, Inc.
++
++ Copying and distribution of this file, with or without modification,
++ are permitted in any medium without royalty provided the copyright
++ notice and this notice are preserved. -->
++
++<!DOCTYPE feature SYSTEM "gdb-target.dtd">
++<feature name="org.gnu.gdb.aarch64.tls">
++ <reg name="tpidr" bitsize="64" type="data_ptr"/>
++</feature>
+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);
diff --git a/devel/gdb/files/commit-4bd817e71ee b/devel/gdb/files/commit-4bd817e71ee
new file mode 100644
index 000000000000..37353505f277
--- /dev/null
+++ b/devel/gdb/files/commit-4bd817e71ee
@@ -0,0 +1,1726 @@
+commit 9ea194902df6599ae8f4096fe0426feae12cd7ab
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <http://www.gnu.org/licenses/>. */
++
++#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 <http://www.gnu.org/licenses/>. */
++
++#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 <elf.h>
+
+-/* 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)
diff --git a/devel/gdb/files/commit-6719bc690e2 b/devel/gdb/files/commit-6719bc690e2
new file mode 100644
index 000000000000..8d1183ada96c
--- /dev/null
+++ b/devel/gdb/files/commit-6719bc690e2
@@ -0,0 +1,48 @@
+commit 20c8aa681d97f5ab8a8f374b23339777b1dc4353
+Author: John Baldwin <jhb@FreeBSD.org>
+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 */
diff --git a/devel/gdb/files/commit-684943d213b b/devel/gdb/files/commit-684943d213b
new file mode 100644
index 000000000000..729d5a912e57
--- /dev/null
+++ b/devel/gdb/files/commit-684943d213b
@@ -0,0 +1,102 @@
+commit 1264775133315cab3598b3bceea4aa969e49715c
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <http://www.gnu.org/licenses/>. */
+
+ #include "defs.h"
++#include "inferior.h"
+ #include "target.h"
+
++#include "elf/common.h"
++
+ #include <sys/types.h>
+ #include <sys/ptrace.h>
+ #include <machine/reg.h>
+
+ #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<struct vfpreg> (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<uint32_t> (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<struct vfpreg> (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<uint32_t> (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;
diff --git a/devel/gdb/files/commit-711b0b6698f b/devel/gdb/files/commit-711b0b6698f
new file mode 100644
index 000000000000..c3efd54151f9
--- /dev/null
+++ b/devel/gdb/files/commit-711b0b6698f
@@ -0,0 +1,55 @@
+commit 8a8b3a6ad25f6bd379f7cbd6cc1f9edcf076d940
+Author: John Baldwin <jhb@FreeBSD.org>
+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
diff --git a/devel/gdb/files/commit-8e6afe4013f b/devel/gdb/files/commit-8e6afe4013f
new file mode 100644
index 000000000000..ae1f77619eaa
--- /dev/null
+++ b/devel/gdb/files/commit-8e6afe4013f
@@ -0,0 +1,38 @@
+commit 8e1e09542c37a8937af47fd740806ea71ff260e9
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <jhb@FreeBSD.org>
++
++ * elf.c (elfcore_grok_freebsd_note): Handle NT_ARM_TLS notes.
++
+ 2022-04-01 John Baldwin <jhb@FreeBSD.org>
+
+ * 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);
+
diff --git a/devel/gdb/files/commit-922c2fc18e4 b/devel/gdb/files/commit-922c2fc18e4
new file mode 100644
index 000000000000..e1251e42c757
--- /dev/null
+++ b/devel/gdb/files/commit-922c2fc18e4
@@ -0,0 +1,132 @@
+commit 0167735706a3328fb8d2206e6eae472e231e8695
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <unordered_map>
++
+ /* 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<pid_t,
++ struct x86_debug_reg_state> 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
diff --git a/devel/gdb/files/commit-92d48a1e4ea b/devel/gdb/files/commit-92d48a1e4ea
new file mode 100644
index 000000000000..585835ec342d
--- /dev/null
+++ b/devel/gdb/files/commit-92d48a1e4ea
@@ -0,0 +1,288 @@
+commit 1a0c401bbc882307404666733808666715f93dd7
+Author: John Baldwin <jhb@FreeBSD.org>
+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 @@
++<?xml version="1.0"?>
++<!-- Copyright (C) 2022 Free Software Foundation, Inc.
++
++ Copying and distribution of this file, with or without modification,
++ are permitted in any medium without royalty provided the copyright
++ notice and this notice are preserved. -->
++
++<!DOCTYPE feature SYSTEM "gdb-target.dtd">
++<feature name="org.gnu.gdb.arm.tls">
++ <reg name="tpidruro" bitsize="32" type="data_ptr"/>
++</feature>
diff --git a/devel/gdb/files/commit-983b1119bc3 b/devel/gdb/files/commit-983b1119bc3
new file mode 100644
index 000000000000..8d510809f0f1
--- /dev/null
+++ b/devel/gdb/files/commit-983b1119bc3
@@ -0,0 +1,42 @@
+commit 1371da3a2d71dbd58f5ba3dd3c39841f0182556d
+Author: John Baldwin <jhb@FreeBSD.org>
+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;
diff --git a/devel/gdb/files/commit-a171378aa47 b/devel/gdb/files/commit-a171378aa47
new file mode 100644
index 000000000000..27b0166df11b
--- /dev/null
+++ b/devel/gdb/files/commit-a171378aa47
@@ -0,0 +1,45 @@
+commit 9f5989ef192efab3d477fd6cc8712a8fd53e1856
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <jhb@FreeBSD.org>
++
++ * elf/common.h (NT_FREEBSD_X86_SEGBASES): Define.
++
+ 2022-03-16 Simon Marchi <simon.marchi@efficios.com>
+
+ * 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". */
diff --git a/devel/gdb/files/commit-a3627b54280 b/devel/gdb/files/commit-a3627b54280
new file mode 100644
index 000000000000..e3a871f2b950
--- /dev/null
+++ b/devel/gdb/files/commit-a3627b54280
@@ -0,0 +1,53 @@
+commit 28207615d3f3d639a71df51be9ceed3033bb17c6
+Author: John Baldwin <jhb@FreeBSD.org>
+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;
diff --git a/devel/gdb/files/commit-a49ce729c80 b/devel/gdb/files/commit-a49ce729c80
new file mode 100644
index 000000000000..fe249c42d992
--- /dev/null
+++ b/devel/gdb/files/commit-a49ce729c80
@@ -0,0 +1,157 @@
+commit 6f5759385274e15c5ef1a7d879ce7324ab0605ab
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <sys/user.h>
+ #include <machine/reg.h>
+
+-#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<fbsd_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 <sys/sysctl.h>
+ #include <sys/user.h>
+
+-#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<fbsd_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 <http://www.gnu.org/licenses/>. */
++
++#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<fbsd_nat_target>
++{
++ bool supports_stopped_by_hw_breakpoint () override
++ { return true; }
++};
++
++#endif /* x86-bsd-nat.h */
diff --git a/devel/gdb/files/commit-b1babce7c31 b/devel/gdb/files/commit-b1babce7c31
new file mode 100644
index 000000000000..e2e29597e81e
--- /dev/null
+++ b/devel/gdb/files/commit-b1babce7c31
@@ -0,0 +1,50 @@
+commit 8a528699fdc82963d528bbbbd3f3509e1472a64b
+Author: John Baldwin <jhb@FreeBSD.org>
+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<pid_t,
+ struct x86_debug_reg_state> 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. */
+
diff --git a/devel/gdb/files/commit-b5c2367c3ac b/devel/gdb/files/commit-b5c2367c3ac
new file mode 100644
index 000000000000..49a0767b598d
--- /dev/null
+++ b/devel/gdb/files/commit-b5c2367c3ac
@@ -0,0 +1,89 @@
+commit f5bae6f6cb45860d63ebc6d309404cf5d7d29052
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <jhb@FreeBSD.org>
++
++ * 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 <jhb@FreeBSD.org>
+
+ * 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)
diff --git a/devel/gdb/files/commit-b7fe5463cf0 b/devel/gdb/files/commit-b7fe5463cf0
new file mode 100644
index 000000000000..9b9aece926ee
--- /dev/null
+++ b/devel/gdb/files/commit-b7fe5463cf0
@@ -0,0 +1,102 @@
+commit 0e67403c6b094d638a4ca130ff6dcd6a153f3eb2
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <sys/param.h>
+ #include <sys/ptrace.h>
+ #include <machine/armreg.h>
+ #include <machine/reg.h>
+
+ #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<struct fpreg> (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<uint64_t> (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<struct fpreg> (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<uint64_t> (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
diff --git a/devel/gdb/files/commit-c13566fdd57 b/devel/gdb/files/commit-c13566fdd57
new file mode 100644
index 000000000000..085834f0f243
--- /dev/null
+++ b/devel/gdb/files/commit-c13566fdd57
@@ -0,0 +1,35 @@
+commit 7995cf839e5c608372e78f8bd5f6d120803a4e63
+Author: John Baldwin <jhb@FreeBSD.org>
+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;
diff --git a/devel/gdb/files/commit-c77282d8ba9 b/devel/gdb/files/commit-c77282d8ba9
new file mode 100644
index 000000000000..74260afce1e4
--- /dev/null
+++ b/devel/gdb/files/commit-c77282d8ba9
@@ -0,0 +1,41 @@
+commit 066ae99a326d77966288c59066018ca6f3f1d22d
+Author: John Baldwin <jhb@FreeBSD.org>
+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;
diff --git a/devel/gdb/files/commit-e330d4c033e b/devel/gdb/files/commit-e330d4c033e
new file mode 100644
index 000000000000..0d8b47fbd6b4
--- /dev/null
+++ b/devel/gdb/files/commit-e330d4c033e
@@ -0,0 +1,55 @@
+commit 1ec77d89016f9b26dde3de6cdc4f4eaa44bbff13
+Author: John Baldwin <jhb@FreeBSD.org>
+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 <jhb@FreeBSD.org>
++
++ * elf.c (elfcore_grok_freebsd_note): Remove checks for namesz.
++
+ 2022-03-18 Viorel Preoteasa <viorel.preoteasa@gmail.com>
+
+ 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",
diff --git a/devel/gdb/files/commit-f3215e1526d b/devel/gdb/files/commit-f3215e1526d
new file mode 100644
index 000000000000..8817df2345a7
--- /dev/null
+++ b/devel/gdb/files/commit-f3215e1526d
@@ -0,0 +1,114 @@
+commit 87716bf398bfa17f73de9d6ac4a8573e520985e5
+Author: John Baldwin <jhb@FreeBSD.org>
+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),
diff --git a/devel/gdb/files/commit-f9fbb7636a5 b/devel/gdb/files/commit-f9fbb7636a5
new file mode 100644
index 000000000000..2031673e4986
--- /dev/null
+++ b/devel/gdb/files/commit-f9fbb7636a5
@@ -0,0 +1,68 @@
+commit e6107bf932b37ae7e30a5fffe93f9998c4b9c20a
+Author: John Baldwin <jhb@FreeBSD.org>
+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 ();
diff --git a/devel/gdb/files/extrapatch-kgdb b/devel/gdb/files/extrapatch-kgdb
index f94bb3a49699..e298ca3642da 100644
--- a/devel/gdb/files/extrapatch-kgdb
+++ b/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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
@$(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 @@ index b8729ed7b2e..660476c11e2 100644
# 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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
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 @@ index b8729ed7b2e..660476c11e2 100644
# 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 @@ index 2c30504905b..edf57bf48a9 100644
#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 @@ index 5d89635c043..2ab494696c6 100755
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 @@ index b8c79bcac9a..9b73cb6018d 100644
# 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 @@ index e34cccffd98..d15a915d2c9 100644
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 @@ index 97a5a57c378..19ef5c7a48f 100644
*-*-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 @@ index 97a5a57c378..19ef5c7a48f 100644
;;
aarch64*-*-linux*)
-@@ -176,7 +176,7 @@ arm*-*-linux*)
+@@ -187,7 +187,7 @@ arm*-*-linux*)
;;
arm*-*-freebsd*)
# Target: FreeBSD/arm
@@ -402,7 +400,7 @@ index 97a5a57c378..19ef5c7a48f 100644
;;
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 @@ index 97a5a57c378..19ef5c7a48f 100644
;;
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 @@ index 97a5a57c378..19ef5c7a48f 100644
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 @@ index 97a5a57c378..19ef5c7a48f 100644
;;
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 @@ index 97a5a57c378..19ef5c7a48f 100644
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 @@ index 97a5a57c378..19ef5c7a48f 100644
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 @@ index aabf895c045..5b5ef033f90 100644
{ "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 @@ index 1ecbed4611d..9f701076063 100644
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 @@ index fde0c612975..818c62bbf31 100644
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);
diff --git a/devel/gdb/files/kgdb/aarch64-fbsd-kern.c b/devel/gdb/files/kgdb/aarch64-fbsd-kern.c
index 6cdbb66397b0..095b438a0be1 100644
--- a/devel/gdb/files/kgdb/aarch64-fbsd-kern.c
+++ b/devel/gdb/files/kgdb/aarch64-fbsd-kern.c
@@ -169,7 +169,7 @@ static const struct frame_unwind aarch64_fbsd_trapframe_unwind = {
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);
diff --git a/devel/gdb/files/kgdb/arm-fbsd-kern.c b/devel/gdb/files/kgdb/arm-fbsd-kern.c
index 552c3a95a257..be24ab2e4530 100644
--- a/devel/gdb/files/kgdb/arm-fbsd-kern.c
+++ b/devel/gdb/files/kgdb/arm-fbsd-kern.c
@@ -183,7 +183,7 @@ static const struct frame_unwind arm_fbsd_trapframe_unwind = {
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);
diff --git a/devel/gdb/files/kgdb/fbsd-kld.c b/devel/gdb/files/kgdb/fbsd-kld.c
index baaca7fda26e..b36592e08060 100644
--- a/devel/gdb/files/kgdb/fbsd-kld.c
+++ b/devel/gdb/files/kgdb/fbsd-kld.c
@@ -377,17 +377,17 @@ kld_solib_create_inferior_hook (int from_tty)
"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"));
diff --git a/devel/gdb/files/kgdb/fbsd-kthr.c b/devel/gdb/files/kgdb/fbsd-kthr.c
index b1c55a2ba6f5..f74d8843f201 100644
--- a/devel/gdb/files/kgdb/fbsd-kthr.c
+++ b/devel/gdb/files/kgdb/fbsd-kthr.c
@@ -254,16 +254,16 @@ kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int))
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 @@ kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int))
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 @@ kgdb_thr_init(CORE_ADDR (*cpu_pcb_addr) (u_int))
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);
diff --git a/devel/gdb/files/kgdb/fbsd-kvm.c b/devel/gdb/files/kgdb/fbsd-kvm.c
index 78fa9d331a5b..e1166a54d52e 100644
--- a/devel/gdb/files/kgdb/fbsd-kvm.c
+++ b/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 <sys/user.h>
@@ -479,7 +480,7 @@ fbsd_kvm_target::files_info()
{
printf_filtered ("\t`%s', ", vmcore);
- wrap_here (" ");
+ gdb_stdout->wrap_here (8);
printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore");
}
diff --git a/devel/gdb/files/kgdb/ppcfbsd-kern.c b/devel/gdb/files/kgdb/ppcfbsd-kern.c
index 3a6eb466a92c..4246c39d11ba 100644
--- a/devel/gdb/files/kgdb/ppcfbsd-kern.c
+++ b/devel/gdb/files/kgdb/ppcfbsd-kern.c
@@ -64,7 +64,7 @@ _Static_assert(offsetof(struct pcb, pcb_lr) == PCB_OFF_LR * sizeof(register_t),
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 @@ static struct trad_frame_cache *
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 const struct frame_unwind ppcfbsd_trapframe_unwind =
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);
diff --git a/devel/gdb/files/patch-fixes b/devel/gdb/files/patch-fixes
deleted file mode 100644
index 1d7714c94144..000000000000
--- a/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)
- {
diff --git a/devel/gdb/files/patch-gdb_amd64-bsd-nat.c b/devel/gdb/files/patch-gdb_amd64-bsd-nat.c
deleted file mode 100644
index 9b34d1513cca..000000000000
--- a/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 <sys/types.h>
- #include <sys/ptrace.h>
- #include <machine/reg.h>
-+#include <machine/psl.h>
-
- #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) &regs, 0) == -1)
- perror_with_name (_("Couldn't get registers"));
-
-+ old_rflags = regs.r_rflags;
- amd64_collect_native_gregset (regcache, &regs, 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) &regs, 0) == -1)
- perror_with_name (_("Couldn't write registers"));
-
diff --git a/devel/gdb/files/patch-gdb_i386-fbsd-nat.c b/devel/gdb/files/patch-gdb_i386-fbsd-nat.c
index bba42ea41cb0..e037c13fd396 100644
--- a/devel/gdb/files/patch-gdb_i386-fbsd-nat.c
+++ b/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:
- const struct target_desc *read_description () override;
- #endif
+--- 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;
-- void resume (ptid_t, int, enum gdb_signal) override;
+ const struct target_desc *read_description () 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"));
}
diff --git a/devel/gdb/files/patch-include_libiberty.h b/devel/gdb/files/patch-include_libiberty.h
deleted file mode 100644
index 26afe105b0f7..000000000000
--- a/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 <libgen.h>
- #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
diff --git a/devel/gdb/files/patch-libiberty_configure b/devel/gdb/files/patch-libiberty_configure
deleted file mode 100644
index fb52c901e7e7..000000000000
--- a/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
diff --git a/devel/gdb/pkg-plist b/devel/gdb/pkg-plist
index 4efe03c46e1a..7217f14e3bf4 100644
--- a/devel/gdb/pkg-plist
+++ b/devel/gdb/pkg-plist
@@ -21,6 +21,8 @@ man/man1/gdb%%VER%%.1.gz
%%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