diff --git a/.gitignore b/.gitignore
index f288cc8..8733cd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
/v2.0.5.tar.gz
/gdb-14.2.tar.xz
/gdb-16.3.tar.xz
+/gdb-17.2.tar.xz
diff --git a/README.local-patches.md b/README.local-patches.md
new file mode 100644
index 0000000..b9ef2c6
--- /dev/null
+++ b/README.local-patches.md
@@ -0,0 +1,102 @@
+# Fedora GDB local patches policy
+
+In order to make things easier for the Fedora GDB maintainer, we
+choose to auto-generate the local patches by making use of an upstream
+git repository. Below you can find a few instructions on how to work
+using this method.
+
+You need to run the following commands from the directory that
+contains the "gdb.spec" file.
+
+## Importing the GDB patches into a git repository
+
+1) The local patches (`*.patch`) need to be imported into an upstream
+git repository. For example, let's assume you cloned the repository
+by doing:
+
+`$ git clone git://sourceware.org/git/binutils-gdb.git`
+
+> TIP: if you already have the repository cloned somewhere in your
+> system, you can pass a "--reference
" to the "git clone"
+> command and it will use your local repository as much as possible
+> to make the clone, speeding up things.
+
+2) After cloning the upstream repository, you can import your patches
+by using the script "generate-git-repo-from-patches.sh":
+
+`$ sh generate-git-repo-from-patches.sh `
+
+The script will basically cd into the repository, checkout the
+revision specified in the file `_git_upstream_commit`, iterate through
+the file `_patch_order` and "git-am" every patch *in that order*.
+This operation should complete without errors; if you find a problem
+with `git-am`, it probably means that the revision specified in the
+file `_git_upstream_commit` is wrong.
+
+## Rebasing the patches against a newer version/release
+
+1) First, cd into the upstream repository. All you have to do is
+choose the revision against which you plan to rebase the patches, and
+`git rebase `. git will do the rest, and you will be able
+to perform conflict resolution by git's algorithm, which is smarter.
+
+## Creating new patches
+
+1) Create the new patch on top of the the others, as usual. Note that
+you can use `git rebase` whenever you want to reorder patch order, or
+even to delete a patch.
+
+2) When writing the commit log, you must obey a few rules. The
+subject line *must* be the filename of the patch. This line will be
+used when exporting the patches from the git repository, and
+(obviously) it gives the filename that should be used for this
+specific patch.
+
+3) You can also add comments that will go into the auto-generated
+`Patch:` file (see below). To do that, use the special marker `;;` at
+the beginning of the line. This way, a commit log that says:
+
+~~~~~~~~~~~
+ test-patch.patch
+
+ ;; This is a test patch
+ ;; Second line
+~~~~~~~~~~~
+
+Will generate the following entry in the auto-generated `Patch:` file:
+
+~~~~~~~~~~~
+ # This is a test patch
+ # Second line
+ PatchXYZ: test-patch.patch
+~~~~~~~~~~~
+
+## Exporting the GDB patches from the git repository
+
+1) When you're done working with the patches, go back to the directory
+that contains the `gdb.spec` file, and from there you run:
+
+`$ sh generate-patches-from-git-repo.sh `
+
+This will regenerate all of the `*.patch` files (excluding the ones that
+were also excluded from the git repository), and also regenerate a few
+control files. These control files are:
+
+ - `_gdb.spec.Patch.include`: This file contains the `Patch:` directives.
+
+ - `_patch_order`: This file contains the patches, in the exact order
+ that they must be applied. It is used when importing the patches
+ into the git repository.
+
+ - `_git_upstream_commit`: This file contains the last upstream commit
+ against which the patches were rebased. It is used when importing
+ the patches into the git repository.
+
+NOTE: If you did a rebase against a newer upstream version, you need
+to specify the commit/tag/branch against which you rebased:
+
+`$ sh generate-patches-from-git-repo.sh `
+
+For example, if you rebased against `gdb-8.1-release`:
+
+`$ sh generate-patches-from-git-repo.sh gdb-8.1-release`
diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include
index b7ab9d0..bed92a5 100644
--- a/_gdb.spec.Patch.include
+++ b/_gdb.spec.Patch.include
@@ -1,43 +1,5 @@
# Check distro name is included in the version output.
-Patch001: gdb-6.3-rh-testversion-20041202.patch
-
-# Test sideeffects of skipping ppc .so libs trampolines (BZ 218379).
-#=fedoratest
-Patch002: gdb-6.5-bz218379-ppc-solib-trampoline-test.patch
-
-# Support for stepping over PPC atomic instruction sequences (BZ 237572).
-#=fedoratest
-Patch003: gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
-
-# Test gcore memory and time requirements for large inferiors.
-#=fedoratest
-Patch004: gdb-6.5-gcore-buffer-limit-test.patch
-
-# Test GCORE for shmid 0 shared memory mappings.
-#=fedoratest: But it is broken anyway, sometimes the case being tested is not reproducible.
-Patch005: gdb-6.3-mapping-zero-inode-test.patch
-
-# Fix resolving of variables at locations lists in prelinked libs (BZ 466901).
-#=fedoratest
-Patch006: gdb-6.8-bz466901-backtrace-full-prelinked.patch
-
-# Fix follow-exec for C++ programs (bugreported by Martin Stransky).
-#=fedoratest
-Patch007: gdb-archer-next-over-throw-cxx-exec.patch
-
-# Testcase for `Setting solib-absolute-prefix breaks vDSO' (BZ 818343).
-#=fedoratest
-Patch008: gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
-
-# Fix '`catch syscall' doesn't work for parent after `fork' is called'
-# (Philippe Waroquiers, RH BZ 1149205).
-#=fedoratest
-Patch009: gdb-rhbz1149205-catch-syscall-after-fork-test.patch
-
-# Fix '[ppc64] and [s390x] wrong prologue skip on -O2 -g code' (Jan
-# Kratochvil, RH BZ 1084404).
-#=fedoratest
-Patch010: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
+Patch001: gdb-test-show-version.patch
# Update gdb-add-index.sh such that, when the GDB environment
# variable is not set, the script is smarter than just looking for
@@ -51,72 +13,85 @@ Patch010: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
# https://fedoraproject.org/wiki/Changes/Minimal_GDB_in_buildroot
#
#=fedora
-Patch011: gdb-add-index.patch
+Patch002: gdb-add-index.patch
# Not a backport. Add a new script which hooks into GDB and suggests
# RPMs to install when GDB finds an objfile with no debug info.
-Patch012: gdb-add-rpm-suggestion-script.patch
+Patch003: gdb-rpm-suggestion-script.patch
-# Backport "s390: Add support for z17 as CPU name"
-# (Jens Remus, RHEL-50069)
-Patch013: gdb-rhel-50069-support-z17.patch
+# Backport Guinevere Larsen's build warning fixes (RH BZ 2424325).
+Patch004: gdb-rhbz2424325-c23-const-build-warnings.patch
-# [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 1
-# (Tom de Vries, RHEL-7329)
-Patch014: gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch
+# Backport Keith Seitz's C23 const-correctness fixes (pending upstream review).
+# Mailing list: https://sourceware.org/pipermail/binutils/2026-January/...
+# Posted 2026-01-07, not yet approved.
+Patch005: gdb-rhbz2424325-c23-more-const-fixes.patch
-# [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 2
-# (Tom de Vries, RHEL-7329)
-Patch015: gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch
+# Backport Tom de Vries fix regarding implicit lambda captures
+# (RH BZ 2424325).
+Patch006: gdb-rhbz2424325-c++20-implicit-lambda-capture.patch
-# [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 3
-# (Tom de Vries, RHEL-7329)
-Patch016: gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch
+# Backport of upstream commit 70b66cf338b14336 to address RHBZ
+# 2402580. This backport can be dropped when rebasing to GDB 18.
+# There were some moderate merge conflicts which needed resolving
+# when backporting this fix.
+Patch007: gdb-rhbz2403580-misplaced-symtabs.patch
-# [gdb/tdep] Factor out amd64_get_used_input_int_regs
-# (Tom de Vries, RHEL-7329)
-Patch017: gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch
+# Backport of upstream commit c1da013915e from Kevin Buettner
+# (RHBZ 2413405).
+Patch008: gdb-rhbz2413405-gcore-unreadable-pages.patch
-# [gdb/tdep] Add amd64-insn-decode selftest
-# (Tom de Vries, RHEL-7329)
-Patch018: gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch
+# Backport of upstream commit d2cc16cd7fc from Jan Vrany fixing
+# FAILs in gdb.base/fileio.exp caused by macro expansion of
+# path components in OUTDIR.gdb/testsuite: fix FAILs in fileio.exp
+Patch009: gdb-fileio-test-fixes.patch
-# [gdb/tdep] Factor out rip_relative_p
-# (Tom de Vries, RHEL-7329)
-Patch019: gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch
+# Backport upstream commit 8bd08ee92c4 to address rhbz2366461. This
+# commit will drop out with GDB 18.
+Patch010: gdb-rhbz2366461-missing-thread.patch
-# [gdb/tdep] Fix rip-relative insn handling in amd64_get_used_input_int_reg
-# (Tom de Vries, RHEL-7329)
-Patch020: gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch
+# Backport upstream commit cd289df068e to address rhbz2366461. This
+# commit will drop out with GDB 18.
+Patch011: gdb-rhbz2366461-bad-solib-entry-addr.patch
-# [gdb/tdep] Factor out part of fixup_riprel
-# (Tom de Vries, RHEL-7329)
-Patch021: gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch
+# Fix use of deprecated trace variable subcommand
+# (Tom de Vries)
+Patch012: gdb-fix-testsuite-newer-tcl.patch
-# [gdb/tdep] Add vex2_to_vex3
-# (Tom de Vries, RHEL-7329)
-Patch022: gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch
+# Backport the following upstream commits in order to address RHBZ
+# 2467251: d980317c7f1, 958d06262a7, 7d1d7386561, 8915de0883c,
+# 8f65ab7b71f. These commits will all drop out when we rebase to GDB
+# 18.
+Patch013: gdb-rhbz2467251-computed-location-synthetic-pointers.patch
-# [gdb/tdep] Add vzeroupper and vzeroall in amd64-insn-decode selftest
-# (Tom de Vries, RHEL-7329)
-Patch023: gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch
-
-# [gdb/tdep] Make amd64_get_insn_details more regular
-# (Tom de Vries, RHEL-7329)
-Patch024: gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch
-
-# [gdb/tdep] Fix vmovdqu decoding
-# (Tom de Vries, RHEL-7329)
-Patch025: gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch
-
-# [gdb/tdep] Support REX2 and EVEX prefix
-# (Tom de Vries, RHEL-7329)
-Patch026: gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch
-
-# Backport of three upstream patches. The first two relate to index
-# generation, while the third relates to symbol lookup, but is needed
-# so that the tests from the earlier two patches will pass.
+# Fix EILSEQ problems for UTF8 related tests when using expect
+# enabled with Tcl 9 and full set of Tcl 9 compatibility fixes
+# from upstream PR80674 branch. Required for testing GDB on
+# Fedora 44 and rawhide (Fedora 45).
#
-# (Tom Tromey and Andrew Burgess, RHEL-150992)
-Patch027: gdb-rhel-150992-index-generation-fixes.patch
+# At the time of this Fedora commit, this patch was not upstream yet.
+# For its status, see:
+#
+# https://inbox.sourceware.org/gdb-patches/20260526192701.3835262-2-kevinb@redhat.com/T/#u
+Patch014: gdb-tcl9-utf8-encoding-fix.patch
+
+# Backport of upstream commit e492fb22b70
+# gdb: backport DAP core file support
+Patch015: gdb-backport-dap-core-file-support.patch
+
+# Backport of upstream commit be3a9405ceb4d6d6 to fix RHBZ 2368350, an
+# out of memory issue with the D demangler.
+#
+# The commit being pulled in here is a commit that syncs multiple
+# commits to libiberty from gcc to binutils-gdb. Most of these commits
+# are spelling and white space fixes, which should have no real impact.
+# The only commit we actually care about is gcc commit bc4d9b6aeb3,
+# which fixes the D demangler issue.
+#
+# This commit will not be needed once we rebase to GDB 18.
+Patch016: gdb-backport-libiberty-sync.patch
+
+# Backport of upstream commit 93f536d813c41527e8c939a5f8a90a4 to fix
+# RHBZ2498034.
+Patch017: gdb-backport-corefile-use-after-free-fix.patch
diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include
index efd00da..f630fc2 100644
--- a/_gdb.spec.patch.include
+++ b/_gdb.spec.patch.include
@@ -13,15 +13,3 @@
%patch -p1 -P013
%patch -p1 -P014
%patch -p1 -P015
-%patch -p1 -P016
-%patch -p1 -P017
-%patch -p1 -P018
-%patch -p1 -P019
-%patch -p1 -P020
-%patch -p1 -P021
-%patch -p1 -P022
-%patch -p1 -P023
-%patch -p1 -P024
-%patch -p1 -P025
-%patch -p1 -P026
-%patch -p1 -P027
diff --git a/_git_upstream_commit b/_git_upstream_commit
index 1e79418..da4c92e 100644
--- a/_git_upstream_commit
+++ b/_git_upstream_commit
@@ -1 +1 @@
-140ba011c003fda0fb2f746cf2bc0f010bf4ac03
+7adf9fa6b1ccb3c70f86cb630368b9d3dffcf3aa
diff --git a/_patch_order b/_patch_order
index 5a9f83c..aed5ae3 100644
--- a/_patch_order
+++ b/_patch_order
@@ -1,27 +1,17 @@
-gdb-6.3-rh-testversion-20041202.patch
-gdb-6.5-bz218379-ppc-solib-trampoline-test.patch
-gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
-gdb-6.5-gcore-buffer-limit-test.patch
-gdb-6.3-mapping-zero-inode-test.patch
-gdb-6.8-bz466901-backtrace-full-prelinked.patch
-gdb-archer-next-over-throw-cxx-exec.patch
-gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
-gdb-rhbz1149205-catch-syscall-after-fork-test.patch
-gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
+gdb-test-show-version.patch
gdb-add-index.patch
-gdb-add-rpm-suggestion-script.patch
-gdb-rhel-50069-support-z17.patch
-gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch
-gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch
-gdb-rhel-150992-index-generation-fixes.patch
+gdb-rpm-suggestion-script.patch
+gdb-rhbz2424325-c23-const-build-warnings.patch
+gdb-rhbz2424325-c23-more-const-fixes.patch
+gdb-rhbz2424325-c++20-implicit-lambda-capture.patch
+gdb-rhbz2403580-misplaced-symtabs.patch
+gdb-rhbz2413405-gcore-unreadable-pages.patch
+gdb-fileio-test-fixes.patch
+gdb-rhbz2366461-missing-thread.patch
+gdb-rhbz2366461-bad-solib-entry-addr.patch
+gdb-fix-testsuite-newer-tcl.patch
+gdb-rhbz2467251-computed-location-synthetic-pointers.patch
+gdb-tcl9-utf8-encoding-fix.patch
+gdb-backport-dap-core-file-support.patch
+gdb-backport-libiberty-sync.patch
+gdb-backport-corefile-use-after-free-fix.patch
diff --git a/gdb-6.3-mapping-zero-inode-test.patch b/gdb-6.3-mapping-zero-inode-test.patch
deleted file mode 100644
index 32b62d5..0000000
--- a/gdb-6.3-mapping-zero-inode-test.patch
+++ /dev/null
@@ -1,247 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.3-mapping-zero-inode-test.patch
-
-;; Test GCORE for shmid 0 shared memory mappings.
-;;=fedoratest: But it is broken anyway, sometimes the case being tested is not reproducible.
-
-diff --git a/gdb/testsuite/gdb.base/gcore-shmid0.c b/gdb/testsuite/gdb.base/gcore-shmid0.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-shmid0.c
-@@ -0,0 +1,128 @@
-+/* Copyright 2007, 2009 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 2 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, write to the Free Software
-+ Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA. */
-+
-+/*
-+ * Test GDB's handling of gcore for mapping with a name but zero inode.
-+ */
-+
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+/* The same test running in a parallel testsuite may steal us the zero SID,
-+ even if we never get any EEXIST. Just try a while. */
-+
-+#define TIMEOUT_SEC 10
-+
-+static volatile int v;
-+
-+static void
-+initialized (void)
-+{
-+ v++;
-+}
-+
-+static void
-+unresolved (void)
-+{
-+ v++;
-+}
-+
-+int
-+main (void)
-+{
-+ int sid;
-+ unsigned int *addr = (void *) -1L;
-+ int attempt, round = 0;
-+ time_t ts_start, ts;
-+
-+ if (time (&ts_start) == (time_t) -1)
-+ {
-+ printf ("time (): %m\n");
-+ exit (1);
-+ }
-+
-+ /* The generated SID will cycle with an increment of 32768, attempt until it
-+ * wraps to 0. */
-+
-+ for (attempt = 0; addr == (void *) -1L; attempt++)
-+ {
-+ /* kernel-2.6.25-8.fc9.x86_64 just never returns the value 0 by
-+ shmget(2). shmget returns SID range 0..1<<31 in steps of 32768,
-+ 0x1000 should be enough but wrap the range it to be sure. */
-+
-+ if (attempt > 0x21000)
-+ {
-+ if (time (&ts) == (time_t) -1)
-+ {
-+ printf ("time (): %m\n");
-+ exit (1);
-+ }
-+
-+ if (ts >= ts_start && ts < ts_start + TIMEOUT_SEC)
-+ {
-+ attempt = 0;
-+ round++;
-+ continue;
-+ }
-+
-+ printf ("Problem is not reproducible on this kernel (attempt %d, "
-+ "round %d)\n", attempt, round);
-+ unresolved ();
-+ exit (1);
-+ }
-+
-+ sid = shmget ((key_t) rand (), 0x1000, IPC_CREAT | IPC_EXCL | 0777);
-+ if (sid == -1)
-+ {
-+ if (errno == EEXIST)
-+ continue;
-+
-+ printf ("shmget (%d, 0x1000, IPC_CREAT): errno %d\n", 0, errno);
-+ exit (1);
-+ }
-+
-+ /* Use SID only if it is 0, retry it otherwise. */
-+
-+ if (sid == 0)
-+ {
-+ addr = shmat (sid, NULL, SHM_RND);
-+ if (addr == (void *) -1L)
-+ {
-+ printf ("shmat (%d, NULL, SHM_RND): errno %d\n", sid,
-+ errno);
-+ exit (1);
-+ }
-+ }
-+ if (shmctl (sid, IPC_RMID, NULL) != 0)
-+ {
-+ printf ("shmctl (%d, IPC_RMID, NULL): errno %d\n", sid, errno);
-+ exit (1);
-+ }
-+ }
-+
-+ initialized ();
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/gcore-shmid0.exp b/gdb/testsuite/gdb.base/gcore-shmid0.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-shmid0.exp
-@@ -0,0 +1,101 @@
-+# Copyright 2007, 2009 Free Software Foundation, Inc.
-+
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+# Test GDB's handling of gcore for mapping with a name but zero inode.
-+
-+if { [prepare_for_testing gcore-shmid0.exp gcore-shmid0] } {
-+ return -1
-+}
-+
-+# Does this gdb support gcore?
-+set test "help gcore"
-+gdb_test_multiple $test $test {
-+ -re "Undefined command: .gcore.*$gdb_prompt $" {
-+ # gcore command not supported -- nothing to test here.
-+ unsupported "gdb does not support gcore on this target"
-+ return -1;
-+ }
-+ -re "Save a core file .*$gdb_prompt $" {
-+ pass $test
-+ }
-+}
-+
-+if { ! [ runto_main ] } then {
-+ untested gcore-shmid0.exp
-+ return -1
-+}
-+
-+gdb_breakpoint "initialized"
-+gdb_breakpoint "unresolved"
-+
-+set oldtimeout $timeout
-+set timeout [expr $oldtimeout + 120]
-+
-+set test "Continue to initialized."
-+gdb_test_multiple "continue" $test {
-+ -re "Breakpoint .*, initialized .* at .*\r\n$gdb_prompt $" {
-+ pass $test
-+ }
-+ -re "Breakpoint .*, unresolved .* at .*\r\n$gdb_prompt $" {
-+ set timeout $oldtimeout
-+ unsupported $test
-+ return -1
-+ }
-+}
-+set timeout $oldtimeout
-+
-+set escapedfilename [string_to_regexp [standard_output_file gcore-shmid0.test]]
-+
-+set test "save a corefile"
-+gdb_test_multiple "gcore [standard_output_file gcore-shmid0.test]" $test {
-+ -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" {
-+ pass $test
-+ }
-+ -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" {
-+ unsupported $test
-+ }
-+}
-+
-+# Be sure to remove the handle first.
-+# But it would get removed even on a kill by GDB as the handle is already
-+# deleted, just it is still attached.
-+gdb_continue_to_end "finish"
-+
-+set test "core-file command"
-+gdb_test_multiple "core-file [standard_output_file gcore-shmid0.test]" $test {
-+ -re ".* program is being debugged already.*y or n. $" {
-+ # gdb_load may connect us to a gdbserver.
-+ send_gdb "y\n"
-+ exp_continue;
-+ }
-+ -re "Core was generated by .*\r\n\#0 .*\\\(\\\).*\r\n$gdb_prompt $" {
-+ # The filename does not fit there anyway so do not check it.
-+ pass $test
-+ }
-+ -re ".*registers from core file: File in wrong format.* $" {
-+ fail "core-file command (could not read registers from core file)"
-+ }
-+}
-+
-+set test "backtrace"
-+gdb_test_multiple "bt" $test {
-+ -re "#0 *initialized \\\(\\\) at .*#1 .* main \\\(.*$gdb_prompt $" {
-+ pass $test
-+ }
-+ -re "#0 *initialized \\\(\\\) at .*Cannot access memory at address .*$gdb_prompt $" {
-+ fail $test
-+ }
-+}
diff --git a/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch b/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch
deleted file mode 100644
index db4229d..0000000
--- a/gdb-6.5-bz218379-ppc-solib-trampoline-test.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.5-bz218379-ppc-solib-trampoline-test.patch
-
-;; Test sideeffects of skipping ppc .so libs trampolines (BZ 218379).
-;;=fedoratest
-
-https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=218379
-
-diff --git a/gdb/testsuite/gdb.base/step-over-trampoline.c b/gdb/testsuite/gdb.base/step-over-trampoline.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/step-over-trampoline.c
-@@ -0,0 +1,28 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2006 Free Software Foundation, Inc.
-+
-+ 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 2 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, write to the Free Software
-+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+ Please email any bugs, comments, and/or additions to this file to:
-+ bug-gdb@prep.ai.mit.edu */
-+
-+#include
-+
-+int main (void)
-+{
-+ puts ("hello world");
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/step-over-trampoline.exp b/gdb/testsuite/gdb.base/step-over-trampoline.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/step-over-trampoline.exp
-@@ -0,0 +1,59 @@
-+# Copyright 2006 Free Software Foundation, Inc.
-+
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+if {[use_gdb_stub]} {
-+ untested "skipping test because of use_gdb_stub"
-+ return -1
-+}
-+
-+if $tracelevel then {
-+ strace $tracelevel
-+}
-+
-+set testfile step-over-trampoline
-+set srcfile ${testfile}.c
-+set binfile [standard_output_file ${testfile}]
-+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
-+ untested "Couldn't compile test program"
-+ return -1
-+}
-+
-+# Get things started.
-+
-+gdb_exit
-+gdb_start
-+gdb_reinitialize_dir $srcdir/$subdir
-+gdb_load ${binfile}
-+
-+# For C programs, "start" should stop in main().
-+
-+gdb_test "start" \
-+ "main \\(\\) at .*$srcfile.*" \
-+ "start"
-+
-+# main () at hello2.c:5
-+# 5 puts("hello world\n");
-+# (gdb) next
-+# 0x100007e0 in call___do_global_ctors_aux ()
-+
-+gdb_test_multiple "next" "invalid `next' output" {
-+ -re "\nhello world.*return 0;.*" {
-+ pass "stepped over"
-+ }
-+ -re " in call___do_global_ctors_aux \\(\\).*" {
-+ fail "stepped into trampoline"
-+ }
-+}
diff --git a/gdb-6.5-gcore-buffer-limit-test.patch b/gdb-6.5-gcore-buffer-limit-test.patch
deleted file mode 100644
index 07ba1e9..0000000
--- a/gdb-6.5-gcore-buffer-limit-test.patch
+++ /dev/null
@@ -1,154 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.5-gcore-buffer-limit-test.patch
-
-;; Test gcore memory and time requirements for large inferiors.
-;;=fedoratest
-
-diff --git a/gdb/testsuite/gdb.base/gcore-excessive-memory.c b/gdb/testsuite/gdb.base/gcore-excessive-memory.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-excessive-memory.c
-@@ -0,0 +1,37 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2008 Free Software Foundation, Inc.
-+
-+ 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 2 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, write to the Free Software
-+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+ Please email any bugs, comments, and/or additions to this file to:
-+ bug-gdb@prep.ai.mit.edu */
-+
-+#include
-+#include
-+
-+#define MEGS 64
-+
-+int main()
-+{
-+ void *mem;
-+
-+ mem = malloc (MEGS * 1024ULL * 1024ULL);
-+
-+ for (;;)
-+ sleep (1);
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/gcore-excessive-memory.exp b/gdb/testsuite/gdb.base/gcore-excessive-memory.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-excessive-memory.exp
-@@ -0,0 +1,99 @@
-+# Copyright 2008 Free Software Foundation, Inc.
-+
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+if {[use_gdb_stub]} {
-+ untested "skipping test because of use_gdb_stub"
-+ return -1
-+}
-+
-+set testfile gcore-excessive-memory
-+set srcfile ${testfile}.c
-+set shfile [standard_output_file ${testfile}-gdb.sh]
-+set corefile [standard_output_file ${testfile}.core]
-+set binfile [standard_output_file ${testfile}]
-+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
-+ untested "Couldn't compile test program"
-+ return -1
-+}
-+
-+set f [open "|getconf PAGESIZE" "r"]
-+gets $f pagesize
-+close $f
-+
-+set pid_of_bin [eval exec $binfile &]
-+sleep 2
-+
-+# Get things started.
-+
-+gdb_exit
-+gdb_start
-+gdb_reinitialize_dir $srcdir/$subdir
-+gdb_load ${binfile}
-+
-+set pid_of_gdb [exp_pid -i [board_info host fileid]]
-+
-+gdb_test "attach $pid_of_bin" "Attaching to .*" "attach"
-+gdb_test "up 99" "in main .*" "verify we can get to main"
-+
-+proc memory_v_pages_get {} {
-+ global pid_of_gdb pagesize
-+ set fd [open "/proc/$pid_of_gdb/statm"]
-+ gets $fd line
-+ close $fd
-+ # number of pages of virtual memory
-+ scan $line "%d" drs
-+ return $drs
-+}
-+
-+set pages_found [memory_v_pages_get]
-+
-+# It must be definitely less than `MEGS' of `gcore-excessive-memory.c'.
-+set mb_gcore_reserve 4
-+verbose -log "pages_found = $pages_found, mb_gcore_reserve = $mb_gcore_reserve"
-+set kb_found [expr $pages_found * $pagesize / 1024]
-+set kb_permit [expr $kb_found + 1 * 1024 + $mb_gcore_reserve * 1024]
-+verbose -log "kb_found = $kb_found, kb_permit = $kb_permit"
-+
-+# Create the ulimit wrapper.
-+set f [open $shfile "w"]
-+puts $f "#! /bin/sh"
-+puts $f "ulimit -v $kb_permit"
-+puts $f "exec $GDB \"\$@\""
-+close $f
-+remote_exec host "chmod +x $shfile"
-+
-+gdb_exit
-+set GDBold $GDB
-+set GDB "$shfile"
-+gdb_start
-+set GDB $GDBold
-+
-+gdb_reinitialize_dir $srcdir/$subdir
-+gdb_load ${binfile}
-+
-+set pid_of_gdb [exp_pid -i [board_info host fileid]]
-+
-+gdb_test "attach $pid_of_bin" "Attaching to .*" "attach"
-+gdb_test "up 99" "in main .*" "verify we can get to main"
-+
-+verbose -log "kb_found before gcore = [expr [memory_v_pages_get] * $pagesize / 1024]"
-+
-+gdb_test "gcore $corefile" "Saved corefile \[^\n\r\]*" "Save the core file"
-+
-+verbose -log "kb_found after gcore = [expr [memory_v_pages_get] * $pagesize / 1024]"
-+
-+# Cleanup.
-+exec kill -9 $pid_of_bin
diff --git a/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch b/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
deleted file mode 100644
index 4faef13..0000000
--- a/gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
+++ /dev/null
@@ -1,278 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Jan Kratochvil
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
-
-;; Support for stepping over PPC atomic instruction sequences (BZ 237572).
-;;=fedoratest
-
-2007-06-25 Jan Kratochvil
-
- * gdb.threads/atomic-seq-threaded.c,
- gdb.threads/atomic-seq-threaded.exp: New files.
-
-diff --git a/gdb/testsuite/gdb.threads/atomic-seq-threaded.c b/gdb/testsuite/gdb.threads/atomic-seq-threaded.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.threads/atomic-seq-threaded.c
-@@ -0,0 +1,171 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2007 Free Software Foundation, Inc.
-+
-+ 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 2 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, write to the Free Software
-+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-+ MA 02110-1301, USA. */
-+
-+/* Test stepping over RISC atomic sequences.
-+ This variant testcases the code for stepping another thread while skipping
-+ over the atomic sequence in the former thread
-+ (STEPPING_PAST_SINGLESTEP_BREAKPOINT).
-+ Code comes from gcc/testsuite/gcc.dg/sync-2.c */
-+
-+/* { dg-options "-march=i486" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-+/* { dg-options "-mcpu=v9" { target sparc*-*-* } } */
-+
-+/* Test functionality of the intrinsics for 'short' and 'char'. */
-+
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#define LOOPS 2
-+
-+static int unused;
-+
-+static char AI[18];
-+static char init_qi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
-+static char test_qi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
-+
-+static void
-+do_qi (void)
-+{
-+ if (__sync_fetch_and_add(AI+4, 1) != 0)
-+ abort ();
-+ if (__sync_fetch_and_add(AI+5, 4) != 0)
-+ abort ();
-+ if (__sync_fetch_and_add(AI+6, 22) != 0)
-+ abort ();
-+ if (__sync_fetch_and_sub(AI+7, 12) != 0)
-+ abort ();
-+ if (__sync_fetch_and_and(AI+8, 7) != (char)-1)
-+ abort ();
-+ if (__sync_fetch_and_or(AI+9, 8) != 0)
-+ abort ();
-+ if (__sync_fetch_and_xor(AI+10, 9) != 0)
-+ abort ();
-+ if (__sync_fetch_and_nand(AI+11, 7) != 0)
-+ abort ();
-+
-+ if (__sync_add_and_fetch(AI+12, 1) != 1)
-+ abort ();
-+ if (__sync_sub_and_fetch(AI+13, 12) != (char)-12)
-+ abort ();
-+ if (__sync_and_and_fetch(AI+14, 7) != 7)
-+ abort ();
-+ if (__sync_or_and_fetch(AI+15, 8) != 8)
-+ abort ();
-+ if (__sync_xor_and_fetch(AI+16, 9) != 9)
-+ abort ();
-+ if (__sync_nand_and_fetch(AI+17, 7) != 7)
-+ abort ();
-+}
-+
-+static short AL[18];
-+static short init_hi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
-+static short test_hi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
-+
-+static void
-+do_hi (void)
-+{
-+ if (__sync_fetch_and_add(AL+4, 1) != 0)
-+ abort ();
-+ if (__sync_fetch_and_add(AL+5, 4) != 0)
-+ abort ();
-+ if (__sync_fetch_and_add(AL+6, 22) != 0)
-+ abort ();
-+ if (__sync_fetch_and_sub(AL+7, 12) != 0)
-+ abort ();
-+ if (__sync_fetch_and_and(AL+8, 7) != -1)
-+ abort ();
-+ if (__sync_fetch_and_or(AL+9, 8) != 0)
-+ abort ();
-+ if (__sync_fetch_and_xor(AL+10, 9) != 0)
-+ abort ();
-+ if (__sync_fetch_and_nand(AL+11, 7) != 0)
-+ abort ();
-+
-+ if (__sync_add_and_fetch(AL+12, 1) != 1)
-+ abort ();
-+ if (__sync_sub_and_fetch(AL+13, 12) != -12)
-+ abort ();
-+ if (__sync_and_and_fetch(AL+14, 7) != 7)
-+ abort ();
-+ if (__sync_or_and_fetch(AL+15, 8) != 8)
-+ abort ();
-+ if (__sync_xor_and_fetch(AL+16, 9) != 9)
-+ abort ();
-+ if (__sync_nand_and_fetch(AL+17, 7) != 7)
-+ abort ();
-+}
-+
-+static void *
-+start1 (void *arg)
-+{
-+ unsigned loop;
-+ sleep(1);
-+
-+ for (loop = 0; loop < LOOPS; loop++)
-+ {
-+ memcpy(AI, init_qi, sizeof(init_qi));
-+
-+ do_qi ();
-+
-+ if (memcmp (AI, test_qi, sizeof(test_qi)))
-+ abort ();
-+ }
-+
-+ return arg; /* _delete1_ */
-+}
-+
-+static void *
-+start2 (void *arg)
-+{
-+ unsigned loop;
-+
-+ for (loop = 0; loop < LOOPS; loop++)
-+ {
-+ memcpy(AL, init_hi, sizeof(init_hi));
-+
-+ do_hi ();
-+
-+ if (memcmp (AL, test_hi, sizeof(test_hi)))
-+ abort ();
-+ }
-+
-+ return arg; /* _delete2_ */
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ pthread_t thread;
-+ int i;
-+
-+ i = pthread_create (&thread, NULL, start1, NULL); /* _create_ */
-+ assert (i == 0); /* _create_after_ */
-+
-+ sleep (1);
-+
-+ start2 (NULL);
-+
-+ i = pthread_join (thread, NULL); /* _delete_ */
-+ assert (i == 0);
-+
-+ return 0; /* _exit_ */
-+}
-diff --git a/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp b/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp
-@@ -0,0 +1,84 @@
-+# atomic-seq-threaded.exp -- Test case for stepping over RISC atomic code seqs.
-+# This variant testcases the code for stepping another thread while skipping
-+# over the atomic sequence in the former thread
-+# (STEPPING_PAST_SINGLESTEP_BREAKPOINT).
-+# Copyright (C) 2007 Free Software Foundation, Inc.
-+
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-+
-+# Please email any bugs, comments, and/or additions to this file to:
-+# bug-gdb@prep.ai.mit.edu
-+
-+set testfile atomic-seq-threaded
-+set srcfile ${testfile}.c
-+set binfile [standard_output_file ${testfile}]
-+
-+foreach opts {{} {compiler=gcc4} {FAIL}} {
-+ if {$opts eq "FAIL"} {
-+ return -1
-+ }
-+ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $opts]] eq "" } {
-+ break
-+ }
-+}
-+
-+gdb_exit
-+gdb_start
-+gdb_reinitialize_dir $srcdir/$subdir
-+
-+gdb_load ${binfile}
-+if ![runto_main] then {
-+ fail "Can't run to main"
-+ return 0
-+}
-+
-+# pthread_create () will not pass even on x86_64 with software watchpoint.
-+# Pass after pthread_create () without any watchpoint active.
-+set line [gdb_get_line_number "_create_after_"]
-+gdb_test "tbreak $line" \
-+ "reakpoint (\[0-9\]+) at .*$srcfile, line $line\..*" \
-+ "set breakpoint after pthread_create ()"
-+gdb_test "c" \
-+ ".*/\\* _create_after_ \\*/.*" \
-+ "run till after pthread_create ()"
-+
-+# Without a watchpoint being software no single-stepping would be used.
-+set test "Start (software) watchpoint"
-+gdb_test_multiple "watch unused" $test {
-+ -re "Watchpoint \[0-9\]+: unused.*$gdb_prompt $" {
-+ pass $test
-+ }
-+ -re "Hardware watchpoint \[0-9\]+: unused.*$gdb_prompt $" {
-+ # We do not test the goal but still the whole testcase should pass.
-+ unsupported $test
-+ }
-+}
-+
-+# More thorough testing of the scheduling logic.
-+gdb_test "set scheduler-locking step" ""
-+
-+# Critical code path is stepped through at this point.
-+set line [gdb_get_line_number "_exit_"]
-+gdb_test "tbreak $line" \
-+ "reakpoint \[0-9\]+ at .*$srcfile, line $line\..*" \
-+ "set breakpoint at _exit_"
-+gdb_test "c" \
-+ ".*/\\* _exit_ \\*/.*" \
-+ "run till _exit_"
-+
-+# Just a nonproblematic program exit.
-+gdb_test "c" \
-+ ".*Program exited normally\\..*" \
-+ "run till program exit"
diff --git a/gdb-6.8-bz466901-backtrace-full-prelinked.patch b/gdb-6.8-bz466901-backtrace-full-prelinked.patch
deleted file mode 100644
index 39d8947..0000000
--- a/gdb-6.8-bz466901-backtrace-full-prelinked.patch
+++ /dev/null
@@ -1,481 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.8-bz466901-backtrace-full-prelinked.patch
-
-;; Fix resolving of variables at locations lists in prelinked libs (BZ 466901).
-;;=fedoratest
-
-Fix resolving of variables at locations lists in prelinked libs (BZ 466901).
-
-diff --git a/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-func.S b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-func.S
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-func.S
-@@ -0,0 +1,328 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2008 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see . */
-+
-+/*
-+#include
-+
-+void
-+func (void)
-+{
-+ int i;
-+
-+ abort ();
-+}
-+*/
-+ .file "dw2-loclist-prelinked.c"
-+ .section .debug_abbrev,"",@progbits
-+.Ldebug_abbrev0:
-+ .section .debug_info,"",@progbits
-+.Ldebug_info0:
-+ .section .debug_line,"",@progbits
-+.Ldebug_line0:
-+ .text
-+.Ltext0:
-+.globl func
-+ .type func, @function
-+func:
-+.LFB2:
-+ .file 1 "dw2-loclist-prelinked.c"
-+ .loc 1 5 0
-+ pushl %ebp
-+.LCFI0:
-+ movl %esp, %ebp
-+.LCFI1:
-+ subl $24, %esp
-+.LCFI2:
-+ .loc 1 8 0
-+ call abort
-+.LFE2:
-+ .size func, .-func
-+ .section .debug_frame,"",@progbits
-+.Lframe0:
-+ .long .LECIE0-.LSCIE0
-+.LSCIE0:
-+ .long 0xffffffff
-+ .byte 0x1
-+ .string ""
-+ .uleb128 0x1
-+ .sleb128 -4
-+ .byte 0x8
-+ .byte 0xc
-+ .uleb128 0x4
-+ .uleb128 0x4
-+ .byte 0x88
-+ .uleb128 0x1
-+ .align 4
-+.LECIE0:
-+.LSFDE0:
-+ .long .LEFDE0-.LASFDE0
-+.LASFDE0:
-+ .long .Lframe0
-+ .long .LFB2
-+ .long .LFE2-.LFB2
-+ .byte 0x4
-+ .long .LCFI0-.LFB2
-+ .byte 0xe
-+ .uleb128 0x8
-+ .byte 0x85
-+ .uleb128 0x2
-+ .byte 0x4
-+ .long .LCFI1-.LCFI0
-+ .byte 0xd
-+ .uleb128 0x5
-+ .align 4
-+.LEFDE0:
-+ .text
-+.Letext0:
-+ .section .debug_loc,"",@progbits
-+.Ldebug_loc0:
-+.LLST0:
-+ .long .LFB2-.Ltext0
-+ .long .LCFI0-.Ltext0
-+ .value 0x2
-+ .byte 0x74
-+ .sleb128 4
-+ .long .LCFI0-.Ltext0
-+ .long .LCFI1-.Ltext0
-+ .value 0x2
-+ .byte 0x74
-+ .sleb128 8
-+ .long .LCFI1-.Ltext0
-+ .long .LFE2-.Ltext0
-+ .value 0x2
-+ .byte 0x75
-+ .sleb128 8
-+ .long 0x0
-+ .long 0x0
-+ .section .debug_info
-+ .long 0x94
-+ .value 0x2
-+ .long .Ldebug_abbrev0
-+ .byte 0x4
-+ .uleb128 0x1
-+ .long .LASF10
-+ .byte 0x1
-+ .long .LASF11
-+ .long .LASF12
-+ .long .Ltext0
-+ .long .Letext0
-+ .long .Ldebug_line0
-+ .uleb128 0x2
-+ .byte 0x4
-+ .byte 0x7
-+ .long .LASF0
-+ .uleb128 0x3
-+ .byte 0x4
-+ .byte 0x5
-+ .string "int"
-+ .uleb128 0x2
-+ .byte 0x4
-+ .byte 0x5
-+ .long .LASF1
-+ .uleb128 0x2
-+ .byte 0x1
-+ .byte 0x8
-+ .long .LASF2
-+ .uleb128 0x2
-+ .byte 0x2
-+ .byte 0x7
-+ .long .LASF3
-+ .uleb128 0x2
-+ .byte 0x4
-+ .byte 0x7
-+ .long .LASF4
-+ .uleb128 0x2
-+ .byte 0x1
-+ .byte 0x6
-+ .long .LASF5
-+ .uleb128 0x2
-+ .byte 0x2
-+ .byte 0x5
-+ .long .LASF6
-+ .uleb128 0x2
-+ .byte 0x8
-+ .byte 0x5
-+ .long .LASF7
-+ .uleb128 0x2
-+ .byte 0x8
-+ .byte 0x7
-+ .long .LASF8
-+ .uleb128 0x4
-+ .byte 0x4
-+ .byte 0x7
-+ .uleb128 0x2
-+ .byte 0x1
-+ .byte 0x6
-+ .long .LASF9
-+ .uleb128 0x5
-+ .byte 0x1
-+ .long .LASF13
-+ .byte 0x1
-+ .byte 0x5
-+ .byte 0x1
-+ .long .LFB2
-+ .long .LFE2
-+ .long .LLST0
-+ .uleb128 0x6
-+ .string "i"
-+ .byte 0x1
-+ .byte 0x6
-+ .long 0x2c
-+ .byte 0x2
-+ .byte 0x91
-+ .sleb128 -12
-+ .byte 0x0
-+ .byte 0x0
-+ .section .debug_abbrev
-+ .uleb128 0x1
-+ .uleb128 0x11
-+ .byte 0x1
-+ .uleb128 0x25
-+ .uleb128 0xe
-+ .uleb128 0x13
-+ .uleb128 0xb
-+ .uleb128 0x3
-+ .uleb128 0xe
-+ .uleb128 0x1b
-+ .uleb128 0xe
-+ .uleb128 0x11
-+ .uleb128 0x1
-+ .uleb128 0x12
-+ .uleb128 0x1
-+ .uleb128 0x10
-+ .uleb128 0x6
-+ .byte 0x0
-+ .byte 0x0
-+ .uleb128 0x2
-+ .uleb128 0x24
-+ .byte 0x0
-+ .uleb128 0xb
-+ .uleb128 0xb
-+ .uleb128 0x3e
-+ .uleb128 0xb
-+ .uleb128 0x3
-+ .uleb128 0xe
-+ .byte 0x0
-+ .byte 0x0
-+ .uleb128 0x3
-+ .uleb128 0x24
-+ .byte 0x0
-+ .uleb128 0xb
-+ .uleb128 0xb
-+ .uleb128 0x3e
-+ .uleb128 0xb
-+ .uleb128 0x3
-+ .uleb128 0x8
-+ .byte 0x0
-+ .byte 0x0
-+ .uleb128 0x4
-+ .uleb128 0x24
-+ .byte 0x0
-+ .uleb128 0xb
-+ .uleb128 0xb
-+ .uleb128 0x3e
-+ .uleb128 0xb
-+ .byte 0x0
-+ .byte 0x0
-+ .uleb128 0x5
-+ .uleb128 0x2e
-+ .byte 0x1
-+ .uleb128 0x3f
-+ .uleb128 0xc
-+ .uleb128 0x3
-+ .uleb128 0xe
-+ .uleb128 0x3a
-+ .uleb128 0xb
-+ .uleb128 0x3b
-+ .uleb128 0xb
-+ .uleb128 0x27
-+ .uleb128 0xc
-+ .uleb128 0x11
-+ .uleb128 0x1
-+ .uleb128 0x12
-+ .uleb128 0x1
-+ .uleb128 0x40
-+ .uleb128 0x6
-+ .byte 0x0
-+ .byte 0x0
-+ .uleb128 0x6
-+ .uleb128 0x34
-+ .byte 0x0
-+ .uleb128 0x3
-+ .uleb128 0x8
-+ .uleb128 0x3a
-+ .uleb128 0xb
-+ .uleb128 0x3b
-+ .uleb128 0xb
-+ .uleb128 0x49
-+ .uleb128 0x13
-+ .uleb128 0x2
-+ .uleb128 0xa
-+ .byte 0x0
-+ .byte 0x0
-+ .byte 0x0
-+ .section .debug_pubnames,"",@progbits
-+ .long 0x17
-+ .value 0x2
-+ .long .Ldebug_info0
-+ .long 0x98
-+ .long 0x75
-+ .string "func"
-+ .long 0x0
-+ .section .debug_aranges,"",@progbits
-+ .long 0x1c
-+ .value 0x2
-+ .long .Ldebug_info0
-+ .byte 0x4
-+ .byte 0x0
-+ .value 0x0
-+ .value 0x0
-+ .long .Ltext0
-+ .long .Letext0-.Ltext0
-+ .long 0x0
-+ .long 0x0
-+ .section .debug_str,"MS",@progbits,1
-+.LASF7:
-+ .string "long long int"
-+.LASF0:
-+ .string "unsigned int"
-+.LASF11:
-+ .string "dw2-loclist-prelinked.c"
-+.LASF12:
-+ .string "gdb-6.8/gdb/testsuite/gdb.dwarf2"
-+.LASF4:
-+ .string "long unsigned int"
-+.LASF8:
-+ .string "long long unsigned int"
-+.LASF2:
-+ .string "unsigned char"
-+.LASF9:
-+ .string "char"
-+.LASF1:
-+ .string "long int"
-+.LASF3:
-+ .string "short unsigned int"
-+.LASF5:
-+ .string "signed char"
-+.LASF10:
-+ .string "GNU C 4.3.2 20081007 (Red Hat 4.3.2-6)"
-+.LASF13:
-+ .string "func"
-+.LASF6:
-+ .string "short int"
-+ .ident "GCC: (GNU) 4.3.2 20081007 (Red Hat 4.3.2-6)"
-+ .section .note.GNU-stack,"",@progbits
-diff --git a/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c
-@@ -0,0 +1,26 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2008 Free Software Foundation, Inc.
-+
-+ 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 . */
-+
-+/* dw2-loclist-prelinked-func.S */
-+extern void func (void);
-+
-+int
-+main (void)
-+{
-+ func ();
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked.exp b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked.exp
-@@ -0,0 +1,102 @@
-+# Copyright 2008 Free Software Foundation, Inc.
-+
-+# 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 2 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, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+
-+# Minimal DWARF-2 unit test
-+
-+# This test can only be run on i386/x86_64 targets which support DWARF-2.
-+# For now pick a sampling of likely targets.
-+if {(![istarget *-*-linux*]
-+ && ![istarget *-*-gnu*]
-+ && ![istarget *-*-elf*]
-+ && ![istarget *-*-openbsd*])
-+ || (![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"])} {
-+ return 0
-+}
-+
-+set testfile "dw2-loclist-prelinked"
-+set srcfuncfile ${testfile}-func.S
-+set binsharedfuncfile [standard_output_file ${testfile}.so]
-+set srcmainfile ${testfile}-main.c
-+set binfile [standard_output_file ${testfile}]
-+
-+remote_exec build "rm -f ${binfile}"
-+
-+# get the value of gcc_compiled
-+if [get_compiler_info ${binfile}] {
-+ return -1
-+}
-+
-+# This test can only be run on gcc as we use additional_flags=FIXME
-+if {$gcc_compiled == 0} {
-+ return 0
-+}
-+
-+if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcfuncfile}" "${binsharedfuncfile}" {debug additional_flags=-m32}] != "" } {
-+ untested "Couldn't compile test library"
-+ return -1
-+}
-+
-+# The new separate debug info file will be stored in the .debug subdirectory.
-+
-+if [gdb_gnu_strip_debug ${binsharedfuncfile}] {
-+ # check that you have a recent version of strip and objcopy installed
-+ unsupported "cannot produce separate debug info files"
-+ return -1
-+}
-+
-+if {[catch "system \"/usr/sbin/prelink -qNR --no-exec-shield ${binsharedfuncfile}\""] != 0} {
-+ # Maybe we don't have prelink.
-+ return -1
-+}
-+
-+if { [gdb_compile "${srcdir}/${subdir}/${srcmainfile}" \
-+ "${binfile}" executable [list debug additional_flags=-m32 shlib=${binsharedfuncfile}]] != "" } {
-+ return -1
-+}
-+
-+gdb_exit
-+gdb_start
-+gdb_reinitialize_dir $srcdir/$subdir
-+gdb_load ${binfile}
-+
-+gdb_run_cmd
-+
-+gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()"
-+
-+# Incorrect:
-+# #0 0x00110430 in __kernel_vsyscall ()
-+# No symbol table info available.
-+# #1 0x003d44c0 in raise () from /lib/libc.so.6
-+# No symbol table info available.
-+# #2 0x003d5e88 in abort () from /lib/libc.so.6
-+# No symbol table info available.
-+# #3 0x44f10437 in func () at dw2-loclist-prelinked.c:8
-+# i = Could not find the frame base for "func".
-+
-+# Correct:
-+# #0 0x00110430 in __kernel_vsyscall ()
-+# No symbol table info available.
-+# #1 0x003d44c0 in raise () from /lib/libc.so.6
-+# No symbol table info available.
-+# #2 0x003d5e88 in abort () from /lib/libc.so.6
-+# No symbol table info available.
-+# #3 0x4ae36437 in func () at dw2-loclist-prelinked.c:8
-+# i = 3827288
-+# #4 0x0804851a in main () at ../../../gdb/testsuite/gdb.dwarf2/dw2-loclist-prelinked-main.c:24
-+# No locals.
-+
-+# `abort' can get expressed as `*__GI_abort'.
-+gdb_test "bt full" "in \[^ \]*abort \\(.*in func \\(.*\r\n\[\t \]+i = -?\[0-9\].*in main \\(.*" "Backtrace after abort()"
diff --git a/gdb-add-index.patch b/gdb-add-index.patch
index 52a3145..69175d7 100644
--- a/gdb-add-index.patch
+++ b/gdb-add-index.patch
@@ -19,7 +19,7 @@ Subject: gdb-add-index.patch
diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
--- a/gdb/contrib/gdb-add-index.sh
+++ b/gdb/contrib/gdb-add-index.sh
-@@ -16,14 +16,52 @@
+@@ -16,9 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
@@ -31,7 +31,9 @@ diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
OBJCOPY=${OBJCOPY:=objcopy}
READELF=${READELF:=readelf}
- myname="${0##*/}"
+@@ -52,6 +51,45 @@ print_version() {
+ echo "GNU gdb-add-index (${PKGVERSION}) ${VERSION}"
+ }
+# For GDB itself we need to be a little smarter. If GDB is set in the
+# environment then we will use that. But if GDB is not set in the
@@ -73,5 +75,5 @@ diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
+fi
+
dwarf5=""
- if [ "$1" = "-dwarf-5" ]; then
- dwarf5="$1"
+
+ # Parse options.
diff --git a/gdb-archer-next-over-throw-cxx-exec.patch b/gdb-archer-next-over-throw-cxx-exec.patch
deleted file mode 100644
index c5d58b3..0000000
--- a/gdb-archer-next-over-throw-cxx-exec.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-archer-next-over-throw-cxx-exec.patch
-
-;; Fix follow-exec for C++ programs (bugreported by Martin Stransky).
-;;=fedoratest
-
-Archer-upstreamed:
-http://sourceware.org/ml/archer/2010-q2/msg00031.html
-
-diff --git a/gdb/testsuite/gdb.cp/cxxexec.cc b/gdb/testsuite/gdb.cp/cxxexec.cc
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.cp/cxxexec.cc
-@@ -0,0 +1,25 @@
-+/* This test script is part of GDB, the GNU debugger.
-+
-+ Copyright 2010 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see . */
-+
-+#include
-+
-+int
-+main()
-+{
-+ execlp ("true", "true", NULL);
-+ return 1;
-+}
-diff --git a/gdb/testsuite/gdb.cp/cxxexec.exp b/gdb/testsuite/gdb.cp/cxxexec.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.cp/cxxexec.exp
-@@ -0,0 +1,42 @@
-+# Copyright 2010 Free Software Foundation, Inc.
-+
-+# 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 .
-+
-+require allow_cplus_tests
-+
-+set testfile cxxexec
-+if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.cc {c++ debug}] } {
-+ return -1
-+}
-+
-+runto_main
-+
-+# We could stop after `continue' again at `main'.
-+delete_breakpoints
-+
-+set test "p _Unwind_DebugHook"
-+gdb_test_multiple $test $test {
-+ -re " = .* 0x\[0-9a-f\].*\r\n$gdb_prompt $" {
-+ pass $test
-+ }
-+ -re "\r\nNo symbol .*\r\n$gdb_prompt $" {
-+ xfail $test
-+ untested ${testfile}.exp
-+ return -1
-+ }
-+}
-+
-+# Run to end. The buggy GDB failed instead with:
-+# Cannot access memory at address ADDR.
-+gdb_continue_to_end "" "continue" 1
diff --git a/gdb-backport-corefile-use-after-free-fix.patch b/gdb-backport-corefile-use-after-free-fix.patch
new file mode 100644
index 0000000..64aa23e
--- /dev/null
+++ b/gdb-backport-corefile-use-after-free-fix.patch
@@ -0,0 +1,77 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Lancelot SIX
+Date: Mon, 13 Oct 2025 15:11:09 +0100
+Subject: gdb-backport-corefile-use-after-free-fix.patch
+
+;; Backport of upstream commit 93f536d813c41527e8c939a5f8a90a4 to fix
+;; RHBZ2498034.
+
+gdb/corelow: Fix use-after-free in gdb_read_core_file_mappings
+
+A recent refactor (fc8e5a565b3 -- gdb: make structured core file
+mappings processing global) in gdb/corelow.c:gdb_read_core_file_mappings
+introduced a use-after-free bug detected by address sanitizer.
+
+In this change, a cache is built which holds addresses to elements of a
+std::vector. However, as elements as inserted in the vector, the
+addresses in the cache should be invalidated, but are not, leading to
+the use-after-free issue.
+
+This patch proposes to store the index in the vector in the cache
+instead of the address of the element, solving the invalidation issue.
+An alternative approach could be to use a std::list which does not need
+invalidation of addresses/references/iterators as the container is
+grown.
+
+Change-Id: Ib57d87c5d0405ffa3b7d38557fb33f7283c5d063
+Approved-By: Andrew Burgess
+
+diff --git a/gdb/corelow.c b/gdb/corelow.c
+--- a/gdb/corelow.c
++++ b/gdb/corelow.c
+@@ -2090,19 +2090,20 @@ gdb_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd)
+ /* A map entry used while building RESULTS. */
+ struct map_entry
+ {
+- explicit map_entry (core_mapped_file *ptr)
+- : file_data (ptr)
++ explicit map_entry (size_t idx)
++ : file_data_index (idx),
++ ignore_build_id_p (false)
+ { /* Nothing. */ }
+
+ /* Points to an entry in RESULTS, this allows entries to be quickly
+ looked up and updated as new mappings are read. */
+- core_mapped_file *file_data = nullptr;
++ size_t file_data_index;
+
+ /* If true then we have seen multiple different build-ids associated
+ with the filename of FILE_DATA. The FILE_DATA->build_id field will
+ have been set to nullptr, and we should not set FILE_DATA->build_id
+ in future. */
+- bool ignore_build_id_p = false;
++ bool ignore_build_id_p;
+ };
+
+ /* All files mapped into the core file. The key is the filename. */
+@@ -2141,8 +2142,9 @@ gdb_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd)
+ results.emplace_back ();
+
+ /* The entry to be added to the lookup map. */
+- map_entry entry (&results.back ());
+- entry.file_data->filename = filename;
++ map_entry entry (std::distance (&results.front (),
++ &results.back ()));
++ results[entry.file_data_index].filename = filename;
+
+ /* Add entry to the quick lookup map and update ITER. */
+ auto inserted_result
+@@ -2151,7 +2153,7 @@ gdb_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd)
+ iter = inserted_result.first;
+ }
+
+- core_mapped_file &file_data = *iter->second.file_data;
++ core_mapped_file &file_data = results[iter->second.file_data_index];
+ bool &ignore_build_id_p = iter->second.ignore_build_id_p;
+
+ file_data.regions.emplace_back (start, end, file_ofs);
diff --git a/gdb-backport-dap-core-file-support.patch b/gdb-backport-dap-core-file-support.patch
new file mode 100644
index 0000000..deb0ea7
--- /dev/null
+++ b/gdb-backport-dap-core-file-support.patch
@@ -0,0 +1,2956 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Michal Kolar
+Date: Wed, 24 Jun 2026 21:25:33 +0000
+Subject: gdb-backport-dap-core-file-support.patch
+
+;; Backport of upstream commit e492fb22b70
+;; gdb: backport DAP core file support
+
+Back-port the following upstream commits to enable core file support
+within GDB's DAP protocol implementation:
+
+ * 0a481bb9a6d gdb/dap: add support for opening core files
+ * 4ecaac39c26 gdb/python: new events.corefile_changed event
+ * ecac42af735 Always propagate exceptions in DAP
+ * fc8e5a565b3 gdb: make structured core file mappings processing global
+ * f69c1d03c4d gdb/python: add Corefile.mapped_files method
+ * 7862554bcf4 gdb/python: introduce gdb.Corefile API
+
+The commit messages for each individual commit follow:
+
+~~~ 0a481bb9a6d:
+
+gdb/dap: add support for opening core files
+
+This patch adds core file support to GDB's DAP interface.
+
+Core files are supported as a GDB specific argument to 'attach', the
+new argument is 'coreFile', the name of the core file to debug.
+
+I think handling core files via attach makes the most sense; attach is
+for connecting to existing processes, but these targets are (usually)
+stopped as soon as GDB attaches, and that's what a core file looks
+like, a target that was running, but is now stopped. It just happens
+that core file targets are special in that the target cannot be
+resumed again, nor can the user modify the program state (e.g. write
+to memory or registers).
+
+Prior to starting this work I took a look at what lldb does. The
+documentation is not super clear, but this page seems to indicate that
+lldb might also use the 'coreFile' argument to 'attach':
+
+ https://lldb.llvm.org/use/lldbdap.html#configuration-settings-reference
+
+Like I said, it's not very clear, but search for "coreFile" and you'll
+see it mentioned, just once, under the "attach" header. In order to
+be compatible with lldb I used the same argument name with the same
+capitalisation.
+
+The new argument is added to the documentation and mentioned in NEWS.
+
+I had to make some changes to testsuite/lib/dap-support.exp to support
+this new feature. There's a new dap_corefile proc to handle setting
+up the initial connection. This seemed cleaner that overloading
+dap_attach, even though under the hood it is still an 'attach' request
+that gets sent.
+
+The new test tries to write to memory and registers with the core file
+target in place, neither of these requests succeed, which is what we
+want, but the exceptions are logged into the dap log file. The
+dap_shutdown proc calls dap_check_log_file to check the log for
+exceptions, and these two exceptions are spotted and trigger a FAIL.
+To avoid this I've added a new "expected_exception_count" argument
+for dap_shutdown. Now we check that we see the expected number of
+exceptions. We don't check for the specific exception types right
+now, but as the test is already checking that the expected requests
+fail, I think we're OK.
+
+Approved-By: Tom Tromey
+
+~~~ 4ecaac39c26:
+
+gdb/python: new events.corefile_changed event
+
+Add a new Python event registry, events.corefile_changed. This event
+is emitted each time the corefile within an inferior changes.
+
+The event object has a single 'inferior' attribute which is the
+gdb.Inferior object for which the core file changed. The user can
+then inspect Inferior.corefile to see details about the new core file,
+or this will be None if the core file was removed from the inferior.
+
+I've updated the existing test to cover this new event.
+
+The new test covers both the corefile_changed event, but also monitors
+the exited event. This ties into the work done in the previous
+commit where we use whether the inferior has exited or not as a guard
+for whether core_target::exit_core_file_inferior should be called.
+Unloading a core file should result in a single corefile_changed event
+and a single exited event.
+
+Reviewed-By: Eli Zaretskii
+
+~~~ ecac42af735:
+
+Always propagate exceptions in DAP
+
+This changes the DAP exec_and_log function to always transform an
+exception into a DAPException and propagate it.
+
+As the bug points out, we haven't always wrapped calls when
+appropriate. I think it's better to cause the request to fail by
+default; if any spot truly needs to ignore errors, that is readily
+done at the point of call.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33346
+
+~~~ fc8e5a565b3:
+
+gdb: make structured core file mappings processing global
+
+In corelow.c, within core_target::build_file_mappings, we have code
+that wraps around a call to gdbarch_read_core_file_mappings and
+provides more structure to the results.
+
+Specifically, gdbarch_read_core_file_mappings calls a callback once
+for every region of every mapped file. The wrapper code groups all of
+the mappings for one file into an instance of 'struct mapped_file',
+this allows all of the mapped regions to be associated with the
+build-id and filename of a file.
+
+In the next commit I plan to make this information available via the
+Python API, and so I need to allow access to this structured wrapping
+outside of corelow.c.
+
+This commit renames 'struct mapped_file' to 'struct core_mapped_file'
+and moves the struct into gdbcore.h. Then a new global function
+gdb_read_core_file_mappings is created into which I move the code to
+build the structured data.
+
+Then corelow.c is updated to call gdb_read_core_file_mappings.
+
+This commit does not extend the Python API, that is for the next
+commit.
+
+There should be no user visible changes after this commit.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32844
+
+Approved-By: Tom Tromey
+
+~~~ f69c1d03c4d:
+
+gdb/python: add Corefile.mapped_files method
+
+Add a new Corefile.mapped_files method which returns a list of
+gdb.CorefileMappedFile objects.
+
+Each gdb.CorefileMappedFile object represents a file that was mapped
+into the process when the core file was created.
+
+A gdb.CorefileMappedFile has attributes:
+
+ + filename -- A string, the name of the mapped file.
+ + build_id -- A string or None, the build-id of the mapped file if
+ GDB could find it (None if not).
+ + is_main_executable -- A boolean, True if this mapping is the main
+ executable.
+ + regions -- A list containing the regions of this file that were
+ mapped into the process.
+
+The 'regions' list is a list of gdb.CorefileMappedFileRegion objects,
+each of these objects has the following attributes:
+
+ + start -- the start address within the inferior.
+ + end -- the end address within the inferior.
+ + file_offset -- the offset within the mapped file for this mapping.
+
+There are docs and tests.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32844
+
+Approved-By: Tom Tromey
+
+~~~ 7862554bcf4:
+
+gdb/python: introduce gdb.Corefile API
+
+This commit starts adding some core file related features to the
+Python API.
+
+In this initial commit I've tried to keep the changes as small as
+possible for easy review.
+
+There's a new Python class gdb.Corefile, which represents a loaded
+core file. This API doesn't allow the user to create their own
+gdb.Corefile objects, a core file must be loaded using the 'core-file'
+command, then a gdb.Corefile object can be obtained by querying the
+inferior in which the core file was loaded.
+
+There's a new attribute gdb.Inferior.corefile, this is None when no
+core file is loaded, or contains a gdb.Corefile object if a core file
+has been loaded.
+
+Currently, the gdb.Corefile object has one attribute, and one method,
+these are:
+
+ gdb.Corefile.filename -- the file name of the loaded core file.
+
+ gdb.Corefile.is_valid() -- indicates if a gdb.Corefile object is
+ valid or not. See notes below.
+
+A gdb.Corefile object is only valid while the corresponding core file
+is loaded into an inferior. Unloading the core file, or loading a
+different one will cause a gdb.Corefile object to become invalid. For
+example:
+
+ (gdb) core-file /tmp/core.54313
+ ... snip ...
+ (gdb) python core=gdb.selected_inferior().corefile
+ (gdb) python print(core)
+
+ (gdb) python print(core.is_valid())
+ True
+ (gdb) core-file
+ No core file now.
+ (gdb) python print(core)
+
+ (gdb) python print(core.is_valid())
+ False
+ (gdb)
+
+In order to track changes to the core file, there is a new observable
+'core_file_changed', which accounts for the changes in corelow.c,
+observable,c, and observable.h. Currently, this observable is not
+visible as a Python event.
+
+I chose to access the core file via the inferior even though the core
+file BFD object is actually stored within the program_space. As such,
+it might seem that the natural choice would be to add the attribute as
+gdb.Progspace.corefile.
+
+For background reading on my choice, please see:
+
+ https://inbox.sourceware.org/gdb-patches/577f2c47793acb501c2611c0e6c7ea379f774830.1668789658.git.aburgess@redhat.com
+
+This patch was never merged, it is still on my backlog, but the
+observation in that work is that some targets are not really
+shareable. For example, the core_target (corelow.c) stores
+information about the loaded core file within the target instance. As
+such, each target instance represents a single loaded core file.
+
+Except that the BFD part of the core file is stored in the
+program_space, which is a little weird.
+
+During review, Tom made the observation, that maybe we should
+investigate moving the core file BFD into the core_target. I'm
+inclined to agree with this as a direction of travel.
+
+All this leaves us with two observations:
+
+ 1. Currently, loading a core file into an inferior, then using
+ 'add-inferior' will try to share the core_target between
+ inferiors. This is broken, and can trigger GDB crashes. The
+ obvious fix, without reworking core_target, is just to prevent
+ this sharing, making core_target per-inferior.
+
+ 2. Having the core file information split between the core_target
+ instance, and the BFD stored in the program_space is a little
+ weird, and is really just historical. Planning for a future
+ where the BFD is also stored in the core_target might be wise.
+
+So, if we imagine that the BFD is (one day) moved into the
+core_target, and that the core_target really becomes non-shareable,
+then it is, I think, clearer that the corefile attribute should live
+on the gdb.Inferior object, not the gdb.Progspace object.
+
+There's testing for all the functionality added in this commit.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32844
+
+Reviewed-By: Eli Zaretskii
+Approved-By: Tom Tromey
+
+diff --git a/gdb/Makefile.in b/gdb/Makefile.in
+--- a/gdb/Makefile.in
++++ b/gdb/Makefile.in
+@@ -399,6 +399,7 @@ SUBDIR_PYTHON_SRCS = \
+ python/py-color.c \
+ python/py-connection.c \
+ python/py-continueevent.c \
++ python/py-corefile.c \
+ python/py-dap.c \
+ python/py-disasm.c \
+ python/py-event.c \
+diff --git a/gdb/NEWS b/gdb/NEWS
+--- a/gdb/NEWS
++++ b/gdb/NEWS
+@@ -13,6 +13,8 @@
+
+ ** GDB now supports the "completions" request.
+
++ ** The attach request now accepts the coreFile parameter.
++
+ * "set style" commands now supports numeric format for basic colors
+ from 0 to 255 and #RRGGBB format for TrueColor.
+
+@@ -176,6 +178,32 @@ info threads [-gid] [-stopped] [-running] [ID]...
+ unavailability like gdb.Value.is_optimized_out checks for
+ optimized out values.
+
++ ** New gdb.Corefile class which represents a loaded core file. This
++ has an attribute Corefile.filename, the file name of the loaded
++ core file, and a method Corefile.is_valid(), which returns False
++ when a Corefile object becomes invalid (e.g. when the core file
++ is unloaded). There is also Corefile.mapped_files() which
++ returns a list of CorefileMappedFile objects, representing files
++ that were mapped into the core file when it was created.
++
++ ** New gdb.CorefileMappedFile type representing a file that was
++ mapped when the core file was created. Has read-only attributes
++ filename (string), build_id (string), is_main_executable
++ (boolean), and regions (list of CorefileMappedFileRegion objects).
++
++ ** New gdb.CorefileMappedFileRegion type, which represents a mapped
++ region of a file (see gdb.CorefileMappedFile above). Has
++ read-only attributes start, end, and file_offset.
++
++ ** New Inferior.corefile attribute. This read only attribute
++ contains the gdb.Corefile object if a core file is loaded into
++ the inferior, otherwise, this contains None.
++
++ ** New event registry gdb.events.corefile_changed, which emits a
++ CorefileChangedEvent whenever the core file associated with an
++ inferior changes. The event has an 'inferior' attribute which is
++ the gdb.Inferior in which the core file has changed.
++
+ * Guile API
+
+ ** New type for dealing with colors.
+diff --git a/gdb/corelow.c b/gdb/corelow.c
+--- a/gdb/corelow.c
++++ b/gdb/corelow.c
+@@ -53,6 +53,7 @@
+ #include "xml-tdesc.h"
+ #include "memtag.h"
+ #include "cli/cli-style.h"
++#include "observable.h"
+
+ #ifndef O_LARGEFILE
+ #define O_LARGEFILE 0
+@@ -365,108 +366,27 @@ core_target::core_target ()
+ void
+ core_target::build_file_mappings ()
+ {
+- /* Type holding information about a single file mapped into the inferior
+- at the point when the core file was created. Associates a build-id
+- with the list of regions the file is mapped into. */
+- struct mapped_file
+- {
+- /* Type for a region of a file that was mapped into the inferior when
+- the core file was generated. */
+- struct region
+- {
+- /* Constructor. See member variables for argument descriptions. */
+- region (CORE_ADDR start_, CORE_ADDR end_, CORE_ADDR file_ofs_)
+- : start (start_),
+- end (end_),
+- file_ofs (file_ofs_)
+- { /* Nothing. */ }
+-
+- /* The inferior address for the start of the mapped region. */
+- CORE_ADDR start;
+-
+- /* The inferior address immediately after the mapped region. */
+- CORE_ADDR end;
+-
+- /* The offset within the mapped file for this content. */
+- CORE_ADDR file_ofs;
+- };
+-
+- /* If not nullptr, then this is the build-id associated with this
+- file. */
+- const bfd_build_id *build_id = nullptr;
+-
+- /* If true then we have seen multiple different build-ids associated
+- with the same filename. The build_id field will have been set back
+- to nullptr, and we should not set build_id in future. */
+- bool ignore_build_id_p = false;
+-
+- /* All the mapped regions of this file. */
+- std::vector regions;
+- };
+-
+ gdb::unordered_map bfd_map;
+ gdb::unordered_set unavailable_paths;
+
+ /* All files mapped into the core file. The key is the filename. */
+- gdb::unordered_map mapped_files;
+-
+- /* See linux_read_core_file_mappings() in linux-tdep.c for an example
+- read_core_file_mappings method. */
+- gdbarch_read_core_file_mappings (m_core_gdbarch,
+- current_program_space->core_bfd (),
+-
+- /* After determining the number of mappings, read_core_file_mappings
+- will invoke this lambda. */
+- [&] (ULONGEST)
+- {
+- },
+-
+- /* read_core_file_mappings will invoke this lambda for each mapping
+- that it finds. */
+- [&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
+- const char *filename, const bfd_build_id *build_id)
+- {
+- /* Architecture-specific read_core_mapping methods are expected to
+- weed out non-file-backed mappings. */
+- gdb_assert (filename != nullptr);
++ std::vector mapped_files
++ = gdb_read_core_file_mappings (m_core_gdbarch,
++ current_program_space->core_bfd ());
+
+- /* Add this mapped region to the data for FILENAME. */
+- mapped_file &file_data = mapped_files[filename];
+- file_data.regions.emplace_back (start, end, file_ofs);
+- if (build_id != nullptr && !file_data.ignore_build_id_p)
+- {
+- if (file_data.build_id == nullptr)
+- file_data.build_id = build_id;
+- else if (!build_id_equal (build_id, file_data.build_id))
+- {
+- warning (_("Multiple build-ids found for %ps"),
+- styled_string (file_name_style.style (), filename));
+- file_data.build_id = nullptr;
+- file_data.ignore_build_id_p = true;
+- }
+- }
+- });
+-
+- /* Get the build-id of the core file. */
+- const bfd_build_id *core_build_id
+- = build_id_bfd_get (current_program_space->core_bfd ());
+-
+- for (const auto &[filename, file_data] : mapped_files)
++ for (const core_mapped_file &file_data : mapped_files)
+ {
+- /* If this mapped file has the same build-id as was discovered for
+- the core-file itself, then we assume this is the main
+- executable. Record the filename as we can use this later. */
+- if (file_data.build_id != nullptr
+- && m_expected_exec_filename.empty ()
+- && build_id_equal (file_data.build_id, core_build_id))
+- m_expected_exec_filename = filename;
++ /* If this mapped file is marked as the main executable then record
++ the filename as we can use this later. */
++ if (file_data.is_main_exec && m_expected_exec_filename.empty ())
++ m_expected_exec_filename = file_data.filename;
+
+ /* Use exec_file_find() to do sysroot expansion. It'll
+ also strip the potential sysroot "target:" prefix. If
+ there is no sysroot, an equivalent (possibly more
+ canonical) pathname will be provided. */
+ gdb::unique_xmalloc_ptr expanded_fname
+- = exec_file_find (filename.c_str (), nullptr);
++ = exec_file_find (file_data.filename.c_str (), nullptr);
+
+ bool build_id_mismatch = false;
+ if (expanded_fname != nullptr && file_data.build_id != nullptr)
+@@ -508,7 +428,7 @@ core_target::build_file_mappings ()
+ {
+ abfd = find_objfile_by_build_id (current_program_space,
+ file_data.build_id,
+- filename.c_str ());
++ file_data.filename.c_str ());
+
+ if (abfd != nullptr)
+ {
+@@ -526,7 +446,7 @@ core_target::build_file_mappings ()
+ }
+
+ std::vector ranges;
+- for (const mapped_file::region ®ion : file_data.regions)
++ for (const core_mapped_file::region ®ion : file_data.regions)
+ ranges.emplace_back (region.start, region.end - region.start);
+
+ if (expanded_fname == nullptr
+@@ -544,7 +464,7 @@ core_target::build_file_mappings ()
+ bool content_is_in_core_file_p = true;
+
+ /* Record all regions for this file as unavailable. */
+- for (const mapped_file::region ®ion : file_data.regions)
++ for (const core_mapped_file::region ®ion : file_data.regions)
+ {
+ /* Check to see if the region is available within the core
+ file. */
+@@ -576,33 +496,33 @@ core_target::build_file_mappings ()
+ if (build_id_mismatch)
+ {
+ if (expanded_fname == nullptr
+- || filename == expanded_fname.get ())
++ || file_data.filename == expanded_fname.get ())
+ warning (_("File %ps doesn't match build-id from core-file "
+ "during file-backed mapping processing"),
+ styled_string (file_name_style.style (),
+- filename.c_str ()));
++ file_data.filename.c_str ()));
+ else
+ warning (_("File %ps which was expanded to %ps, doesn't match "
+ "build-id from core-file during file-backed "
+ "mapping processing"),
+ styled_string (file_name_style.style (),
+- filename.c_str ()),
++ file_data.filename.c_str ()),
+ styled_string (file_name_style.style (),
+ expanded_fname.get ()));
+ }
+ else if (!content_is_in_core_file_p)
+ {
+ if (expanded_fname == nullptr
+- || filename == expanded_fname.get ())
++ || file_data.filename == expanded_fname.get ())
+ warning (_("Can't open file %ps during file-backed mapping "
+ "note processing"),
+ styled_string (file_name_style.style (),
+- filename.c_str ()));
++ file_data.filename.c_str ()));
+ else
+ warning (_("Can't open file %ps which was expanded to %ps "
+ "during file-backed mapping note processing"),
+ styled_string (file_name_style.style (),
+- filename.c_str ()),
++ file_data.filename.c_str ()),
+ styled_string (file_name_style.style (),
+ expanded_fname.get ()));
+ }
+@@ -616,7 +536,7 @@ core_target::build_file_mappings ()
+ abfd.get ());
+
+ /* Create sections for each mapped region. */
+- for (const mapped_file::region ®ion : file_data.regions)
++ for (const core_mapped_file::region ®ion : file_data.regions)
+ {
+ /* Make new BFD section. All sections have the same name,
+ which is permitted by bfd_make_section_anyway(). */
+@@ -652,7 +572,7 @@ core_target::build_file_mappings ()
+ soname = gdb_bfd_read_elf_soname (actual_filename);
+ }
+
+- m_mapped_file_info.add (soname.get (), filename.c_str (),
++ m_mapped_file_info.add (soname.get (), file_data.filename.c_str (),
+ actual_filename, std::move (ranges),
+ file_data.build_id);
+ }
+@@ -678,6 +598,9 @@ core_target::clear_core ()
+ clear_solib (current_program_space);
+
+ current_program_space->cbfd.reset (nullptr);
++
++ /* Notify that the core file has changed. */
++ gdb::observers::core_file_changed.notify (current_inferior ());
+ }
+ }
+
+@@ -1278,6 +1201,9 @@ core_target_open (const char *arg, int from_tty)
+ exception_print (gdb_stderr, except);
+ }
+ }
++
++ /* Notify that the core file has changed. */
++ gdb::observers::core_file_changed.notify (current_inferior ());
+ }
+
+ void
+@@ -2156,6 +2082,103 @@ mapped_file_info::lookup (const char *filename,
+
+ /* See gdbcore.h. */
+
++std::vector
++gdb_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd)
++{
++ std::vector results;
++
++ /* A map entry used while building RESULTS. */
++ struct map_entry
++ {
++ explicit map_entry (core_mapped_file *ptr)
++ : file_data (ptr)
++ { /* Nothing. */ }
++
++ /* Points to an entry in RESULTS, this allows entries to be quickly
++ looked up and updated as new mappings are read. */
++ core_mapped_file *file_data = nullptr;
++
++ /* If true then we have seen multiple different build-ids associated
++ with the filename of FILE_DATA. The FILE_DATA->build_id field will
++ have been set to nullptr, and we should not set FILE_DATA->build_id
++ in future. */
++ bool ignore_build_id_p = false;
++ };
++
++ /* All files mapped into the core file. The key is the filename. */
++ gdb::unordered_map mapped_files;
++
++ /* Get the build-id of the core file. At least on Linux, this will be
++ the build-id for the main executable. If other targets add the
++ gdbarch_read_core_file_mappings method, then it might turn out that
++ this logic is no longer true, in which case this might need to move
++ into the gdbarch_read_core_file_mappings method. */
++ const bfd_build_id *core_build_id = build_id_bfd_get (cbfd);
++
++ /* See linux_read_core_file_mappings() in linux-tdep.c for an example
++ read_core_file_mappings method. */
++ gdbarch_read_core_file_mappings (gdbarch, cbfd,
++ /* After determining the number of mappings, read_core_file_mappings
++ will invoke this lambda. */
++ [&] (ULONGEST)
++ {
++ },
++
++ /* read_core_file_mappings will invoke this lambda for each mapping
++ that it finds. */
++ [&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
++ const char *filename, const bfd_build_id *build_id)
++ {
++ /* Architecture-specific read_core_mapping methods are expected to
++ weed out non-file-backed mappings. */
++ gdb_assert (filename != nullptr);
++
++ /* Add this mapped region to the data for FILENAME. */
++ auto iter = mapped_files.find (filename);
++ if (iter == mapped_files.end ())
++ {
++ /* Create entry in results list. */
++ results.emplace_back ();
++
++ /* The entry to be added to the lookup map. */
++ map_entry entry (&results.back ());
++ entry.file_data->filename = filename;
++
++ /* Add entry to the quick lookup map and update ITER. */
++ auto inserted_result
++ = mapped_files.insert ({filename, std::move (entry)});
++ gdb_assert (inserted_result.second);
++ iter = inserted_result.first;
++ }
++
++ core_mapped_file &file_data = *iter->second.file_data;
++ bool &ignore_build_id_p = iter->second.ignore_build_id_p;
++
++ file_data.regions.emplace_back (start, end, file_ofs);
++ if (build_id != nullptr && !ignore_build_id_p)
++ {
++ if (file_data.build_id == nullptr)
++ file_data.build_id = build_id;
++ else if (!build_id_equal (build_id, file_data.build_id))
++ {
++ warning (_("Multiple build-ids found for %ps"),
++ styled_string (file_name_style.style (), filename));
++ file_data.build_id = nullptr;
++ ignore_build_id_p = true;
++ }
++ }
++
++ if (build_id != nullptr
++ && core_build_id != nullptr
++ && build_id_equal (build_id, core_build_id))
++ file_data.is_main_exec = true;
++ });
++
++ return results;
++}
++
++/* See gdbcore.h. */
++
+ std::optional
+ core_target_find_mapped_file (const char *filename,
+ std::optional addr)
+diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
+--- a/gdb/doc/gdb.texinfo
++++ b/gdb/doc/gdb.texinfo
+@@ -40029,10 +40029,10 @@ will set a temporary breakpoint at the program's first instruction, using
+ the same approach as the @code{starti} command. @xref{Starting}.
+ @end table
+
+-@value{GDBN} defines some parameters that can be passed to the
+-@code{attach} request. Either @code{pid} or @code{target} must be
+-specified, but if both are specified then @code{target} will be
+-ignored.
++@value{GDBN} defines some additional parameters that can be passed to
++the @code{attach} request. One of @code{pid}, @code{target}, or
++@code{coreFile} must be specified. If multiple are specified, they
++are checked for in that order, and the first one found is used.
+
+ @table @code
+ @item pid
+@@ -40048,6 +40048,10 @@ should be supplied.
+ @item target
+ The target to which @value{GDBN} should connect. This is a string and
+ is passed to the @code{target remote} command. @xref{Connecting}.
++
++@item coreFile
++A string that specifies a core file to use. This corresponds to the
++@kbd{core-file} command. @xref{core-file command}.
+ @end table
+
+ In response to the @code{disassemble} request, DAP allows the client
+diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
+--- a/gdb/doc/python.texi
++++ b/gdb/doc/python.texi
+@@ -233,6 +233,7 @@ optional arguments while skipping others. Example:
+ * Disassembly In Python:: Instruction Disassembly In Python
+ * Missing Debug Info In Python:: Handle missing debug info from Python.
+ * Missing Objfiles In Python:: Handle objfiles from Python.
++* Core Files In Python:: Python representation of core files.
+ @end menu
+
+ @node Basic Python
+@@ -3626,6 +3627,15 @@ necessary quoting for the shell; when a sequence is assigned, the
+ quoting is applied by @value{GDBN}.
+ @end defvar
+
++@defvar Inferior.corefile
++If a core file has been loaded into this inferior (@pxref{core-file
++command}), then this contains a @code{gdb.Corefile} object that
++represents the loaded core file (@pxref{Core Files In Python}).
++
++If no core file has been loaded into this inferior, then this
++attribute contains @code{None}.
++@end defvar
++
+ A @code{gdb.Inferior} object has the following methods:
+
+ @defun Inferior.is_valid ()
+@@ -4094,6 +4104,17 @@ file is updated first, so when this event is emitted, the executable
+ filename will have changed, but the symbol filename might still hold
+ its previous value.
+
++@item events.corefile_changed
++Emits @code{gdb.CorefileChangedEvent} which indicates that the core
++file associated with a @code{gdb.Inferior} has changed, either a new
++core file has been loaded, or the existing core file has been
++unloaded (@pxref{Core Files In Python}).
++
++@defvar CorefileChangedEvent.inferior
++The @code{gdb.Inferior} in which the core file has changed
++(@pxref{Inferiors In Python}).
++@end defvar
++
+ @item events.new_progspace
+ This is emitted when @value{GDBN} adds a new program space
+ (@pxref{Progspaces In Python,,Program Spaces In Python}). The event
+@@ -8624,6 +8645,106 @@ handlers, all of the matching handlers are enabled. The
+ @code{enabled} field of each matching handler is set to @code{True}.
+ @end table
+
++@node Core Files In Python
++@subsubsection Core Files In Python
++@cindex python, core files
++
++When a core file is loaded into an inferior (@pxref{Inferiors In
++Python}) for examination (@pxref{core-file command}), information
++about the core file is contained in a @code{gdb.Corefile} object.
++
++The @code{gdb.Corefile} for an inferior can be accessed using the
++@code{Inferior.corefile} attribute. This will be @code{None} if
++no core file is loaded.
++
++A @code{gdb.Corefile} object has the following attributes:
++
++@defvar Corefile.filename
++This read only attribute contains a non-empty string, the file name of
++the core file. Attempting to access this attribute on an invalid
++@code{gdb.Corefile} object will raise a @code{RuntimeError} exception.
++@end defvar
++
++A @code{gdb.Corefile} object has the following methods:
++
++@defun Corefile.is_valid ()
++Returns @code{True} if the @code{gdb.Corefile} object is valid,
++@code{False} if not. A @code{gdb.Corefile} object will become invalid
++when the core file is unloaded from the inferior using the
++@kbd{core-file} command (@pxref{core-file command}), or if the
++inferior in which the core file is loaded is deleted. All other
++@code{gdb.Corefile} methods and attributes will throw an exception if
++it is invalid at the time the method is called, or the attribute
++accessed.
++@end defun
++
++@defun Corefile.mapped_files ()
++Return a list of @code{gdb.CorefileMappedFile} (see below) objects
++representing files that were mapped into the process when the core
++file was created. This information is read from the @samp{NT_FILE}
++core file note on Linux. Not every target supports accessing this
++information, for targets without support, an empty list will be
++returned.
++@end defun
++
++One may add arbitrary attributes to @code{gdb.Corefile} objects in the
++usual Python way. This is useful if, for example, one needs to do
++some extra record keeping associated with the corefile.
++@xref{choosing attribute names}, for guidance on selecting a suitable
++name for new attributes.
++
++The @code{Corefile.mapped_files ()} method returns a list of
++@code{gdb.CorefileMappedFile} objects. Each of these objects
++represents a file that was fully, or partially, mapped into the
++processes address space when the core file was created.
++
++A @code{gdb.CorefileMappedFile} object has the following attributes:
++
++@defvar CorefileMappedFile.filename
++This read only attribute contains a non-empty string, the file name of
++the mapped file.
++@end defvar
++
++@defvar CorefileMappedFile.build_id
++This read only attribute contains a non-empty string or @code{None}.
++This is the build-id of the mapped file extracted from the core file,
++or @code{None} if there was no build-id, or @value{GDBN} was unable to
++extract the build-id.
++@end defvar
++
++@defvar CorefileMappedFile.is_main_executable
++This read only attribute is @code{True} if @value{GDBN} believes this
++mapping represents the main executable for which this core file was
++created. This will be @code{False} for all other mappings.
++@end defvar
++
++@defvar CorefileMappedFile.regions
++This read only attribute contains a list of
++@code{gdb.CorefileMappedFileRegion} objects. Each of these objects
++describes a region of the file that was mapped into the process when
++the core file was created, further details are given below.
++@end defvar
++
++The @code{gdb.CorefileMappedFileRegion} object describes which part of
++a file that was mapped into a process when the core file was created.
++
++A @code{gdb.CorefileMappedFile} object has the following attributes:
++
++@defvar CorefileMappedFileRegion.start
++This read only attribute contains the start address of this mapping
++within the inferior.
++@end defvar
++
++@defvar CorefileMappedFileRegion.end
++This read only attribute contains end address of this mapping within
++the inferior.
++@end defvar
++
++@defvar CorefileMappedFileRegion.file_offset
++This read only attribute contains the offset within the mapped file
++for this mapping.
++@end defvar
++
+ @node Python Auto-loading
+ @subsection Python Auto-loading
+ @cindex Python auto-loading
+diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
+--- a/gdb/gdbcore.h
++++ b/gdb/gdbcore.h
+@@ -258,4 +258,47 @@ std::optional
+ core_target_find_mapped_file (const char *filename,
+ std::optional addr);
+
++/* Type holding information about a single file mapped into the inferior
++ at the point when the core file was created. Associates a build-id
++ with the list of regions the file is mapped into. */
++struct core_mapped_file
++{
++ /* Type for a region of a file that was mapped into the inferior when
++ the core file was generated. */
++ struct region
++ {
++ /* Constructor. See member variables for argument descriptions. */
++ region (CORE_ADDR start_, CORE_ADDR end_, CORE_ADDR file_ofs_)
++ : start (start_),
++ end (end_),
++ file_ofs (file_ofs_)
++ { /* Nothing. */ }
++
++ /* The inferior address for the start of the mapped region. */
++ CORE_ADDR start;
++
++ /* The inferior address immediately after the mapped region. */
++ CORE_ADDR end;
++
++ /* The offset within the mapped file for this content. */
++ CORE_ADDR file_ofs;
++ };
++
++ /* The filename as recorded in the core file. */
++ std::string filename;
++
++ /* If not nullptr, then this is the build-id associated with this
++ file. */
++ const bfd_build_id *build_id = nullptr;
++
++ /* All the mapped regions of this file. */
++ std::vector regions;
++
++ /* True if this is the main executable. */
++ bool is_main_exec = false;
++};
++
++extern std::vector gdb_read_core_file_mappings
++ (struct gdbarch *gdbarch, struct bfd *cbfd);
++
+ #endif /* GDB_GDBCORE_H */
+diff --git a/gdb/observable.c b/gdb/observable.c
+--- a/gdb/observable.c
++++ b/gdb/observable.c
+@@ -76,6 +76,7 @@ DEFINE_OBSERVABLE (target_post_wait);
+ DEFINE_OBSERVABLE (new_program_space);
+ DEFINE_OBSERVABLE (free_program_space);
+ DEFINE_OBSERVABLE (tui_enabled);
++DEFINE_OBSERVABLE (core_file_changed);
+
+ } /* namespace observers */
+ } /* namespace gdb */
+diff --git a/gdb/observable.h b/gdb/observable.h
+--- a/gdb/observable.h
++++ b/gdb/observable.h
+@@ -260,6 +260,12 @@ extern observable free_program_space;
+
+ extern observable tui_enabled;
+
++/* The core file loaded into the program space inferior INF has changed.
++ The process of changing has completed, i.e. when unloading, the unload
++ is now complete. When loading a new core file, the load is complete,
++ shared libraries have been loaded, registers and threads read in, etc. */
++extern observable core_file_changed;
++
+ } /* namespace observers */
+
+ } /* namespace gdb */
+diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
+--- a/gdb/python/lib/gdb/dap/events.py
++++ b/gdb/python/lib/gdb/dap/events.py
+@@ -161,7 +161,7 @@ _expected_pause = False
+
+
+ @in_gdb_thread
+-def exec_and_expect_stop(cmd, expected_pause=False, propagate_exception=False):
++def exec_and_expect_stop(cmd, expected_pause=False):
+ """A wrapper for exec_and_log that sets the continue-suppression flag.
+
+ When EXPECTED_PAUSE is True, a stop that looks like a pause (e.g.,
+@@ -174,7 +174,7 @@ def exec_and_expect_stop(cmd, expected_pause=False, propagate_exception=False):
+ # continuing.
+ _suppress_cont = not expected_pause
+ # FIXME if the call fails should we clear _suppress_cont?
+- exec_and_log(cmd, propagate_exception)
++ exec_and_log(cmd)
+
+
+ # Map from gdb stop reasons to DAP stop reasons. Some of these can't
+@@ -276,6 +276,31 @@ def _on_inferior_call(event):
+ send_event("stopped", obj)
+
+
++@in_gdb_thread
++def _on_corefile_changed(event):
++ # Ignore events relating to corefile being unloaded.
++ if event.inferior.corefile is None:
++ return
++
++ # Corefiles are usually attached via the 'attach' request, which
++ # sets the global _expected_stop_reason to 'attach'. It is
++ # because of this that it is safe to forward to _on_stop, as when
++ # _expected_stop_reason is set _on_stop doesn't read the
++ # event.details, which EVENT doesn't have.
++ #
++ # However, if the user loads a core file via some mechanism other
++ # than the 'attach' request, e.g. they use the repl to issue a GDB
++ # 'core-file' command, then when we get here _expected_stop_reason
++ # will not be set.
++ #
++ # So, in either case, set _expected_stop_reason now.
++ global _expected_stop_reason
++ _expected_stop_reason = "attach"
++
++ # A corefile was loaded, announce that the inferior has stopped.
++ _on_stop(event)
++
++
+ gdb.events.stop.connect(_on_stop)
+ gdb.events.exited.connect(_on_exit)
+ gdb.events.new_thread.connect(_new_thread)
+@@ -284,3 +309,4 @@ gdb.events.cont.connect(_cont)
+ gdb.events.new_objfile.connect(_new_objfile)
+ gdb.events.free_objfile.connect(_objfile_removed)
+ gdb.events.inferior_call.connect(_on_inferior_call)
++gdb.events.corefile_changed.connect(_on_corefile_changed)
+diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
+--- a/gdb/python/lib/gdb/dap/launch.py
++++ b/gdb/python/lib/gdb/dap/launch.py
+@@ -59,12 +59,16 @@ class _LaunchOrAttachDeferredRequest(DeferredRequest):
+ super().reschedule()
+
+
++# Handle whitespace, quotes, and backslashes here. Exactly what
++# to quote depends on libiberty's buildargv and safe-ctype.
++def escape_filename(filename):
++ return re.sub("[ \t\n\r\f\v\\\\'\"]", "\\\\\\g<0>", filename)
++
++
+ # A wrapper for the 'file' command that correctly quotes its argument.
+ @in_gdb_thread
+ def file_command(program):
+- # Handle whitespace, quotes, and backslashes here. Exactly what
+- # to quote depends on libiberty's buildargv and safe-ctype.
+- program = re.sub("[ \t\n\r\f\v\\\\'\"]", "\\\\\\g<0>", program)
++ program = escape_filename(program)
+ exec_and_log("file " + program)
+
+
+@@ -132,6 +136,7 @@ def attach(
+ program: Optional[str] = None,
+ pid: Optional[int] = None,
+ target: Optional[str] = None,
++ coreFile: Optional[str] = None,
+ **args,
+ ):
+ # The actual attach is handled by this function.
+@@ -143,11 +148,14 @@ def attach(
+ cmd = "attach " + str(pid)
+ elif target is not None:
+ cmd = "target remote " + target
++ elif coreFile is not None:
++ cmd = "core-file " + escape_filename(coreFile)
+ else:
+- raise DAPException("attach requires either 'pid' or 'target'")
++ raise DAPException("attach requires either 'pid', 'target', or 'coreFile'")
+ expect_process("attach")
+ expect_stop("attach")
+ exec_and_log(cmd)
++
+ # Attach response does not have a body.
+ return None
+
+diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py
+--- a/gdb/python/lib/gdb/dap/next.py
++++ b/gdb/python/lib/gdb/dap/next.py
+@@ -76,7 +76,7 @@ def step_in(
+ @request("stepOut")
+ def step_out(*, threadId: int, singleThread: bool = False, **args):
+ _handle_thread_step(threadId, singleThread, True)
+- exec_and_expect_stop("finish &", propagate_exception=True)
++ exec_and_expect_stop("finish &")
+
+
+ @request("continue")
+diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py
+--- a/gdb/python/lib/gdb/dap/server.py
++++ b/gdb/python/lib/gdb/dap/server.py
+@@ -19,6 +19,7 @@ import inspect
+ import json
+ import threading
+ from contextlib import contextmanager
++from typing import Optional
+
+ import gdb
+
+@@ -610,11 +611,29 @@ def terminate(**args):
+ exec_and_log("kill")
+
+
++@in_gdb_thread
++def _disconnect_or_kill(terminate: Optional[bool]):
++ inf = gdb.selected_inferior()
++ if inf.connection is None:
++ # Nothing to do here.
++ return
++ if terminate is None:
++ # The default depends on whether the inferior was attached or
++ # launched.
++ terminate = not inf.was_attached
++
++ if inf.corefile is not None:
++ exec_and_log("core-file")
++ elif terminate:
++ exec_and_log("kill")
++ elif inf.was_attached:
++ exec_and_log("detach")
++
++
+ @request("disconnect", on_dap_thread=True, expect_stopped=False)
+ @capability("supportTerminateDebuggee")
+-def disconnect(*, terminateDebuggee: bool = False, **args):
+- if terminateDebuggee:
+- send_gdb_with_response("kill")
++def disconnect(*, terminateDebuggee: Optional[bool] = None, **args):
++ send_gdb_with_response(lambda: _disconnect_or_kill(terminateDebuggee))
+ _server.shutdown()
+
+
+diff --git a/gdb/python/lib/gdb/dap/startup.py b/gdb/python/lib/gdb/dap/startup.py
+--- a/gdb/python/lib/gdb/dap/startup.py
++++ b/gdb/python/lib/gdb/dap/startup.py
+@@ -204,7 +204,7 @@ def log_stack(level=LogLevel.DEFAULT):
+
+
+ @in_gdb_thread
+-def exec_and_log(cmd, propagate_exception=False):
++def exec_and_log(cmd):
+ """Execute the gdb command CMD.
+ If logging is enabled, log the command and its output."""
+ log("+++ " + cmd)
+@@ -213,10 +213,10 @@ def exec_and_log(cmd, propagate_exception=False):
+ if output != "":
+ log(">>> " + output)
+ except gdb.error as e:
+- if propagate_exception:
+- raise DAPException(str(e)) from e
+- else:
+- log_stack()
++ # Don't normally want to see this, as it interferes with the
++ # test suite.
++ log_stack(LogLevel.FULL)
++ raise DAPException(str(e)) from e
+
+
+ @in_gdb_thread
+diff --git a/gdb/python/py-all-events.def b/gdb/python/py-all-events.def
+--- a/gdb/python/py-all-events.def
++++ b/gdb/python/py-all-events.def
+@@ -46,3 +46,4 @@ GDB_PY_DEFINE_EVENT(executable_changed)
+ GDB_PY_DEFINE_EVENT(new_progspace)
+ GDB_PY_DEFINE_EVENT(free_progspace)
+ GDB_PY_DEFINE_EVENT(tui_enabled)
++GDB_PY_DEFINE_EVENT(corefile_changed)
+diff --git a/gdb/python/py-corefile.c b/gdb/python/py-corefile.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/python/py-corefile.c
+@@ -0,0 +1,723 @@
++/* Python interface to core files.
++
++ Copyright (C) 2025 Free Software Foundation, Inc.
++
++ This file is part of GDB.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see . */
++
++#include "python-internal.h"
++#include "progspace.h"
++#include "observable.h"
++#include "inferior.h"
++#include "gdbcore.h"
++#include "gdbsupport/rsp-low.h"
++#include "py-event.h"
++
++/* A gdb.Corefile object. */
++
++struct corefile_object
++{
++ PyObject_HEAD
++
++ /* The inferior this core file is attached to. This will be set to NULL
++ when the inferior is deleted, or if a different core file is loaded
++ for the inferior. When this is NULL the gdb.Corefile object is
++ considered invalid.*/
++ struct inferior *inferior;
++
++ /* Dictionary holding user-added attributes. This is the __dict__
++ attribute of the object. This is an owning reference. */
++ PyObject *dict;
++
++ /* A Tuple of gdb.CorefileMappedFile objects. This tuple is only created
++ the first time the user calls gdb.Corefile.mapped_files(), the result
++ is cached here. If this pointer is not NULL then this is an owning
++ pointer (i.e. this owns a reference to the Tuple). */
++ PyObject *mapped_files;
++};
++
++extern PyTypeObject corefile_object_type
++ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_object");
++
++/* A gdb.CorefileMapped object. */
++
++struct corefile_mapped_file_object
++{
++ PyObject_HEAD
++
++ /* The name of a file that was mapped when the core file was created.
++ This is a 'str' object. */
++ PyObject *filename;
++
++ /* The build-id of a file that was mapped when the core file was
++ created. This is either a 'str' if the file had a build-id, or
++ 'None' if there was no build-id for this file. */
++ PyObject *build_id;
++
++ /* A List of gdb.CorefileMappedFileRegion objects. */
++ PyObject *regions;
++
++ /* True if this represents the main executable from which the core file
++ was created. */
++ bool is_main_exec_p;
++};
++
++extern PyTypeObject corefile_mapped_file_object_type
++ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_mapped_file_object");
++
++/* A gdb.CorefileMappedFileRegion object. */
++
++struct corefile_mapped_file_region_object
++{
++ PyObject_HEAD
++
++ /* The start and end addresses for this mapping, these are addresses
++ within the inferior's address space. */
++ CORE_ADDR start;
++ CORE_ADDR end;
++
++ /* The offset within the mapped file for this mapping. */
++ ULONGEST file_offset;
++};
++
++extern PyTypeObject corefile_mapped_file_region_object_type
++ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_mapped_file_region_object");
++
++/* Clear the inferior pointer in a Corefile object OBJ when an inferior is
++ deleted. */
++
++struct inferior_corefile_deleter
++{
++ void operator() (corefile_object *obj)
++ {
++ if (!gdb_python_initialized)
++ return;
++
++ gdbpy_enter enter_py;
++
++ /* When OBJECT goes out of scope this will Py_DECREF on OBJ. */
++ gdbpy_ref object (obj);
++
++ /* Clearing the inferior pointer marks the gdb.Corefile as invalid. */
++ object->inferior = nullptr;
++ }
++};
++
++/* Store a gdb.Corefile object in an inferior's registry. */
++
++static const registry::key
++ cfpy_inferior_corefile_data_key;
++
++/* See python-internal.h. */
++
++gdbpy_ref<>
++gdbpy_core_file_from_inferior (inferior *inf)
++{
++ gdb_assert (inf != nullptr);
++ gdb_assert (inf->pspace != nullptr);
++
++ program_space *pspace = inf->pspace;
++
++ if (pspace->core_bfd () == nullptr)
++ return gdbpy_ref<>::new_reference (Py_None);
++
++ PyObject *result = (PyObject *) cfpy_inferior_corefile_data_key.get (inf);
++ if (result == nullptr)
++ {
++ gdbpy_ref object
++ (PyObject_New (corefile_object, &corefile_object_type));
++ if (object == nullptr)
++ return nullptr;
++
++ /* Ensure the 'inferior' field is set to NULL. If the PyDict_New
++ call fails then the gdb.Corefile will be discarded and
++ cfpy_dealloc will be called, which requires that the 'inferior' be
++ set to NULL. */
++ object->inferior = nullptr;
++ object->mapped_files = nullptr;
++ object->dict = PyDict_New ();
++ if (object->dict == nullptr)
++ return nullptr;
++
++ /* Now that the gdb.Corefile has been successfully initialised and we
++ know that it is going to be passed back to the user, move it out
++ of the invalid state by setting the 'inferior' field to a non NULL
++ value. */
++ object->inferior = inf;
++ cfpy_inferior_corefile_data_key.set (inf, object.get ());
++ result = (PyObject *) object.release ();
++ }
++
++ return gdbpy_ref<>::new_reference (result);
++}
++
++/* Return true if OBJ is valid. */
++
++static bool
++cfpy_corefile_object_is_valid (const corefile_object *obj)
++{
++ if (obj->inferior == nullptr)
++ return false;
++
++ gdb_assert (obj->inferior->pspace != nullptr);
++
++ return obj->inferior->pspace->core_bfd () != nullptr;
++}
++
++/* Require that COREFILE_OBJ be a valid core file. A valid core file
++ object has a valid program space, and the program space has a core file
++ loaded into it. */
++#define CFPY_REQUIRE_VALID(corefile_obj) \
++ do { \
++ if (!cfpy_corefile_object_is_valid (corefile_obj)) \
++ { \
++ PyErr_SetString (PyExc_RuntimeError, \
++ _("Corefile no longer exists.")); \
++ return nullptr; \
++ } \
++ } while (0)
++
++/* Read the gdb.Corefile.filename attribute. */
++
++static PyObject *
++cfpy_get_filename (PyObject *self, void *closure)
++{
++ corefile_object *obj = (corefile_object *) self;
++
++ CFPY_REQUIRE_VALID (obj);
++
++ /* If the program space's core file had been cleared, then this Corefile
++ object would have been invalidated. */
++ bfd *abfd = obj->inferior->pspace->core_bfd ();
++ gdb_assert (abfd != nullptr);
++
++ return host_string_to_python_string (bfd_get_filename (abfd)).release ();
++}
++
++/* Implementation of gdb.Corefile.is_valid (self) -> Boolean.
++ Returns True if this core file object is associated with a program space
++ that still exists, an the program space still has a core file loaded. */
++
++static PyObject *
++cfpy_is_valid (PyObject *self, PyObject *args)
++{
++ corefile_object *obj = (corefile_object *) self;
++
++ if (!cfpy_corefile_object_is_valid (obj))
++ Py_RETURN_FALSE;
++
++ Py_RETURN_TRUE;
++}
++
++/* Implement gdb.Corefile.mapped_files (). Return a List of
++ gdb.CorefileMappedFile objects. The list is created the first time
++ this method is called, and then cached within the gdb.Corefile object,
++ future calls just return a reference to the same list. */
++
++static PyObject *
++cfpy_mapped_files (PyObject *self, PyObject *args)
++{
++ corefile_object *obj = (corefile_object *) self;
++
++ CFPY_REQUIRE_VALID (obj);
++
++ /* If we have already created the List then just return another reference
++ to the existing list. */
++ if (obj->mapped_files != nullptr)
++ {
++ Py_INCREF (obj->mapped_files);
++ return obj->mapped_files;
++ }
++
++ /* Get all the mapping data from GDB. */
++ std::vector mapped_files;
++ try
++ {
++ mapped_files
++ = gdb_read_core_file_mappings (obj->inferior->arch (),
++ current_program_space->core_bfd ());
++ }
++ catch (const gdb_exception &except)
++ {
++ return gdbpy_handle_gdb_exception (nullptr, except);
++ }
++
++ /* Create a new list to hold the results. */
++ gdbpy_ref<> tuple (PyTuple_New (mapped_files.size ()));
++ if (tuple == nullptr)
++ return nullptr;
++
++ /* Create each gdb.CorefileMappedFile object. */
++ Py_ssize_t tuple_idx = 0;
++ for (const core_mapped_file &file : mapped_files)
++ {
++ /* The filename 'str' object. */
++ gdbpy_ref<> filename
++ = host_string_to_python_string (file.filename.c_str ());
++ if (filename == nullptr)
++ return nullptr;
++
++ /* The build-id object. Either a 'str' or 'None'. */
++ gdbpy_ref<> build_id;
++ if (file.build_id != nullptr)
++ {
++ std::string hex_form = bin2hex (file.build_id->data,
++ file.build_id->size);
++
++ build_id
++ = host_string_to_python_string (hex_form.c_str ());
++ if (build_id == nullptr)
++ return nullptr;
++ }
++ else
++ build_id = gdbpy_ref<>::new_reference (Py_None);
++
++ /* List to hold all the gdb.CorefileMappedFileRegion objects. */
++ gdbpy_ref<> regions (PyTuple_New (file.regions.size ()));
++ if (regions == nullptr)
++ return nullptr;
++
++ /* Create all the gdb.CorefileMappedFileRegion objects. */
++ Py_ssize_t regions_idx = 0;
++ for (const core_mapped_file::region &r : file.regions)
++ {
++ /* Actually create the object. */
++ gdbpy_ref region_obj
++ (PyObject_New (corefile_mapped_file_region_object,
++ &corefile_mapped_file_region_object_type));
++ if (region_obj == nullptr)
++ return nullptr;
++
++ /* Initialise the object. */
++ region_obj->start = r.start;
++ region_obj->end = r.end;
++ region_obj->file_offset = r.file_ofs;
++
++ /* Add to the gdb.CorefileMappedFileRegion list. */
++ if (PyTuple_SetItem (regions.get (), regions_idx++,
++ (PyObject *) region_obj.release ()) < 0)
++ return nullptr;
++ }
++
++ /* Actually create the gdb.CorefileMappedFile object. */
++ gdbpy_ref entry
++ (PyObject_New (corefile_mapped_file_object,
++ &corefile_mapped_file_object_type));
++ if (entry == nullptr)
++ return nullptr;
++
++ /* Initialise the object. */
++ entry->filename = filename.release ();
++ entry->build_id = build_id.release ();
++ entry->regions = regions.release ();
++ entry->is_main_exec_p = file.is_main_exec;
++
++ /* Add to the gdb.CorefileMappedFile list. */
++ if (PyTuple_SetItem (tuple.get (), tuple_idx++,
++ (PyObject *) entry.release ()) < 0)
++ return nullptr;
++ }
++
++ /* No errors. Move the reference currently in LIST into the Corefile
++ object itself. Then create a new reference and hand this back to the
++ user. */
++ obj->mapped_files = tuple.release ();
++ Py_INCREF (obj->mapped_files);
++ return obj->mapped_files;
++}
++
++/* Emit a CorefileChangedEvent event, INF is the inferior in which the core
++ file changed. Return 0 on success, or a negative value on error. */
++
++static int
++emit_corefile_changed_event (inferior *inf)
++{
++ /* If there are no listeners then we are done. */
++ if (evregpy_no_listeners_p (gdb_py_events.corefile_changed))
++ return 0;
++
++ gdbpy_ref<> event_obj
++ = create_event_object (&corefile_changed_event_object_type);
++ if (event_obj == nullptr)
++ return -1;
++
++ gdbpy_ref inf_obj = inferior_to_inferior_object (inf);
++ if (inf_obj == nullptr
++ || evpy_add_attribute (event_obj.get (), "inferior",
++ (PyObject *) inf_obj.get ()) < 0)
++ return -1;
++
++ return evpy_emit_event (event_obj.get (), gdb_py_events.corefile_changed);
++}
++
++/* Callback from gdb::observers::core_file_changed. The core file for
++ INF has been changed. */
++
++static void
++cfpy_corefile_changed (inferior *inf)
++{
++ /* It's safe to do this even if Python is not initialized, but there
++ should be nothing to clear in that case. */
++ cfpy_inferior_corefile_data_key.clear (inf);
++
++ if (!gdb_python_initialized)
++ return;
++
++ gdbpy_enter enter_py;
++
++ if (emit_corefile_changed_event (inf) < 0)
++ gdbpy_print_stack ();
++}
++
++/* Called when a gdb.Corefile is destroyed. */
++
++static void
++cfpy_dealloc (PyObject *obj)
++{
++ corefile_object *corefile = (corefile_object *) obj;
++
++ /* Every gdb.Corefile is cached in an inferior's registry. The only way
++ for a gdb.Corefile to be deallocated is to remove the object reference
++ from the registry (and dec its ref count), but before we do that, we
++ set the object's inferior pointer to NULL. */
++ gdb_assert (corefile->inferior == nullptr);
++
++ Py_XDECREF (corefile->dict);
++ Py_XDECREF (corefile->mapped_files);
++
++ Py_TYPE (obj)->tp_free (obj);
++}
++
++/* __repr__ implementation for gdb.Corefile. */
++
++static PyObject *
++cfpy_repr (PyObject *self)
++{
++ corefile_object *obj = (corefile_object *) self;
++
++ if (!cfpy_corefile_object_is_valid (obj))
++ return gdb_py_invalid_object_repr (self);
++
++ program_space *pspace = obj->inferior->pspace;
++ gdb_assert (pspace != nullptr);
++ return PyUnicode_FromFormat ("<%s inferior=%d filename='%s'>",
++ Py_TYPE (self)->tp_name,
++ obj->inferior->num,
++ bfd_get_filename (pspace->core_bfd ()));
++}
++
++
++
++/* Called when a gdb.CorefileMappedFile is destroyed. */
++
++static void
++cfmfpy_dealloc (PyObject *obj)
++{
++ corefile_mapped_file_object *mapped_file
++ = (corefile_mapped_file_object *) obj;
++
++ Py_XDECREF (mapped_file->filename);
++ Py_XDECREF (mapped_file->build_id);
++ Py_XDECREF (mapped_file->regions);
++
++ Py_TYPE (obj)->tp_free (obj);
++}
++
++/* Read the gdb.CorefileMappedFile.filename attribute. */
++
++static PyObject *
++cfmfpy_get_filename (PyObject *self, void *closure)
++{
++ corefile_mapped_file_object *obj
++ = (corefile_mapped_file_object *) self;
++
++ gdb_assert (obj->filename != nullptr);
++
++ Py_INCREF (obj->filename);
++ return obj->filename;
++}
++
++/* Read the gdb.CorefileMappedFile.build_id attribute. */
++
++static PyObject *
++cfmfpy_get_build_id (PyObject *self, void *closure)
++{
++ corefile_mapped_file_object *obj
++ = (corefile_mapped_file_object *) self;
++
++ gdb_assert (obj->build_id != nullptr);
++
++ Py_INCREF (obj->build_id);
++ return obj->build_id;
++}
++
++/* Read the gdb.CorefileMappedFile.regions attribute. */
++
++static PyObject *
++cfmfpy_get_regions (PyObject *self, void *closure)
++{
++ corefile_mapped_file_object *obj
++ = (corefile_mapped_file_object *) self;
++
++ gdb_assert (obj->regions != nullptr);
++
++ Py_INCREF (obj->regions);
++ return obj->regions;
++}
++
++/* Read the gdb.CorefileMappedFile.is_main_executable attribute. */
++
++static PyObject *
++cfmf_is_main_exec (PyObject *self, void *closure)
++{
++ corefile_mapped_file_object *obj
++ = (corefile_mapped_file_object *) self;
++
++ if (obj->is_main_exec_p)
++ Py_RETURN_TRUE;
++ else
++ Py_RETURN_FALSE;
++}
++
++
++
++/* Read the gdb.CorefileMappedFileRegion.start attribute. */
++
++static PyObject *
++cfmfrpy_get_start (PyObject *self, void *closure)
++{
++ corefile_mapped_file_region_object *obj
++ = (corefile_mapped_file_region_object *) self;
++
++ return gdb_py_object_from_ulongest (obj->start).release ();
++}
++
++/* Read the gdb.CorefileMappedFileRegion.end attribute. */
++
++static PyObject *
++cfmfrpy_get_end (PyObject *self, void *closure)
++{
++ corefile_mapped_file_region_object *obj
++ = (corefile_mapped_file_region_object *) self;
++
++ return gdb_py_object_from_ulongest (obj->end).release ();
++}
++
++/* Read the gdb.CorefileMappedFileRegion.file_offset attribute. */
++
++static PyObject *
++cfmfrpy_get_file_offset (PyObject *self, void *closure)
++{
++ corefile_mapped_file_region_object *obj
++ = (corefile_mapped_file_region_object *) self;
++
++ return gdb_py_object_from_ulongest (obj->file_offset).release ();
++}
++
++
++
++static int
++gdbpy_initialize_corefile ()
++{
++ gdb::observers::core_file_changed.attach (cfpy_corefile_changed,
++ "py-corefile");
++
++ if (gdbpy_type_ready (&corefile_object_type) < 0)
++ return -1;
++
++ if (gdbpy_type_ready (&corefile_mapped_file_object_type) < 0)
++ return -1;
++
++ if (gdbpy_type_ready (&corefile_mapped_file_region_object_type) < 0)
++ return -1;
++
++ return 0;
++}
++
++GDBPY_INITIALIZE_FILE (gdbpy_initialize_corefile);
++
++
++
++static gdb_PyGetSetDef corefile_getset[] =
++{
++ { "__dict__", gdb_py_generic_dict, nullptr,
++ "The __dict__ for the gdb.Corefile.", &corefile_object_type },
++ { "filename", cfpy_get_filename, nullptr,
++ "The filename of a valid Corefile object.", nullptr },
++ { nullptr }
++};
++
++static PyMethodDef corefile_object_methods[] =
++{
++ { "is_valid", cfpy_is_valid, METH_NOARGS,
++ "is_valid () -> Boolean.\n\
++Return true if this Corefile is valid, false if not." },
++ { "mapped_files", cfpy_mapped_files, METH_NOARGS,
++ "mapped_files () -> List of mapping tuples.\n\
++Return a list of tuples. Each tuple represents a mapping from the\
++core file." },
++ { nullptr }
++};
++
++PyTypeObject corefile_object_type =
++{
++ PyVarObject_HEAD_INIT (nullptr, 0)
++ "gdb.Corefile", /*tp_name*/
++ sizeof (corefile_object), /*tp_basicsize*/
++ 0, /*tp_itemsize*/
++ cfpy_dealloc, /*tp_dealloc*/
++ 0, /*tp_print*/
++ 0, /*tp_getattr*/
++ 0, /*tp_setattr*/
++ 0, /*tp_compare*/
++ cfpy_repr, /*tp_repr*/
++ 0, /*tp_as_number*/
++ 0, /*tp_as_sequence*/
++ 0, /*tp_as_mapping*/
++ 0, /*tp_hash */
++ 0, /*tp_call*/
++ 0, /*tp_str*/
++ 0, /*tp_getattro*/
++ 0, /*tp_setattro*/
++ 0, /*tp_as_buffer*/
++ Py_TPFLAGS_DEFAULT, /*tp_flags*/
++ "GDB corefile object", /* tp_doc */
++ 0, /* tp_traverse */
++ 0, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ corefile_object_methods, /* tp_methods */
++ 0, /* tp_members */
++ corefile_getset, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ offsetof (corefile_object, dict), /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
++
++static gdb_PyGetSetDef corefile_mapped_file_object_getset[] =
++{
++ { "filename", cfmfpy_get_filename, nullptr,
++ "The filename of a CorefileMappedFile object.", nullptr },
++ { "build_id", cfmfpy_get_build_id, nullptr,
++ "The build-id of a CorefileMappedFile object or None.", nullptr },
++ { "regions", cfmfpy_get_regions, nullptr,
++ "The list of regions from a CorefileMappedFile object.", nullptr },
++ { "is_main_executable", cfmf_is_main_exec, nullptr,
++ "True for the main executable mapping, otherwise False.", nullptr },
++ { nullptr }
++};
++
++PyTypeObject corefile_mapped_file_object_type =
++{
++ PyVarObject_HEAD_INIT (NULL, 0)
++ "gdb.CorefileMappedFile", /*tp_name*/
++ sizeof (corefile_mapped_file_object), /*tp_basicsize*/
++ 0, /*tp_itemsize*/
++ cfmfpy_dealloc, /*tp_dealloc*/
++ 0, /*tp_print*/
++ 0, /*tp_getattr*/
++ 0, /*tp_setattr*/
++ 0, /*tp_compare*/
++ 0, /*tp_repr*/
++ 0, /*tp_as_number*/
++ 0, /*tp_as_sequence*/
++ 0, /*tp_as_mapping*/
++ 0, /*tp_hash */
++ 0, /*tp_call*/
++ 0, /*tp_str*/
++ 0, /*tp_getattro*/
++ 0, /*tp_setattro*/
++ 0, /*tp_as_buffer*/
++ Py_TPFLAGS_DEFAULT, /*tp_flags*/
++ "GDB corefile mapped file object", /* tp_doc */
++ 0, /* tp_traverse */
++ 0, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ 0, /* tp_methods */
++ 0, /* tp_members */
++ corefile_mapped_file_object_getset, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ 0, /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
++
++static gdb_PyGetSetDef corefile_mapped_file_region_object_getset[] =
++{
++ { "start", cfmfrpy_get_start, nullptr,
++ "The start address of a CorefileMappedFileRegion object.", nullptr },
++ { "end", cfmfrpy_get_end, nullptr,
++ "The end address of a CorefileMappedFileRegion object.", nullptr },
++ { "file_offset", cfmfrpy_get_file_offset, nullptr,
++ "The file offset of a CorefileMappedFileRegion object.", nullptr },
++ { nullptr }
++};
++
++PyTypeObject corefile_mapped_file_region_object_type =
++{
++ PyVarObject_HEAD_INIT (NULL, 0)
++ "gdb.CorefileMappedFileRegion", /*tp_name*/
++ sizeof (corefile_mapped_file_region_object), /*tp_basicsize*/
++ 0, /*tp_itemsize*/
++ 0, /*tp_dealloc*/
++ 0, /*tp_print*/
++ 0, /*tp_getattr*/
++ 0, /*tp_setattr*/
++ 0, /*tp_compare*/
++ 0, /*tp_repr*/
++ 0, /*tp_as_number*/
++ 0, /*tp_as_sequence*/
++ 0, /*tp_as_mapping*/
++ 0, /*tp_hash */
++ 0, /*tp_call*/
++ 0, /*tp_str*/
++ 0, /*tp_getattro*/
++ 0, /*tp_setattro*/
++ 0, /*tp_as_buffer*/
++ Py_TPFLAGS_DEFAULT, /*tp_flags*/
++ "GDB corefile mapped file region object", /* tp_doc */
++ 0, /* tp_traverse */
++ 0, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ 0, /* tp_methods */
++ 0, /* tp_members */
++ corefile_mapped_file_region_object_getset, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ 0, /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
+diff --git a/gdb/python/py-event-types.def b/gdb/python/py-event-types.def
+--- a/gdb/python/py-event-types.def
++++ b/gdb/python/py-event-types.def
+@@ -145,3 +145,8 @@ GDB_PY_DEFINE_EVENT_TYPE (tui_enabled,
+ "TuiEnabledEvent",
+ "GDB TUI enabled event object",
+ event_object_type);
++
++GDB_PY_DEFINE_EVENT_TYPE (corefile_changed,
++ "CorefileChangedEvent",
++ "GDB corefile changed event",
++ event_object_type);
+diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
+--- a/gdb/python/py-inferior.c
++++ b/gdb/python/py-inferior.c
+@@ -973,6 +973,22 @@ infpy_get_main_name (PyObject *self, void *closure)
+ return host_string_to_python_string (name).release ();
+ }
+
++/* Implement the Inferior.corefile getter. Returns a gdb.Corefile
++ object, or None. */
++
++static PyObject *
++infpy_get_core_file (PyObject *self, void *closure)
++{
++ inferior_object *inf = (inferior_object *) self;
++
++ INFPY_REQUIRE_VALID (inf);
++
++ inferior *inferior = inf->inferior;
++ gdb_assert (inferior != nullptr);
++
++ return gdbpy_core_file_from_inferior (inferior).release ();
++}
++
+ static void
+ infpy_dealloc (PyObject *obj)
+ {
+@@ -1062,6 +1078,8 @@ static gdb_PyGetSetDef inferior_object_getset[] =
+ { "progspace", infpy_get_progspace, NULL, "Program space of this inferior" },
+ { "main_name", infpy_get_main_name, nullptr,
+ "Name of 'main' function, if known.", nullptr },
++ { "corefile", infpy_get_core_file, nullptr,
++ "The corefile loaded in to this inferior, or None.", nullptr },
+ { NULL }
+ };
+
+diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
+--- a/gdb/python/python-internal.h
++++ b/gdb/python/python-internal.h
+@@ -1113,6 +1113,14 @@ extern std::optional gdbpy_print_insn (struct gdbarch *gdbarch,
+ CORE_ADDR address,
+ disassemble_info *info);
+
++/* Return the gdb.Corefile object representing the core file loaded into
++ the program space of INF, or None if there is no core file loaded. INF
++ must not be NULL. If an error occurs then NULL is returned, and a
++ suitable Python error will be set. */
++
++extern gdbpy_ref<> gdbpy_core_file_from_inferior (inferior *inf);
++
++
+ /* A wrapper for PyType_Ready that also automatically registers the
+ type in the appropriate module. Returns 0 on success, -1 on error.
+ If MOD is supplied, then the type is added to that module. If MOD
+diff --git a/gdb/testsuite/gdb.dap/attach-fail.exp b/gdb/testsuite/gdb.dap/attach-fail.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dap/attach-fail.exp
+@@ -0,0 +1,32 @@
++# Copyright 2025 Free Software Foundation, Inc.
++
++# 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 .
++
++# Test "attach" failure in DAP.
++
++require can_spawn_for_attach allow_dap_tests
++
++load_lib dap-support.exp
++
++# Passing an empty remote name here will guarantee a failure without
++# trying to find a real remote.
++set id [dap_target_remote {""}]
++
++dap_check_request_and_response "configurationDone" configurationDone
++
++set resp [lindex [dap_read_response attach $id] 0]
++gdb_assert {[dict get $resp success] == "false"} \
++ "attach failed"
++
++dap_shutdown
+diff --git a/gdb/testsuite/gdb.dap/corefile.c b/gdb/testsuite/gdb.dap/corefile.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dap/corefile.c
+@@ -0,0 +1,45 @@
++/* This testcase is part of GDB, the GNU debugger.
++
++ Copyright 2026 Free Software Foundation, Inc.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see . */
++
++#include
++
++int global_var = 0;
++
++void
++baz (void)
++{
++ abort ();
++}
++
++void
++bar (void)
++{
++ baz ();
++}
++
++void
++foo (void)
++{
++ bar ();
++}
++
++int
++main (void)
++{
++ foo ();
++ return 0;
++}
+diff --git a/gdb/testsuite/gdb.dap/corefile.exp b/gdb/testsuite/gdb.dap/corefile.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dap/corefile.exp
+@@ -0,0 +1,196 @@
++# Copyright 2026 Free Software Foundation, Inc.
++
++# 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 .
++
++# Test using "attach" in DAP for opening a core file.
++
++require allow_dap_tests
++
++load_lib dap-support.exp
++
++standard_testfile
++
++if {[build_executable ${testfile}.exp $testfile] == -1} {
++ return
++}
++
++set corefile [core_find $binfile {}]
++if {$corefile == ""} {
++ untested "unable to create or find corefile"
++ return
++}
++
++set other_corefile [standard_output_file "${testfile} with spaces.core"]
++remote_exec build "cp \"$corefile\" \"$other_corefile\""
++
++# Test that attaching to a core file works at all.
++set attach_id [dap_corefile $corefile $binfile]
++
++dap_check_request_and_response "configurationDone" configurationDone
++
++dap_check_response "attach response" attach $attach_id
++
++dap_wait_for_event_and_check "stopped" stopped \
++ "body reason" attach
++
++# Try 'continue', this should fail.
++set obj [dap_request_and_response continue \
++ {o threadId [i 1]}]
++set response [lindex $obj 0]
++gdb_assert { [dict get $response success] == "false" } \
++ "continue with core file target"
++
++# Get a backtrace from the core file.
++set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
++ {o threadId [i 1]}] 0]
++set frame_id [dict get [lindex [dict get $bt body stackFrames] 0] id]
++
++# Get all scopes for frame 0. Search through scopes to find the
++# register scope.
++set scopes [dap_check_request_and_response "get scopes" scopes \
++ [format {o frameId [i %d]} $frame_id]]
++set scopes [dict get [lindex $scopes 0] body scopes]
++set reg_scope ""
++foreach s $scopes {
++ if {[dict get $s name] == "Registers"} {
++ set reg_scope $s
++ }
++}
++gdb_assert { $reg_scope ne "" } "found register scope"
++
++# Read all the registers from the register scope.
++set num [dict get $reg_scope variablesReference]
++set reply [lindex [dap_check_request_and_response "fetch all registers" \
++ "variables" \
++ [format {o variablesReference [i %d] count [i %d]} $num\
++ [dict get $reg_scope namedVariables]]] 0]
++
++# Find the name and value of a register, we'll use this to try setting
++# a register below.
++set regs [dict get $reply body variables]
++gdb_assert {[llength $regs] > 0} "got at least one register"
++set reg_name [dict get [lindex $regs 0] name]
++set reg_value [dict get [lindex $regs 0] value]
++
++set obj [dap_request_and_response setExpression \
++ {o expression [s global_var] value [s 23]}]
++set response [lindex $obj 0]
++gdb_assert { [dict get $response success] == "false" } \
++ "set global variable fails"
++set expected_exception_count 1
++
++# Try setting a register, this should fail as registers are not
++# writable for a core file target. We need to write back a different
++# register value, so we add one to the current value. This means we
++# can only run the test if the current register value is an integer.
++if {[string is integer -strict $reg_value]} {
++ set new_value [expr {$reg_value + 1}]
++ set obj [dap_request_and_response setExpression \
++ {o expression [s \$$reg_name] value [s $new_value]}]
++ set response [lindex $obj 0]
++ gdb_assert { [dict get $response success] == "false" } \
++ "set register fails"
++ incr expected_exception_count
++}
++
++dap_shutdown false $expected_exception_count
++
++# Reconnect to the core file. This time when we shutdown we will
++# request that the target be terminated, GDB should still just
++# disconnect though as core file targets cannot be killed.
++with_test_prefix "reattach" {
++ set attach_id [dap_corefile $corefile $binfile]
++
++ dap_check_request_and_response "configurationDone" configurationDone
++
++ dap_check_response "attach response" attach $attach_id
++
++ dap_wait_for_event_and_check "stopped" stopped \
++ "body reason" attach
++
++ # Request the target be terminated. This doesn't make sense for
++ # core file targets (which cannot be killed), but GDB should
++ # handle this gracefully and just disconnect.
++ dap_shutdown true
++}
++
++# Test loading a core file with spaces in its name.
++with_test_prefix "core file with spaces" {
++ gdb_exit
++
++ # Test that attaching to a core file works at all.
++ set attach_id [dap_corefile $other_corefile]
++
++ dap_check_request_and_response "configurationDone" configurationDone
++
++ dap_check_response "attach response" attach $attach_id
++
++ dap_wait_for_event_and_check "stopped" stopped \
++ "body reason" attach
++
++ # Use the repl to issue an 'info inferiors' command.
++ set obj [dap_check_request_and_response "command repl" \
++ evaluate {o expression [s "info inferiors"] context [s repl]}]
++ set response [lindex $obj 0]
++ set result [dict get $response body result]
++ set result [string map {\\n \n \\t \t} $result]
++ verbose -log "Info Inferiors Output:\n$result\n\n"
++
++ # Check that the output contains the header line, the executable
++ # name, and the core file name. We didn't pass the executable
++ # name when loading the core file, but GDB should have been able
++ # to find the executable from the core file.
++ gdb_assert { [regexp "Num\\s+Description\\s+Connection\\s+Executable" $result] } \
++ "info inferiors column headers found"
++
++ gdb_assert { [regexp "[string_to_regexp $binfile]\\s*\n" $result] } \
++ "executable name was set during core file load"
++
++ dap_shutdown
++}
++
++# Test loading a core file via the repl.
++with_test_prefix "load core file via repl" {
++ gdb_exit
++
++ if {[dap_initialize] == ""} {
++ return
++ }
++
++ # Use the repl to issue a 'core-file' command.
++ set obj [dap_check_request_and_response "command repl" \
++ evaluate [format {o expression [s "core-file %s"] context [s repl]} $corefile]]
++ set response [lindex $obj 0]
++ set result [dict get $response body result]
++ set result [string map {\\n \n \\t \t} $result]
++ verbose -log "Core-File Command Output:\n$result\n\n"
++
++ # By the time we got the response from the 'core-file' command,
++ # the stopped event, sent when we attach to a core file, should
++ # already have been seen, check for it now.
++ set ok false
++ foreach d [lindex $obj 1] {
++ if {[dict get $d type] != "event"
++ || [dict get $d event] != "stopped"} {
++ continue
++ }
++ if {[dict get $d body reason] == "attach"} {
++ set ok true
++ break
++ }
++ }
++ gdb_assert { $ok } "saw stopped event"
++
++ dap_shutdown
++}
+diff --git a/gdb/testsuite/gdb.python/py-corefile.c b/gdb/testsuite/gdb.python/py-corefile.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-corefile.c
+@@ -0,0 +1,25 @@
++/* Copyright 2025 Free Software Foundation, Inc.
++
++ This file is part of GDB.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see . */
++
++#include
++
++int
++main (void)
++{
++ /* With correct ulimit, etc. this should cause a core dump. */
++ abort ();
++}
+diff --git a/gdb/testsuite/gdb.python/py-corefile.exp b/gdb/testsuite/gdb.python/py-corefile.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-corefile.exp
+@@ -0,0 +1,365 @@
++# Copyright (C) 2025 Free Software Foundation, Inc.
++
++# 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 .
++
++# This file is part of the GDB testsuite. It tests the core file
++# support in Python.
++
++require isnative
++require {!is_remote host}
++
++load_lib gdb-python.exp
++
++require allow_python_tests
++
++standard_testfile
++
++if {[build_executable "build executable" $testfile $srcfile] == -1} {
++ return
++}
++
++set remote_python_file \
++ [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
++
++set corefile [core_find $binfile]
++if {$corefile == ""} {
++ unsupported "couldn't create or find corefile"
++ return
++}
++
++# Helper proc to run the 'core-file' command. Takes optional arguments:
++#
++# -corefile FILENAME : Load FILENAME as the new core file. If this
++# argument is not given then the current core
++# file will be unloaded.
++#
++# -inferior NUM : The inferior in which the corefile is being changed.
++# This is used to match the corefile_changed events
++# that will be emitted.
++#
++# -prefix STRING : A test prefix, to make test names unique.
++#
++# -replacement : There's already a core file loaded when this command
++# is being run.
++proc core_file_cmd { args } {
++ parse_some_args {
++ {corefile ""}
++ {inferior 1}
++ {prefix ""}
++ {replacement}
++ }
++
++ if { $prefix eq "" } {
++ if { $corefile eq "" } {
++ set prefix "unload corefile"
++ } else {
++ set prefix "load corefile"
++ }
++ }
++
++ with_test_prefix $prefix {
++ gdb_test "events corefile_changed check" \
++ "^No corefile_changed event has been seen\\." \
++ "no corefile event has been seen"
++
++ gdb_test "events exited check" \
++ "^No exited event has been seen\\." \
++ "no exited event has been seen"
++
++ if { $corefile eq "" } {
++ gdb_test "core-file" "^No core file now\\." "unload current core file"
++
++ gdb_test "events corefile_changed check" \
++ "Event 1/1, Inferior $inferior, Corefile None" \
++ "expected corefile event has been seen"
++
++ gdb_test "events exited check" \
++ "Event 1/1, Inferior $inferior, Exit Code None" \
++ "expected exited event has been seen"
++ } else {
++ gdb_test "core-file $corefile" ".*" "load core file"
++
++ if { $replacement } {
++ gdb_test "events corefile_changed check" \
++ [multi_line \
++ "Event 1/2, Inferior $inferior, Corefile None" \
++ "Event 2/2, Inferior $inferior, Corefile [string_to_regexp $corefile]"] \
++ "expected corefile event has been seen"
++
++ gdb_test "events exited check" \
++ "Event 1/1, Inferior $inferior, Exit Code None" \
++ "expected exited event has been seen"
++ } else {
++ gdb_test "events corefile_changed check" \
++ "Event 1/1, Inferior $inferior, Corefile [string_to_regexp $corefile]" \
++ "expected corefile event has been seen"
++
++ gdb_test "events exited check" \
++ "^No exited event has been seen\\." \
++ "no exited event was emitted"
++ }
++ }
++ }
++
++ gdb_test_no_output -nopass "events corefile_changed reset"
++ gdb_test_no_output -nopass "events exited reset"
++}
++
++# A helper proc runs clean_restart passing through ARGS, and then loads the
++# test's Python script.
++proc clean_restart_and_load_py_script { args } {
++ clean_restart {*}$args
++
++ # Load the Python script into GDB.
++ gdb_test "source $::remote_python_file" "^Success" \
++ "source python script"
++}
++
++# Create a copy of the corefile.
++set other_corefile [standard_output_file ${testfile}-other.core]
++remote_exec build "cp $corefile $other_corefile"
++
++clean_restart_and_load_py_script
++
++gdb_test_no_output "python inf = gdb.selected_inferior()" \
++ "capture current inferior"
++
++gdb_test "python print(inf.corefile)" "^None" \
++ "Inferior.corefile is None before loading a core file"
++
++core_file_cmd -corefile $corefile
++
++set file_re [string_to_regexp $corefile]
++gdb_test "python print(inf.corefile)" "^" \
++ "Inferior.corefile is a valid object after loading a core file"
++
++gdb_test_no_output "python core1=inf.corefile" "capture gdb.Corefile object"
++
++gdb_test "python print(core1.__dict__)" "^\\{\\}" \
++ "print Corefile.__dict__ when empty"
++
++gdb_test_no_output "python core1._my_attribute = \"Hello\"" \
++ "write new attribute into Corefile object"
++
++gdb_test "python print(core1._my_attribute)" "^Hello" \
++ "immediately read new attribute"
++
++gdb_test "python print(core1.__dict__)" "^\\{'_my_attribute': 'Hello'\\}" \
++ "print Corefile.__dict__ after adding an attribute"
++
++gdb_test "python print(core1.filename)" "^$file_re" \
++ "Corefile.filename attribute works as expected"
++
++gdb_test "python print(core1.is_valid())" "^True" \
++ "Corefile.is_valid() is True while corefile is loaded"
++
++core_file_cmd
++
++gdb_test "python print(core1.is_valid())" "^False" \
++ "Corefile.is_valid() is False after corefile is unloaded"
++
++gdb_test "python print(core1.__dict__)" "^\\{'_my_attribute': 'Hello'\\}" \
++ "print Corefile.__dict__ with attribute when invalid"
++
++gdb_test "python print(core1)" "^" \
++ "print an invalid gdb.Corefile object"
++
++gdb_test "python print(core1.filename)" \
++ [multi_line \
++ "Python Exception : Corefile no longer exists\\." \
++ "Error occurred in Python: Corefile no longer exists\\."] \
++ "error when reading filename from invalid Corefile"
++
++gdb_test "python print(inf.corefile)" "^None" \
++ "Inferior.corefile is None again after corefile unload"
++
++gdb_test "python print(core1._my_attribute)" "^Hello" \
++ "read new attribute from invalid core file"
++
++# Create a second inferior.
++gdb_test "add-inferior"
++gdb_test "inferior 2"
++
++with_test_prefix "in second inferior" {
++ core_file_cmd -corefile $corefile -inferior 2
++
++ gdb_test "python print(inf.corefile)" "^None" \
++ "first inferior still has no core file"
++
++ gdb_test_no_output "python core2=gdb.selected_inferior().corefile" \
++ "capture gdb.Corefile object"
++
++ # The _my_attribute was added to CORE1, not CORE2. Check it
++ # doesn't somehow appear on CORE2.
++ gdb_test "python print(core2._my_attribute)" \
++ "AttributeError.*: 'gdb\\.Corefile' object has no attribute '_my_attribute'" \
++ "try to read attribute that doesn't exist"
++
++ gdb_test "python print(core2.filename)" "^$file_re" \
++ "Corefile.filename attribute works as expected"
++
++ gdb_test "inferior 1"
++}
++
++# Read the name of the core file from the second program space while
++# the current program space is the first one.
++gdb_test "python print(core2.filename)" "^$file_re" \
++ "Corefile.filename attribute works from different progspace"
++
++# Load the other corefile into the first inferior.
++core_file_cmd -corefile $other_corefile \
++ -prefix "load other corefile into inferior 1"
++
++# Delete the second inferior. We need to switch to the second
++# inferior and unload its corefile before we can do that. Then,
++# switch back to the first inferior, delete the second, and try to
++# read the filename of the core file from the (now deleted) second
++# inferior. We should get an error about the gdb.Corefile being
++# invalid.
++with_test_prefix "remove second inferior" {
++ gdb_test "inferior 2"
++
++ gdb_test "python print(inf.corefile.filename)" \
++ "^[string_to_regexp $other_corefile]" \
++ "read inferior 1 corefile when in inferior 2"
++
++ gdb_test_no_output "python core1=inf.corefile" \
++ "capture inferior 1 gdb.Corefile while in inferior 2"
++
++ # This is a new CORE1 object, check that _my_attribute is gone.
++ gdb_test "python print(core1._my_attribute)" \
++ "AttributeError.*: 'gdb\\.Corefile' object has no attribute '_my_attribute'" \
++ "try to read attribute that doesn't exist"
++
++ core_file_cmd -inferior 2
++
++ gdb_test "python print(core2.filename)" \
++ [multi_line \
++ "Python Exception : Corefile no longer exists\\." \
++ "Error occurred in Python: Corefile no longer exists\\."] \
++ "error when reading filename from invalid Corefile"
++
++ gdb_test "inferior 1"
++
++ gdb_test "remove-inferiors 2"
++
++ gdb_test "python print(core2.is_valid())" "^False" \
++ "Corefile.is_valid() is False after corefile is unloaded, and Progspace is deleted"
++
++ gdb_test "python print(core2.filename)" \
++ [multi_line \
++ "Python Exception : Corefile no longer exists\\." \
++ "Error occurred in Python: Corefile no longer exists\\."] \
++ "error when reading filename of an invalid Corefile, from deleted program space"
++
++ gdb_test "python print(core1.is_valid())" "^True" \
++ "check inferior 1 core file is still valid"
++}
++
++# Test the Corefile.mapped_files() API. The Python script that is
++# sourced here implements 'info proc mappings' in Python using the
++# mapped_files API. The output from the built-in command, and the
++# Python command should be identical.
++with_test_prefix "test mapped files data" {
++ clean_restart_and_load_py_script
++
++ # Load the core file.
++ core_file_cmd -corefile $corefile
++
++ # Two files to write the output to.
++ set out_1 [standard_output_file ${gdb_test_file_name}-out-1.txt]
++ set out_2 [standard_output_file ${gdb_test_file_name}-out-2.txt]
++
++ # Run the built-in command, then the new Python command, capture
++ # the output.
++ gdb_test "pipe info proc mappings | tee $out_1" ".*" \
++ "capture built-in mappings output"
++ gdb_test "pipe info proc py-mappings | tee $out_2" ".*" \
++ "capture Python based mappings data"
++
++ # Check the output is identical.
++ gdb_test "shell diff -s $out_1 $out_2" \
++ "Files \[^\r\n\]+-out-1.txt and \[^\r\n\]+-out-2.txt are identical" \
++ "diff input and output one"
++
++ # Check build-ids within the core file mapping data.
++ gdb_test "check-build-ids" "^PASS"
++
++ # Check the is_main_executable flag in the mapping data.
++ gdb_test "check-main-executable" "^PASS"
++
++ # Check that the mapped files "list" is actually an immutable
++ # tuple.
++ gdb_test_no_output "python core = gdb.selected_inferior().corefile"
++ gdb_test_no_output "python mapped_files = core.mapped_files()"
++ gdb_test "python print(type(mapped_files))" \
++ "^"
++ gdb_test "python mapped_files\[0\] = None" \
++ "'tuple' object does not support item assignment"
++ gdb_test "python print(mapped_files\[0\] is None)" "^False"
++
++ # And same for the list of regions for a mapped file.
++ gdb_test_no_output "python regions = mapped_files\[0\].regions"
++ gdb_test "python print(type(regions))" \
++ "^"
++ gdb_test "python regions\[0\] = None" \
++ "'tuple' object does not support item assignment"
++}
++
++# Load a core file. GDB should figure out which file is being debugged.
++# Then use 'start' to run this executable, this will replace the core file
++# target. At least on Linux, this replacement is done without calling
++# target_detach. This test checks that the expected core file changed and
++# inferior exited events are still seen.
++with_test_prefix "start from corefile" {
++ if { [gdb_protocol_is_native] } {
++ clean_restart_and_load_py_script
++
++ # Load the core file.
++ core_file_cmd -corefile $corefile
++
++ # Check GDB figured out the executable.
++ gdb_test "info inferiors 1" \
++ "\[^\r\n\]+[string_to_regexp $binfile]\\s*" \
++ "check executable was detected correctly"
++
++ gdb_test "start" \
++ "Temporary breakpoint $::decimal, main \\(\\).*" \
++
++ gdb_test "events corefile_changed check" \
++ "Event 1/1, Inferior 1, Corefile None" \
++ "expected corefile event has been seen"
++
++ gdb_test "events exited check" \
++ "Event 1/1, Inferior 1, Exit Code None" \
++ "expected exited event has been seen"
++
++ gdb_test_no_output -nopass "events corefile_changed reset"
++ gdb_test_no_output -nopass "events exited reset"
++ }
++}
++
++# Load a core file, then load a different core file to replace it.
++# Check that the events that are emitted are as expected.
++with_test_prefix "load one core file over another" {
++ clean_restart_and_load_py_script
++
++ # Load the core file.
++ core_file_cmd -corefile $corefile \
++ -prefix "load first corefile"
++
++ core_file_cmd -corefile $other_corefile \
++ -prefix "load second corefile" \
++ -replacement
++}
+diff --git a/gdb/testsuite/gdb.python/py-corefile.py b/gdb/testsuite/gdb.python/py-corefile.py
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-corefile.py
+@@ -0,0 +1,261 @@
++# Copyright (C) 2025 Free Software Foundation, Inc.
++
++# 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 .
++
++import pathlib
++
++
++class Mapping:
++ def __init__(self, mapping, region):
++ self._mapping = mapping
++ self._region = region
++
++ @property
++ def start(self):
++ return self._region.start
++
++ @property
++ def end(self):
++ return self._region.end
++
++ @property
++ def offset(self):
++ return self._region.file_offset
++
++ @property
++ def filename(self):
++ return self._mapping.filename
++
++
++def info_proc_mappings():
++ print("Mapped address spaces:")
++ print("")
++ format_str = "%-18s %-18s %-18s %-18s %s "
++ print(format_str % ("Start Addr", "End Addr", "Size", "Offset", "File"))
++
++ core = gdb.selected_inferior().corefile
++ mappings = core.mapped_files()
++
++ result = []
++ for m in mappings:
++ for r in m.regions:
++ result.append(Mapping(m, r))
++
++ result.sort(key=lambda x: x.start)
++ for r in result:
++ sz = r.end - r.start
++ print(
++ format_str
++ % (
++ "0x%016x" % r.start,
++ "0x%016x" % r.end,
++ "0x%-16x" % sz,
++ "0x%-16x" % r.offset,
++ "%s" % r.filename,
++ )
++ )
++
++
++class InfoProcPyMappings(gdb.Command):
++ def __init__(self):
++ gdb.Command.__init__(self, "info proc py-mappings", gdb.COMMAND_DATA)
++
++ def invoke(self, args, from_tty):
++ info_proc_mappings()
++
++
++InfoProcPyMappings()
++
++
++class CheckBuildIds(gdb.Command):
++ def __init__(self):
++ gdb.Command.__init__(self, "check-build-ids", gdb.COMMAND_DATA)
++
++ def invoke(self, args, from_tty):
++ inf = gdb.selected_inferior()
++ objfiles = inf.progspace.objfiles()
++
++ path_to_build_id = {}
++
++ for o in objfiles:
++ if not o.is_file or o.build_id is None:
++ continue
++ p = pathlib.Path(o.filename).resolve()
++ b = o.build_id
++ path_to_build_id[p] = b
++
++ count = 0
++ core_mapped_files = inf.corefile.mapped_files()
++ for m in core_mapped_files:
++ p = pathlib.Path(m.filename).resolve()
++ b = m.build_id
++
++ if p in path_to_build_id:
++ count += 1
++ assert path_to_build_id[p] == b, "build-id mismatch for %s" % p
++
++ assert count > 0, "no mapped files checked"
++
++ print("PASS")
++
++
++CheckBuildIds()
++
++
++class CheckMainExec(gdb.Command):
++ def __init__(self):
++ gdb.Command.__init__(self, "check-main-executable", gdb.COMMAND_DATA)
++
++ def invoke(self, args, from_tty):
++ inf = gdb.selected_inferior()
++ pspace = inf.progspace
++ exec_filename = pathlib.Path(pspace.executable_filename).resolve()
++
++ count = 0
++ core_mapped_files = inf.corefile.mapped_files()
++ for m in core_mapped_files:
++ if not m.is_main_executable:
++ continue
++
++ p = pathlib.Path(m.filename).resolve()
++
++ count += 1
++ assert exec_filename == p, "main exec filename mismatch"
++
++ assert count == 1, "invalid main executable count"
++
++ print("PASS")
++
++
++CheckMainExec()
++
++
++# An 'events' prefix command.
++class events_cmd(gdb.Command):
++ """Information about recent Python events."""
++
++ def __init__(self):
++ gdb.Command.__init__(self, "events", gdb.COMMAND_USER, prefix=True)
++
++
++# An 'events corefile_changed' sub-command.
++class events_corefile_changed_cmd(gdb.Command):
++ """Check recent corefile_changed events.
++
++ Requires a single argument either 'check' or 'reset'. With
++ 'check', print details of every recent corefile_changed event.
++ With 'reset' clear the list of recent corefile_changed events."""
++
++ def __init__(self):
++ gdb.Command.__init__(self, "events corefile_changed", gdb.COMMAND_USER)
++ self._events = []
++ gdb.events.corefile_changed.connect(lambda e: self._corefile_changed_handler(e))
++
++ def _corefile_changed_handler(self, event):
++ assert isinstance(event, gdb.CorefileChangedEvent)
++ inf = event.inferior
++ assert isinstance(inf, gdb.Inferior)
++
++ corefile = inf.corefile
++ if corefile is not None:
++ assert corefile.is_valid()
++ corefile = corefile.filename
++
++ obj = {"inferior": inf.num, "corefile": corefile}
++ self._events.append(obj)
++
++ def invoke(self, args, from_tty):
++ if args == "check":
++ if len(self._events) == 0:
++ print("No corefile_changed event has been seen.")
++ else:
++ total = len(self._events)
++ for idx, obj in enumerate(self._events, start=1):
++ inf_num = obj["inferior"]
++ corefile = obj["corefile"]
++
++ if corefile is None:
++ msg = "None"
++ else:
++ msg = corefile
++
++ print(
++ "Event {}/{}, Inferior {}, Corefile {}".format(
++ idx, total, inf_num, msg
++ )
++ )
++ elif args == "reset":
++ self._events = []
++ else:
++ raise gdb.GdbError("Unknown command args: {}".format(args))
++
++
++# An 'events exited' sub-command.
++class events_exited_cmd(gdb.Command):
++ """Check recent exited events.
++
++ Requires a single argument either 'check' or 'reset'. With
++ 'check', print details of every recent exited event. With 'reset'
++ clear the list of recent exited events."""
++
++ def __init__(self):
++ gdb.Command.__init__(self, "events exited", gdb.COMMAND_USER)
++ self._events = []
++ gdb.events.exited.connect(lambda e: self._exited_handler(e))
++
++ def _exited_handler(self, event):
++ assert isinstance(event, gdb.ExitedEvent)
++ inf = event.inferior
++ assert isinstance(inf, gdb.Inferior)
++
++ if hasattr(event, "exit_code"):
++ assert isinstance(event.exit_code, int)
++ exit_code = event.exit_code
++ else:
++ exit_code = None
++
++ obj = {"inferior": inf.num, "exit_code": exit_code}
++ self._events.append(obj)
++
++ def invoke(self, args, from_tty):
++ if args == "check":
++ if len(self._events) == 0:
++ print("No exited event has been seen.")
++ else:
++ total = len(self._events)
++ for idx, obj in enumerate(self._events, start=1):
++ inf_num = obj["inferior"]
++ exit_code = obj["exit_code"]
++
++ if exit_code is None:
++ msg = "None"
++ else:
++ msg = exit_code
++
++ print(
++ "Event {}/{}, Inferior {}, Exit Code {}".format(
++ idx, total, inf_num, msg
++ )
++ )
++ elif args == "reset":
++ self._events = []
++ else:
++ raise gdb.GdbError("Unknown command args: {}".format(args))
++
++
++events_cmd()
++events_corefile_changed_cmd()
++events_exited_cmd()
++
++print("Success")
+diff --git a/gdb/testsuite/lib/dap-support.exp b/gdb/testsuite/lib/dap-support.exp
+--- a/gdb/testsuite/lib/dap-support.exp
++++ b/gdb/testsuite/lib/dap-support.exp
+@@ -362,6 +362,22 @@ proc dap_attach {pid {prog ""}} {
+ return [dap_send_request attach $args]
+ }
+
++# Start gdb, send a DAP initialize request, and then an attach request
++# specifying COREFILE as the core file to attach to. Returns the
++# empty string on failure, or the attach request sequence ID.
++proc dap_corefile {corefile {prog ""}} {
++ if {[dap_initialize "startup - initialize"] == ""} {
++ return ""
++ }
++
++ set args [format {o coreFile [s "%s"]} $corefile]
++ if {$prog != ""} {
++ append args [format { program [s "%s"]} $prog]
++ }
++
++ return [dap_send_request attach $args]
++}
++
+ # Start gdb, send a DAP initialize request, and then an attach request
+ # specifying TARGET as the remote target. Returns the empty string on
+ # failure, or the attach request sequence ID.
+@@ -372,26 +388,33 @@ proc dap_target_remote {target} {
+ return [dap_send_request attach [format {o target [s %s]} $target]]
+ }
+
+-# Read the most recent DAP log file and check it for exceptions.
+-proc dap_check_log_file {} {
++# Read the most recent DAP log file and check it for exceptions. We
++# expect to see exactly EXPECTED_EXCEPTION_COUNT exceptions in the log.
++proc dap_check_log_file { {expected_exception_count 0} } {
+ set fd [open [current_dap_log_file]]
+ set contents [read $fd]
+ close $fd
+
+- set ok 1
++ set exception_count 0
+ foreach line [split $contents "\n"] {
+ if {[regexp "^Traceback" $line]} {
+- set ok 0
+- break
++ incr exception_count
++ if { $exception_count > $expected_exception_count} {
++ break
++ }
+ }
+ }
+
+- if {$ok} {
++ if {$exception_count == $expected_exception_count} {
+ pass "exceptions in log file"
+ } else {
+ verbose -log -- "--- DAP LOG START ---"
+ verbose -log -- $contents
+ verbose -log -- "--- DAP LOG END ---"
++ if { $expected_exception_count > 0 } {
++ verbose -log -- [join [list "Expected $expected_exception_count" \
++ "exception(s), saw $exception_count"]]
++ }
+ fail "exceptions in log file"
+ }
+ }
+@@ -407,8 +430,9 @@ proc dap_check_log_file_re { re } {
+ }
+
+ # Cleanly shut down gdb. TERMINATE is passed as the terminateDebuggee
+-# parameter to the request.
+-proc dap_shutdown {{terminate false}} {
++# parameter to the request. The EXPECTED_EXCEPTION_COUNT is the
++# number of exceptions that we expect to see in the latest DAP log.
++proc dap_shutdown {{terminate false} {expected_exception_count 0}} {
+ dap_check_request_and_response "shutdown" disconnect \
+ [format {o terminateDebuggee [l %s]} $terminate]
+
+@@ -420,7 +444,7 @@ proc dap_shutdown {{terminate false}} {
+
+ clear_gdb_spawn_id
+
+- dap_check_log_file
++ dap_check_log_file $expected_exception_count
+ }
+
+ # Search the event list EVENTS for an output event matching the regexp
diff --git a/gdb-backport-libiberty-sync.patch b/gdb-backport-libiberty-sync.patch
new file mode 100644
index 0000000..a84d5e7
--- /dev/null
+++ b/gdb-backport-libiberty-sync.patch
@@ -0,0 +1,616 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess
+Date: Thu, 14 May 2026 09:22:42 +0000
+Subject: gdb-backport-libiberty-sync.patch
+
+;; Backport of upstream commit be3a9405ceb4d6d6 to fix RHBZ 2368350, an
+;; out of memory issue with the D demangler.
+;;
+;; The commit being pulled in here is a commit that syncs multiple
+;; commits to libiberty from gcc to binutils-gdb. Most of these commits
+;; are spelling and white space fixes, which should have no real impact.
+;; The only commit we actually care about is gcc commit bc4d9b6aeb3,
+;; which fixes the D demangler issue.
+;;
+;; This commit will not be needed once we rebase to GDB 18.
+
+libiberty: sync with gcc commit df3510f80e7c02d9
+
+Sync the libiberty/ directory with gcc commit
+df3510f80e7c02d9c19d7cb33759cd925880f53a. This pulls in the following
+gcc commits and the associated updates to 'libiberty/ChangeLog':
+
+ * 06fb00cb66d libiberty: Fix typos in various files
+ * fbf903e5b9f Re-flow lines made longer than 80 characters by typo fixes
+ * cfb945957ee Regenerate some autoconf configure scripts after recent spelling fixes.
+ * bc4d9b6aeb3 libiberty: avoid exponential back reference issue in D demangler
+
+I have retained the changes that are in the following binutils-gdb
+commit, which are not in gcc:
+
+ commit 219822fd5db6305592b45677a3b38c02b523360e
+ Date: Tue Apr 9 06:39:21 2024 -0700
+
+ mmap: Avoid the sanitizer configure check failure
+
+diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
+--- a/libiberty/ChangeLog
++++ b/libiberty/ChangeLog
+@@ -1,3 +1,62 @@
++2026-06-07 Andrew Burgess
++
++ * d-demangle.c (struct dlang_info::options): New field,
++ carries options passed to the demangler.
++ (struct dlang_info::num_backrefs): Count total number of back
++ referenced types that have been processed.
++ (struct dlang_info::backref_depth): Count the depth of
++ recursive back references.
++ (dlang_type_backref): Track recursive back reference depth,
++ and the total number of back references encountered. Bail out
++ early if the total number gets too high.
++ (dlang_demangle_init_info): Initialise new 'struct dlang_info'
++ fields.
++ (dlang_demangle): Pass demangler options to
++ dlang_demangle_init_info.
++ * testsuite/d-demangle-expected: Add new test.
++
++2026-06-01 Jakub Jelinek
++
++ * configure: Regenerate.
++
++2026-05-30 Dhruv Chawla
++
++ * simple-object-mach-o.c (simple_object_mach_o_write_segment): Reflow
++ long line.
++
++2026-05-30 Dhruv Chawla
++
++ * bcopy.c: Fix typos.
++ * bsearch.c: Likewise.
++ * bsearch_r.c: Likewise.
++ * configure.ac: Likewise.
++ * cp-demangle.c (d_print_comp_inner): Likewise.
++ (d_print_comp): Likewise.
++ * d-demangle.c (dlang_identifier): Likewise.
++ * dyn-string.c: Likewise.
++ * ldirname.c: Likewise.
++ * make-relative-prefix.c (make_relative_prefix_1): Likewise.
++ * obstacks.texi: Likewise.
++ * pex-win32.c (argv_to_cmdline): Likewise.
++ (spawn_script): Likewise.
++ * random.c (random): Likewise.
++ (setstate): Likewise.
++ * regex.c (WIDE_CHAR_SUPPORT): Likewise.
++ (convert_mbs_to_wcs): Likewise.
++ (PREFIX): Likewise.
++ (wcs_compile_range): Likewise.
++ (count_mbs_length): Likewise.
++ (wcs_re_match_2_internal): Likewise.
++ (byte_re_match_2_internal): Likewise.
++ * sigsetmask.c: Likewise.
++ * simple-object-elf.c (SHT_SYMTAB_SHNDX): Likewise.
++ (STV_HIDDEN): Likewise.
++ (simple_object_elf_copy_lto_debug_sections): Likewise.
++ * simple-object-mach-o.c (struct mach_o_header_32): Likewise.
++ (struct mach_o_header_64): Likewise.
++ (simple_object_mach_o_write_segment): Likewise.
++ * strsignal.c (defined): Likewise.
++
+ 2025-08-06 Matthieu Longo
+
+ * testsuite/test-doubly-linked-list.c: disable debug logging on
+diff --git a/libiberty/bcopy.c b/libiberty/bcopy.c
+--- a/libiberty/bcopy.c
++++ b/libiberty/bcopy.c
+@@ -1,4 +1,4 @@
+-/* bcopy -- copy memory regions of arbitary length
++/* bcopy -- copy memory regions of arbitrary length
+
+ @deftypefn Supplemental void bcopy (char *@var{in}, char *@var{out}, int @var{length})
+
+diff --git a/libiberty/bsearch.c b/libiberty/bsearch.c
+--- a/libiberty/bsearch.c
++++ b/libiberty/bsearch.c
+@@ -60,7 +60,7 @@ is respectively less than, matching, or greater than the array member.
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1. If lim is even, the same applies. If lim
+- * is odd, moving right again involes halving lim, this time moving
++ * is odd, moving right again involves halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+diff --git a/libiberty/bsearch_r.c b/libiberty/bsearch_r.c
+--- a/libiberty/bsearch_r.c
++++ b/libiberty/bsearch_r.c
+@@ -61,7 +61,7 @@ is respectively less than, matching, or greater than the array member.
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1. If lim is even, the same applies. If lim
+- * is odd, moving right again involes halving lim, this time moving
++ * is odd, moving right again involves halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+diff --git a/libiberty/configure b/libiberty/configure
+--- a/libiberty/configure
++++ b/libiberty/configure
+@@ -5967,7 +5967,7 @@ _ACEOF
+
+
+
+-# Check for presense of long long
++# Check for presence of long long
+ ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
+ if test "x$ac_cv_type_long_long" = xyes; then :
+
+diff --git a/libiberty/configure.ac b/libiberty/configure.ac
+--- a/libiberty/configure.ac
++++ b/libiberty/configure.ac
+@@ -302,7 +302,7 @@ AC_CHECK_SIZEOF([int])
+ AC_CHECK_SIZEOF([long])
+ AC_CHECK_SIZEOF([size_t])
+
+-# Check for presense of long long
++# Check for presence of long long
+ AC_CHECK_TYPE([long long],
+ [AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the `long long' type.]) AC_CHECK_SIZEOF([long long])],
+ [])
+diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
+--- a/libiberty/cp-demangle.c
++++ b/libiberty/cp-demangle.c
+@@ -82,7 +82,7 @@
+
+ IN_GLIBCPP_V3
+ If defined, this file defines only __cxa_demangle() and
+- __gcclibcxx_demangle_callback(), and no other publically visible
++ __gcclibcxx_demangle_callback(), and no other publicly visible
+ functions or variables.
+
+ STANDALONE_DEMANGLER
+@@ -5549,7 +5549,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
+ const struct d_component_stack *dcse;
+ int found_self_or_parent = 0;
+
+- /* This traversal is reentering SUB as a substition.
++ /* This traversal is reentering SUB as a substitution.
+ If we are not beneath SUB or DC in the tree then we
+ need to restore SUB's template stack temporarily. */
+ for (dcse = dpi->component_stack; dcse != NULL;
+@@ -6341,7 +6341,7 @@ d_print_comp (struct d_print_info *dpi, int options,
+ dpi->recursion--;
+ }
+
+-/* Print a Java dentifier. For Java we try to handle encoded extended
++/* Print a Java identifier. For Java we try to handle encoded extended
+ Unicode characters. The C++ ABI doesn't mention Unicode encoding,
+ so we don't it for C++. Characters are encoded as
+ __U+_. */
+diff --git a/libiberty/d-demangle.c b/libiberty/d-demangle.c
+--- a/libiberty/d-demangle.c
++++ b/libiberty/d-demangle.c
+@@ -175,8 +175,33 @@ struct dlang_info
+ {
+ /* The string we are demangling. */
+ const char *s;
++
++ /* The options passed to the demangler. */
++ int options;
++
+ /* The index of the last back reference. */
+ int last_backref;
++
++ /* The total number of back referenced types, including nested back
++ referenced types. This is reset to zero each time a back
++ reference is processed at the "top level" (i.e. not a nested back
++ reference).
++
++ Cases have been encountered where a back reference type includes
++ references to other back reference types, which include further
++ back references. This was observed to a depth of 57. If each
++ layer only references the layer before twice then the innermost
++ string will be duplicated 2^57 times!
++
++ We count the number of nested back references and compare this to
++ the recursion limit, even though this isn't strictly recursion. */
++ int num_backrefs;
++
++ /* Track the depth of back references. Depth 0 is considered the
++ top level. When we encounter a back reference at this depth the
++ NUM_BACKREFS field is reset to 0. At greater depths,
++ NUM_BACKREFS will be incremented. */
++ int backref_depth;
+ };
+
+ /* Pass as the LEN to dlang_parse_template if symbol length is not known. */
+@@ -411,6 +436,24 @@ dlang_type_backref (string *decl, const char *mangled, struct dlang_info *info,
+ if (mangled - info->s >= info->last_backref)
+ return NULL;
+
++ /* A back reference might point to a type that itself contains back
++ references, which might themselves contain back references.
++ There might not be recursion going on, but we can run into
++ problems of exponential growth caused by the inner type appearing
++ to be referenced 10s of millions of times. */
++ if (info->backref_depth > 0)
++ {
++ if ((info->options & DMGL_NO_RECURSE_LIMIT) == 0
++ && info->num_backrefs > DEMANGLE_RECURSION_LIMIT)
++ return NULL;
++
++ info->num_backrefs++;
++ }
++ else
++ info->num_backrefs = 0;
++
++ info->backref_depth++;
++
+ int save_refpos = info->last_backref;
+ info->last_backref = mangled - info->s;
+
+@@ -424,6 +467,7 @@ dlang_type_backref (string *decl, const char *mangled, struct dlang_info *info,
+ backref = dlang_type (decl, backref, info);
+
+ info->last_backref = save_refpos;
++ info->backref_depth--;
+
+ if (backref == NULL)
+ return NULL;
+@@ -1067,7 +1111,7 @@ dlang_identifier (string *decl, const char *mangled, struct dlang_info *info)
+ }
+
+ /* Extract the plain identifier from MANGLED and prepend/append it to DECL
+- with special treatment for some magic compiler generted symbols.
++ with special treatment for some magic compiler generated symbols.
+ Return the remaining string on success or NULL on failure. */
+ static const char *
+ dlang_lname (string *decl, const char *mangled, unsigned long len)
+@@ -1931,17 +1975,20 @@ dlang_parse_template (string *decl, const char *mangled,
+ /* Initialize the information structure we use to pass around information. */
+ static void
+ dlang_demangle_init_info (const char *mangled, int last_backref,
+- struct dlang_info *info)
++ int options, struct dlang_info *info)
+ {
+ info->s = mangled;
++ info->options = options;
+ info->last_backref = last_backref;
++ info->num_backrefs = 0;
++ info->backref_depth = 0;
+ }
+
+ /* Extract and demangle the symbol in MANGLED. Returns the demangled
+ signature on success or NULL on failure. */
+
+ char *
+-dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
++dlang_demangle (const char *mangled, int options)
+ {
+ string decl;
+ char *demangled = NULL;
+@@ -1962,7 +2009,7 @@ dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
+ {
+ struct dlang_info info;
+
+- dlang_demangle_init_info (mangled, strlen (mangled), &info);
++ dlang_demangle_init_info (mangled, strlen (mangled), options, &info);
+ mangled = dlang_parse_mangle (&decl, mangled, &info);
+
+ /* Check that the entire symbol was successfully demangled. */
+diff --git a/libiberty/dyn-string.c b/libiberty/dyn-string.c
+--- a/libiberty/dyn-string.c
++++ b/libiberty/dyn-string.c
+@@ -49,8 +49,8 @@ Boston, MA 02110-1301, USA. */
+ function can be used with a dyn_string struct on the stack or
+ embedded in another object. The contents of the string itself
+ are still dynamically allocated. The string initially is capable
+- of holding at least SPACE characeters, including the terminating
+- NUL. If SPACE is 0, it will silently be increated to 1.
++ of holding at least SPACE characters, including the terminating
++ NUL. If SPACE is 0, it will silently be increased to 1.
+
+ If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
+ fails, returns 0. Otherwise returns 1. */
+diff --git a/libiberty/ldirname.c b/libiberty/ldirname.c
+--- a/libiberty/ldirname.c
++++ b/libiberty/ldirname.c
+@@ -26,7 +26,7 @@ Given a pointer to a string containing a typical pathname
+ (@samp{/usr/src/cmd/ls/ls.c} for example), returns a string containing the
+ passed string up to, but not including, the final directory separator.
+
+-If the given pathname doesn't contain a directory separator then this funtion
++If the given pathname doesn't contain a directory separator then this function
+ returns the empty string; this includes an empty given pathname. @code{NULL}
+ is returned on memory allocation error.
+
+diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c
+--- a/libiberty/make-relative-prefix.c
++++ b/libiberty/make-relative-prefix.c
+@@ -410,7 +410,7 @@ make_relative_prefix_1 (const char *progname, const char *bin_prefix,
+ /* Do the full job, including symlink resolution.
+ This path will find files installed in the same place as the
+ program even when a soft link has been made to the program
+- from somwhere else. */
++ from somewhere else. */
+
+ char *
+ make_relative_prefix (const char *progname, const char *bin_prefix,
+diff --git a/libiberty/obstacks.texi b/libiberty/obstacks.texi
+--- a/libiberty/obstacks.texi
++++ b/libiberty/obstacks.texi
+@@ -695,7 +695,7 @@ Initialize use of an obstack, with an initial chunk of
+ @var{chunk_size} bytes.
+
+ @item int obstack_specify_allocation (struct obstack *@var{obstack-ptr}, size_t chunk_size, size_t alignment, void *(*chunkfun) (size_t), void (*freefun) (void *))
+-Initialize use of an obstack, specifying intial chunk size, chunk
++Initialize use of an obstack, specifying initial chunk size, chunk
+ alignment, and memory allocation functions.
+
+ @item int obstack_specify_allocation_with_arg (struct obstack *@var{obstack-ptr}, size_t chunk_size, size_t alignment, void *(*chunkfun) (void *, size_t), void (*freefun) (void *, void *), void *arg)
+diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c
+--- a/libiberty/pex-win32.c
++++ b/libiberty/pex-win32.c
+@@ -350,7 +350,7 @@ argv_to_cmdline (char *const *argv)
+ /* We only quote arguments that contain spaces, \t or " characters to
+ prevent wasting 2 chars per argument of the CreateProcess 32k char
+ limit. We need only escape embedded double-quotes and immediately
+- preceeding backslash characters. A sequence of backslach characters
++ preceding backslash characters. A sequence of backslach characters
+ that is not followed by a double quote character will not be
+ escaped. */
+ needs_quotes = 0;
+@@ -363,7 +363,7 @@ argv_to_cmdline (char *const *argv)
+
+ if (argv[i][j] == '"')
+ {
+- /* Escape preceeding backslashes. */
++ /* Escape preceding backslashes. */
+ for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
+ cmdline_len++;
+ /* Escape the quote character. */
+@@ -695,7 +695,7 @@ spawn_script (struct pex_obj *obj,
+ int fd = _open (executable, _O_RDONLY);
+
+ /* Try to open script, check header format, extract interpreter path,
+- and spawn script using that interpretter. */
++ and spawn script using that interpreter. */
+ if (fd >= 0)
+ {
+ char buf[MAX_PATH + 5];
+diff --git a/libiberty/random.c b/libiberty/random.c
+--- a/libiberty/random.c
++++ b/libiberty/random.c
+@@ -88,7 +88,7 @@ long int random (void);
+ then initialized to contain information for random number generation with
+ that much state information. Good sizes for the amount of state
+ information are 32, 64, 128, and 256 bytes. The state can be switched by
+- calling the setstate() function with the same array as was initiallized
++ calling the setstate() function with the same array as was initialized
+ with initstate(). By default, the package runs with 128 bytes of state
+ information and generates far better random numbers than a linear
+ congruential generator. If the amount of state information is less than
+@@ -362,7 +362,7 @@ setstate (void *arg_state)
+
+ /* If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
+- same in all ther other cases due to all the global variables that have been
++ same in all the other cases due to all the global variables that have been
+ set up. The basic operation is to add the number at the rear pointer into
+ the one at the front pointer. Then both pointers are advanced to the next
+ location cyclically in the table. The value returned is the sum generated,
+diff --git a/libiberty/regex.c b/libiberty/regex.c
+--- a/libiberty/regex.c
++++ b/libiberty/regex.c
+@@ -58,7 +58,7 @@
+
+ # define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
+
+-/* For platform which support the ISO C amendement 1 functionality we
++/* For platform which support the ISO C amendment 1 functionality we
+ support user defined character classes. */
+ # if defined _LIBC || WIDE_CHAR_SUPPORT
+ /* Solaris 2.5 has a bug: must be included before . */
+@@ -1235,7 +1235,7 @@ printchar (int c)
+
+ # ifdef WCHAR
+ /* This convert a multibyte string to a wide character string.
+- And write their correspondances to offset_buffer(see below)
++ And write their correspondences to offset_buffer(see below)
+ and write whether each wchar_t is binary data to is_binary.
+ This assume invalid multibyte sequences as binary data.
+ We assume offset_buffer and is_binary is already allocated
+@@ -1247,7 +1247,7 @@ static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src,
+ static size_t
+ convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len,
+ int *offset_buffer, char *is_binary)
+- /* It hold correspondances between src(char string) and
++ /* It hold correspondences between src(char string) and
+ dest(wchar_t string) for optimization.
+ e.g. src = "xxxyzz"
+ dest = {'X', 'Y', 'Z'}
+@@ -1281,7 +1281,7 @@ convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len,
+
+ if (consumed <= 0)
+ /* failed to convert. maybe src contains binary data.
+- So we consume 1 byte manualy. */
++ So we consume 1 byte manually. */
+ {
+ *pdest = *psrc;
+ consumed = 1;
+@@ -2174,7 +2174,7 @@ typedef struct
+ # ifndef DEFINED_ONCE
+ # if defined _LIBC || WIDE_CHAR_SUPPORT
+ /* The GNU C library provides support for user-defined character classes
+- and the functions from ISO C amendement 1. */
++ and the functions from ISO C amendment 1. */
+ # ifdef CHARCLASS_NAME_MAX
+ # define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+ # else
+@@ -3416,7 +3416,7 @@ PREFIX(regex_compile) (const char *ARG_PREFIX(pattern),
+ int32_t idx2 = table[ch];
+ size_t len = weights[idx2];
+
+- /* Test whether the lenghts match. */
++ /* Test whether the lengths match. */
+ if (weights[idx] == len)
+ {
+ /* They do. New compare the bytes of
+@@ -4389,7 +4389,7 @@ wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr,
+ {
+ /* range_start is a collating symbol. */
+ int32_t *wextra;
+- /* Retreive the index and get collation sequence value. */
++ /* Retrieve the index and get collation sequence value. */
+ wextra = (int32_t*)(extra + char_set[-range_start_char]);
+ start_val = wextra[1 + *wextra];
+ }
+@@ -5502,7 +5502,7 @@ count_mbs_length(int *offset_buffer, int length)
+ return 0;
+
+ /* If there are no multibyte character, offset_buffer[i] == i.
+- Optmize for this case. */
++ Optimize for this case. */
+ if (offset_buffer[length] == length)
+ return length;
+
+@@ -5538,7 +5538,7 @@ wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
+ struct re_registers *regs,
+ int stop,
+ /* string1 == string2 == NULL means string1/2, size1/2 and
+- mbs_offset1/2 need seting up in this function. */
++ mbs_offset1/2 need setting up in this function. */
+ /* We need wchar_t* buffers correspond to cstring1, cstring2. */
+ wchar_t *string1, int size1,
+ wchar_t *string2, int size2,
+@@ -5739,7 +5739,7 @@ byte_re_match_2_internal (struct re_pattern_buffer *bufp,
+ fill them with converted string. */
+ if (string1 == NULL && string2 == NULL)
+ {
+- /* We need seting up buffers here. */
++ /* We need setting up buffers here. */
+
+ /* We must free wcs buffers in this function. */
+ cant_free_wcs_buf = 0;
+diff --git a/libiberty/sigsetmask.c b/libiberty/sigsetmask.c
+--- a/libiberty/sigsetmask.c
++++ b/libiberty/sigsetmask.c
+@@ -1,7 +1,7 @@
+ /* Version of sigsetmask.c
+ Written by Steve Chamberlain (sac@cygnus.com).
+ Contributed by Cygnus Support.
+- This file is in the public doamin. */
++ This file is in the public domain. */
+
+ /*
+
+diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
+--- a/libiberty/simple-object-elf.c
++++ b/libiberty/simple-object-elf.c
+@@ -198,7 +198,7 @@ typedef struct {
+ #define SHT_RELA 4 /* Relocation entries with addends */
+ #define SHT_REL 9 /* Relocation entries, no addends */
+ #define SHT_GROUP 17 /* Section contains a section group */
+-#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
++#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
+
+ /* Values for sh_flags field. */
+
+@@ -246,7 +246,7 @@ typedef struct
+ #define STB_WEAK 2 /* Weak global */
+
+ #define STV_DEFAULT 0 /* Visibility is specified by binding type */
+-#define STV_HIDDEN 2 /* Can only be seen inside currect component */
++#define STV_HIDDEN 2 /* Can only be seen inside current component */
+
+ /* Functions to fetch and store different ELF types, depending on the
+ endianness and size. */
+@@ -1512,7 +1512,7 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ of __gnu_lto_slim symbol. */
+ if (st_shndx == SHN_COMMON)
+ discard = 1;
+- /* We also need to remove symbols refering to sections
++ /* We also need to remove symbols referring to sections
+ we'll eventually remove as with fat LTO objects
+ we otherwise get duplicate symbols at final link
+ (with GNU ld, gold is fine and ignores symbols in
+diff --git a/libiberty/simple-object-mach-o.c b/libiberty/simple-object-mach-o.c
+--- a/libiberty/simple-object-mach-o.c
++++ b/libiberty/simple-object-mach-o.c
+@@ -53,7 +53,7 @@ struct mach_o_header_32
+ unsigned char filetype[4]; /* Type of file. */
+ unsigned char ncmds[4]; /* Number of load commands. */
+ unsigned char sizeofcmds[4]; /* Total size of load commands. */
+- unsigned char flags[4]; /* Flags for special featues. */
++ unsigned char flags[4]; /* Flags for special features. */
+ };
+
+ /* Mach-O header (64-bit version). */
+@@ -66,7 +66,7 @@ struct mach_o_header_64
+ unsigned char filetype[4]; /* Type of file. */
+ unsigned char ncmds[4]; /* Number of load commands. */
+ unsigned char sizeofcmds[4]; /* Total size of load commands. */
+- unsigned char flags[4]; /* Flags for special featues. */
++ unsigned char flags[4]; /* Flags for special features. */
+ unsigned char reserved[4]; /* Reserved. Duh. */
+ };
+
+@@ -1204,8 +1204,8 @@ simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
+ unsigned int i;
+
+ /* Write the section header for the wrapper. */
+- /* Account for any initial aligment - which becomes the alignment for this
+- created section. */
++ /* Account for any initial alignment - which becomes the alignment for
++ this created section. */
+
+ secsize = (offset - index[0]);
+ if (!simple_object_mach_o_write_section_header (sobj, descriptor,
+@@ -1218,7 +1218,7 @@ simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
+ errmsg, err))
+ return 0;
+
+- /* Subtract the wrapper section start from the begining of each sub
++ /* Subtract the wrapper section start from the beginning of each sub
+ section. */
+
+ for (i = 1; i < nsects_in; ++i)
+diff --git a/libiberty/strsignal.c b/libiberty/strsignal.c
+--- a/libiberty/strsignal.c
++++ b/libiberty/strsignal.c
+@@ -152,7 +152,7 @@ static const struct signal_info signal_table[] =
+ #endif
+ #if defined (SIGIO)
+ /* "I/O pending" has also been suggested, but is misleading since the
+- signal only happens when the process has asked for it, not everytime
++ signal only happens when the process has asked for it, not every time
+ I/O is pending. */
+ ENTRY(SIGIO, "SIGIO", "I/O possible"),
+ #endif
+@@ -208,7 +208,7 @@ static const struct signal_info signal_table[] =
+ ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"),
+ #endif
+ #if defined (SIGRETRACT)
+- ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"),
++ ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinquish monitor mode"),
+ #endif
+ #if defined (SIGMSG)
+ ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"),
+diff --git a/libiberty/testsuite/d-demangle-expected b/libiberty/testsuite/d-demangle-expected
+--- a/libiberty/testsuite/d-demangle-expected
++++ b/libiberty/testsuite/d-demangle-expected
+@@ -1475,3 +1475,15 @@ demangle.anonymous.foo
+ --format=auto
+ _D8demangle9anonymous03fooZ
+ demangle.anonymous.foo
++#
++# This symbol was seen in the wild. It has a pattern of back
++# references that result in exponential growth, with the innermost
++# type being referenced 10s of millions of times. We use the
++# demangler's recursion limit to place a hard cap on back reference
++# usage, which causes the demangler to safely bail out before
++# consuming an excessive amount of memory. Trying to demangle this
++# without the recursion limit in place will eventually cause the OOM
++# killer to kick in.
++--format=dlang
++_D3std6format5write__T14formattedWriteTDFAxaZvTaTS2ae5utils4text7functor__T13stringifiableTSQBqQBqQBi10primitives__TQCaSQCsQCsQCk11composition__T3seqTSQDxQDxQDpQCh__TQDySQEqQEqQEnQEl__T17formattingFunctorVAyaa2_2573Vii250TQrZ15__lambda_L40_C3TQBmZ7FunctorTSQHzQHzQHrQGj__TQIaSQIsQIsQIpQIn__TQEcVQDma2_2573Vii250TSQKdQKdQKaQJy__TQJtTSQKxQKxQKpQJh__TQKyS4btdu2ui6curses6Curses4Wand__T8withAttrTSQNfQNfQNcQNa__TQMvTSQNzQNzQNrQMj__TQOaSQOsQOsQOkQMa__T6selectTSQPqQPqQPiQOa__TQPrSQQjQQjQQbQOt__T12valueFunctorTbZQrFbZ17__lambda_L143_C57TbZQLbTSQSvQSvQSnQRf__TQSwSQToQToQTlQTj__T5fmtIfVQOlnTbTPFNaNbNiNfZQPdTSQVhQVhQUzQTr__TQViSQKkQKi7browser7Browser6updateMFZ__T17__lambda_L1185_C4TQSeTSQYiQYiQYfQYd__TQXyTSQZcQZcQYuQXm__TQZdSQZvQZvQZnQXd__TQLdTQKzTSQBAtQBAuQBAnQZg__TQBAxSQBBqQBBrQBBpQBBo__TQIgVQWonTbTSQBCvQBCwQBCpQBBi__TQBDaSQBDtQBDuQBDnQBCg__TQNoTSQBErQBEsQBEqQBEp__TQBElTSQBFqQBFrQBFkQBEd__TQBFvSQBGoQBGpQBGiQBDz__TQBDqTSQBHnQBHoQBHhQBGa__TQBHsSQBIlQBImQBIkQBIj__TQBDzVQBDka2_2573Vii250TSQBKcQBKdQBKbQBKa__TQBJwTSQBLbQBLcQBKvQBJo__TQBLgSQBAjQBAiQBAjQBAgQBAd__TQBAcTQBHcTSQBNhQBNiQBNgQBNf__TQBNbTSQBOgQBOhQBOaQBMt__TQBOlSQBDoQBDnQBDoQBDlQBDi__TQBDhTQBKhZQBDrMFEQBFcQBFbQBFcQBEzQBEw9AttributebKQBLzZ19__lambda_L503_C20_1TPSQBHlQBHkQBHlQBHiQBHfTQDfTbTSQBUdQBUeQBUcQBUb__TQBTxTSQBVcQBVdQBUwQBTp__TQBVhSQBWaQBWbQBVuQBTl__TQBTcTQBTcZ3funTQBTmZQBPyZQBWtFQCwZ13StringifiableZQBRcZQBXxFQKwZQBeTQBTkZQBMuMFQJdbQBTzQMwQBUgZ17__lambda_L503_C20TQIfTQKrTbTSQCBpQCBqQCBoQCBn__TQCBjTSQCCoQCCpQCCiQCBb__TQCCtSQCDmQCDnQCDgQCAx__TQCAoTQCAoTSQCEqQCErQCEkQCDd__TQCEvSQCFoQCFpQCFnQCFm__TQCBcVQCAna2_2573Vii250TQTyZ17__lambda_L40_C3_1TQUwZQCArTQCEpZQLnTQCEyTQEkTQCFhZQCBtZQCIoFQHfZQLvZQCClZQCJgFQZkZQMnZ17__lambda_L40_C3_3TQBBlZQCEcTQCIaTQBEpZQPdTQBEyTQCItTQBFiZQCFkZQCMfFQBHuZQPnZQBWuFQBJhZ19__lambda_L143_C57_1TQBKiZQCHoTSQCPjQCPkQCPdQCNw__TQCPoSQCQhQCQiQCQbQCOu__TQCAcTQBHeZQCAmFQBHoZ19__lambda_L143_C57_2TQBIpZQCLgZQBYxFNibQBQoQEeZQWnTQBRaZQCMkTSQCUfQCUgQCTzQCSs__TQCUkSQCVdQCVeQCVcQCVb__TQCBtVQCQcnTbTQBTpTQHgZQCCpFNibQBUgQHwZQBAfTQIfZQCQcZQBAtTQCImTQBXoTQEhZQCRaZQCXvFQBZyZQBBdZQCCaMFQCTqQCBmbSQCOjQCOiQCEbQCDx13ScrollContextPSQCPq5paths11BrowserPathZ20__lambda_L1195_C76_1TQBxZQCVqZQCJhFNibQCJbQCIqZQBGyTQCJpZQCWwTSQDErQDEsQDElQDDe__TQDEwSQDFpQDFqQDFoQDFn__TQCMfVQDAonTbTQCMeTQCLuZQCNcFNibQCMwQCMlZQBKtTQCMvZQDArZQBLiTQCTbTQCQbTQEkZQDBpZQDIkFQCVqZQBLsZQCXeMFQBTnbQCXfZ19__lambda_L503_C20_2TQBSlTQBUyTbTSQDLxQDLyQDLwQDLv__TQDLrTSQDMwQDMxQDMqQDLj__TQDNbSQDNuQDNvQDNoQDLf__TQDKwTSQDOtQDOuQDOnQDNg__TQDOySQDPrQDPsQDPqQDPp__TQDLfVQDKqa2_2573Vii250TQDEdZ17__lambda_L40_C3_7TQDFcZQDKwZQBVnTQEdZQDLkZQDSfFQGoZQBVmZQDMdZQDSyFQDJgZQBWgZ17__lambda_L40_C3_8TQDLeZQDNwZQBYnTQDRzTQDOcZQDOqZQDVlFQDVaZQBYtZQDYbFKQDXqMxAaQDXoZk
++_D3std6format5write__T14formattedWriteTDFAxaZvTaTS2ae5utils4text7functor__T13stringifiableTSQBqQBqQBi10primitives__TQCaSQCsQCsQCk11composition__T3seqTSQDxQDxQDpQCh__TQDySQEqQEqQEnQEl__T17formattingFunctorVAyaa2_2573Vii250TQrZ15__lambda_L40_C3TQBmZ7FunctorTSQHzQHzQHrQGj__TQIaSQIsQIsQIpQIn__TQEcVQDma2_2573Vii250TSQKdQKdQKaQJy__TQJtTSQKxQKxQKpQJh__TQKyS4btdu2ui6curses6Curses4Wand__T8withAttrTSQNfQNfQNcQNa__TQMvTSQNzQNzQNrQMj__TQOaSQOsQOsQOkQMa__T6selectTSQPqQPqQPiQOa__TQPrSQQjQQjQQbQOt__T12valueFunctorTbZQrFbZ17__lambda_L143_C57TbZQLbTSQSvQSvQSnQRf__TQSwSQToQToQTlQTj__T5fmtIfVQOlnTbTPFNaNbNiNfZQPdTSQVhQVhQUzQTr__TQViSQKkQKi7browser7Browser6updateMFZ__T17__lambda_L1185_C4TQSeTSQYiQYiQYfQYd__TQXyTSQZcQZcQYuQXm__TQZdSQZvQZvQZnQXd__TQLdTQKzTSQBAtQBAuQBAnQZg__TQBAxSQBBqQBBrQBBpQBBo__TQIgVQWonTbTSQBCvQBCwQBCpQBBi__TQBDaSQBDtQBDuQBDnQBCg__TQNoTSQBErQBEsQBEqQBEp__TQBElTSQBFqQBFrQBFkQBEd__TQBFvSQBGoQBGpQBGiQBDz__TQBDqTSQBHnQBHoQBHhQBGa__TQBHsSQBIlQBImQBIkQBIj__TQBDzVQBDka2_2573Vii250TSQBKcQBKdQBKbQBKa__TQBJwTSQBLbQBLcQBKvQBJo__TQBLgSQBAjQBAiQBAjQBAgQBAd__TQBAcTQBHcTSQBNhQBNiQBNgQBNf__TQBNbTSQBOgQBOhQBOaQBMt__TQBOlSQBDoQBDnQBDoQBDlQBDi__TQBDhTQBKhZQBDrMFEQBFcQBFbQBFcQBEzQBEw9AttributebKQBLzZ19__lambda_L503_C20_1TPSQBHlQBHkQBHlQBHiQBHfTQDfTbTSQBUdQBUeQBUcQBUb__TQBTxTSQBVcQBVdQBUwQBTp__TQBVhSQBWaQBWbQBVuQBTl__TQBTcTQBTcZ3funTQBTmZQBPyZQBWtFQCwZ13StringifiableZQBRcZQBXxFQKwZQBeTQBTkZQBMuMFQJdbQBTzQMwQBUgZ17__lambda_L503_C20TQIfTQKrTbTSQCBpQCBqQCBoQCBn__TQCBjTSQCCoQCCpQCCiQCBb__TQCCtSQCDmQCDnQCDgQCAx__TQCAoTQCAoTSQCEqQCErQCEkQCDd__TQCEvSQCFoQCFpQCFnQCFm__TQCBcVQCAna2_2573Vii250TQTyZ17__lambda_L40_C3_1TQUwZQCArTQCEpZQLnTQCEyTQEkTQCFhZQCBtZQCIoFQHfZQLvZQCClZQCJgFQZkZQMnZ17__lambda_L40_C3_3TQBBlZQCEcTQCIaTQBEpZQPdTQBEyTQCItTQBFiZQCFkZQCMfFQBHuZQPnZQBWuFQBJhZ19__lambda_L143_C57_1TQBKiZQCHoTSQCPjQCPkQCPdQCNw__TQCPoSQCQhQCQiQCQbQCOu__TQCAcTQBHeZQCAmFQBHoZ19__lambda_L143_C57_2TQBIpZQCLgZQBYxFNibQBQoQEeZQWnTQBRaZQCMkTSQCUfQCUgQCTzQCSs__TQCUkSQCVdQCVeQCVcQCVb__TQCBtVQCQcnTbTQBTpTQHgZQCCpFNibQBUgQHwZQBAfTQIfZQCQcZQBAtTQCImTQBXoTQEhZQCRaZQCXvFQBZyZQBBdZQCCaMFQCTqQCBmbSQCOjQCOiQCEbQCDx13ScrollContextPSQCPq5paths11BrowserPathZ20__lambda_L1195_C76_1TQBxZQCVqZQCJhFNibQCJbQCIqZQBGyTQCJpZQCWwTSQDErQDEsQDElQDDe__TQDEwSQDFpQDFqQDFoQDFn__TQCMfVQDAonTbTQCMeTQCLuZQCNcFNibQCMwQCMlZQBKtTQCMvZQDArZQBLiTQCTbTQCQbTQEkZQDBpZQDIkFQCVqZQBLsZQCXeMFQBTnbQCXfZ19__lambda_L503_C20_2TQBSlTQBUyTbTSQDLxQDLyQDLwQDLv__TQDLrTSQDMwQDMxQDMqQDLj__TQDNbSQDNuQDNvQDNoQDLf__TQDKwTSQDOtQDOuQDOnQDNg__TQDOySQDPrQDPsQDPqQDPp__TQDLfVQDKqa2_2573Vii250TQDEdZ17__lambda_L40_C3_7TQDFcZQDKwZQBVnTQEdZQDLkZQDSfFQGoZQBVmZQDMdZQDSyFQDJgZQBWgZ17__lambda_L40_C3_8TQDLeZQDNwZQBYnTQDRzTQDOcZQDOqZQDVlFQDVaZQBYtZQDYbFKQDXqMxAaQDXoZk
diff --git a/gdb-fileio-test-fixes.patch b/gdb-fileio-test-fixes.patch
new file mode 100644
index 0000000..045cb38
--- /dev/null
+++ b/gdb-fileio-test-fixes.patch
@@ -0,0 +1,89 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Kevin Buettner
+Date: Wed, 25 Feb 2026 20:02:22 -0700
+Subject: gdb-fileio-test-fixes.patch
+
+;; Backport of upstream commit d2cc16cd7fc from Jan Vrany fixing
+;; FAILs in gdb.base/fileio.exp caused by macro expansion of
+;; path components in OUTDIR.gdb/testsuite: fix FAILs in fileio.exp
+
+I'm experiencing intermittent FAILs in fileio.exp when running on (my)
+CI:
+
+ FAIL: gdb.base/fileio.exp: Open a file
+ FAIL: gdb.base/fileio.exp: Creating already existing file returns EEXIST
+ FAIL: gdb.base/fileio.exp: Open for write but no write permission returns EACCES
+ FAIL: gdb.base/fileio.exp: Writing to a file
+ ...
+
+The problem turned out to be the way the OUTDIR gets defined in fileio.c.
+The path is passed down "naked" and turned into string by STRINGIFY macro.
+
+However, if the path happens to contain name of unrelated pre-existing
+C macro, this macro gets expanded during the "stringification", resulting
+in (likely) different path than used in fileio.exp and therefore causing
+failures.
+
+For example, if the GDB is compiled and tested in directory
+
+ /var/lib/jenkins/workspace/binutils-gdb/build/x86_64-linux-gnu
+
+then fileio.c is compiled with
+
+ -DOUTDIR_=/var/lib/jenkins/workspace/binutils-gdb/build/x86_64-linux-gnu/gdb/testsuite/outputs/gdb.base/fileio
+
+But because there's also C macro named "linux" defined to 1, the resulting
+OUTDIR is actually:
+
+ /var/lib/jenkins/workspace/binutils-gdb/build/x86_64-1-gnu/gdb/testsuite/outputs/gdb.base/fileio
+
+This commit fixes this by defining the OUTDIR as string literal in first
+place (similarly to how it was done prior commit cc91060) and updating
+quote_for_host to handle strings that themselves contains quote (").
+
+Tested on x86_64-linux by running all tests using quote_for_host with
+both target board unix and host/target board local-remote-host-native.
+
+Approved-By: Tom Tromey
+
+diff --git a/gdb/testsuite/gdb.base/fileio.c b/gdb/testsuite/gdb.base/fileio.c
+--- a/gdb/testsuite/gdb.base/fileio.c
++++ b/gdb/testsuite/gdb.base/fileio.c
+@@ -73,10 +73,6 @@ static const char *strerrno (int err);
+
+ #define STRING "Hello World"
+
+-#define STRINGIFY(s) STRINGIFY_(s)
+-#define STRINGIFY_(s) #s
+-#define OUTDIR STRINGIFY (OUTDIR_)
+-
+ static void stop (void) {}
+
+ /* A NULL string. We pass this to stat below instead of a NULL
+diff --git a/gdb/testsuite/gdb.base/fileio.exp b/gdb/testsuite/gdb.base/fileio.exp
+--- a/gdb/testsuite/gdb.base/fileio.exp
++++ b/gdb/testsuite/gdb.base/fileio.exp
+@@ -27,7 +27,7 @@ if {[is_remote host]} {
+
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable \
+- [list debug additional_flags=[quote_for_host -DOUTDIR_=$outdir/]]] != "" } {
++ [list debug additional_flags=[quote_for_host -DOUTDIR=\"$outdir/\"]]] != "" } {
+ untested "failed to compile"
+ return -1
+ }
+diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
+--- a/gdb/testsuite/lib/gdb.exp
++++ b/gdb/testsuite/lib/gdb.exp
+@@ -6150,9 +6150,9 @@ proc escape_for_host { str } {
+ proc quote_for_host { args } {
+ set str [join $args]
+ if { [is_remote host] } {
+- set str [join [list {\"} $str {\"}] ""]
++ set str [join [list {\"} [regsub -all {"} $str {\\\"}] {\"}] ""]
+ } else {
+- set str [join [list {"} $str {"}] ""]
++ set str [join [list {"} [regsub -all {"} $str {\"}] {"}] ""]
+ }
+ return $str
+ }
diff --git a/gdb-fix-testsuite-newer-tcl.patch b/gdb-fix-testsuite-newer-tcl.patch
new file mode 100644
index 0000000..5e0e16c
--- /dev/null
+++ b/gdb-fix-testsuite-newer-tcl.patch
@@ -0,0 +1,46 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Tom de Vries
+Date: Fri, 20 Mar 2026 10:13:27 +0100
+Subject: gdb-fix-testsuite-newer-tcl.patch
+
+;; Fix use of deprecated trace variable subcommand
+;; (Tom de Vries)
+
+With Tcl 9.0, we get:
+...
+bad option "variable": must be add, info, or remove
+ while executing
+"trace variable "boards_dir" w append_gdb_boards_dir"
+ (file "lib/append_gdb_boards_dir.exp" line 48)
+...
+
+The trace subcommand "trace variable " [1]:
+- is equivalent to "trace add variable "
+- is for backwards compatibility,
+- uses "an older syntax in which array, read, write, unset are replaced by a,
+ r, w and u respectively",
+- has an ops argument which is "not a list, but simply a string concatenation
+ of the operations", and
+- is "deprecated and will likely be removed in a future version of Tcl".
+
+Fix this by using "trace add variable":
+...
+-trace variable "boards_dir" w append_gdb_boards_dir
++trace add variable "boards_dir" {write} append_gdb_boards_dir
+...
+
+Approved-By: Tom Tromey
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33948
+
+[1] https://www.tcl-lang.org/man/tcl8.6/TclCmd/trace.htm#M27
+
+diff --git a/gdb/testsuite/lib/append_gdb_boards_dir.exp b/gdb/testsuite/lib/append_gdb_boards_dir.exp
+--- a/gdb/testsuite/lib/append_gdb_boards_dir.exp
++++ b/gdb/testsuite/lib/append_gdb_boards_dir.exp
+@@ -45,4 +45,4 @@ proc append_gdb_boards_dir { name1 name2 op } {
+ }
+ lappend boards_dir "${gdb_boards_dir}"
+ }
+-trace variable "boards_dir" w append_gdb_boards_dir
++trace add variable "boards_dir" {write} append_gdb_boards_dir
diff --git a/gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch b/gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
deleted file mode 100644
index 20e5f75..0000000
--- a/gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
-
-;; Testcase for `Setting solib-absolute-prefix breaks vDSO' (BZ 818343).
-;;=fedoratest
-
-diff --git a/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c
-@@ -0,0 +1,26 @@
-+/* Copyright (C) 2012 Free Software Foundation, Inc.
-+
-+ This file is part of GDB.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see . */
-+
-+#include
-+#include
-+
-+int
-+main (int argc, char *argv[])
-+{
-+ printf ("Hello, World.\n");
-+ abort ();
-+}
-diff --git a/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp
-@@ -0,0 +1,39 @@
-+# Copyright 2012 Free Software Foundation, Inc.
-+
-+# 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 .
-+
-+set testfile "set-solib-absolute-prefix"
-+set srcfile ${testfile}.c
-+
-+# It is necessary to verify if the binary is 32-bit, so that the system
-+# call `__kernel_vsyscall' originates from vDSO.
-+
-+if { ![is_ilp32_target] } {
-+ return -1
-+}
-+
-+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
-+ return -1
-+}
-+
-+if { ![runto_main] } {
-+ return -1
-+}
-+
-+gdb_test "continue" "Program received signal SIGABRT, Aborted.*" \
-+ "continue until abort"
-+gdb_test "set solib-absolute-prefix /BOGUS_DIRECT" \
-+ ".*warning: Unable to find dynamic linker breakpoint function.*" \
-+ "set solib-absolute-prefix"
-+gdb_test "bt" "__kernel_vsyscall.*" "backtrace with __kernel_vsyscall"
diff --git a/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch b/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
deleted file mode 100644
index d92bfc3..0000000
--- a/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
+++ /dev/null
@@ -1,235 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
-
-;; Fix '[ppc64] and [s390x] wrong prologue skip on -O2 -g code' (Jan
-;; Kratochvil, RH BZ 1084404).
-;;=fedoratest
-
-These testcases have been created by compiling glibc-2.17-78 on
-RHEL-7.1 s390x/ppc64 boxes, and then taking the "select.o" file
-present at $builddir/misc/select.o.
-
-diff --git a/gdb/testsuite/gdb.arch/ppc64-prologue-skip.exp b/gdb/testsuite/gdb.arch/ppc64-prologue-skip.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.arch/ppc64-prologue-skip.exp
-@@ -0,0 +1,34 @@
-+# Copyright 2015 Free Software Foundation, Inc.
-+
-+# 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 .
-+
-+if { ![istarget powerpc64-*linux-*] || ![is_lp64_target] } {
-+ verbose "Skipping ppc64-prologue-skip.exp"
-+ return
-+}
-+
-+set testfile "ppc64-prologue-skip"
-+set uufile "${srcdir}/${subdir}/${testfile}.o.uu"
-+set ofile "${srcdir}/${subdir}/${testfile}.o"
-+
-+if { [catch "system \"uudecode -o ${ofile} ${uufile}\"" ] != 0 } {
-+ untested "failed uudecode"
-+ return -1
-+}
-+
-+gdb_exit
-+gdb_start
-+gdb_load $ofile
-+
-+gdb_test "break ___newselect_nocancel" "Breakpoint $decimal at 0xc: file ../sysdeps/unix/syscall-template.S, line 81." "breakpoint on ___newselect_nocancel"
-diff --git a/gdb/testsuite/gdb.arch/ppc64-prologue-skip.o.uu b/gdb/testsuite/gdb.arch/ppc64-prologue-skip.o.uu
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.arch/ppc64-prologue-skip.o.uu
-@@ -0,0 +1,70 @@
-+begin 644 ppc64-skip-prologue.o.uu
-+M?T5,1@("`0`````````````!`!4````!````````````````````````````
-+M``-(``````!```````!``!0`$8%-B-`L"@``0,(`-#@``(Y$```"3.,`('P(
-+M`J;X`0`0^"'_D4@```%@````Z`$`@#@A`'!\"`.F3H``(/@A_X%]*`*F^2$`
-+MD/CA`-#XP0#(^*$`P/B!`+CX80"P2````6````#X80!PZ.$`T.C!`,CHH0#`
-+MZ($`N.AA`+`X``".1````GP``";X80!X^`$`B.AA`'!(```!8````.DA`)#H
-+M`0"(Z&$`>'TH`Z9\#_$@."$`@$SC`"!+__]@```````,($``````````O``(
-+M7U]S96QE8W0```````````````````````````!6``(````Y!`'[#@T``0$!
-+M`0````$```$N+B]S>7-D97!S+W5N:7@``'-Y"]S>7-C86QL+71E;7!L871E
-+M+E,`+W)O;W0O9VQI8F,O9VQI8F,M,BXQ-RTW."YE;#$$!&PP!````
-+M`#`````8`````````+P`20YP$4%^1`X`009!0@Z``4(107Y2$49_20X`!D$&
-+M1@``````+G-Y;71A8@`N`````````!(````$@````$`````````"``````````8````
-+M)@````$``````````P```````````````````1@`````````````````````
-+M``````````$``````````````"P````(``````````,`````````````````
-+M``$8```````````````````````````````!```````````````V`````0``
-+M```````#```````````````````!&``````````0````````````````````
-+M"```````````````,0````0`````````````````````````````"L``````
-+M````,````!(````%``````````@`````````&````#L````!````````````
-+M``````````````````$H```````````````````````````````!````````
-+M``````!0`````0`````````````````````````````!*`````````!:````
-+M`````````````````0``````````````2P````0`````````````````````
-+M````````"O``````````&````!(````(``````````@`````````&````&$`
-+M```!``````````````````````````````&"`````````),`````````````
-+M```````!``````````````!<````!``````````````````````````````+
-+M"`````````!@````$@````H`````````"``````````8````;0````$`````
-+M`````````````````````````A4`````````%`````````````````````$`
-+M`````````````(`````!``````````````````````````````(P````````
-+M`#`````````````````````0``````````````![````!```````````````
-+M```````````````+:``````````P````$@````T`````````"``````````8
-+M````E`````$``````````@```````````````````F``````````2```````
-+M``````````````@``````````````(\````$````````````````````````
-+M``````N8`````````!@````2````#P`````````(`````````!@````1````
-+M`P`````````````````````````````"J`````````">````````````````
-+M`````0```````````````0````(`````````````````````````````"$@`
-+M```````!L````!,````+``````````@`````````&`````D````#````````
-+M``````````````````````GX`````````'H````````````````````!````
-+M`````````````````````````````````````````````P```0``````````
-+M`````````````````P```P```````````````````````````P``!```````
-+M`````````````````````P``!0```````````````````````````P``"@``
-+M`````````````````````````P``#````````````````````````````P``
-+M"````````````````````````````P``#0``````````````````````````
-+M`P``#P```````````````````````````P``!P``````````````````````
-+M```!$@``!0```````````````````-@````*$@```0`````````,````````
-+M`#`````@$``````````````````````````````P$```````````````````
-+M``````````!*$`````````````````````````````!E(@``!0``````````
-+M`````````-@```!S(@``!0```````````````````-@`7U]S96QE8W0`7U]?
-+M;F5W6YC8V%N8V5L`%]?;&EB8U]D:7-A8FQE7V%S>6YC8V%N8V5L`%]?
-+M;&EB8U]S96QE8W0`.
-+
-+if { ![istarget s390x-*linux-*] || ![is_lp64_target] } {
-+ verbose "Skipping s390x-prologue-skip.exp"
-+ return
-+}
-+
-+set testfile "s390x-prologue-skip"
-+set uufile "${srcdir}/${subdir}/${testfile}.o.uu"
-+set ofile "${srcdir}/${subdir}/${testfile}.o"
-+
-+if { [catch "system \"uudecode -o ${ofile} ${uufile}\"" ] != 0 } {
-+ untested "failed uudecode"
-+ return -1
-+}
-+
-+gdb_exit
-+gdb_start
-+gdb_load $ofile
-+
-+gdb_test "break select" "Breakpoint $decimal at 0x48: file ../sysdeps/unix/syscall-template.S, line 81." "breakpoint on select"
-diff --git a/gdb/testsuite/gdb.arch/s390x-prologue-skip.o.uu b/gdb/testsuite/gdb.arch/s390x-prologue-skip.o.uu
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.arch/s390x-prologue-skip.o.uu
-@@ -0,0 +1,64 @@
-+begin 644 s390x-prologue-skip.o.uu
-+M?T5,1@("`0`````````````!`!8````!````````````````````````````
-+M``+```````!```````!``!(`#^LE\!``).O?\&@`)+D$`.^G^_]@X^#P```D
-+MP.4`````N00``NLE\+``!`J.N00`TKD$`"#`Y0````"Y!``MZ]_Q"``$I_0`
-+M"L`0`````+\/$`"G=/_7"HZG2?`!N2$`),"T``````?^````5@`"````.0$!
-+M^PX-``$!`0$````!```!+BXO7-C86QL+71E;7!L
-+M871E+E,``0`````)`@```````````]```0)F$P("``$!````CP`"``````@!
-+M```````````````````````````N+B]S>7-D97!S+W5N:7@OE(``7@.
-+M`1L,#Z`!````````&````!P`````````1`!,CP6.!HT'2`[``@```!`````X
-+M`````````"```````"YS>6UT86(`+G-T``````````&````!`````&``````````@`````````
-+M&````%<````!``````````````````````````````$"`````````),`````
-+M```````````````!``````````````!2````!```````````````````````
-+M```````)^`````````!@````$`````@`````````"``````````8````8P``
-+M``$``````````````````````````````94`````````%```````````````
-+M``````$``````````````'8````!``````````````````````````````&P
-+M`````````#`````````````````````0``````````````!Q````!```````
-+M```````````````````````*6``````````P````$`````L`````````"```
-+M```````8````B@````$``````````@```````````````````>``````````
-+M2`````````````````````@``````````````(4````$````````````````
-+M``````````````J(`````````#`````0````#0`````````(`````````!@`
-+M```1`````P`````````````````````````````"*`````````"4````````
-+M`````````````0```````````````0````(`````````````````````````
-+M````!T`````````!L````!$````*``````````@`````````&`````D````#
-+M``````````````````````````````CP`````````(X`````````````````
-+M```!`````````````````````````````````````````````````P```0``
-+M`````````````````````````P```P```````````````````````````P``
-+M!````````````````````````````P``"```````````````````````````
-+M`P``"@```````````````````````````P``!@``````````````````````
-+M`````P``"P```````````````````````````P``#0``````````````````
-+M`````````P``!0`````````````````````````!$```````````````````
-+M```````````;$``````````````````````````````V$@```0````````!(
-+M`````````"`````_$`````````````````````````````!7$@```0``````
-+M``!6`````````!````!I$`````````````````````````````!Y(@```0``
-+M``````!(`````````"````"'(@```0````````!(`````````"``7U]L:6)C
-+M7V5N86)L95]A
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-rhbz1149205-catch-syscall-after-fork-test.patch
-
-;; Fix '`catch syscall' doesn't work for parent after `fork' is called'
-;; (Philippe Waroquiers, RH BZ 1149205).
-;;=fedoratest
-
-URL:
-Message-ID: <1368136582.30058.7.camel@soleil>
-
- From: Philippe Waroquiers
- To: gdb-patches at sourceware dot org
- Subject: RFA: fix gdb_assert caused by 'catch signal ...' and fork
- Date: Thu, 09 May 2013 23:56:22 +0200
-
- The attached patch fixes a gdb_assert caused by the combination of catch
- signal and fork:
- break-catch-sig.c:152: internal-error: signal_catchpoint_remove_location: Assertion `signal_catch_counts[iter] > 0' failed.
-
- The problem is that the signal_catch_counts is decremented by detach_breakpoints.
- The fix consists in not detaching breakpoint locations of type bp_loc_other.
- The patch introduces a new test.
-
-Comments by Sergio Durigan Junior:
-
- I addded a specific testcase for this patch, which tests exactly the
- issue that the customer is facing. This patch does not solve the
- whole problem of catching a syscall and forking (for more details,
- see ,
- specifically comment #3), but it solves the issue reported by the
- customer.
-
- I also removed the original testcase of this patch, because it
- relied on "catch signal", which is a command that is not implemented
- in this version of GDB.
-
-commit bd9673a4ded96ea5c108601501c8e59003ea1be6
-Author: Philippe Waroquiers
-Date: Tue May 21 18:47:05 2013 +0000
-
- Fix internal error caused by interaction between catch signal and fork
-
-diff --git a/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.c b/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.c
-@@ -0,0 +1,11 @@
-+#include
-+#include
-+
-+int
-+main (int argc, char **argv)
-+{
-+ if (fork () == 0)
-+ sleep (1);
-+ chdir (".");
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.exp b/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gdb-rhbz1149205-catch-syscall-fork.exp
-@@ -0,0 +1,58 @@
-+# Copyright 2015 Free Software Foundation, Inc.
-+
-+# 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 .
-+
-+if { [is_remote target] || ![isnative] } then {
-+ continue
-+}
-+
-+set testfile "gdb-rhbz1149205-catch-syscall-fork"
-+set srcfile ${testfile}.c
-+set binfile [standard_output_file ${testfile}]
-+
-+# Until "catch syscall" is implemented on other targets...
-+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
-+ continue
-+}
-+
-+# This shall be updated whenever 'catch syscall' is implemented
-+# on some architecture.
-+#if { ![istarget "i\[34567\]86-*-linux*"]
-+if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"]
-+ && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"]
-+ && ![istarget "sparc-*-linux*"] && ![istarget "sparc64-*-linux*"] } {
-+ continue
-+}
-+
-+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
-+ untested ${testfile}.exp
-+ return -1
-+}
-+
-+gdb_exit
-+gdb_start
-+gdb_reinitialize_dir $srcdir/$subdir
-+gdb_load $binfile
-+
-+if { ![runto_main] } {
-+ return -1
-+}
-+
-+gdb_test "catch syscall chdir" \
-+ "Catchpoint $decimal \\\(syscall (.)?chdir(.)? \\\[$decimal\\\]\\\)" \
-+ "catch syscall chdir"
-+
-+gdb_test "continue" \
-+ "Continuing\.\r\n.*\r\nCatchpoint $decimal \\\(call to syscall .?chdir.?.*" \
-+ "continue from catch syscall after fork"
diff --git a/gdb-rhbz2366461-bad-solib-entry-addr.patch b/gdb-rhbz2366461-bad-solib-entry-addr.patch
new file mode 100644
index 0000000..836ab5f
--- /dev/null
+++ b/gdb-rhbz2366461-bad-solib-entry-addr.patch
@@ -0,0 +1,453 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess
+Date: Wed, 15 Apr 2026 10:43:31 +0100
+Subject: gdb-rhbz2366461-bad-solib-entry-addr.patch
+
+;; Backport upstream commit cd289df068e to address rhbz2366461. This
+;; commit will drop out with GDB 18.
+
+gdb: don't use .text as default entry point section
+
+We got a Fedora GDB bug report that a user tried to debug an Appimage,
+and GDB would reliably crash like this:
+
+ (gdb) run
+ Starting program: /tmp/build/gdb/testsuite/outputs/gdb.base/solib-bad-entry-addr/solib-bad-entry-addr
+ ../../src/gdb/symfile.c:843: internal-error: sect_index_text not initialized
+ A problem internal to GDB has been detected,
+ further debugging may prove unreliable.
+ ----- Backtrace -----
+ ... etc ...
+
+The specific AppImage being debugged can be found here, I've modified
+the URL with a warning marker. I make no claims about whether it is
+safe to download the image, and running it is definitely at your own
+risk. If you wish to, delete the warning marker to download:
+
+ https://github.com/Murmele/Gittyup//releases/download/gittyup_v1.4.0/Gittyup-1.4.0-x86_64.AppImage
+
+At the point of the above crash GDB's stack is:
+
+ #9 0x000000000190c6ed in internal_error_loc (file=0x1e4a94e "../../src/gdb/symfile.c", line=838, fmt=0x1e4aa50 "sect_index_text not initialized") at ../../src/gdbsupport/errors.cc:57
+ #10 0x0000000000f5f5ac in init_entry_point_info (objfile=0x5a98e80) at ../../src/gdb/symfile.c:838
+ #11 0x0000000000f5f943 in syms_from_objfile (objfile=0x5a98e80, addrs=0x7ffd78728490, add_flags=...) at ../../src/gdb/symfile.c:962
+ #12 0x0000000000f5fe6d in symbol_file_add_with_addrs (abfd=..., name=0x3e76e50 "/tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56", add_flags=..., addrs=0x7ffd78728490, flags=..., parent=0x0) at ../../src/gdb/symfile.c:1071
+ #13 0x0000000000f601aa in symbol_file_add_from_bfd (abfd=..., name=0x3e76e50 "/tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56", add_flags=..., addrs=0x7ffd78728490, flags=..., parent=0x0) at ../../src/gdb/symfile.c:1145
+ #14 0x0000000000f0f2ad in solib_read_symbols (so=..., flags=...) at ../../src/gdb/solib.c:627
+ #15 0x0000000000f10263 in solib_add (pattern=0x0, from_tty=0, readsyms=1) at ../../src/gdb/solib.c:960
+
+From this we can see GDB is trying to add the shared library:
+
+ /tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56
+
+The internal error is triggered from these lines in
+init_entry_point_info:
+
+ if (!found)
+ ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);
+
+Where SECT_OFF_TEXT is:
+
+ #define SECT_OFF_TEXT(objfile) \
+ ((objfile->sect_index_text == -1) \
+ ? (internal_error (_("sect_index_text not initialized")), -1) \
+ : objfile->sect_index_text)
+
+So we can see that objfile::sect_index_text is -1, which leads to the
+internal error.
+
+Looking at the 'readelf -Wa ...' output for the shared library in
+question we see this:
+
+ ELF Header:
+ Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
+ Class: ELF64
+ Data: 2's complement, little endian
+ Version: 1 (current)
+ OS/ABI: UNIX - System V
+ ABI Version: 0
+ Type: DYN (Shared object file)
+ Machine: Advanced Micro Devices X86-64
+ Version: 0x1
+ Entry point address: 0x2d7
+ Start of program headers: 25051136 (bytes into file)
+ Start of section headers: 25047552 (bytes into file)
+ Flags: 0x0
+ Size of this header: 64 (bytes)
+ Size of program headers: 56 (bytes)
+ Number of program headers: 7
+ Size of section headers: 64 (bytes)
+ Number of section headers: 11
+ Section header string table index: 7
+
+ Section Headers:
+ [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+ [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
+ [ 1] .note.gnu.build-id NOTE 0000000000000190 000190 000024 00 A 0 0 4
+ [ 2] .gnu.hash GNU_HASH 00000000000001b8 0001b8 000034 00 A 3 0 8
+ [ 3] .dynsym DYNSYM 00000000000001f0 0001f0 000090 18 A 10 2 8
+ [ 4] .rodata PROGBITS 00000000000002e0 0002e0 17e27d0 00 A 0 0 16
+ [ 5] .eh_frame PROGBITS 00000000017e2ab0 17e2ab0 000000 00 A 0 0 8
+ [ 6] .dynamic DYNAMIC 00000000019e2f10 17e2f10 0000f0 10 WA 10 0 8
+ [ 7] .shstrtab STRTAB 0000000000000000 17e3000 000063 00 0 0 1
+ [ 8] .symtab SYMTAB 0000000000000000 17e3068 000150 18 9 10 8
+ [ 9] .strtab STRTAB 0000000000000000 17e31b8 000044 00 0 0 1
+ [10] .dynstr STRTAB 00000000019e3188 17e4188 000420 00 A 0 0 8
+ Key to Flags:
+ W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
+ L (link order), O (extra OS processing required), G (group), T (TLS),
+ C (compressed), x (unknown), o (OS specific), E (exclude),
+ D (mbind), l (large), p (processor specific)
+
+ There are no section groups in this file.
+
+ Program Headers:
+ Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+ LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x17e2ab0 0x17e2ab0 R 0x200000
+ GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
+ NOTE 0x000190 0x0000000000000190 0x0000000000000190 0x000024 0x000024 R 0x4
+ LOAD 0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 RW 0x200000
+ DYNAMIC 0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 RW 0x8
+ GNU_RELRO 0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 R 0x1
+ LOAD 0x17e4000 0x00000000019e3000 0x00000000019e3000 0x0005a8 0x0005a8 RW 0x1000
+
+Things to note here are:
+
+ 1. There really is no .text section, or any executable sections,
+
+ 2. there are 3 LOAD segments. This will be important later, and
+
+ 3. the "Entry point address" is outside all sections, and is
+ non-zero.
+
+Next we can investigate where objfile::sect_index_text is set to
+something other than -1. Starting in init_objfile_sect_indices, if
+the objfile has a ".text" section then sect_index_text can be set.
+This case clearly doesn't apply.
+
+Next symfile_find_segment_sections is called. This tries to match a
+common case where we have either 1 or 2 LOAD segments, and assumes a
+default distribution of sections to segments. However, we have 3 LOAD
+segments, so these lines:
+
+ if (data->segments.size () != 1 && data->segments.size () != 2)
+ return;
+
+result in an early return from symfile_find_segment_sections without
+sect_index_text being set.
+
+Back in init_objfile_sect_indices, if no sections have an offset then
+we set any currently unset sect_index_* values, including
+sect_index_text, to point at section 0. However, in our case the
+objfile is a relocatable shared library, so the sections will have an
+offset, and so this final fallback case doesn't apply.
+
+The result is that init_objfile_sect_indices never sets
+sect_index_text. This worries me a little as
+init_objfile_sect_indices contains this comment:
+
+ /* This is where things get really weird... We MUST have valid
+ indices for the various sect_index_* members or gdb will abort.
+ So if for example, there is no ".text" section, we have to
+ accommodate that. First, check for a file with the standard
+ one or two segments. */
+
+Notice the emphasis on MUST in that comment, and indeed, we exit this
+function without setting sect_index_text, and GDB does indeed abort.
+The comment seems to imply that the following code is going to try to
+figure out a suitable stand-in sect_index_text for when there is no
+".text" section, but clearly I've run into a case that isn't covered.
+
+All of this code relating to setting sect_index_text was introduced in
+commit:
+
+ commit 31d99776c73d6fca13163da59c852b0fa99f89b8
+ Date: Mon Jun 18 15:46:38 2007 +0000
+
+Which unfortunately is from a time where we didn't write useful commit
+messages, so to understand the commit you need to go read the mailing
+list archive, but they don't offer much more insight:
+
+ https://sourceware.org/pipermail/gdb-patches/2007-May/050527.html
+
+Clearly the comment in init_objfile_sect_indices would suggest that
+the fix here is to figure out some "fake" value for sect_index_text,
+and that would certainly avoid the problem here. But, at least for
+this problem, I think there's maybe a better solution.
+
+The original internal error is triggered by a use of SECT_OFF_TEXT in
+init_entry_point_info. We have an entry point address, we try to find
+the section index for the section containing the entry point, and
+failing that, we assume the entry point is in the text section. This
+fall-back assumption means that, if the text section has an offset
+applied, then the entry point will also have that same offset
+applied. But it's not clear to me why picking the text section is
+going to be any more valid than any other section, especially in a
+case like this where we don't even have a text section, so the
+sect_index_text might itself point to some other arbitrary section.
+
+Earlier in init_entry_point_info we already have a fall-back case
+where we set entry_info::entry_point_p to false to indicate that the
+objfile has no entry point, so this is always a possibility. So I
+wondered about writing something like:
+
+ if (!found)
+ {
+ if (objfile->sect_index_text != -1)
+ ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);
+ else
+ ei->entry_point_p = false;
+ }
+
+If we have no text section index then we just claim the objfile has no
+entry point. But I didn't like this for two reasons, first, the
+comment back in init_objfile_sect_indices saying that the index should
+be set, this seems to indicate that we should not be making decisions
+later within GDB based on whether the index is set or not.
+
+And second, using the text section as a fall back, when the entry
+address is outside every section, just seems off. So I wondered, why
+not just reject the entry point completely in this case? Which is how
+I ended up with:
+
+ if (!found)
+ ei->entry_point_p = false;
+
+With this patch in place I was able to start debugging the AppImage
+linked above.
+
+I created a simple test case which reproduces this issue. It's a
+little contrived because it has to hit all the points required to
+trigger this bug:
+
+ 1. No .text section,
+
+ 2. more than 2 LOAD segments, and
+
+ 3. entry address outside every section.
+
+I have no idea what caused the original shared library to take on
+these characteristics, it might even be a tool issue building the
+original shared library. I haven't investigated this, as I don't
+think it really matters, GDB shouldn't be crashing just because the
+incoming objects are a little weird.
+
+I've attached a link to the Fedora bug in the 'Bug:' tag, but it's a
+little confusing. An automated system has merged together two bug
+reports. As such the overall bug report linked too is for a
+completely different issue, only comments 21, 22, 23, and 24 relate to
+the bug being fixed here.
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2366461#c21
+
+Approved-By: Tom Tromey
+
+diff --git a/gdb/symfile.c b/gdb/symfile.c
+--- a/gdb/symfile.c
++++ b/gdb/symfile.c
+@@ -822,7 +822,6 @@ init_entry_point_info (struct objfile *objfile)
+ if (ei->entry_point_p)
+ {
+ CORE_ADDR entry_point = ei->entry_point;
+- int found;
+
+ /* Make certain that the address points at real code, and not a
+ function descriptor. */
+@@ -834,7 +833,7 @@ init_entry_point_info (struct objfile *objfile)
+ ei->entry_point
+ = gdbarch_addr_bits_remove (objfile->arch (), entry_point);
+
+- found = 0;
++ bool found = false;
+ for (obj_section &osect : objfile->sections ())
+ {
+ struct bfd_section *sect = osect.the_bfd_section;
+@@ -845,13 +844,17 @@ init_entry_point_info (struct objfile *objfile)
+ {
+ ei->the_bfd_section_index
+ = gdb_bfd_section_index (objfile->obfd.get (), sect);
+- found = 1;
++ found = true;
+ break;
+ }
+ }
+
++ /* We store the section index so that the entry address can be
++ relocated when used. If the entry address is outside of any
++ section then we cannot relocate it. Just claim that there is no
++ entry address in this case. */
+ if (!found)
+- ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);
++ ei->entry_point_p = false;
+ }
+ }
+
+diff --git a/gdb/testsuite/gdb.base/solib-bad-entry-addr-lib.s b/gdb/testsuite/gdb.base/solib-bad-entry-addr-lib.s
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/solib-bad-entry-addr-lib.s
+@@ -0,0 +1,33 @@
++/* Copyright 2026 Free Software Foundation, Inc.
++
++ 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 . */
++
++ .section .rodata
++ .globl lib_var
++ .type lib_var, @object
++lib_var:
++ .long 42
++ .size lib_var, .-lib_var
++
++ /* This executable section exists solely to force the linker
++ to create an additional LOAD segment (with R+X permissions),
++ giving the library 3+ LOAD segments instead of the default 2.
++
++ This matters because GDB's symfile_find_segment_sections only
++ runs for objects with exactly 1 or 2 segments. When it runs,
++ it sets sect_index_text from the first section in segment 1,
++ which masks the bug we are testing for, see the .exp file for
++ details. */
++ .section .not_text, "ax", @progbits
++ .byte 0
+diff --git a/gdb/testsuite/gdb.base/solib-bad-entry-addr.c b/gdb/testsuite/gdb.base/solib-bad-entry-addr.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/solib-bad-entry-addr.c
+@@ -0,0 +1,22 @@
++/* Copyright 2026 Free Software Foundation, Inc.
++
++ 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 . */
++
++extern int lib_var;
++
++int
++main ()
++{
++ return lib_var;
++}
+diff --git a/gdb/testsuite/gdb.base/solib-bad-entry-addr.exp b/gdb/testsuite/gdb.base/solib-bad-entry-addr.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/solib-bad-entry-addr.exp
+@@ -0,0 +1,99 @@
++# Copyright 2026 Free Software Foundation, Inc.
++
++# 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 .
++
++# This test aims to exercise a specific situation which was seen
++# causing GDB to crash. An application has a shared library that
++# meets the following conditions:
++#
++# 1. No ".text" section,
++# 2. at least 3 LOAD segments, and
++# 3. a non-zero entry address that is outside of every section.
++#
++# When these 3 conditions are met then GDB would run into a problem in
++# init_entry_point_info for the shared library. The non-zero entry
++# address means GDB would try to find the section corresponding to the
++# address. As the address is outside of all sections then GDB would
++# try to use the .text section as a fall-back. But there is no text
++# section, so an internal error would be triggered.
++#
++# The 3 LOAD segments is important because, if there are only 1 or 2
++# segments GDB has a default in symfile_find_segment_sections where
++# it assumes the text section is the first section in the first
++# segment, which means init_entry_point_info will have a .text section
++# to use.
++#
++# This test has a very simple assembler file (which hopefully contains
++# no architecture specific content), which will compile to a couple of
++# sections, but no .text section. These sections force the creation
++# of more than 2 LOAD segments. The compiler flags then set the entry
++# address to 0x1, which (we hope) is outside all sections. This
++# assembler file is compiled into a shared library.
++
++require allow_shlib_tests
++require !use_gdb_stub
++require {istarget *-linux*}
++
++standard_testfile .c -lib.s
++
++# Build shared library.
++set lib_testfile ${testfile}-lib.so
++set lib_srcfile ${srcfile2}
++set lib_binfile [standard_output_file ${lib_testfile}]
++set lib_flags {shlib \
++ additional_flags=-nostartfiles \
++ additional_flags=-Wl,-e,0x1 \
++ additional_flags=-Wl,-z,separate-code}
++if { [build_executable "build solib" $lib_testfile $lib_srcfile \
++ $lib_flags] == -1 } {
++ return
++}
++
++# Build the test executable.
++if { [build_executable "build exec" $testfile $srcfile \
++ [list debug pie shlib=${lib_binfile}]] == -1 } {
++ return
++}
++
++# Confirm we have more than 2 LOAD segments in the shared library.
++set readelf_program [gdb_find_readelf]
++set command "exec $readelf_program -Wl $lib_binfile"
++verbose -log "command is $command"
++set result [catch {{*}$command} output]
++verbose -log "result is $result"
++verbose -log "output is $output"
++if {$result != 0} {
++ fail "read program headers from $lib_testfile"
++ return
++}
++if {![regexp {\nProgram Headers:\n *Type [^\n]* Align\n(.*?)\n\n} $output trash phdr]} {
++ fail "no Program Headers found"
++ return
++}
++set load_segment_count 0
++foreach line [regexp -line -all -inline {^ *LOAD .* 0x[0-9]+$} $phdr] {
++ incr load_segment_count
++}
++if { $load_segment_count <= 2 } {
++ fail "not enough LOAD segments"
++ return
++}
++
++# Start GDB and run to main. If the shared library is causing issues
++# then we will see an internal error once the inferior starts running.
++clean_restart $testfile
++
++if {![runto_main message]} {
++ return 0
++}
diff --git a/gdb-rhbz2366461-missing-thread.patch b/gdb-rhbz2366461-missing-thread.patch
new file mode 100644
index 0000000..9dacf97
--- /dev/null
+++ b/gdb-rhbz2366461-missing-thread.patch
@@ -0,0 +1,499 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess
+Date: Fri, 16 May 2025 17:56:58 +0100
+Subject: gdb-rhbz2366461-missing-thread.patch
+
+;; Backport upstream commit 8bd08ee92c4 to address rhbz2366461. This
+;; commit will drop out with GDB 18.
+
+gdb: crash if thread unexpectedly disappears from thread list
+
+A bug was reported to Red Hat where GDB was crashing with an assertion
+failure, the assertion message is:
+
+ ../../gdb/regcache.c:432: internal-error: get_thread_regcache: Assertion `thread->state != THREAD_EXITED' failed.
+
+The backtrace for the crash is:
+
+ #5 0x000055a21da8a880 in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (problem=problem@entry=0x55a21e289060 , file=, line=, fmt=, ap=ap@entry=0x7ffec7576be0) at ../../gdb/utils.c:477
+ #6 0x000055a21da8aadf in internal_verror (file=, line=, fmt=, ap=ap@entry=0x7ffec7576be0) at ../../gdb/utils.c:503
+ #7 0x000055a21dcbd055 in internal_error_loc (file=file@entry=0x55a21dd33b71 "../../gdb/regcache.c", line=line@entry=432, fmt=) at ../../gdbsupport/errors.cc:57
+ #8 0x000055a21d8baaa9 in get_thread_regcache (thread=thread@entry=0x55a258de3a50) at ../../gdb/regcache.c:432
+ #9 0x000055a21d74fa18 in print_signal_received_reason (uiout=0x55a258b649b0, siggnal=GDB_SIGNAL_TRAP) at ../../gdb/infrun.c:9287
+ #10 0x000055a21d7daad9 in mi_interp::on_signal_received (this=0x55a258af5f60, siggnal=GDB_SIGNAL_TRAP) at ../../gdb/mi/mi-interp.c:372
+ #11 0x000055a21d76ef99 in interps_notify (method=&virtual table offset 88, this adjustment 974682) at ../../gdb/interps.c:369
+ #12 0x000055a21d76e58f in interps_notify_signal_received (sig=, sig@entry=GDB_SIGNAL_TRAP) at ../../gdb/interps.c:378
+ #13 0x000055a21d75074d in notify_signal_received (sig=GDB_SIGNAL_TRAP) at ../../gdb/infrun.c:6818
+ #14 0x000055a21d755af0 in normal_stop () at ../../gdb/gdbthread.h:432
+ #15 0x000055a21d768331 in fetch_inferior_event () at ../../gdb/infrun.c:4753
+
+The user is using a build of GDB with 32-bit ARM support included, and
+they gave the following description for what they were doing at the
+time of the crash:
+
+ Suspended the execution of the firmware in Eclipse. The gdb was
+ connected to JLinkGDBServer with activated FreeRTOS awareness JLink
+ plugin.
+
+So they are remote debugging with a non-gdbserver target.
+
+Looking in normal_stop() we see this code:
+
+ /* As we're presenting a stop, and potentially removing breakpoints,
+ update the thread list so we can tell whether there are threads
+ running on the target. With target remote, for example, we can
+ only learn about new threads when we explicitly update the thread
+ list. Do this before notifying the interpreters about signal
+ stops, end of stepping ranges, etc., so that the "new thread"
+ output is emitted before e.g., "Program received signal FOO",
+ instead of after. */
+ update_thread_list ();
+
+ if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+ notify_signal_received (inferior_thread ()->stop_signal ());
+
+Which accounts for the transition from frame #14 to frame #13. But it
+is the update_thread_list() call which interests me. This call asks
+the target (remote target in this case) for the current thread list,
+and then marks threads exited based on the answer.
+
+And so, if a (badly behaved) target (incorrectly) removes a thread
+from the thread list, then the update_thread_list() call will mark the
+impacted thread as exited, even if GDB is currently handling a signal
+stop event for that target.
+
+My guess for what's going on here then is this:
+
+ 1. Thread receives a signal.
+ 2. Remote target sends GDB a stop with signal packet.
+ 3. Remote decides that the thread is going away soon, and marks the
+ thread as exited.
+ 4. GDB asks for the thread list.
+ 5. Remote sends back the thread list, which doesn't include the
+ event thread, as the remote things this thread has exited.
+ 6. GDB marks the thread as exited, and then proceeds to try and
+ print the signal stop event for the event thread.
+ 7. Printing the signal stop requires reading registers, which
+ requires a regache. We can only get a regcache for a non-exited
+ thread, and so GDB raises an assertion.
+
+Using the gdbreplay test frame work I was able to reproduce this
+failure using gdbserver. I create an inferior with two threads, the
+main thread sends a signal to the second thread, GDB sees the signal
+arrive and prints this information for the user.
+
+Having captured the trace of this activity, I then find the thread
+list reply in the log file, and modify it to remove the second thread.
+
+Now, when I replay the modified log file I see the same assertion
+complaining about an attempt to get a regcache for an exited thread.
+
+I'm not entirely sure the best way to fix this. Clearly the problem
+here is a bad remote target. But, replies from a remote target
+should (in my opinion) not be considered trusted, as a consequence, we
+should not be asserting based on data coming from a remote. Instead,
+we should be giving warnings or errors and have GDB handle the bad
+data as best it can.
+
+This is the second attempt to fix this issue, my first patch can be
+seen here:
+
+ https://inbox.sourceware.org/gdb-patches/062e438c8677e2ab28fac6183d2ea6d444cb9121.1747567717.git.aburgess@redhat.com
+
+In the first patch I was to checking in normal_stop, immediately after
+the call to update_thread_list, to see if the current thread was now
+marked as exited. However CI testing showed an issue with this
+approach; I was already checking for many different TARGET_WAITKIND_*
+kinds where the "is the current thread exited" question didn't make
+sense, and it turns out that the list of kinds in my first attempt was
+already insufficient.
+
+Rather than trying to just adding to the list, in this revised patch
+I'm proposing to move the "is this thread exited" check inside the
+block which handles signal stop events.
+
+Right now, the only part of normal_stop which I know relies on the
+current thread not being exited is the call to notify_signal_received,
+so before calling notify_signal_received I check to see if the current
+thread is now exited. If it is then I print a warning to indicate
+that the thread has unexpectedly exited and that the current
+command (continue/step/etc) has been cancelled, I then change the
+current event type to TARGET_WAITKIND_SPURIOUS.
+
+GDB's output now looks like this in all-stop mode:
+
+ (gdb) continue
+ Continuing.
+ [New Thread 3483690.3483693]
+ [Thread 3483690.3483693 exited]
+ warning: Thread 3483690.3483693 unexpectedly exited after non-exit event
+ [Switching to Thread 3483690.3483693]
+ (gdb)
+
+The non-stop output is identical, except we don't switch thread (stop
+events never trigger a thread switch in non-stop mode).
+
+The include test makes use of the gdbreplay framework, and tests in
+all-stop and non-stop modes. I would like to do more extensive
+testing of GDB's state after the receiving the unexpected thread list,
+but due to using gdbreplay for testing, this is quite hard. Many
+commands, especially those looking at thread state, are likely to
+trigger additional packets being sent to the remote, which causes
+gdbreplay to bail out as the new packet doesn't match the original
+recorded state. However, I really don't think it is a good idea to
+change gdbserver in order to "fake" this error case, so for now, using
+gdbreplay is the best idea I have.
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2366461
+
+diff --git a/gdb/infrun.c b/gdb/infrun.c
+--- a/gdb/infrun.c
++++ b/gdb/infrun.c
+@@ -9562,7 +9562,38 @@ normal_stop ()
+ update_thread_list ();
+
+ if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+- notify_signal_received (inferior_thread ()->stop_signal ());
++ {
++ gdb_assert (inferior_ptid != null_ptid);
++
++ /* Calling update_thread_list pulls information from the target. For
++ native targets we can be (reasonably) sure that the information we
++ get back is sane, but for remote targets, we cannot reply on the
++ returned thread list to be correct.
++
++ Specifically, a remote target (not gdbserver), has been seen to
++ prematurely remove threads from the thread list after sending a
++ signal stop event. The consequence of this, is that the thread
++ might now be exited. This is bad as, trying to calling
++ notify_signal_received will cause GDB to read registers for the
++ current thread, but requesting the regcache for an exited thread
++ will trigger an assertion.
++
++ Check for the exited thread case here, and convert the stop reason
++ to a spurious stop event. The thread exiting will have already
++ been reported (when the thread list was parsed), so making this a
++ spurious stop will cause GDB to drop back to the prompt. */
++ if (inferior_thread ()->state != THREAD_EXITED)
++ notify_signal_received (inferior_thread ()->stop_signal ());
++ else
++ {
++ warning (_("command aborted, %s unexpectedly exited after signal stop event"),
++ target_pid_to_str (inferior_thread ()->ptid).c_str ());
++
++ /* Mark this as a spurious stop. GDB will return to the
++ prompt. The warning above tells the user why. */
++ last.set_spurious ();
++ }
++ }
+
+ /* As with the notification of thread events, we want to delay
+ notifying the user that we've switched thread context until
+diff --git a/gdb/testsuite/gdb.replay/missing-thread.c b/gdb/testsuite/gdb.replay/missing-thread.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.replay/missing-thread.c
+@@ -0,0 +1,61 @@
++/* This testcase is part of GDB, the GNU debugger.
++
++ Copyright 2025 Free Software Foundation, Inc.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++
++pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
++pthread_cond_t g_condvar = PTHREAD_COND_INITIALIZER;
++
++void *
++worker_function (void *arg)
++{
++ printf ("In worker, about to notify\n");
++ pthread_cond_signal (&g_condvar);
++
++ while (true)
++ sleep(1);
++
++ return NULL;
++}
++
++int
++main()
++{
++ pthread_t my_thread;
++
++ int result = pthread_create (&my_thread, NULL, worker_function, NULL);
++ assert (result == 0);
++
++ pthread_mutex_lock (&g_mutex);
++ pthread_cond_wait (&g_condvar, &g_mutex);
++
++ printf ("In main, have been woken.\n");
++ pthread_mutex_unlock (&g_mutex);
++
++ result = pthread_kill (my_thread, SIGTRAP);
++ assert (result == 0);
++
++ result = pthread_join (my_thread, NULL);
++ assert (result == 0);
++
++ return 0;
++}
+diff --git a/gdb/testsuite/gdb.replay/missing-thread.exp b/gdb/testsuite/gdb.replay/missing-thread.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.replay/missing-thread.exp
+@@ -0,0 +1,237 @@
++# Copyright 2025 Free Software Foundation, Inc.
++#
++# 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 . */
++
++# This test confirms how GDB handles a badly behaving remote target. The
++# remote target reports a stop event (signal delivery), then, as GDB is
++# processing the stop it syncs the thread list with the remote.
++#
++# The badly behaving remote target was dropping the signaled thread from the
++# thread list at this point, that is, the thread appeared to exit before an
++# exit event had been sent to (and seen by) GDB.
++#
++# At one point this was causing an assertion failed. GDB would try to
++# process the signal stop event, and to do this would try to read some
++# registers. Reading registers requires a regcache, and GDB will only
++# create a regcache for a non-exited thread.
++
++load_lib gdbserver-support.exp
++load_lib gdbreplay-support.exp
++
++require allow_gdbserver_tests
++require has_gdbreplay
++
++standard_testfile
++
++if { [build_executable "failed to build exec" $testfile $srcfile {debug pthreads}] } {
++ return -1
++}
++
++# Start the inferior and record a remote log for our interaction with it.
++# All we do is start the inferior and wait for thread 2 to receive a signal.
++# Check that GDB correctly shows the signal as received. LOG_FILENAME is
++# where we should write the remote log.
++proc_with_prefix record_initial_logfile { log_filename } {
++ clean_restart $::testfile
++
++ # Make sure we're disconnected, in case we're testing with an
++ # extended-remote board, therefore already connected.
++ gdb_test "disconnect" ".*"
++
++ gdb_test_no_output "set sysroot" \
++ "setting sysroot before starting gdbserver"
++
++ # Start gdbserver like:
++ # gdbserver :PORT ....
++ set res [gdbserver_start "" $::binfile]
++ set gdbserver_protocol [lindex $res 0]
++ set gdbserver_gdbport [lindex $res 1]
++
++ gdb_test_no_output "set remotelogfile $log_filename" \
++ "setup remotelogfile"
++
++ # Connect to gdbserver.
++ if {![gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0} {
++ unsupported "$testfile (couldn't start gdbserver)"
++ return
++ }
++
++ gdb_breakpoint main
++ gdb_continue_to_breakpoint "continuing to main"
++
++ gdb_test "continue" \
++ "Thread $::decimal \[^\r\n\]+ received signal SIGTRAP, .*"
++
++ gdb_test "disconnect" ".*" \
++ "disconnect after seeing signal"
++}
++
++# Copy the remote log from IN_FILENAME to OUT_FILENAME, but modify one
++# particular line.
++#
++# The line to be modified is the last ... line, this is
++# the reply from the remote that indicates the thread list. It is expected
++# that the thread list will contain two threads.
++#
++# Whn DROP_BOTH is true then both threads will be removed from the modified
++# line. Otherwise, only the second thread is removed.
++proc update_replay_log { in_filename out_filename drop_both } {
++ # Read IN_FILENAME into a list.
++ set fd [open $in_filename]
++ set data [read $fd]
++ close $fd
++ set lines [split $data "\n"]
++
++ # Find the last line in LINES that contains the list.
++ set idx -1
++ for { set i 0 } { $i < [llength $lines] } { incr i } {
++ if { [regexp "^r.*.*" [lindex $lines $i]] } {
++ set idx $i
++ }
++ }
++
++ # Modify the line by dropping the second thread. This does assume
++ # the thread order as seen in the ... list, but
++ # this seems stable for now.
++ set line [lindex $lines $idx]
++ set fixed_log false
++ if {[regexp "^(r .*\\\\n)(\\\\n)(\\\\n)(.*)$" $line \
++ match part1 part2 part3 part4]} {
++ if { $drop_both } {
++ set line $part1$part4
++ } else {
++ set line $part1$part2$part4
++ }
++ set lines [lreplace $lines $idx $idx $line]
++ set fixed_log true
++ }
++
++ # Write all the lines to OUT_FILENAME
++ set fd [open $out_filename "w"]
++ foreach l $lines {
++ puts $fd $l
++ }
++ close $fd
++
++ # Did we manage to update the log file?
++ return $fixed_log
++}
++
++# Replay the test process using REMOTE_LOG as the logfile to replay. If
++# EXPECT_ERROR is true then after the final 'continue' we expect GDB to give
++# an error as the required thread is missing. When EXPECT_ERROR is false
++# then we expect the test to complete as normal. NON_STOP is eithe 'on' or
++# 'off' and indicates GDBs non-stop mode.
++proc_with_prefix replay_with_log { remote_log expect_error non_stop } {
++ clean_restart $::testfile
++
++ # Make sure we're disconnected, in case we're testing with an
++ # extended-remote board, therefore already connected.
++ gdb_test "disconnect" ".*"
++
++ gdb_test_no_output "set sysroot"
++
++ set res [gdbreplay_start $remote_log]
++ set gdbserver_protocol [lindex $res 0]
++ set gdbserver_gdbport [lindex $res 1]
++
++ # Connect to gdbserver.
++ if {![gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0} {
++ fail "couldn't connect to gdbreplay"
++ return
++ }
++
++ gdb_breakpoint main
++ gdb_continue_to_breakpoint "continuing to main"
++
++ if { $expect_error } {
++ set expected_output \
++ [list \
++ "\\\[Thread \[^\r\n\]+ exited\\\]" \
++ "warning: command aborted, Thread \[^\r\n\]+ unexpectedly exited after signal stop event"]
++
++ if { !$non_stop } {
++ lappend expected_output "\\\[Switching to Thread \[^\r\n\]+\\\]"
++ }
++
++ gdb_test "continue" [multi_line {*}$expected_output]
++ } else {
++ # This is the original behaviour, we see this when running
++ # with the unmodified log.
++ gdb_test "continue" \
++ "Thread ${::decimal}(?: \[^\r\n\]+)? received signal SIGTRAP, .*"
++ }
++
++ gdb_test "disconnect" ".*" \
++ "disconnect after seeing signal"
++}
++
++# Run the complete test cycle; generate an initial log file, modify the log
++# file, then check that GDB correctly handles replaying the modified log
++# file.
++#
++# NON_STOP is either 'on' or 'off' and indicates GDB's non-stop mode.
++proc run_test { non_stop } {
++ if { $non_stop } {
++ set suffix "-ns"
++ } else {
++ set suffix ""
++ }
++
++ # The replay log is placed in 'replay.log'.
++ set remote_log [standard_output_file replay${suffix}.log]
++ set missing_1_log [standard_output_file replay-missing-1${suffix}.log]
++ set missing_2_log [standard_output_file replay-missing-2${suffix}.log]
++
++ record_initial_logfile $remote_log
++
++ if { ![update_replay_log $remote_log $missing_1_log false] } {
++ fail "couldn't update remote replay log (drop 1 case)"
++ }
++
++ if { ![update_replay_log $remote_log $missing_2_log true] } {
++ fail "couldn't update remote replay log (drop 2 case)"
++ }
++
++ with_test_prefix "with unmodified log" {
++ # Replay with the unmodified log. This confirms that we can replay this
++ # scenario correctly.
++ replay_with_log $remote_log false $non_stop
++ }
++
++ with_test_prefix "missing 1 thread log" {
++ # Now replay with the modified log, this time the thread that receives
++ # the event should be missing from the thread list, GDB will give an
++ # error when the inferior stops.
++ replay_with_log $missing_1_log true $non_stop
++ }
++
++ with_test_prefix "missing 2 threads log" {
++ # When we drop both threads from the reply, GDB doesn't
++ # actually remove both threads from the inferior; an inferior must
++ # always have at least one thread. So in this case, as the primary
++ # thread is first, GDB drops this, then retains the second thread, which
++ # is the one we're stopping in, and so, we don't expect to see the error
++ # in this case.
++ replay_with_log $missing_2_log false $non_stop
++ }
++}
++
++# Run the test twice, with non-stop on and off.
++foreach_with_prefix non_stop { on off } {
++ save_vars { ::GDBFLAGS } {
++ append ::GDBFLAGS " -ex \"set non-stop $non_stop\""
++ run_test $non_stop
++ }
++}
diff --git a/gdb-rhbz2403580-misplaced-symtabs.patch b/gdb-rhbz2403580-misplaced-symtabs.patch
new file mode 100644
index 0000000..35fdaad
--- /dev/null
+++ b/gdb-rhbz2403580-misplaced-symtabs.patch
@@ -0,0 +1,151 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess
+Date: Thu, 11 Dec 2025 10:33:15 +0000
+Subject: gdb-rhbz2403580-misplaced-symtabs.patch
+
+;; Backport of upstream commit 70b66cf338b14336 to address RHBZ
+;; 2402580. This backport can be dropped when rebasing to GDB 18.
+;; There were some moderate merge conflicts which needed resolving
+;; when backporting this fix.
+
+diff --git a/gdb/dwarf2/line-header.c b/gdb/dwarf2/line-header.c
+--- a/gdb/dwarf2/line-header.c
++++ b/gdb/dwarf2/line-header.c
+@@ -417,3 +417,46 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
+
+ return lh;
+ }
++
++/* See dwarf2/line-header.h. */
++
++struct symtab *
++file_entry::symtab (dwarf2_cu &cu)
++{
++ if (m_symtab == nullptr)
++ {
++ buildsym_compunit *builder = cu.get_builder ();
++ compunit_symtab *cust = builder->get_compunit_symtab ();
++
++ {
++ std::string filename_holder;
++ const char *filename = this->name;
++ const char *dirname = cu.line_header->include_dir_at (this->d_index);
++
++ /* In order not to lose the line information directory,
++ we concatenate it to the filename when it makes sense.
++ Note that the Dwarf3 standard says (speaking of filenames in line
++ information): ``The directory index is ignored for file names
++ that represent full path names''. Thus ignoring dirname in the
++ `else' branch below isn't an issue. */
++
++ if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
++ {
++ filename_holder = path_join (dirname, filename);
++ filename = filename_holder.c_str ();
++ }
++
++ std::string filename_for_id = cu.line_header->file_file_name (*this);
++ cu.get_builder ()->start_subfile (filename, filename_for_id.c_str ());
++ }
++
++ subfile *sf = builder->get_current_subfile ();
++ if (sf->symtab == nullptr)
++ sf->symtab = allocate_symtab (cust, sf->name.c_str (),
++ sf->name_for_id.c_str ());
++
++ m_symtab = sf->symtab;
++ }
++
++ return m_symtab;
++}
+diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h
+--- a/gdb/dwarf2/line-header.h
++++ b/gdb/dwarf2/line-header.h
+@@ -23,6 +23,7 @@
+ #include "dwarf2/types.h"
+
+ struct dwarf2_per_objfile;
++struct dwarf2_cu;
+
+ /* dir_index is 1-based in DWARF 4 and before, and is 0-based in DWARF 5 and
+ later. */
+@@ -65,8 +66,18 @@ struct file_entry
+
+ unsigned int length {};
+
++ /* Get the symtab for this file_entry. If no symtab has yet been created
++ or set (see set_symtab) for this file_entry then a new one will be
++ created. */
++ struct symtab *symtab (struct dwarf2_cu &cu);
++
++ /* Set the symtab for this file_entry. */
++ void set_symtab (struct symtab *s)
++ { m_symtab = s; }
++
++private:
+ /* The associated symbol table, if any. */
+- struct symtab *symtab {};
++ struct symtab *m_symtab {};
+ };
+
+ /* The line number information for a compilation unit (found in the
+diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
+--- a/gdb/dwarf2/read.c
++++ b/gdb/dwarf2/read.c
+@@ -6227,8 +6227,8 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die)
+ sf->symtab = allocate_symtab (cust, name, name_for_id);
+ }
+
+- fe.symtab = b->get_current_subfile ()->symtab;
+- tug_unshare->symtabs[i] = fe.symtab;
++ fe.set_symtab (b->get_current_subfile ()->symtab);
++ tug_unshare->symtabs[i] = fe.symtab (*this);
+ }
+ }
+ else
+@@ -6246,7 +6246,7 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die)
+ for (i = 0; i < file_names.size (); ++i)
+ {
+ file_entry &fe = file_names[i];
+- fe.symtab = tug_unshare->symtabs[i];
++ fe.set_symtab (tug_unshare->symtabs[i]);
+ }
+ }
+
+@@ -11589,7 +11589,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
+ {
+ /* Any related symtab will do. */
+ symtab
+- = cu->line_header->file_names ()[0].symtab;
++ = cu->line_header->file_names ()[0].symtab (*cu);
+ }
+ else
+ {
+@@ -16592,6 +16592,9 @@ dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu,
+ if (decode_mapping)
+ dwarf_decode_lines_1 (lh, cu, lowpc);
+
++ if (cu->per_cu->is_dwz)
++ return;
++
+ /* Make sure a symtab is created for every file, even files
+ which contain only variables (i.e. no code with associated
+ line numbers). */
+@@ -16607,7 +16610,7 @@ dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu,
+ sf->symtab = allocate_symtab (cust, sf->name.c_str (),
+ sf->name_for_id.c_str ());
+
+- fe.symtab = sf->symtab;
++ fe.set_symtab (sf->symtab);
+ }
+ }
+
+@@ -16884,7 +16887,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
+ if (fe == NULL)
+ complaint (_("file index out of range"));
+ else
+- sym->set_symtab (fe->symtab);
++ sym->set_symtab (fe->symtab (*file_cu));
+ }
+ }
+
diff --git a/gdb-rhbz2413405-gcore-unreadable-pages.patch b/gdb-rhbz2413405-gcore-unreadable-pages.patch
new file mode 100644
index 0000000..9dd5847
--- /dev/null
+++ b/gdb-rhbz2413405-gcore-unreadable-pages.patch
@@ -0,0 +1,188 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Kevin Buettner
+Date: Wed, 25 Feb 2026 19:58:50 -0700
+Subject: gdb-rhbz2413405-gcore-unreadable-pages.patch
+
+;; Backport of upstream commit c1da013915e from Kevin Buettner
+;; (RHBZ 2413405).
+
+gcore: Handle unreadable pages within readable memory regions
+
+GLIBC 2.42 changed how thread stack guard pages are implemented [2].
+In GLIBC 2.41 and earlier, guard pages were set up using mprotect() to
+mark guard regions with no permissions. Once configured, guard pages
+were visible as separate entries in /proc/PID/maps with no permissions
+(i.e. they're inaccessible). In GLIBC 2.42, guard pages are
+installed using the kernel's MADV_GUARD_INSTALL mechanism [1], which
+marks them at the page table entry (PTE) level within the existing
+mapping.
+
+As a consequence, guard pages do not appear as separate entries in
+/proc/PID/maps, but remain as part of the containing mapping. Moreover,
+thread stacks from multiple mmap() calls may be merged into a single
+virtual memory area (VMA) with read and write permissions since there's
+no guard page VMA to separate them. These guard pages cannot be
+distinguished by examining VMA listings but do return EIO when read
+from /proc/PID/mem.
+
+GDB's gcore code reads /proc/PID/smaps to discover memory regions and
+creates one BFD section per mapping. (On linux, this is performed in
+linux_find_memory_regions_full in linux-tdep.c.) With the old layout,
+memory areas with guard pages appeared separately with no permissions,
+which were filtered out. Each thread stack became its own section
+containing only readable data. With the new layout, using
+MADV_GUARD_INSTALL instead of the older mechanism, it's often the case
+that thread stacks created with multiple calls to mmap() are exposed
+as a single mapping appearing in /proc/PID/smaps with read and write
+permissions. Should that happen, GDB's code creates a single section
+covering all thread stacks and their guard pages. (Even if each
+thread stack appears in its own mapping, the fact remains that there
+will be an inaccessible portion of the mapping. When one or more
+thread stacks are coalesced into a single mapping, there will be
+several inaccessible "holes" representing the guard pages.)
+
+When gcore_copy_callback copies section contents, it reads memory in
+1MB (MAX_COPY_BYTES) chunks. If any page in the chunk is a guard page,
+the call to target_read_memory() fails. The old code responded by
+breaking out of the copy loop, abandoning the entire section. This
+prevents correct copying of thread stack data, resulting in core files
+with zero-filled thread stacks, resulting in nearly empty backtraces.
+
+Fix this by falling back to page-by-page reading when a 1MB chunk read
+fails. Individual pages that cannot be read are filled with zeros,
+allowing the remaining readable memory to be captured.
+
+I also considered a simpler change using the value of
+FALLBACK_PAGE_SIZE (4096) as the read size instead of MAX_COPY_BYTES
+(1MB). This would avoid the fallback logic but would cause up to 256x
+more syscalls. The proposed approach also allows meaningful warnings:
+we warn only if an entire region is unreadable (indicating a real
+problem), whereas per-page reads would make it harder to distinguish
+guard page failures from actual errors. Since guard pages are at
+offset 0 for downward-growing stacks, a large target_read_memory()
+fails early at the first unreadable byte anyway.
+
+With this fix, I see 16 failures resolved in the following test cases:
+
+ gdb.ada/task_switch_in_core.exp
+ gdb.arch/i386-tls-regs.exp
+ gdb.threads/threadcrash.exp
+ gdb.threads/tls-core.exp
+
+Looking at just one of these, from gdb.log without the fix, I see:
+
+ thread apply 5 backtrace
+
+ Thread 5 (LWP 3414829):
+ #0 0x00007ffff7d1d982 in __syscall_cancel_arch () from /lib64/libc.so.6
+ #1 0x0000000000000000 in ?? ()
+ (gdb) FAIL: gdb.threads/threadcrash.exp: test_gcore: thread apply 5 backtrace
+
+And this is what it looks like with the fix in place (some paths have
+been shortened):
+
+ thread apply 5 backtrace
+
+ Thread 5 (Thread 0x7fffeffff6c0 (LWP 1282651) "threadcrash"):
+ #0 0x00007ffff7d1d982 in __syscall_cancel_arch () from /lib64/libc.so.6
+ #1 0x00007ffff7d11c3c in __internal_syscall_cancel () from /lib64/libc.so.6
+ #2 0x00007ffff7d61b62 in clock_nanosleep@GLIBC_2.2.5 () from /lib64/libc.so.6
+ #3 0x00007ffff7d6db37 in nanosleep () from /lib64/libc.so.6
+ #4 0x00007ffff7d8008e in sleep () from /lib64/libc.so.6
+ #5 0x00000000004006a8 in do_syscall_task (location=NORMAL) at threadcrash.c:158
+ #6 0x0000000000400885 in thread_function (arg=0x404340) at threadcrash.c:277
+ #7 0x00007ffff7d15464 in start_thread () from /lib64/libc.so.6
+ #8 0x00007ffff7d985ac in __clone3 () from /lib64/libc.so.6
+ (gdb) PASS: gdb.threads/threadcrash.exp: test_live_inferior: thread apply 5 backtrace
+
+Regression testing on Fedora 42 (glibc 2.41) shows no new failures.
+
+The v1 patch used SPARSE_BLOCK_SIZE as the fallback size. While it
+was the correct size, it's used for an entirely different purpose
+elsewhere in this file. This v2 commit introduces the constant
+FALLBACK_PAGE_SIZE instead.
+
+References:
+
+[1] Linux commit 662df3e5c376 ("mm: madvise: implement lightweight
+ guard page mechanism")
+ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=662df3e5c37666d6ed75c88098699e070a4b35b5
+[2] glibc commit a6fbe36b7f31 ("nptl: Add support for setup guard
+ pages with MADV_GUARD_INSTALL")
+ https://sourceware.org/git/?p=glibc.git;a=commit;h=a6fbe36b7f31292981422692236465ab56670ea9
+
+Claude Opus 4.5 and GLM 4.7 assisted with the development of this commit.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33855
+Approved-By: Tom de Vries
+
+diff --git a/gdb/gcore.c b/gdb/gcore.c
+--- a/gdb/gcore.c
++++ b/gdb/gcore.c
+@@ -744,6 +744,12 @@ sparse_bfd_set_section_contents (bfd *obfd, asection *osec,
+ return true;
+ }
+
++/* Fallback page size to use when target_read_memory fails when attempting
++ to read MAX_COPY_BYTES in gcore_copy_callback. 4KB is the correct size
++ to use for x86 and most other architectures. Some may have larger pages,
++ but this size will still work at the cost of more syscalls. */
++#define FALLBACK_PAGE_SIZE 0x1000
++
+ static void
+ gcore_copy_callback (bfd *obfd, asection *osec)
+ {
+@@ -766,15 +772,45 @@ gcore_copy_callback (bfd *obfd, asection *osec)
+ if (size > total_size)
+ size = total_size;
+
+- if (target_read_memory (bfd_section_vma (osec) + offset,
+- memhunk.data (), size) != 0)
++ CORE_ADDR vma = bfd_section_vma (osec) + offset;
++
++ if (target_read_memory (vma, memhunk.data (), size) != 0)
+ {
+- warning (_("Memory read failed for corefile "
+- "section, %s bytes at %s."),
+- plongest (size),
+- paddress (current_inferior ()->arch (),
+- bfd_section_vma (osec)));
+- break;
++ /* Large read failed. This can happen when the memory region
++ contains unreadable pages (such as guard pages embedded within
++ a larger mapping). Fall back to reading page by page, filling
++ unreadable pages with zeros. */
++ gdb_byte *p = memhunk.data ();
++ bfd_size_type remaining = size;
++ CORE_ADDR addr = vma;
++ bool at_least_one_page_read = false;
++
++ while (remaining > 0)
++ {
++ bfd_size_type chunk_size
++ = std::min (remaining, (bfd_size_type) FALLBACK_PAGE_SIZE);
++
++ if (target_read_memory (addr, p, chunk_size) != 0)
++ {
++ /* Failed to read this page. Fill with zeros. This
++ handles guard pages and other unreadable regions
++ that may exist within a larger readable mapping. */
++ memset (p, 0, chunk_size);
++ }
++ else
++ at_least_one_page_read = true;
++
++ p += chunk_size;
++ addr += chunk_size;
++ remaining -= chunk_size;
++ }
++ /* Warn only if the entire region was unreadable - this
++ indicates a real problem, not just embedded guard pages. */
++ if (!at_least_one_page_read)
++ warning (_("Memory read failed for corefile "
++ "section, %s bytes at %s."),
++ plongest (size),
++ paddress (current_inferior ()->arch (), vma));
+ }
+
+ if (!sparse_bfd_set_section_contents (obfd, osec, memhunk.data (),
diff --git a/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch b/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch
new file mode 100644
index 0000000..90473a1
--- /dev/null
+++ b/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch
@@ -0,0 +1,27 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Kevin Buettner
+Date: Wed, 7 Jan 2026 23:51:38 -0700
+Subject: gdb-rhbz2424325-c++20-implicit-lambda-capture.patch
+
+;; Backport Tom de Vries fix regarding implicit lambda captures
+;; (RH BZ 2424325).
+
+[gdb/build, c++20] Fix deprecated implicit capture in cooked_index::set_contents
+
+Fix deprecated implicit capture of this in cooked_index::set_contents, by
+removing the capture default, and explicitly listing all captures.
+
+Tested on x86_64-linux.
+
+diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
+--- a/gdb/dwarf2/cooked-index.c
++++ b/gdb/dwarf2/cooked-index.c
+@@ -102,7 +102,7 @@ cooked_index::set_contents ()
+ {
+ auto this_shard = shard.get ();
+ const parent_map_map *parent_maps = m_state->get_parent_map_map ();
+- finalizers.add_task ([=] ()
++ finalizers.add_task ([this, this_shard, parent_maps] ()
+ {
+ scoped_time_it time_it ("DWARF finalize worker",
+ m_state->m_per_command_time);
diff --git a/gdb-rhbz2424325-c23-const-build-warnings.patch b/gdb-rhbz2424325-c23-const-build-warnings.patch
new file mode 100644
index 0000000..517ee6e
--- /dev/null
+++ b/gdb-rhbz2424325-c23-const-build-warnings.patch
@@ -0,0 +1,209 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Kevin Buettner
+Date: Wed, 7 Jan 2026 22:12:42 -0700
+Subject: gdb-rhbz2424325-c23-const-build-warnings.patch
+
+;; Backport Guinevere Larsen's build warning fixes (RH BZ 2424325).
+
+bfd: fix build with C23
+
+Starting in C23, strchr and strrchr will return const char *, if fed a
+const char *. This means that several files in the BFD directory will
+fail to build as they are assigning the return of those functions to a
+char *.
+
+Fix this by const-ifying several variables. The only place where that
+wasn't just that was in targets.c, where a variable was being used in
+subsequent strrchr invocations to change the underlying string, so a new
+variable had to be introduced.
+
+No user-visible change should happen after this commit.
+
+diff --git a/bfd/bfd.c b/bfd/bfd.c
+--- a/bfd/bfd.c
++++ b/bfd/bfd.c
+@@ -1060,7 +1060,7 @@ _bfd_doprnt (bfd_print_callback print, void *stream, const char *format,
+ if (*ptr != '%')
+ {
+ /* While we have regular characters, print them. */
+- char *end = strchr (ptr, '%');
++ const char *end = strchr (ptr, '%');
+ if (end != NULL)
+ result = print (stream, "%.*s", (int) (end - ptr), ptr);
+ else
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -148,7 +148,7 @@ _bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie,
+ struct elf_link_hash_entry *h;
+
+ h = get_ext_sym_hash_from_cookie (cookie, r_symndx);
+-
++
+ if (h != NULL)
+ {
+ if ((h->root.type == bfd_link_hash_defined
+@@ -588,7 +588,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
+ if (h->dynindx == -1)
+ {
+ struct elf_strtab_hash *dynstr;
+- char *p;
++ const char *p;
+ const char *name;
+ size_t indx;
+
+@@ -718,7 +718,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
+ if (h->versioned == unknown)
+ {
+ /* Set versioned if symbol version is unknown. */
+- char *version = strrchr (name, ELF_VER_CHR);
++ const char *version = strrchr (name, ELF_VER_CHR);
+ if (version)
+ {
+ if (version > name && version[-1] != ELF_VER_CHR)
+@@ -1152,7 +1152,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ bool newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
+ bool newweak, oldweak, newfunc, oldfunc;
+ const struct elf_backend_data *bed;
+- char *new_version;
++ const char *new_version;
+ bool default_sym = *matched;
+ struct elf_link_hash_table *htab;
+
+@@ -1224,7 +1224,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ {
+ /* OLD_VERSION is the symbol version of the existing
+ symbol. */
+- char *old_version;
++ const char *old_version;
+
+ if (h->versioned >= versioned)
+ old_version = strrchr (h->root.root.string,
+@@ -1950,7 +1950,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
+ bool collect;
+ bool dynamic;
+ bfd *override;
+- char *p;
++ const char *p;
+ size_t len, shortlen;
+ asection *tmp_sec;
+ bool matched;
+@@ -2642,7 +2642,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
+ struct bfd_link_info *info;
+ const struct elf_backend_data *bed;
+ struct elf_info_failed eif;
+- char *p;
++ const char *p;
+ bool hide;
+
+ sinfo = (struct elf_info_failed *) data;
+@@ -5641,7 +5641,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
+ && !dynamic
+ && (abfd->flags & BFD_PLUGIN) == 0)
+ {
+- char *p = strchr (name, ELF_VER_CHR);
++ const char *p = strchr (name, ELF_VER_CHR);
+ if (p != NULL && p[1] != ELF_VER_CHR)
+ {
+ /* Queue non-default versions so that .symver x, x@FOO
+@@ -5891,7 +5891,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
+ for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt)
+ {
+ struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
+- char *shortname, *p;
++ char *shortname;
++ const char *p;
+ size_t amt;
+
+ p = strchr (h->root.root.string, ELF_VER_CHR);
+@@ -6171,7 +6172,8 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
+ const char *name)
+ {
+ struct bfd_link_hash_entry *h;
+- char *p, *copy;
++ const char *p;
++ char *copy;
+ size_t len, first;
+
+ h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+@@ -6466,7 +6468,7 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
+ name = h->root.root.string;
+ if (h->versioned >= versioned)
+ {
+- char *p = strchr (name, ELF_VER_CHR);
++ const char *p = strchr (name, ELF_VER_CHR);
+ if (p != NULL)
+ {
+ alc = (char *) bfd_malloc (p - name + 1);
+@@ -6539,7 +6541,7 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
+ name = h->root.root.string;
+ if (h->versioned >= versioned)
+ {
+- char *p = strchr (name, ELF_VER_CHR);
++ const char *p = strchr (name, ELF_VER_CHR);
+ if (p != NULL)
+ {
+ alc = (char *) bfd_malloc (p - name + 1);
+@@ -10378,8 +10380,8 @@ elf_link_output_symstrtab (void *finf,
+ {
+ /* Keep only one '@' for versioned symbols defined in
+ shared objects. */
+- char *version = strrchr (name, ELF_VER_CHR);
+- char *base_end = strchr (name, ELF_VER_CHR);
++ const char *version = strrchr (name, ELF_VER_CHR);
++ const char *base_end = strchr (name, ELF_VER_CHR);
+ if (version != base_end)
+ {
+ size_t base_len;
+@@ -11118,7 +11120,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
+ || h->ref_dynamic
+ || !h->def_regular))
+ {
+- char *p = strrchr (h->root.root.string, ELF_VER_CHR);
++ const char *p = strrchr (h->root.root.string, ELF_VER_CHR);
+
+ if (p && p [1] != '\0')
+ {
+@@ -11670,7 +11672,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
+ input_bfd);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+- }
++ }
+
+ /* Arrange for symbol to be output. */
+ h->indx = -2;
+@@ -15142,7 +15144,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
+ struct elf_link_hash_entry *h;
+
+ h = get_ext_sym_hash_from_cookie (rcookie, r_symndx);
+-
++
+ if (h != NULL)
+ {
+ if ((h->root.type == bfd_link_hash_defined
+diff --git a/bfd/targets.c b/bfd/targets.c
+--- a/bfd/targets.c
++++ b/bfd/targets.c
+@@ -1660,7 +1660,7 @@ bfd_get_target_info (const char *target_name, bfd *abfd,
+
+ if (arches && tname)
+ {
+- char *hyp = strchr (tname, '-');
++ const char *hyp = strchr (tname, '-');
+
+ if (hyp != NULL)
+ {
+@@ -1673,9 +1673,10 @@ bfd_get_target_info (const char *target_name, bfd *abfd,
+ char new_tname[50];
+
+ strcpy (new_tname, hyp);
+- while ((hyp = strrchr (new_tname, '-')) != NULL)
++ char *new_hyp;
++ while ((new_hyp = strrchr (new_tname, '-')) != NULL)
+ {
+- *hyp = 0;
++ *new_hyp = 0;
+ if (_bfd_find_arch_match (new_tname, arches,
+ def_target_arch))
+ break;
diff --git a/gdb-rhbz2424325-c23-more-const-fixes.patch b/gdb-rhbz2424325-c23-more-const-fixes.patch
new file mode 100644
index 0000000..6655e73
--- /dev/null
+++ b/gdb-rhbz2424325-c23-more-const-fixes.patch
@@ -0,0 +1,175 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Keith Seitz
+Date: Wed, 7 Jan 2026 09:36:28 -0800
+Subject: gdb-rhbz2424325-c23-more-const-fixes.patch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+;; Backport Keith Seitz's C23 const-correctness fixes (pending upstream review).
+;; Mailing list: https://sourceware.org/pipermail/binutils/2026-January/...
+;; Posted 2026-01-07, not yet approved.
+
+Fix some more C23 const-correctness issues
+
+Fedora Rawhide is failing to build due to new glibc header changes
+enforcing const-correctness in functions like strchr and memchr.
+For example:
+
+../../opcodes/aarch64-dis.c: In function ‘remove_dot_suffix’:
+../../opcodes/aarch64-dis.c:4027:7: error: assignment discards ‘const’ qualifier from po
+inter target type [-Werror=discarded-qualifiers]
+ 4027 | ptr = strchr (inst->opcode->name, '.');
+ | ^
+cc1: all warnings being treated as errors
+
+This patch addresses all the discovered issues with --enable-targets=all
+and regenerates a few cgen files along the way.
+
+diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c
+--- a/bfd/elf32-arc.c
++++ b/bfd/elf32-arc.c
+@@ -550,7 +550,7 @@ arc_extract_features (const char *p)
+
+ for (i = 0; i < ARRAY_SIZE (bfd_feature_list); i++)
+ {
+- char *t = strstr (p, bfd_feature_list[i].attr);
++ const char *t = strstr (p, bfd_feature_list[i].attr);
+ unsigned l = strlen (bfd_feature_list[i].attr);
+ if ((t != NULL)
+ && (t[l] == ','
+diff --git a/bfd/vms-misc.c b/bfd/vms-misc.c
+--- a/bfd/vms-misc.c
++++ b/bfd/vms-misc.c
+@@ -492,14 +492,14 @@ get_vms_time_string (unsigned char *tbuf)
+ }
+
+ /* Create module name from filename (ie, extract the basename and convert it
+- in upper cases). Works on both VMS and UNIX pathes.
++ in upper cases). Works on both VMS and UNIX paths.
+ The result has to be free(). */
+
+ char *
+ vms_get_module_name (const char *filename, bool upcase)
+ {
+ char *fname, *fptr;
+- const char *fout;
++ const char *fout, *p;
+
+ /* Strip VMS path. */
+ fout = strrchr (filename, ']');
+@@ -511,9 +511,9 @@ vms_get_module_name (const char *filename, bool upcase)
+ fout = filename;
+
+ /* Strip UNIX path. */
+- fptr = strrchr (fout, '/');
+- if (fptr != NULL)
+- fout = fptr + 1;
++ p = strrchr (fout, '/');
++ if (p != NULL)
++ fout = p + 1;
+
+ fname = strdup (fout);
+
+diff --git a/cpu/ip2k.opc b/cpu/ip2k.opc
+--- a/cpu/ip2k.opc
++++ b/cpu/ip2k.opc
+@@ -94,7 +94,7 @@ parse_fr (CGEN_CPU_DESC cd,
+ {
+ const char *errmsg;
+ const char *old_strp;
+- char *afteroffset;
++ const char *afteroffset;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+ extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
+diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
+--- a/opcodes/aarch64-dis.c
++++ b/opcodes/aarch64-dis.c
+@@ -4061,7 +4061,7 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode,
+ static void
+ remove_dot_suffix (char *name, const aarch64_inst *inst)
+ {
+- char *ptr;
++ const char *ptr;
+ size_t len;
+
+ ptr = strchr (inst->opcode->name, '.');
+diff --git a/opcodes/ia64-opc.c b/opcodes/ia64-opc.c
+--- a/opcodes/ia64-opc.c
++++ b/opcodes/ia64-opc.c
+@@ -66,7 +66,7 @@ const struct ia64_templ_desc ia64_templ_desc[16] =
+ static void
+ get_opc_prefix (const char **ptr, char *dest)
+ {
+- char *c = strchr (*ptr, '.');
++ const char *c = strchr (*ptr, '.');
+ if (c != NULL)
+ {
+ memcpy (dest, *ptr, c - *ptr);
+diff --git a/opcodes/ip2k-asm.c b/opcodes/ip2k-asm.c
+--- a/opcodes/ip2k-asm.c
++++ b/opcodes/ip2k-asm.c
+@@ -59,7 +59,7 @@ parse_fr (CGEN_CPU_DESC cd,
+ {
+ const char *errmsg;
+ const char *old_strp;
+- char *afteroffset;
++ const char *afteroffset;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+ extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
+diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
+--- a/opcodes/riscv-dis.c
++++ b/opcodes/riscv-dis.c
+@@ -110,7 +110,7 @@ parse_riscv_dis_option_without_args (const char *option,
+ /* Parse RISC-V disassembler option (possibly with arguments). */
+
+ static void
+-parse_riscv_dis_option (const char *option, struct disassemble_info *info)
++parse_riscv_dis_option (char *option, struct disassemble_info *info)
+ {
+ char *equal, *value;
+
+@@ -1140,7 +1140,7 @@ riscv_update_map_state (int n,
+
+ /* ISA mapping string may be numbered, suffixed with '.n'. Do not
+ consider this as part of the ISA string. */
+- char *suffix = strchr (name, '.');
++ const char *suffix = strchr (name, '.');
+ if (suffix)
+ {
+ int suffix_index = (int)(suffix - name);
+diff --git a/opcodes/tilegx-opc.c b/opcodes/tilegx-opc.c
+--- a/opcodes/tilegx-opc.c
++++ b/opcodes/tilegx-opc.c
+@@ -8003,7 +8003,7 @@ tilegx_spr_compare (const void *a_ptr, const void *b_ptr)
+ const char *
+ get_tilegx_spr_name (int num)
+ {
+- void *result;
++ const void *result;
+ struct tilegx_spr key;
+
+ key.number = num;
+diff --git a/opcodes/tilepro-opc.c b/opcodes/tilepro-opc.c
+--- a/opcodes/tilepro-opc.c
++++ b/opcodes/tilepro-opc.c
+@@ -10119,7 +10119,7 @@ tilepro_spr_compare (const void *a_ptr, const void *b_ptr)
+ const char *
+ get_tilepro_spr_name (int num)
+ {
+- void *result;
++ const void *result;
+ struct tilepro_spr key;
+
+ key.number = num;
+@@ -10131,7 +10131,7 @@ get_tilepro_spr_name (int num)
+ return NULL;
+
+ {
+- struct tilepro_spr *result_ptr = (struct tilepro_spr *) result;
++ const struct tilepro_spr *result_ptr = (const struct tilepro_spr *) result;
+
+ return result_ptr->name;
+ }
diff --git a/gdb-rhbz2467251-computed-location-synthetic-pointers.patch b/gdb-rhbz2467251-computed-location-synthetic-pointers.patch
new file mode 100644
index 0000000..f2c1e0a
--- /dev/null
+++ b/gdb-rhbz2467251-computed-location-synthetic-pointers.patch
@@ -0,0 +1,1229 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess
+Date: Fri, 8 May 2026 21:44:12 +0100
+Subject: gdb-rhbz2467251-computed-location-synthetic-pointers.patch
+
+;; Backport the following upstream commits in order to address RHBZ
+;; 2467251: d980317c7f1, 958d06262a7, 7d1d7386561, 8915de0883c,
+;; 8f65ab7b71f. These commits will all drop out when we rebase to GDB
+;; 18.
+
+*** Commit d980317c7f1: gdb: int to bool conversion in valprint.{c,}h
+
+gdb: int to bool conversion in valprint.{c,h}
+
+Some int to bool conversion in valprint.c and valprint.h. I also
+moved the header comment on val_print_scalar_type_p into the header.
+
+There should be no user visible changes after this commit.
+
+Approved-By: Tom Tromey
+
+Commit 958d06262a7: gdb: fix coerce_pieced_ref for multi-piece values
+
+gdb: fix coerce_pieced_ref for multi-piece values
+
+Bug PR gdb/30693 describes a case where the following assertion can be
+triggered:
+
+ ../../gdb/dwarf2/loc.c:2213: internal-error: value* coerce_pieced_ref(const value*): Assertion `closure->pieces.size () == 1' failed.
+
+The problem is that coerce_pieced_ref makes the following claim:
+
+ /* gdb represents synthetic pointers as pieced values with a single
+ piece. */
+ gdb_assert (closure != NULL);
+ gdb_assert (closure->pieces.size () == 1);
+
+But this is not really true. If an aggregate type contains a synthetic
+pointer, then it is possible that the aggregate type will have a
+computed location consisting of multiple pieces. When GDB prints the
+fields of that aggregate type these fields are extracted by calling
+value::primitive_field. Within value::primitive_field the location of
+the field is set by calling value::set_component_location.
+
+When the parent value that holds the field has a computed location, the
+field value gains a reference to the parent value's closure, this can be
+seen in copy_pieced_value_closure in dwarf2/expr.c.
+
+What this means is that, if the aggregate value has a multi-piece
+computed location, then the synthetic pointer field will also have a
+reference to that same multi-piece computed location, even if there is
+really only a single piece that describes the synthetic pointer itself.
+
+Some parts of GDB are already aware of this. If we look at
+check_pieced_synthetic_pointer which implements the
+value::bits_synthetic_pointer function, you'll see that this function
+searches through all of the pieces to find the piece that covers the
+value we are looking for, it then checks if that piece is an implicit
+pointer location. But back in coerce_pieced_ref, after calling
+value::bits_synthetic_pointer, we still make the assertion that there
+will be just a single piece.
+
+Fix this by copying the search through all pieces logic into
+coerce_pieced_ref (see note on efficiency below). We now search through
+all the pieces looking for a piece that describes the location of the
+synthetic pointer, and we then use that piece to form the pointer's
+value.
+
+There are some assertions in the new code, these align with how
+check_pieced_synthetic_pointer operates.
+
+In addition, there is an error for the case where multiple pieces are
+used to describe the location of a synthetic pointer. This case is
+technically allowed by check_pieced_synthetic_pointer, but supporting
+this would require changes to indirect_synthetic_pointer, so I propose
+leaving that until we see such a case in the wild.
+
+On efficiency, you'll notice that check_pieced_synthetic_pointer
+performs a search through all the location pieces, and
+coerce_pieced_ref also has to search through the pieces. It would be
+nice if this could be avoided in order to avoid multiple searches.
+Currently though coerce_pieced_ref calls
+value->bits_synthetic_pointer, which is an API that should be agnostic
+to the underlying implementation, i.e. shouldn't need to know that the
+implementation is computed, so passing pieces back would be harder.
+
+Maybe coerce_pieced_ref could avoid the value::bits_synthetic_pointer
+call, and instead call check_pieced_synthetic_pointer directly, or
+some related helper function, and could get the pieces back that way.
+But this breaks the cleanly structured API that we currently have.
+
+For now I'm leaving things as they are. My assumption is that the
+number of pieces used to represent a value is pretty low, so the
+search is actually pretty cheap.
+
+There's a new test that uses the DWARF assembler to create a
+representative example of a multi-piece aggregate that contains a
+synthetic pointer member variable. This test triggers the assertion
+before this commit.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30693
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2467251
+
+Approved-By: Tom Tromey
+
+Commit 7d1d7386561: gdb: rename argument in valprint_check_validity
+
+gdb: rename argument in valprint_check_validity
+
+To understand the motivation for this commit you'll need to look ahead
+two commits in this series for an upcoming bug fix.
+
+Look at coerce_pieced_ref in dwarf2/expr.c, and this call:
+
+ if (value->bits_synthetic_pointer (value->embedded_offset (),
+ TARGET_CHAR_BIT * type->length ()))
+ { ... }
+
+This passes the result from value::embedded_offset as the first argument.
+Though it's not clear from value.h, the number returned by
+value::embedded_offset is a byte offset.
+
+The value::bits_synthetic_pointer call can end up calling
+check_pieced_synthetic_pointer, with the first argument to
+value::bits_synthetic_pointer becoming the second argument to
+check_pieced_synthetic_pointer. The second argument to
+check_pieced_synthetic_pointer is called BIT_OFFSET, a value in bits.
+Looking at how this argument is used confirms that it is expected to be
+a value in bits, not bytes.
+
+The fix should be easy, multiply the embedded offset by
+TARGET_CHAR_BIT, but I think things are a little more complex than
+this.
+
+I started looking at how value::bits_synthetic_pointer is used, there
+are only 7 uses, and they can be grouped as follows:
+
+gdb/dwarf2/expr.c
+gdb/valops.c
+
+ These call value::embedded_offset directly within the call to
+ value::bits_synthetic_pointer.
+
+gdb/opencl-lang.c
+
+ This function is used as a wrapper that implements a
+ lval_funcs::check_synthetic_pointer callback, it adjusts the
+ arguments and then calls value::bits_synthetic_pointer. As such we'd
+ not expect to see embedded offset mentioned here as that would (we
+ assume) be handled by the caller.
+
+gdb/valprint.c (in generic_val_print_ref)
+
+ This call passes an argument called 'embedded_offset', but the
+ function generic_val_print_ref is only used in one place, and the
+ embedded_offset is always passed as zero.
+
+gdb/valprint.c (in valprint_check_validity)
+
+ This call also passes an argument called 'embedded_offset'. This
+ function is used in two places. In common_val_print the
+ embedded_offset is always passed as zero, but in
+ valprint_check_validity (in cp-valprint.c) the embedded_offset being
+ passed is the offset of a field within the value, not the value's
+ embedded_offset within some larger value.
+
+gdb/cp-valprint.c
+gdb/p-valprint.c
+
+ As with the call to valprint_check_validity in cp-valprint.c, these
+ two direct calls to value::bits_synthetic_pointer pass the offset of a
+ field within the value, rather than the value's embedded_offset.
+
+What I see in the above is some confusion. In some places we are
+passing the value::embedded_offset, while in other places we are
+passing the offset of a field within the value itself.
+
+If we consider the direct call to value::bits_synthetic_pointer in
+gdb/cp-valprint.c, where a field offset is passed, then it should be
+possible, that if we can create an object with a non-zero
+embedded_offset (which isn't accounted for in this code path), then we
+should see some bugs in GDB, and indeed, this is what I do see.
+
+My plan for fixing this is to have the offset passed to
+value::bits_synthetic_pointer always be a field offset within the value,
+the value::embedded_offset will then be handled directly within the
+various value::bits_synthetic_pointer implementations.
+
+This commit is a small refactor in preparation for this fix.
+
+I believe part of the confusion here is that we have functions that
+take arguments called embedded_offset, when the value they should
+accept is no longer the embedded offset.
+
+So in this commit I propose renaming the embedded_offset argument to
+field_byte_offset in valprint_check_validity. This is purely a
+mechanical rename, there should be no user visible changes after this
+commit.
+
+Approved-By: Tom Tromey
+
+Commit 8915de0883c: gdb: remove embedded_offset argument that is always 0
+
+gdb: remove embedded_offset argument that is always 0
+
+For the background and motivation for this patch you should read the
+previous commit.
+
+The goal of this commit started as similar to the previous one; rename
+the embedded_offset argument to generic_val_print_ref. To do this I
+started tracing back which values are passed into this function so I
+could make sure the new argument name matched the usage.
+
+But it turns out that the only value that is ever passed to this
+function is zero.
+
+I believe that, like the last commit, the embedded_offset is actually
+representing the offset of a field within a value. However, in all of
+the use cases, the "field" being accessed is the entire value, hence
+why we always pass 0, we are asking about the whole value starting
+from the very beginning.
+
+Given this, I couldn't bring myself to rename the argument. Let's just
+remove it. It turns out that there's a bunch of functions in
+valprint.c that take an argument called embedded_offset, which are
+always zero.
+
+This commit removes the argument, and updates the code to assume zero.
+
+There should be no user visible changes after this commit.
+
+Approved-By: Tom Tromey
+
+Commit 8f65ab7b71f: gdb: use value::embedded_offset in check_pieced_synthetic_pointer
+
+gdb: use value::embedded_offset in check_pieced_synthetic_pointer
+
+This commit builds on the previous two commits. You should go and
+read them both for context.
+
+Looking at the users of value::bits_synthetic_pointer, all callers but
+two are now passing either the offset of a field within the value, or
+hard-coded zero as they want to ask about the entire value.
+
+The two exceptions are in coerce_pieced_ref (in dwarf2/expr.c) and in
+value_addr (in valops.c) where we still pass value::embedded_offset.
+
+The problem is that some of the other callers, where we currently pass
+just a field offset, might also have a non-zero embedded offset,
+specifically, the call in cp_print_value_fields is in this category.
+In cp_print_value_fields we are printing fields from a value which is
+potentially a base class contained within an instance of a derived
+class, this will be represented by a non-zero embedded_offset, which
+is currently not taken into account.
+
+Additionally, the two callers that currently pass the
+value::embedded_offset don't scale the embedded offset from bytes to
+bits.
+
+The failure to scale from bytes to bits is interesting, I originally
+tried to create some tests that exposed this, but constantly failed.
+It turns out, that in both these locations, in all code paths that I
+could find, the value::embedded_offset will always be zero. For
+example in coerce_pieced_ref, a reference cannot be a base class, and
+so we never expect to see a non-zero embedded_offset in this case.
+
+Similarly, in value_addr, the use of value::bits_synthetic_pointer is
+within a block that only applies to reference types, which means the
+embedded_offset will be zero.
+
+Now within check_pieced_synthetic_pointer we already add the
+value::offset into the bit_offset which is passed in. Remember, after
+the previous two commits, the incoming bit_offset is (almost) always
+the offset of a field within the value. The almost here is the two
+cases mentioned above.
+
+I propose that within check_pieced_synthetic_pointer we should take
+into account both value::offset and value::embedded_offset. Then the
+two cases that currently pass value::embedded_offset can be changed to
+just pass zero.
+
+With this done, and the previous two commits, we now have a consistent
+model. value::bits_synthetic_pointer expects the (bit) offset of a
+field within the value to check. In many cases this will be zero
+meaning we want to check from the start of the value, but in some
+cases it can be non-zero.
+
+Then within value::bits_synthetic_pointer implementations, like
+check_pieced_synthetic_pointer, we will take the value::offset and
+value::embedded_offset into account, remembering to scale them from
+bytes to bits.
+
+I have also changed indirect_pieced_value to also take the
+embedded_offset into account. I have done this for consistency rather
+than necessity. I believe that the embedded_offset will always be
+zero within indirect_pieced_value. The indirect_pieced_value function
+is only called from value_ind (in valops.c), and only operates on
+TYPE_CODE_PTR types (checked for in indirect_pieced_value). As a
+TYPE_CODE_PTR cannot be the base class for a derived type, then we
+don't expect to ever see a TYPE_CODE_PTR value with a non-zero
+embedded_offset. But, having indirect_pieced_value take the embedded
+offset into account is simple enough, and future proofs the code.
+
+In both check_pieced_synthetic_pointer and indirect_pieced_value I
+have changed uses of '8' to 'TARGET_CHAR_BIT', I was already touching
+some of these lines, and I think TARGET_CHAR_BIT is clearer, but one
+line in indirect_pieced_value was just updated to use TARGET_CHAR_BIT,
+this is done for consistency.
+
+The gdb.dwarf2/multi-piece-inherited-bitfield.exp test fails without
+this patch, this exposes the case where the embedded_offset is
+non-zero and we were previously failing to take this into account.
+
+The gdb.dwarf2/multi-piece-primitive-field.exp test was something I
+wrote while trying to exercise the coerce_pieced_ref code path some
+more. It is an inheritance based version of the existing test, I was
+wondering if this would result in a value with a non-zero
+embedded_offset, but due to how the fields are extracted from the
+aggregate prior to calling coerce_pieced_ref the embedded_offset is
+always zero in this function.
+
+Approved-By: Tom Tromey
+
+diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
+--- a/gdb/dwarf2/expr.c
++++ b/gdb/dwarf2/expr.c
+@@ -492,7 +492,8 @@ check_pieced_synthetic_pointer (const value *value, LONGEST bit_offset,
+ piece_closure *c = (piece_closure *) value->computed_closure ();
+ int i;
+
+- bit_offset += 8 * value->offset ();
++ bit_offset += (TARGET_CHAR_BIT
++ * (value->offset () + value->embedded_offset ()));
+ if (value->bitsize ())
+ bit_offset += value->bitpos ();
+
+@@ -537,8 +538,9 @@ indirect_pieced_value (value *value)
+ if (type->code () != TYPE_CODE_PTR)
+ return NULL;
+
+- int bit_length = 8 * type->length ();
+- LONGEST bit_offset = 8 * value->offset ();
++ int bit_length = TARGET_CHAR_BIT * type->length ();
++ LONGEST bit_offset
++ = (TARGET_CHAR_BIT * (value->offset () + value->embedded_offset ()));
+ if (value->bitsize ())
+ bit_offset += value->bitpos ();
+
+@@ -602,22 +604,62 @@ coerce_pieced_ref (const value *value)
+ {
+ struct type *type = check_typedef (value->type ());
+
+- if (value->bits_synthetic_pointer (value->embedded_offset (),
+- TARGET_CHAR_BIT * type->length ()))
++ if (value->bits_synthetic_pointer (0, TARGET_CHAR_BIT * type->length ()))
+ {
+ const piece_closure *closure
+ = (piece_closure *) value->computed_closure ();
+ frame_info_ptr frame
+ = get_selected_frame (_("No frame selected."));
+
+- /* gdb represents synthetic pointers as pieced values with a single
+- piece. */
+- gdb_assert (closure != NULL);
+- gdb_assert (closure->pieces.size () == 1);
++ gdb_assert (closure != nullptr);
++
++ /* The value::bits_synthetic_pointer will return true if multiple
++ pieces are used to cover VALUE, so long as each piece is
++ DWARF_VALUE_IMPLICIT_POINTER. I guess maybe this is possible, but
++ we've not seen such a case in the wild yet. For now then we look
++ in CLOSURE for a single DWARF_VALUE_IMPLICIT_POINTER piece that
++ covers VALUE. */
++ LONGEST bit_offset = TARGET_CHAR_BIT * (value->embedded_offset ()
++ + value->offset ());
++ if (value->bitsize ())
++ bit_offset += value->bitpos ();
++ int bit_length = TARGET_CHAR_BIT * type->length ();
++
++ const dwarf_expr_piece *piece = nullptr;
++ for (size_t i = 0; i < closure->pieces.size (); i++)
++ {
++ const dwarf_expr_piece *p = &closure->pieces[i];
++ size_t this_size_bits = p->size;
++
++ if (bit_offset >= this_size_bits)
++ {
++ bit_offset -= this_size_bits;
++ continue;
++ }
++
++ /* value::bits_synthetic_pointer does allow for multiple
++ pieces to describe the location of a single synthetic
++ pointer, or for a synthetic pointer to not start at the
++ exact start of a piece, however, we don't currently
++ support this case. */
++ if (bit_offset != 0 || bit_length != this_size_bits)
++ error (_("unsupported value-piece configuration "
++ "bit_offset = %s, bit_length = %d, this_size_bits = %s"),
++ plongest (bit_offset), bit_length,
++ pulongest (this_size_bits));
++
++ piece = p;
++ break;
++ }
++
++ /* If value::bits_synthetic_pointer returned true then we should have
++ found a suitable piece. */
++ gdb_assert (piece != nullptr);
++ gdb_assert (piece->location == DWARF_VALUE_IMPLICIT_POINTER);
+
+ return indirect_synthetic_pointer
+- (closure->pieces[0].v.ptr.die_sect_off,
+- closure->pieces[0].v.ptr.offset,
++ (piece->v.ptr.die_sect_off,
++ piece->v.ptr.offset,
+ closure->per_cu, closure->per_objfile, frame, type);
+ }
+ else
+diff --git a/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.c b/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.c
+@@ -0,0 +1,25 @@
++/* Copyright (C) 2026 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 . */
++
++int target_var = 42;
++
++int
++main (void)
++{
++ asm ("main_label: .globl main_label");
++ return 0;
++}
+diff --git a/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.exp b/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dwarf2/multi-piece-inherited-bitfield.exp
+@@ -0,0 +1,151 @@
++# Copyright 2026 Free Software Foundation, Inc.
++#
++# 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 .
++
++# Setup a derived struct that uses multiple inheritance and is described
++# by a multi-piece DWARF location. The second base class contains a
++# bitfield member. At one time, printing such a struct would incorrectly
++# display the bitfield as .
++#
++# The cause was that check_pieced_synthetic_pointer (dwarf2/expr.c)
++# computes the bit offset as 8 * value->offset() but does not add
++# 8 * value->embedded_offset(). When a base subobject is extracted via
++# primitive_field, it gets a non-zero embedded_offset but offset remains
++# zero. check_pieced_synthetic_pointer then checks piece 0 instead of
++# the correct piece, and if piece 0 happens to be an implicit pointer,
++# it incorrectly reports the bitfield as a synthetic pointer.
++
++require allow_cplus_tests
++
++load_lib dwarf.exp
++
++# This test can only be run on targets which support DWARF-2 and use gas.
++require dwarf2_support
++
++standard_testfile .c .S
++
++set asm_file [standard_output_file ${srcfile2}]
++
++# First compile the C file only, so we can query some type sizes.
++if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
++ return
++}
++
++Dwarf::assemble ${asm_file} {
++ cu {} {
++ DW_TAG_compile_unit {
++ {DW_AT_language @DW_LANG_C_plus_plus}
++ } {
++ declare_labels char_label int_label first_label second_label \
++ derived_label target_label
++ set int_size [get_sizeof "int" -1]
++
++ char_label: DW_TAG_base_type {
++ {DW_AT_byte_size 1 DW_FORM_udata}
++ {DW_AT_encoding @DW_ATE_unsigned_char}
++ {DW_AT_name "char"}
++ }
++
++ int_label: DW_TAG_base_type {
++ {DW_AT_byte_size ${int_size} DW_FORM_udata}
++ {DW_AT_encoding @DW_ATE_signed}
++ {DW_AT_name "int"}
++ }
++
++ first_label: DW_TAG_structure_type {
++ {DW_AT_name "First"}
++ {DW_AT_byte_size 1 DW_FORM_udata}
++ } {
++ DW_TAG_member {
++ {DW_AT_name "a"}
++ {DW_AT_type :${char_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++ }
++
++ second_label: DW_TAG_structure_type {
++ {DW_AT_name "Second"}
++ {DW_AT_byte_size 1 DW_FORM_udata}
++ } {
++ DW_TAG_member {
++ {DW_AT_name "bf"}
++ {DW_AT_type :${int_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ {DW_AT_bit_size 8 DW_FORM_udata}
++ }
++ }
++
++ derived_label: DW_TAG_structure_type {
++ {DW_AT_name "Derived"}
++ {DW_AT_byte_size 2 DW_FORM_udata}
++ } {
++ DW_TAG_inheritance {
++ {DW_AT_type :${first_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++
++ DW_TAG_inheritance {
++ {DW_AT_type :${second_label}}
++ {DW_AT_data_member_location 1 DW_FORM_udata}
++ }
++ }
++
++ target_label: DW_TAG_variable {
++ {DW_AT_name "target_var"}
++ {DW_AT_type :${int_label}}
++ {DW_AT_external 1 DW_FORM_flag}
++ {DW_AT_location {
++ DW_OP_addr [gdb_target_symbol "target_var"]
++ } SPECIAL_expr}
++ }
++
++ DW_TAG_subprogram {
++ {MACRO_AT_func { "main" }}
++ {DW_AT_type :${int_label}}
++ {DW_AT_external 1 DW_FORM_flag}
++ } {
++ DW_TAG_variable {
++ {DW_AT_name "d"}
++ {DW_AT_type :${derived_label}}
++ {DW_AT_location {
++ DW_OP_GNU_implicit_pointer $target_label 0
++ DW_OP_piece 1
++ DW_OP_const1u 42
++ DW_OP_stack_value
++ DW_OP_piece 1
++ } SPECIAL_expr}
++ }
++ }
++ }
++ }
++}
++
++# Now compile both C source and generated DWARF assembly.
++if {[prepare_for_testing "failed to prepare" ${testfile} \
++ [list ${asm_file} ${srcfile}] {}]} {
++ return
++}
++
++# Start the inferior so that 'd' is in scope.
++if {![runto_main]} {
++ return
++}
++
++# With the bug in check_pieced_synthetic_pointer, the bitfield bf in the
++# Second base subobject is incorrectly reported as .
++# This happens because check_pieced_synthetic_pointer does not account for
++# embedded_offset, so it checks piece 0 (the implicit pointer covering
++# First) instead of piece 1 (the stack value covering Second).
++gdb_test "print d" " = { = {a = }, = {bf = 42}, }" \
++ "bitfield in base subobject is not synthetic pointer"
+diff --git a/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.c b/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.c
+@@ -0,0 +1,25 @@
++/* Copyright (C) 2026 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 . */
++
++int target_var = 42;
++
++int
++main (void)
++{
++ asm ("main_label: .globl main_label");
++ return 0;
++}
+diff --git a/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.exp b/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.dwarf2/multi-piece-primitive-field.exp
+@@ -0,0 +1,190 @@
++# Copyright 2026 Free Software Foundation, Inc.
++#
++# 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 .
++
++# Setup a struct variable that is described by a multi-piece DWARF location.
++# One of the struct's fields is a C++ reference type implemented via
++# DW_OP_GNU_implicit_pointer. At one time, attempting to print such a field
++# would trigger an assertion in GDB.
++#
++# The cause was that primitive_field extracts the reference field and
++# set_component_location copies the parent's entire piece_closure (just
++# incrementing its refcount). Then coerce_pieced_ref would assert
++# closure->pieces.size() == 1, which failed because the closure still had
++# all the parent's pieces.
++#
++# This test confirms that this issue has now been fixed.
++
++require allow_cplus_tests
++
++load_lib dwarf.exp
++
++# This test can only be run on targets which support DWARF-2 and use gas.
++require dwarf2_support
++
++standard_testfile .c .S
++
++set asm_file [standard_output_file ${srcfile2}]
++
++# First compile the C file only, so we can query some type sizes.
++if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
++ return
++}
++
++Dwarf::assemble ${asm_file} {
++ cu {} {
++ DW_TAG_compile_unit {
++ {DW_AT_language @DW_LANG_C_plus_plus}
++ } {
++ declare_labels int_label struct_label ref_type_label target_label \
++ first_label second_label derived_label
++ set int_size [get_sizeof "int" -1]
++ set addr_size [get_sizeof "void *" -1]
++ set struct_size [expr {$int_size + $addr_size}]
++
++ int_label: DW_TAG_base_type {
++ {DW_AT_byte_size ${int_size} DW_FORM_udata}
++ {DW_AT_encoding @DW_ATE_signed}
++ {DW_AT_name "int"}
++ }
++
++ ref_type_label: DW_TAG_reference_type {
++ {DW_AT_byte_size ${addr_size} DW_FORM_udata}
++ {DW_AT_type :${int_label}}
++ }
++
++ struct_label: DW_TAG_structure_type {
++ {DW_AT_name "S"}
++ {DW_AT_byte_size ${struct_size} DW_FORM_udata}
++ } {
++ DW_TAG_member {
++ {DW_AT_name "x"}
++ {DW_AT_type :${int_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++
++ DW_TAG_member {
++ {DW_AT_name "ref"}
++ {DW_AT_type :${ref_type_label}}
++ {DW_AT_data_member_location ${int_size} DW_FORM_udata}
++ }
++ }
++
++ first_label: DW_TAG_structure_type {
++ {DW_AT_name "first"}
++ {DW_AT_byte_size ${int_size} DW_FORM_udata}
++ } {
++ DW_TAG_member {
++ {DW_AT_name "x"}
++ {DW_AT_type :${int_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++ }
++
++ second_label: DW_TAG_structure_type {
++ {DW_AT_name "second"}
++ {DW_AT_byte_size ${addr_size} DW_FORM_udata}
++ } {
++ DW_TAG_member {
++ {DW_AT_name "ref"}
++ {DW_AT_type :${ref_type_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++ }
++
++ derived_label: DW_TAG_structure_type {
++ {DW_AT_name "derived"}
++ {DW_AT_byte_size ${struct_size} DW_FORM_udata}
++ } {
++ DW_TAG_inheritance {
++ {DW_AT_type :${first_label}}
++ {DW_AT_data_member_location 0 DW_FORM_udata}
++ }
++
++ DW_TAG_inheritance {
++ {DW_AT_type :${second_label}}
++ {DW_AT_data_member_location ${int_size} DW_FORM_udata}
++ }
++ }
++
++ target_label: DW_TAG_variable {
++ {DW_AT_name "target_var"}
++ {DW_AT_type :${int_label}}
++ {DW_AT_external 1 DW_FORM_flag}
++ {DW_AT_location {
++ DW_OP_addr [gdb_target_symbol "target_var"]
++ } SPECIAL_expr}
++ }
++
++ DW_TAG_subprogram {
++ {MACRO_AT_func { "main" }}
++ {DW_AT_type :${int_label}}
++ {DW_AT_external 1 DW_FORM_flag}
++ } {
++ DW_TAG_variable {
++ {DW_AT_name "s"}
++ {DW_AT_type :${struct_label}}
++ {DW_AT_location {
++ DW_OP_const4u 123
++ DW_OP_stack_value
++ DW_OP_piece $int_size
++ DW_OP_GNU_implicit_pointer $target_label 0
++ DW_OP_piece $addr_size
++ } SPECIAL_expr}
++ }
++
++ DW_TAG_variable {
++ {DW_AT_name "d"}
++ {DW_AT_type :${derived_label}}
++ {DW_AT_location {
++ DW_OP_const4u 456
++ DW_OP_stack_value
++ DW_OP_piece $int_size
++ DW_OP_GNU_implicit_pointer $target_label 0
++ DW_OP_piece $addr_size
++ } SPECIAL_expr}
++ }
++ }
++ }
++ }
++}
++
++# Now compile both C source and generated DWARF assembly.
++if {[prepare_for_testing "failed to prepare" ${testfile} \
++ [list ${asm_file} ${srcfile}] {}]} {
++ return
++}
++
++# Start the inferior so that 's' is in scope.
++if {![runto_main]} {
++ return
++}
++
++# Printing `s` used to crash with an assertion failure in coerce_pieced_ref
++# because the ref field inherited the parent struct's multi-piece closure.
++gdb_test "print s" " = {x = 123, ref = @$hex}" \
++ "print multi-piece struct with implicit pointer reference field"
++
++gdb_test "print s.ref" " = \\(int &\\) @$hex: 42" \
++ "print ref member of multi-piece struct"
++
++# Same test but with inheritance. The reference field is in the
++# second base class, so it reaches coerce_pieced_ref through a
++# different path to the above case.
++gdb_test "print d" \
++ " = { = {x = 456}, = {ref = @$hex}, }" \
++ "print inherited multi-piece struct with implicit pointer ref"
++
++gdb_test "print d.ref" " = \\(int &\\) @$hex: 42" \
++ "print ref member of inherited multi-piece struct"
+diff --git a/gdb/valops.c b/gdb/valops.c
+--- a/gdb/valops.c
++++ b/gdb/valops.c
+@@ -1545,8 +1545,7 @@ value_addr (struct value *arg1)
+
+ if (TYPE_IS_REFERENCE (type))
+ {
+- if (arg1->bits_synthetic_pointer (arg1->embedded_offset (),
+- TARGET_CHAR_BIT * type->length ()))
++ if (arg1->bits_synthetic_pointer (0, TARGET_CHAR_BIT * type->length ()))
+ arg1 = coerce_ref (arg1);
+ else
+ {
+diff --git a/gdb/valprint.c b/gdb/valprint.c
+--- a/gdb/valprint.c
++++ b/gdb/valprint.c
+@@ -92,7 +92,6 @@ static void set_output_radix_1 (int, unsigned);
+
+ static void val_print_type_code_flags (struct type *type,
+ struct value *original_value,
+- int embedded_offset,
+ struct ui_file *stream);
+
+ /* Start print_max at this value. */
+@@ -310,11 +309,9 @@ show_symbol_print (struct ui_file *file, int from_tty,
+
+
+
+-/* A helper function for val_print. When printing in "summary" mode,
+- we want to print scalar arguments, but not aggregate arguments.
+- This function distinguishes between the two. */
++/* See valprint.h. */
+
+-int
++bool
+ val_print_scalar_type_p (struct type *type)
+ {
+ type = check_typedef (type);
+@@ -330,9 +327,9 @@ val_print_scalar_type_p (struct type *type)
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_STRING:
+- return 0;
++ return false;
+ default:
+- return 1;
++ return true;
+ }
+ }
+
+@@ -350,10 +347,10 @@ val_print_scalar_or_string_type_p (struct type *type,
+
+ /* See valprint.h. */
+
+-int
++bool
+ valprint_check_validity (struct ui_file *stream,
+ struct type *type,
+- LONGEST embedded_offset,
++ LONGEST field_byte_offset,
+ const struct value *val)
+ {
+ type = check_typedef (type);
+@@ -361,31 +358,31 @@ valprint_check_validity (struct ui_file *stream,
+ if (type_not_associated (type))
+ {
+ val_print_not_associated (stream);
+- return 0;
++ return false;
+ }
+
+ if (type_not_allocated (type))
+ {
+ val_print_not_allocated (stream);
+- return 0;
++ return false;
+ }
+
+ if (type->code () != TYPE_CODE_UNION
+ && type->code () != TYPE_CODE_STRUCT
+ && type->code () != TYPE_CODE_ARRAY)
+ {
+- if (val->bits_any_optimized_out (TARGET_CHAR_BIT * embedded_offset,
++ if (val->bits_any_optimized_out (TARGET_CHAR_BIT * field_byte_offset,
+ TARGET_CHAR_BIT * type->length ()))
+ {
+ val_print_optimized_out (val, stream);
+- return 0;
++ return false;
+ }
+
+- if (val->bits_synthetic_pointer (TARGET_CHAR_BIT * embedded_offset,
++ if (val->bits_synthetic_pointer (TARGET_CHAR_BIT * field_byte_offset,
+ TARGET_CHAR_BIT * type->length ()))
+ {
+- const int is_ref = type->code () == TYPE_CODE_REF;
+- int ref_is_addressable = 0;
++ const bool is_ref = type->code () == TYPE_CODE_REF;
++ bool ref_is_addressable = false;
+
+ if (is_ref)
+ {
+@@ -403,14 +400,14 @@ valprint_check_validity (struct ui_file *stream,
+ return is_ref;
+ }
+
+- if (!val->bytes_available (embedded_offset, type->length ()))
++ if (!val->bytes_available (field_byte_offset, type->length ()))
+ {
+ val_print_unavailable (stream);
+- return 0;
++ return false;
+ }
+ }
+
+- return 1;
++ return true;
+ }
+
+ void
+@@ -595,14 +592,13 @@ generic_value_print_ptr (struct value *val, struct ui_file *stream,
+
+ static void
+ print_ref_address (struct type *type, const gdb_byte *address_buffer,
+- int embedded_offset, struct ui_file *stream)
++ struct ui_file *stream)
+ {
+ struct gdbarch *gdbarch = type->arch ();
+
+ if (address_buffer != NULL)
+ {
+- CORE_ADDR address
+- = extract_typed_address (address_buffer + embedded_offset, type);
++ CORE_ADDR address = extract_typed_address (address_buffer, type);
+
+ gdb_printf (stream, "@");
+ gdb_puts (paddress (gdbarch, address), stream);
+@@ -631,32 +627,27 @@ get_value_addr_contents (struct value *deref_val)
+
+ static void
+ generic_val_print_ref (struct type *type,
+- int embedded_offset, struct ui_file *stream, int recurse,
++ struct ui_file *stream, int recurse,
+ struct value *original_value,
+ const struct value_print_options *options)
+ {
+ struct type *elttype = check_typedef (type->target_type ());
+ struct value *deref_val = NULL;
+ const bool value_is_synthetic
+- = original_value->bits_synthetic_pointer (TARGET_CHAR_BIT * embedded_offset,
+- TARGET_CHAR_BIT * type->length ());
+- const int must_coerce_ref = ((options->addressprint && value_is_synthetic)
+- || options->deref_ref);
+- const int type_is_defined = elttype->code () != TYPE_CODE_UNDEF;
++ = original_value->bits_synthetic_pointer (0, (TARGET_CHAR_BIT
++ * type->length ()));
++ const bool must_coerce_ref = ((options->addressprint && value_is_synthetic)
++ || options->deref_ref);
++ const bool type_is_defined = elttype->code () != TYPE_CODE_UNDEF;
+ const gdb_byte *valaddr = original_value->contents_for_printing ().data ();
+
+ if (must_coerce_ref && type_is_defined)
+ {
+ deref_val = coerce_ref_if_computed (original_value);
+
+- if (deref_val != NULL)
+- {
+- /* More complicated computed references are not supported. */
+- gdb_assert (embedded_offset == 0);
+- }
+- else
++ if (deref_val == nullptr)
+ deref_val = value_at (type->target_type (),
+- unpack_pointer (type, valaddr + embedded_offset));
++ unpack_pointer (type, valaddr));
+ }
+ /* Else, original_value isn't a synthetic reference or we don't have to print
+ the reference's contents.
+@@ -676,7 +667,7 @@ generic_val_print_ref (struct type *type,
+ ? get_value_addr_contents (deref_val)
+ : valaddr);
+
+- print_ref_address (type, address, embedded_offset, stream);
++ print_ref_address (type, address, stream);
+
+ if (options->deref_ref)
+ gdb_puts (": ", stream);
+@@ -718,7 +709,7 @@ generic_val_print_enum_1 (struct type *type, LONGEST val,
+ }
+ else if (type->is_flag_enum ())
+ {
+- int first = 1;
++ bool first = true;
+
+ /* We have a "flag" enum, so we try to decompose it into pieces as
+ appropriate. The enum may have multiple enumerators representing
+@@ -738,7 +729,7 @@ generic_val_print_enum_1 (struct type *type, LONGEST val,
+ if (first)
+ {
+ gdb_puts ("(", stream);
+- first = 0;
++ first = false;
+ }
+ else
+ gdb_puts (" | ", stream);
+@@ -780,20 +771,15 @@ generic_val_print_enum_1 (struct type *type, LONGEST val,
+ /* generic_val_print helper for TYPE_CODE_ENUM. */
+
+ static void
+-generic_val_print_enum (struct type *type,
+- int embedded_offset, struct ui_file *stream,
++generic_val_print_enum (struct type *type, struct ui_file *stream,
+ struct value *original_value,
+ const struct value_print_options *options)
+ {
+- LONGEST val;
+- struct gdbarch *gdbarch = type->arch ();
+- int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);
+-
+ gdb_assert (!options->format);
+
+ const gdb_byte *valaddr = original_value->contents_for_printing ().data ();
+
+- val = unpack_long (type, valaddr + embedded_offset * unit_size);
++ LONGEST val = unpack_long (type, valaddr);
+
+ generic_val_print_enum_1 (type, val, stream);
+ }
+@@ -801,8 +787,7 @@ generic_val_print_enum (struct type *type,
+ /* generic_val_print helper for TYPE_CODE_FUNC and TYPE_CODE_METHOD. */
+
+ static void
+-generic_val_print_func (struct type *type,
+- int embedded_offset, CORE_ADDR address,
++generic_val_print_func (struct type *type, CORE_ADDR address,
+ struct ui_file *stream,
+ struct value *original_value,
+ const struct value_print_options *options)
+@@ -1015,7 +1000,7 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
+
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+- generic_val_print_ref (type, 0, stream, recurse,
++ generic_val_print_ref (type, stream, recurse,
+ val, options);
+ break;
+
+@@ -1023,14 +1008,14 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
+ if (options->format)
+ value_print_scalar_formatted (val, options, 0, stream);
+ else
+- generic_val_print_enum (type, 0, stream, val, options);
++ generic_val_print_enum (type, stream, val, options);
+ break;
+
+ case TYPE_CODE_FLAGS:
+ if (options->format)
+ value_print_scalar_formatted (val, options, 0, stream);
+ else
+- val_print_type_code_flags (type, val, 0, stream);
++ val_print_type_code_flags (type, val, stream);
+ break;
+
+ case TYPE_CODE_FUNC:
+@@ -1038,7 +1023,7 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
+ if (options->format)
+ value_print_scalar_formatted (val, options, 0, stream);
+ else
+- generic_val_print_func (type, 0, val->address (), stream,
++ generic_val_print_func (type, val->address (), stream,
+ val, options);
+ break;
+
+@@ -1190,11 +1175,11 @@ val_print_check_max_depth (struct ui_file *stream, int recurse,
+ return false;
+ }
+
+-/* Check whether the value VAL is printable. Return 1 if it is;
+- return 0 and print an appropriate error message to STREAM according to
+- OPTIONS if it is not. */
++/* Check whether the value VAL is printable. Return true if it is;
++ return false and print an appropriate error message to STREAM
++ according to OPTIONS if it is not. */
+
+-static int
++static bool
+ value_check_printable (struct value *val, struct ui_file *stream,
+ const struct value_print_options *options)
+ {
+@@ -1202,7 +1187,7 @@ value_check_printable (struct value *val, struct ui_file *stream,
+ {
+ fprintf_styled (stream, metadata_style.style (),
+ _(""));
+- return 0;
++ return false;
+ }
+
+ if (val->entirely_optimized_out ())
+@@ -1211,7 +1196,7 @@ value_check_printable (struct value *val, struct ui_file *stream,
+ gdb_printf (stream, "...");
+ else
+ val_print_optimized_out (val, stream);
+- return 0;
++ return false;
+ }
+
+ if (val->entirely_unavailable ())
+@@ -1220,7 +1205,7 @@ value_check_printable (struct value *val, struct ui_file *stream,
+ gdb_printf (stream, "...");
+ else
+ val_print_unavailable (stream);
+- return 0;
++ return false;
+ }
+
+ if (val->type ()->code () == TYPE_CODE_INTERNAL_FUNCTION)
+@@ -1228,16 +1213,16 @@ value_check_printable (struct value *val, struct ui_file *stream,
+ fprintf_styled (stream, metadata_style.style (),
+ _(""),
+ value_internal_function_name (val));
+- return 0;
++ return false;
+ }
+
+ if (type_not_allocated (val->type ()))
+ {
+ val_print_not_allocated (stream);
+- return 0;
++ return false;
+ }
+
+- return 1;
++ return true;
+ }
+
+ /* See valprint.h. */
+@@ -1292,10 +1277,9 @@ debug_val (struct value *val)
+
+ static void
+ val_print_type_code_flags (struct type *type, struct value *original_value,
+- int embedded_offset, struct ui_file *stream)
++ struct ui_file *stream)
+ {
+- const gdb_byte *valaddr = (original_value->contents_for_printing ().data ()
+- + embedded_offset);
++ const gdb_byte *valaddr = (original_value->contents_for_printing ().data ());
+ ULONGEST val = unpack_long (type, valaddr);
+ int field, nfields = type->num_fields ();
+ struct gdbarch *gdbarch = type->arch ();
+@@ -3188,7 +3172,7 @@ test_print_flags (gdbarch *arch)
+ store_unsigned_integer (contents, 4, gdbarch_byte_order (arch), 0xaa);
+
+ string_file out;
+- val_print_type_code_flags (flags_type, val, 0, &out);
++ val_print_type_code_flags (flags_type, val, &out);
+ SELF_CHECK (out.string () == "[ A=2 B=1 C=5 ]");
+ }
+
+diff --git a/gdb/valprint.h b/gdb/valprint.h
+--- a/gdb/valprint.h
++++ b/gdb/valprint.h
+@@ -197,17 +197,15 @@ extern void print_function_pointer_address (const struct value_print_options *op
+
+ /* Helper function to check the validity of some bits of a value.
+
+- If TYPE represents some aggregate type (e.g., a structure), return 1.
++ If TYPE represents some aggregate type (e.g., a structure), return true.
+
+- Otherwise, any of the bytes starting at OFFSET and extending for
+- TYPE->length () bytes are invalid, print a message to STREAM and
+- return 0. The checking is done using FUNCS.
++ For non-aggregate TYPEs, if any of the bytes starting at FIELD_BYTE_OFFSET
++ and extending for TYPE->length () bytes are invalid, print a message to
++ STREAM and return false. Otherwise, return true. */
+
+- Otherwise, return 1. */
+-
+-extern int valprint_check_validity (struct ui_file *stream, struct type *type,
+- LONGEST embedded_offset,
+- const struct value *val);
++extern bool valprint_check_validity (struct ui_file *stream, struct type *type,
++ LONGEST field_byte_offset,
++ const struct value *val);
+
+ extern void val_print_optimized_out (const struct value *val,
+ struct ui_file *stream);
+@@ -272,7 +270,11 @@ extern void generic_printstr (struct ui_file *stream, struct type *type,
+
+ extern void output_command (const char *args, int from_tty);
+
+-extern int val_print_scalar_type_p (struct type *type);
++/* When printing in "summary" mode we want to print scalar arguments
++ but not aggregate arguments. Return true if TYPE is a scalar type,
++ false if it is an aggregate. */
++
++extern bool val_print_scalar_type_p (struct type *type);
+
+ struct format_data
+ {
diff --git a/gdb-rhel-150992-index-generation-fixes.patch b/gdb-rhel-150992-index-generation-fixes.patch
deleted file mode 100644
index 9ff6853..0000000
--- a/gdb-rhel-150992-index-generation-fixes.patch
+++ /dev/null
@@ -1,1272 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Keith Seitz
-Date: Thu, 19 Feb 2026 10:14:13 -0800
-Subject: gdb-rhel-150992-index-generation-fixes.patch
-
-;; Backport of three upstream patches. The first two relate to index
-;; generation, while the third relates to symbol lookup, but is needed
-;; so that the tests from the earlier two patches will pass.
-;;
-;; (Tom Tromey and Andrew Burgess, RHEL-150992)
-
-Upstream commit: 0fa4f62568b1deeb071c4a6ae8a1671c8ec7ba6e
-=========================================================
-
-Emit some type declarations in .gdb_index
-
-If you run struct-decl.exp with the .gdb_index board, you will see
-that "the_type" is not emitted in the index. This would cause a
-failure in this series. The fix is to ensure that certain necessary
-type declarations are emitted.
-
-However, a naive fix here will regress stub-array-size.exp, where a
-type declaration and a type definition are both seen -- but the
-declaration is seen first and causes a failure. This is handled by
-adding some code (including a mild hack) to filter out type
-declarations when a corresponding type definition is seen.
-
-Acked-By: Simon Marchi
-
-Upstream commit: ccd56e22703c094e5b6d0025e28059277ed8d8c5
-=========================================================
-
-gdb: remove attempted type de-duplication when building gdb-index
-
-This commit removes the attempted de-duplication of types when
-building the gdb-index. This commit is the natural extension of this
-earlier commit:
-
- commit aef36dee93bf194cb0b976a4ae49a79a736a188d
- Date: Sun Aug 13 14:08:06 2023 +0200
-
- [gdb/symtab] Don't deduplicate variables in gdb-index
-
-Which removed the de-duplication of variables. It is worth reading
-the earlier commit as all the justifications for that patch also
-apply to this one.
-
-Currently, when building the gdb-index we sort the type entries,
-moving declarations to the end of the entry list, and non-declarations
-to the front. Then within each group, declarations, and
-non-declarations, the index entries are sorted by CU offset.
-
-We then emit the first entry for any given type name.
-
-There are two problems with this.
-
-First, a non-declaration entry could be a definition, but it could
-also be a typedef. Now sure, a typedef is a type definition, but not
-necessarily a useful one.
-
-If we have a header file that contains:
-
- typedef struct foo_t foo_t;
-
-And a CU which makes use of 'foo_t', then the CU will include both a
-typedef and a type declaration. The target of the typedef will be the
-declaration. But notice, the CU will not include a type definition.
-
-If we have two CUs, one which only sees the above typedef and
-declaration, and another which sees the typedef and an actual type
-definition, then the final list of entries for this type's name will
-be:
-
- 1. A typedef entry that points at the declaration.
- 2. A typedef entry that points at the definition.
- 3. A definition.
- 4. A declaration.
-
-Now (4) will get sorted to the end of the entry list. But the order
-of (1), (2), and (3) will depend on the CU offset. If the CU which
-containing the typedef and declaration has the smallest offset,
-then (1) will be sorted to the front of the list of entries for this
-type name. Due to the de-duplication code this means that only (1)
-will be added to the gdb-index.
-
-After GDB starts and parses the index, if a user references 'foo_t'
-GDB will look in the index and find just (1). GDB loads the CU
-containing (1) and finds both the typedef and the declaration. But
-GDB does not find the full type definition. As a result GDB will
-display 'foo_t' as an incomplete type.
-
-This differs from the behaviour when no index is used. With no index
-GDB expands the first CU containing 'foo_t', finds the typedef and
-type declaration, decides that this is not good enough and carries on.
-GDB will then expand the second CU and find the type's definition, GDB
-now has a full understanding of the type, and can print the type
-correctly.
-
-We could solve this problem by marking typedefs as a distinct
-sub-category of types, just as we do with declarations. Then we could
-sort definitions to the front of the list, then typedefs, and finally,
-declarations after that. This would, I think, mean that we always
-prefer emitting a definition for a type, which would resolve this
-first problem, or at least, it would resolve it well enough, but it
-wouldn't fix the second problem.
-
-The second problem is that the Python API and the 'info types' command
-can be used to query all type symbols. As such, GDB needs to be able
-to find all the CUs which contain a given type. Especially as it is
-possible that a type might be defined differently within different
-CUs.
-
-NOTE: Obviously a program doing this (defining a type differently in
- different CUs) would need to be mindful of the One Definition Rule,
- but so long as the type doesn't escape outside of a single CU then
- reusing a type name isn't, as I understand it, wrong. And even if
- it is, the fact that it compiles, and could be a source of bugs,
- means (in my opinion) that GDB should handle this case to enable
- debugging of it.
-
-Even something as simple as 'info types ....' relies on GDB being able
-to find multiple entries for a given type in different CUs. If the
-index only contains a single type entry, then this means GDB will see
-different things depending on which CUs happen to have been expanded.
-
-Given all of the above, I think that any attempt to remove type
-entries from the gdb-index is unsafe and can result in GDB behaving
-differently when using the gdb-index compared to using no index.
-
-The solution is to remove the de-duplication code, which is what this
-patch does.
-
-Now that we no longer need to sort declarations to the end of the
-entry list, I've removed all the code related to the special use of
-GDB_INDEX_SYMBOL_KIND_UNUSED5 (which is how we marked declarations),
-this cleans things up a little bit.
-
-I've also renamed some of the functions away from minimize, now that
-there's no minimization being done.
-
-A problem was revealed by this change. When running the test
-gdb.cp/stub-array-size.exp with the --target_board=cc-with-gdb-index,
-I was seeing a failure using gcc 15.1.0.
-
-This test has two CUs, and a type 'A'. The test description says:
-
- Test size of arrays of stubbed types (structures where the full
- definition is not immediately available).
-
-Which I don't really understand given the test's source code. The
-type 'A' is defined in a header, which is included in both CUs.
-However, the test description does seem to be accurate; in one CU the
-type looks like this:
-
- <1><4a>: Abbrev Number: 8 (DW_TAG_structure_type)
- <4b> DW_AT_name : A
- <4d> DW_AT_declaration : 1
- <4d> DW_AT_sibling : <0x6d>
- <2><51>: Abbrev Number: 9 (DW_TAG_subprogram)
- <52> DW_AT_external : 1
- <52> DW_AT_name : ~A
- <55> DW_AT_decl_file : 2
- <56> DW_AT_decl_line : 20
- <57> DW_AT_decl_column : 11
- <58> DW_AT_linkage_name: (indirect string, offset: 0x103): _ZN1AD4Ev
- <5c> DW_AT_virtuality : 1 (virtual)
- <5d> DW_AT_containing_type: <0x4a>
- <61> DW_AT_declaration : 1
- <61> DW_AT_object_pointer: <0x66>
- <65> DW_AT_inline : 0 (not inlined)
- <3><66>: Abbrev Number: 10 (DW_TAG_formal_parameter)
- <67> DW_AT_type : <0x8c>
- <6b> DW_AT_artificial : 1
- <3><6b>: Abbrev Number: 0
- <2><6c>: Abbrev Number: 0
-
-while in the second CU, the type looks like this:
-
- <1><178>: Abbrev Number: 4 (DW_TAG_structure_type)
- <179> DW_AT_name : A
- <17b> DW_AT_byte_size : 8
- <17c> DW_AT_decl_file : 2
- <17d> DW_AT_decl_line : 18
- <17e> DW_AT_decl_column : 8
- <17f> DW_AT_containing_type: <0x178>
- <183> DW_AT_sibling : <0x1ac>
- <2><187>: Abbrev Number: 5 (DW_TAG_member)
- <188> DW_AT_name : (indirect string, offset: 0x19e): _vptr.A
- <18c> DW_AT_type : <0x1be>
- <190> DW_AT_data_member_location: 0
- <191> DW_AT_artificial : 1
- <2><191>: Abbrev Number: 6 (DW_TAG_subprogram)
- <192> DW_AT_external : 1
- <192> DW_AT_name : ~A
- <195> DW_AT_decl_file : 1
- <196> DW_AT_decl_line : 20
- <197> DW_AT_decl_column : 1
- <198> DW_AT_linkage_name: (indirect string, offset: 0x103): _ZN1AD4Ev
- <19c> DW_AT_virtuality : 1 (virtual)
- <19d> DW_AT_containing_type: <0x178>
- <1a1> DW_AT_declaration : 1
- <1a1> DW_AT_object_pointer: <0x1a5>
- <3><1a5>: Abbrev Number: 7 (DW_TAG_formal_parameter)
- <1a6> DW_AT_type : <0x1cd>
- <1aa> DW_AT_artificial : 1
- <3><1aa>: Abbrev Number: 0
- <2><1ab>: Abbrev Number: 0
-
-So, for reasons that I don't understand, the type, despite (as far as
-I can see) having its full definition available, is recorded only as
-declared in one CU.
-
-The test then performs some actions that rely on 'sizeof(A)' and
-expects GDB to correctly figure out the size. This requires GDB to
-find, and expand the CU containing the real definition of 'A'.
-
-Prior to this patch GDB would sort the two type entries for 'A',
-placing the declaration second, and then record only one entry, the
-definition. When it came to expansion there was only one thing to
-expand, and this is the declaration we needed. It happens that in
-this test the definition is in the second CU, that is, the CU with the
-biggest offset. This means that, if all index entries were considered
-equal, the definition entry would be second. However, currently, due
-to the way GDB forces definitions to the front, the entry for the
-second CU, the definition, is placed first in the index, and with
-de-duplication, this is the only entry added to the index.
-
-After this patch, both the declaration and the definition are placed
-in the index, and as the declaration is in the CU at offset 0, the
-declaration is added first to the index.
-
-This should be fine. When looking for 'A' GDB should expand the CU
-containing the declaration, see that all we have is a declaration, and
-so continue, next expanding the definition, at which point we're done.
-
-However, in read-gdb-index.c, in the function
-mapped_gdb_index::build_name_components, there is a work around for
-gold bug PR gold/15646. Ironically, the bug here is that gold was not
-removing duplicate index entries, and it is noted that this has a
-performance impact on GDB. A work around for this was added to GDB in
-commit:
-
- commit 8943b874760d9cf35b71890a70af9866e4fab2a6
- Date: Tue Nov 12 09:43:17 2013 -0800
-
- Work around gold/15646.
-
-A test for this was added in:
-
- commit 40d22035a7fc239ac1e944b75a2e3ee9029d1b76
- Date: Tue May 26 11:35:32 2020 +0200
-
- [gdb/testsuite] Add test-case gold-gdb-index.exp
-
-And the fix was tweaked in commit:
-
- commit f030440daa989ae3dadc1fa4342cfa16d690db3c
- Date: Thu May 28 17:26:22 2020 +0200
-
- [gdb/symtab] Make gold index workaround more precise
-
-The problem specifically called out in the bug report is that
-namespaces can appear in multiple CUs, and that trying to complete
-'ns::misspelled' would expand every CU containing namespace 'ns' due
-to the duplicate 'ns' type symbols.
-
-The work around that was added in 8943b874760d9cf3 was to ignore
-duplicate global symbols when expanding entries from the index. In
-commit f030440daa989ae3 this work around was restricted to only ignore
-duplicate type entries. This restriction was required to allow the
-earlier de-duplication patch aef36dee93bf194c to function correctly.
-
-Now that I'm taking the work started in aef36dee93bf194c to its
-logical conclusion, and allowing duplicate type entries, the work
-around of ignoring duplicate global type symbols is no longer needed,
-and can be removed.
-
-The associated test for this, added in 40d22035a7fc239a, is also
-removed in this commit.
-
-To be clear; the performance issue mentioned in PR gold/15646 is now
-back again. But my claim is that gold was right all along to include
-the duplicate index entries, and any performance hit we see as a
-result, though unfortunate, is just a consequence of doing it right.
-
-That doesn't mean there's not room for optimisation and improvement in
-the future, though I don't have any immediate ideas, or plans in this
-area. It's just we can't throw out a bunch of index entries that are
-critical, and claim this as a performance optimisation.
-
-I am seeing some failure with this patch when using the board file
-dwarf5-fission-debug-types. These failures all have the error:
-
- DWARF Error: wrong unit_type in unit header (is DW_UT_skeleton, should be DW_UT_type) [in module ....]
-
-However, I ran the whole testsuite with this board, and this error
-crops up often, so I don't think this is something specific to my
-patch, so I'm choosing to ignore this.
-
-Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15646
-Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15035
-
-Approved-By: Tom Tromey
-
-Upstream commit: c09ebee0d3ae9148e33aa861cbd857bf2d4100ba
-=========================================================
-
-gdb: symbol_search objects of different types are not the same
-
-Consider the C construct:
-
- typedef struct foo
- {
- int a;
- int b;
- } foo;
-
-GDB will see two types here, 'struct foo' and the typedef 'foo'.
-However, if we use 'info types foo' we will see this:
-
- File test.c:
- 18: struct foo;
-
-At least that's what I see with current HEAD of master. However, it
-is really just luck that we see the 'struct' here. See more below.
-
-When searching for symbols matching 'foo' GDB ends up in the function
-global_symbol_searcher::add_matching_symbols, where we consider all
-possible matching symbols. This will include the 'struct foo' and the
-typedef 'foo'. However, before a new symbols is added to the results,
-we attempt to remove duplicates with this code:
-
- /* Match, insert if not already in the results. */
- symbol_search ss (block, sym);
- if (result_set->find (ss) == result_set->end ())
- result_set->insert (ss);
-
-If a symbol is already present in result_set then it will not be added
-a second time.
-
-The symbol_search equality check is done using the function
-symbol_search::compare_search_syms, this function does a number of
-checks, but at the end, any two symbols that are in the same block
-within the same file, with the same name, are considered the same,
-even if the types of those symbols are different.
-
-This makes sense in most cases, it usually wouldn't make sense to have
-two symbols within a single block with different types. But the
-'struct foo' and typedef 'foo' case is a bit of a strange one. Within
-DWARF and GDB we consider both of these as just types. But in C
-types and structure names live in different namespaces, and so we can
-have both in the same block. I don't think that GDB should consider
-these two as the same, especially if we consider something really
-ill-advised like this:
-
- struct foo
- {
- int a;
- int b;
- };
-
- typedef int foo;
-
-This is perfectly valid C code, 'struct foo' and the typedef 'foo' are
-in different namespaces, and can be used within the same block. But
-please, never write C code like this.
-
-Given the above, I think, when asked about 'foo', GDB should, report
-both 'struct foo' and the typedef 'foo'.
-
-To do this I propose extending symbol_search::compare_search_syms such
-that if two symbol_search objects are in the same block, within the
-same file, and they have the same name, then if just one of them is a
-typedef, the two objects will not be considered equal. The results
-will be sorted by line number if the line numbers are different, or,
-if the line numbers are the same, the non-typedef will be sorted
-first. This means that for something like this:
-
- typedef struct foo { int a; } foo;
-
-We'll get an 'info types foo' result like:
-
- File test.c:
- 18: struct foo;
- 18: typedef struct foo foo;
-
-I mentioned earlier that it is really just luck that we see 'struct
-foo'. I ran into this problem while working on another patch. When
-testing with the 'debug-types' board file I was seeing the typedef
-being reported rather than the struct. In "normal" DWARF given the
-'typedef struct foo { ...} foo;' construct, the compiler will usually
-emit the struct definition first, and then the typedef definition. So
-when GDB parses the DWARF it sees the struct first. It is the typedef
-that becomes the duplicate which is not added to the results list.
-
-But with the 'debug-types' board the compiler moves the struct
-definition out to the .debug_types section. And GDB now parses the CU
-containing the typedef first, and then expands the structure
-definition from the separate section afterwards. As a result, it is
-the structure that is now considered the duplicate, and the typedef is
-the result that gets reported.
-
-I think this is yet another motivation for this patch. Changes like
-this (the use of .debug_types section) shouldn't impact what results
-GDB shows to the user.
-
-There is an interesting update to the gdb.base/info-types.exp.tcl test
-script. In this case the C results only needed to change to include
-the typedef. The C++ results already included both the struct and the
-typedef in the expected results. The reason for this is that C places
-both the struct baz_t and the typedef for baz_t into the global block,
-while C++ places the struct in the global block, and the typedef into
-the static block. I have no idea why there's a difference in the
-placement, but I'm choosing to believe the difference is correct. But
-this explains why only the C results needed to change. If anything
-this (I think) is yet another justification for this change; having C
-not show the typedef in this case seems weird when the same source
-code compiled as C++ does show the typedef.
-
-Approved-By: Tom Tromey
-
-diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
---- a/gdb/dwarf2/index-write.c
-+++ b/gdb/dwarf2/index-write.c
-@@ -58,7 +58,7 @@
- #define DW2_GDB_INDEX_SYMBOL_KIND_SET_VALUE(cu_index, value) \
- do { \
- gdb_assert ((value) >= GDB_INDEX_SYMBOL_KIND_TYPE \
-- && (value) <= GDB_INDEX_SYMBOL_KIND_OTHER); \
-+ && (value) < GDB_INDEX_SYMBOL_KIND_UNUSED5); \
- GDB_INDEX_SYMBOL_KIND_SET_VALUE((cu_index), (value)); \
- } while (0)
-
-@@ -178,9 +178,8 @@ struct symtab_index_entry
- of this name. */
- std::vector cu_indices;
-
-- /* Minimize CU_INDICES, sorting them and removing duplicates as
-- appropriate. */
-- void minimize ();
-+ /* Sort CU_INDICES. */
-+ void sort ();
- };
-
- /* The symbol table. This is a power-of-2-sized hash table. */
-@@ -192,16 +191,16 @@ struct mapped_symtab
- }
-
- /* If there are no elements in the symbol table, then reduce the table
-- size to zero. Otherwise call symtab_index_entry::minimize each entry
-+ size to zero. Otherwise call symtab_index_entry::sort each entry
- in the symbol table. */
-
-- void minimize ()
-+ void minimize_and_sort ()
- {
- if (m_element_count == 0)
- m_data.resize (0);
-
- for (symtab_index_entry &item : m_data)
-- item.minimize ();
-+ item.sort ();
- }
-
- /* Add an entry to SYMTAB. NAME is the name of the symbol. CU_INDEX is
-@@ -410,32 +409,19 @@ mapped_symtab::add_index_entry (const char *name, int is_static,
- /* See symtab_index_entry. */
-
- void
--symtab_index_entry::minimize ()
-+symtab_index_entry::sort ()
- {
- if (name == nullptr || cu_indices.empty ())
- return;
-
-- std::sort (cu_indices.begin (), cu_indices.end ());
-+ /* Sort the entries based on the CU offset. */
-+ std::sort (cu_indices.begin (), cu_indices.end (),
-+ [] (offset_type vala, offset_type valb)
-+ {
-+ return vala < valb;
-+ });
- auto from = std::unique (cu_indices.begin (), cu_indices.end ());
- cu_indices.erase (from, cu_indices.end ());
--
-- /* We don't want to enter a type more than once, so
-- remove any such duplicates from the list as well. When doing
-- this, we want to keep the entry from the first CU -- but this is
-- implicit due to the sort. This choice is done because it's
-- similar to what gdb historically did for partial symbols. */
-- std::unordered_set seen;
-- from = std::remove_if (cu_indices.begin (), cu_indices.end (),
-- [&] (offset_type val)
-- {
-- gdb_index_symbol_kind kind = GDB_INDEX_SYMBOL_KIND_VALUE (val);
-- if (kind != GDB_INDEX_SYMBOL_KIND_TYPE)
-- return false;
--
-- val &= ~GDB_INDEX_CU_MASK;
-- return !seen.insert (val).second;
-- });
-- cu_indices.erase (from, cu_indices.end ());
- }
-
- /* A form of 'const char *' suitable for container keys. Only the
-@@ -1193,6 +1179,21 @@ write_cooked_index (cooked_index *table,
- const cu_index_map &cu_index_htab,
- struct mapped_symtab *symtab)
- {
-+ gdb::unordered_set required_decl_entries;
-+ for (const cooked_index_entry *entry : table->all_entries ())
-+ {
-+ /* Any type declaration that is used as a (non-trivial) parent
-+ entry must be written out. */
-+ if ((entry->flags & IS_TYPE_DECLARATION) == 0)
-+ {
-+ for (const cooked_index_entry *parent = entry->get_parent ();
-+ parent != nullptr;
-+ parent = parent->get_parent ())
-+ if ((parent->flags & IS_TYPE_DECLARATION) != 0)
-+ required_decl_entries.insert (parent);
-+ }
-+ }
-+
- for (const cooked_index_entry *entry : table->all_entries ())
- {
- const auto it = cu_index_htab.find (entry->per_cu);
-@@ -1218,11 +1219,10 @@ write_cooked_index (cooked_index *table,
- be redundant are rare and not worth supporting. */
- continue;
- }
-- else if ((entry->flags & IS_TYPE_DECLARATION) != 0)
-- {
-- /* Don't add type declarations to the index. */
-- continue;
-- }
-+ /* Don't add most type declarations to the index. */
-+ else if ((entry->flags & IS_TYPE_DECLARATION) != 0
-+ && !required_decl_entries.contains (entry))
-+ continue;
-
- gdb_index_symbol_kind kind;
- if (entry->tag == DW_TAG_subprogram
-@@ -1341,7 +1341,7 @@ write_gdbindex (dwarf2_per_bfd *per_bfd, cooked_index *table,
-
- /* Now that we've processed all symbols we can shrink their cu_indices
- lists. */
-- symtab.minimize ();
-+ symtab.minimize_and_sort ();
-
- data_buf symtab_vec, constant_pool;
-
-diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c
---- a/gdb/dwarf2/read-gdb-index.c
-+++ b/gdb/dwarf2/read-gdb-index.c
-@@ -194,7 +194,6 @@ dw2_expand_marked_cus
- gdb::function_view lang_matcher)
- {
- offset_type vec_len, vec_idx;
-- bool global_seen = false;
- mapped_gdb_index &index
- = *(gdb::checked_static_cast
- (per_objfile->per_bfd->index_table.get ()));
-@@ -217,17 +216,6 @@ dw2_expand_marked_cus
- (index.version >= 7
- && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE);
-
-- /* Work around gold/15646. */
-- if (attrs_valid
-- && !is_static
-- && symbol_kind == GDB_INDEX_SYMBOL_KIND_TYPE)
-- {
-- if (global_seen)
-- continue;
--
-- global_seen = true;
-- }
--
- /* Only check the symbol's kind if it has one. */
- if (attrs_valid)
- {
-diff --git a/gdb/symtab.c b/gdb/symtab.c
---- a/gdb/symtab.c
-+++ b/gdb/symtab.c
-@@ -4832,7 +4832,50 @@ symbol_search::compare_search_syms (const symbol_search &sym_a,
- if (sym_a.block != sym_b.block)
- return sym_a.block - sym_b.block;
-
-- return strcmp (sym_a.symbol->print_name (), sym_b.symbol->print_name ());
-+ c = strcmp (sym_a.symbol->print_name (), sym_b.symbol->print_name ());
-+
-+ if (c != 0)
-+ return c;
-+
-+ /* These two symbols have the same name. It is possible, with types,
-+ that we can see two symbols with the same name, but different types,
-+ consider in C: 'typedef struct foo { ... } foo;' which creates a
-+ 'struct foo' type and a 'foo' typedef type. For now this is the only
-+ case we handle. In all other cases, we treat symbols with the same
-+ name as being the same.
-+
-+
-+ First, check the types, if they are the same, then consider these
-+ symbols as the same. */
-+ if (sym_a.symbol->type ()->code () == sym_b.symbol->type ()->code ())
-+ return 0;
-+
-+ /* The types are different, but if neither is a typedef then we still
-+ consider these symbols as the same. */
-+ if (sym_a.symbol->type ()->code () != TYPE_CODE_TYPEDEF
-+ && sym_b.symbol->type ()->code () != TYPE_CODE_TYPEDEF)
-+ return 0;
-+
-+ /* The symbols have different types, and one is a typedef. They cannot
-+ both be typedefs or we'd have taken the "types are the same" exit path
-+ above. If the two types are defined on different lines then order by
-+ line number. As line numbers are unsigned, don't subtract one from
-+ the other in order to avoid underflow. */
-+ if (sym_a.symbol->line () != sym_b.symbol->line ())
-+ return (sym_a.symbol->line () > sym_b.symbol->line () ? 1 : -1);
-+
-+ /* The symbols have different types, and one is a typedef, but both
-+ symbols are defined on the same line. For example:
-+
-+ typedef struct foo { int a; } foo;
-+
-+ In this case we sort the typedef after the non-typedef. This is an
-+ arbitrary decision, but I think looks slightly nicer in the 'info
-+ types' output; first we get the type, then the typedef. */
-+ if (sym_a.symbol->type ()->code () == TYPE_CODE_TYPEDEF)
-+ return 1;
-+ else
-+ return -1;
- }
-
- /* Returns true if the type_name of symbol_type of SYM matches TREG.
-diff --git a/gdb/testsuite/gdb.base/gold-gdb-index.c b/gdb/testsuite/gdb.base/gdb-index-many-types-1.c
-similarity index 68%
-rename from gdb/testsuite/gdb.base/gold-gdb-index.c
-rename to gdb/testsuite/gdb.base/gdb-index-many-types-1.c
---- a/gdb/testsuite/gdb.base/gold-gdb-index.c
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types-1.c
-@@ -1,6 +1,6 @@
- /* This testcase is part of GDB, the GNU debugger.
-
-- Copyright 2020-2024 Free Software Foundation, Inc.
-+ Copyright 2025 Free Software Foundation, Inc.
-
- 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
-@@ -15,15 +15,34 @@
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
--#include "gold-gdb-index.h"
--
--namespace N1
--{
-- void foo () { C1::baz (); }
--}
-+#include "gdb-index-many-types.h"
-
- int
- main ()
- {
-+ foo_func_a (0);
-+ foo_func_b (0);
-+ bar_func_a (0);
-+ bar_func_b (0);
-+ baz_func_a (0);
-+ baz_func_b (0);
- return 0;
- }
-+
-+void
-+foo_func_c (foo_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+void
-+bar_func_c (bar_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+void
-+baz_func_c (baz_t *obj)
-+{
-+ (void) obj;
-+}
-diff --git a/gdb/testsuite/gdb.base/gold-gdb-index-2.c b/gdb/testsuite/gdb.base/gdb-index-many-types-2.c
-similarity index 61%
-rename from gdb/testsuite/gdb.base/gold-gdb-index-2.c
-rename to gdb/testsuite/gdb.base/gdb-index-many-types-2.c
---- a/gdb/testsuite/gdb.base/gold-gdb-index-2.c
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types-2.c
-@@ -1,6 +1,6 @@
- /* This testcase is part of GDB, the GNU debugger.
-
-- Copyright 2020-2024 Free Software Foundation, Inc.
-+ Copyright 2025 Free Software Foundation, Inc.
-
- 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
-@@ -15,9 +15,42 @@
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
--#include "gold-gdb-index.h"
-+#include "gdb-index-many-types.h"
-
--namespace N1
-+typedef struct foo_t
- {
-- void bar () { C1::baz (); }
-+ int foo_t_1;
-+ int foo_t_2;
-+} foo_t;
-+
-+typedef struct woof_t
-+{
-+ int woof_t_1;
-+ int woof_t_2;
-+} woof_t;
-+
-+static void
-+woof_func (woof_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+void
-+foo_func_a (foo_t *obj)
-+{
-+ woof_func (0);
-+ (void) obj;
-+}
-+
-+void
-+baz_func_a (baz_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+void
-+bar_func_a (bar_t *obj)
-+{
-+ woof_func (0);
-+ (void) obj;
- }
-diff --git a/gdb/testsuite/gdb.base/gold-gdb-index.h b/gdb/testsuite/gdb.base/gdb-index-many-types-3.c
-similarity index 61%
-rename from gdb/testsuite/gdb.base/gold-gdb-index.h
-rename to gdb/testsuite/gdb.base/gdb-index-many-types-3.c
---- a/gdb/testsuite/gdb.base/gold-gdb-index.h
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types-3.c
-@@ -1,6 +1,6 @@
- /* This testcase is part of GDB, the GNU debugger.
-
-- Copyright 2020-2024 Free Software Foundation, Inc.
-+ Copyright 2025 Free Software Foundation, Inc.
-
- 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
-@@ -15,11 +15,42 @@
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
--namespace N1
-+#include "gdb-index-many-types.h"
-+
-+typedef struct woof_t
-+{
-+ double woof_t_3;
-+ double woof_t_4;
-+} woof_t;
-+
-+static void
-+woof_func (woof_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+typedef struct bar_t
-+{
-+ int bar_t_1;
-+ int bar_t_2;
-+} bar_t;
-+
-+void
-+bar_func_b (bar_t *obj)
-+{
-+ woof_func (0);
-+ (void) obj;
-+}
-+
-+void
-+baz_func_b (baz_t *obj)
-+{
-+ (void) obj;
-+}
-+
-+void
-+foo_func_b (foo_t *obj)
- {
-- class C1
-- {
-- public:
-- static void baz () {}
-- };
-+ woof_func (0);
-+ (void) obj;
- }
-diff --git a/gdb/testsuite/gdb.base/gdb-index-many-types.exp b/gdb/testsuite/gdb.base/gdb-index-many-types.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types.exp
-@@ -0,0 +1,157 @@
-+# Copyright 2025 Free Software Foundation, Inc.
-+#
-+# 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 .
-+
-+# Check that adding an index to an executable (both a gdb index and a
-+# dwarf-5 index are tested), doesn't prevent GDB from seeing the
-+# expected types.
-+
-+standard_testfile -1.c -2.c -3.c .h
-+
-+# One of the tests uses this Python file. The test_* proc checks that
-+# GDB supports Python tests. Some of the other procs don't use this
-+# Python file.
-+set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
-+
-+if {[build_executable "building" $testfile \
-+ [list $srcfile $srcfile2 $srcfile3]] == -1} {
-+ return
-+}
-+
-+# Run 'info types TYPENAME', expect to see an entry from FILENAME for
-+# the line matching PATTERN.
-+proc check_info_types { testfile typename filename pattern } {
-+ with_test_prefix "$filename '$pattern'" {
-+ clean_restart $testfile
-+
-+ set line_num [gdb_get_line_number $pattern $filename]
-+ gdb_test "info types $typename" \
-+ "File \[^\r\n\]+/${filename}:(?:\r\n${::decimal}:\[^\r\n\]+)*\r\n${line_num}:\[^\r\n\]+.*"
-+ }
-+}
-+
-+# Start GDB with FILENAME, and examine some of the types. This proc
-+# might seem to be using clean_restart a little too much, but we need
-+# to be really careful here. As we examine one type, e.g. foo_t, this
-+# might cause GDB to fully parse a CU, which then means examining
-+# bar_t gives the expected result. When, if we'd first looked for
-+# bar_t, then (due to an index bug) we might not have found the
-+# correct type definition.
-+#
-+# The only way we can be sure that an earlier test isn't going to
-+# trigger CU expansion is to restart GDB before every query.
-+proc run_test { filename } {
-+ # Print all the types for which there is only one representation.
-+ foreach type { foo_t bar_t baz_t } {
-+ clean_restart $filename
-+ gdb_test "ptype $type" \
-+ [multi_line \
-+ "type = struct $type {" \
-+ "\\s+int ${type}_1;" \
-+ "\\s+int ${type}_2;" \
-+ "}"]
-+ }
-+
-+ # There are two different versions of woof_t. For now, when using
-+ # `ptype` GDB will just display the first one it finds, which could
-+ # legitimately be either.
-+ set woof_int_re [multi_line \
-+ "type = struct woof_t {" \
-+ "\\s+int woof_t_1;" \
-+ "\\s+int woof_t_2;" \
-+ "}"]
-+ set woof_double_re [multi_line \
-+ "type = struct woof_t {" \
-+ "\\s+double woof_t_3;" \
-+ "\\s+double woof_t_4;" \
-+ "}"]
-+ clean_restart $filename
-+ gdb_test_multiple "ptype woof_t" "" {
-+ -re -wrap $woof_int_re {
-+ pass $gdb_test_name
-+ }
-+ -re -wrap $woof_double_re {
-+ pass $gdb_test_name
-+ }
-+ }
-+
-+ # Check for declarations and definitions of some types.
-+ check_info_types $filename foo_t $::srcfile2 "typedef struct foo_t"
-+ check_info_types $filename foo_t $::srcfile4 "typedef struct foo_t foo_t;"
-+ check_info_types $filename bar_t $::srcfile3 "typedef struct bar_t"
-+ check_info_types $filename bar_t $::srcfile4 "typedef struct bar_t bar_t;"
-+ check_info_types $filename baz_t $::srcfile4 "typedef struct baz_t"
-+ check_info_types $filename baz_t $::srcfile4 "\} baz_t;"
-+ check_info_types $filename woof_t $::srcfile2 "typedef struct woof_t"
-+ check_info_types $filename woof_t $::srcfile3 "typedef struct woof_t"
-+
-+ # Use Python to look for type symbols.
-+ if { [allow_python_tests] } {
-+ foreach_with_prefix type { foo_t bar_t baz_t } {
-+ clean_restart $filename
-+ gdb_test_no_output "source $::pyfile" "import python scripts"
-+ gdb_test "py-show-type $type" \
-+ [multi_line \
-+ "Looking for type '$type':" \
-+ " Found 3 type symbols" \
-+ " 1: struct $type \\{ int ${type}_1; int ${type}_2; \\}" \
-+ " 2: struct $type \\{ int ${type}_1; int ${type}_2; \\}" \
-+ " 3: struct $type \\{ int ${type}_1; int ${type}_2; \\}"]
-+ }
-+
-+ clean_restart $filename
-+ gdb_test_no_output "source $::pyfile" "import python scripts"
-+ gdb_test "py-show-type woof_t" \
-+ [multi_line \
-+ "Looking for type 'woof_t':" \
-+ " Found 2 type symbols" \
-+ " 1: struct woof_t \\{ (?:int|double) woof_t_(?:1|3); (?:int|double) woof_t_(?:2|4); \\}" \
-+ " 2: struct woof_t \\{ (?:int|double) woof_t_(?:1|3); (?:int|double) woof_t_(?:2|4); \\}"]
-+
-+ }
-+}
-+
-+with_test_prefix "no index" {
-+ run_test $testfile
-+}
-+
-+# The previous call to 'run_test' will have left GDB active. Check if
-+# BINFILE already has an index. If it does then we must be running
-+# with one of the boardfiles that adds an index. We could possibly
-+# try to remove the index, but for now, just don't run the following
-+# parts which rely on adding an index.
-+set index_type [get_index_type $binfile "check debug style"]
-+if { $index_type ne "cooked" } {
-+ unsupported "cannot test without a cooked index"
-+ return
-+}
-+
-+foreach_with_prefix index_type { gdb dwarf5 } {
-+ set binfile_with_index ${binfile}-idx-${index_type}
-+
-+ remote_exec build "cp $binfile $binfile_with_index"
-+
-+ if { $index_type eq "gdb" } {
-+ set style ""
-+ } else {
-+ set style "-dwarf-5"
-+ }
-+
-+ if {[ensure_gdb_index $binfile_with_index $style] != 1} {
-+ unsupported "couldn't add $index_type index"
-+ return
-+ }
-+
-+ run_test [file tail $binfile_with_index]
-+}
-diff --git a/gdb/testsuite/gdb.base/gdb-index-many-types.h b/gdb/testsuite/gdb.base/gdb-index-many-types.h
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types.h
-@@ -0,0 +1,42 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2025 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see . */
-+
-+#ifndef GDB_INDEX_MANY_TYPES_H
-+#define GDB_INDEX_MANY_TYPES_H
-+
-+typedef struct foo_t foo_t;
-+typedef struct bar_t bar_t;
-+
-+extern void foo_func_a (foo_t *obj);
-+extern void foo_func_b (foo_t *obj);
-+extern void foo_func_c (foo_t *obj);
-+
-+extern void bar_func_a (bar_t *obj);
-+extern void bar_func_b (bar_t *obj);
-+extern void bar_func_c (bar_t *obj);
-+
-+typedef struct baz_t
-+{
-+ int baz_t_1;
-+ int baz_t_2;
-+} baz_t;
-+
-+extern void baz_func_a (baz_t *obj);
-+extern void baz_func_b (baz_t *obj);
-+extern void baz_func_c (baz_t *obj);
-+
-+#endif /* GDB_INDEX_MANY_TYPES_H */
-diff --git a/gdb/testsuite/gdb.base/gdb-index-many-types.py b/gdb/testsuite/gdb.base/gdb-index-many-types.py
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gdb-index-many-types.py
-@@ -0,0 +1,54 @@
-+# Copyright 2025 Free Software Foundation, Inc.
-+#
-+# 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 .
-+
-+
-+class TypeViewer(gdb.Command):
-+ """A command which takes a string and looks up types with that name.
-+
-+ The types are expected to all be structs. This command prints a
-+ basic representation of the struct. This is only going to work when
-+ used with the types defined in the gdb-index-many-types test source
-+ files."""
-+
-+ def __init__(self):
-+ super().__init__("py-show-type", gdb.COMMAND_USER)
-+
-+ def invoke(self, args, from_tty):
-+ argv = gdb.string_to_argv(args)
-+ if argv[0] == "":
-+ raise gdb.GdbError("missing argument")
-+ print("Looking for type '" + argv[0] + "':")
-+ syms = gdb.lookup_static_symbols(argv[0], gdb.SYMBOL_TYPE_DOMAIN)
-+ count = len(syms)
-+ print(" Found %d type symbol%s" % (count, "" if count == 1 else "s"))
-+ for i, s in enumerate(syms, start=1):
-+ t = s.type
-+ if t is None:
-+ print(" %d: No type." % i)
-+ else:
-+ fields = "struct " + argv[0] + " {"
-+ try:
-+ for f in t.fields():
-+ if len(fields) > 0:
-+ fields = fields + " "
-+ fields = fields + "%s %s;" % (str(f.type), f.name)
-+ except:
-+ pass
-+ fields = fields + " }"
-+
-+ print(" %d: %s" % (i, fields))
-+
-+
-+TypeViewer()
-diff --git a/gdb/testsuite/gdb.base/gold-gdb-index.exp b/gdb/testsuite/gdb.base/gold-gdb-index.exp
-deleted file mode 100644
---- a/gdb/testsuite/gdb.base/gold-gdb-index.exp
-+++ /dev/null
-@@ -1,51 +0,0 @@
--# Copyright 2020-2024 Free Software Foundation, Inc.
--
--# 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 . */
--
--# This tests the gdb workaround for PR binutils/15646.
--
--standard_testfile .c gold-gdb-index-2.c
--
--if { [have_fuse_ld_gold] == 0} {
-- return -1
--}
--
--if {[prepare_for_testing "failed to prepare" $testfile "$srcfile $srcfile2" \
-- {debug c++ additional_flags=-fuse-ld=gold \
-- ldflags=-Wl,--gdb-index \
-- additional_flags=-ggnu-pubnames}]} {
-- return -1
--}
--
--if { [have_index $binfile] != "gdb_index" } {
-- return -1
--}
--
--if {![runto_main]} {
-- return 0
--}
--
--gdb_test_no_output "nosharedlibrary"
--
--gdb_test_no_output "set breakpoint pending off"
--gdb_test "break N1::misspelled" "Function \"N1::misspelled\" not defined\."
--
--gdb_test_multiple "maint info symtabs" "" {
-- -re -wrap "\{ symtab \[^\r\n\]*gold-gdb-index-2.c.*" {
-- fail $gdb_test_name
-- }
-- -re -wrap "" {
-- pass $gdb_test_name
-- }
--}
-diff --git a/gdb/testsuite/gdb.base/info-types.exp.tcl b/gdb/testsuite/gdb.base/info-types.exp.tcl
---- a/gdb/testsuite/gdb.base/info-types.exp.tcl
-+++ b/gdb/testsuite/gdb.base/info-types.exp.tcl
-@@ -90,6 +90,7 @@ proc run_test { lang } {
- "28:\[\t \]+typedef struct baz_t baz;" \
- "31:\[\t \]+typedef struct baz_t \\* baz_ptr;" \
- "21:\[\t \]+struct baz_t;" \
-+ "27:\[\t \]+typedef struct baz_t baz_t;" \
- "\[\t \]+double" \
- "33:\[\t \]+enum enum_t;" \
- "\[\t \]+float" \
-diff --git a/gdb/testsuite/gdb.base/type-and-typedef.c b/gdb/testsuite/gdb.base/type-and-typedef.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/type-and-typedef.c
-@@ -0,0 +1,48 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2025 Free Software Foundation, Inc.
-+
-+ 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 . */
-+
-+typedef struct foo /* struct foo defined here. */
-+{
-+ int a;
-+ int b;
-+} foo; /* typedef foo defined here. */
-+
-+struct bar /* struct bar defined here. */
-+{
-+ int a;
-+ int b;
-+};
-+
-+/* Yes, this really is typedef-ing 'bar' to something other than 'struct
-+ bar'. Just testing that GDB handles this. This is not good code. */
-+typedef struct foo bar; /* typedef bar defined here. */
-+
-+/* The following must be a single line. This tests the 'struct baz' and
-+ the 'typedef ... baz;' being on the same line. */
-+typedef struct baz { int a; int b; } baz; /* baz defined here. */
-+
-+volatile struct foo obj1 = { 1, 2 };
-+volatile foo obj2 = { 1, 2 };
-+volatile struct bar obj3 = { 1, 2 };
-+volatile bar obj4 = { 1, 2 };
-+volatile baz obj5 = { 1, 2 };
-+
-+int
-+main ()
-+{
-+ return obj1.b + obj2.b + obj3.b + obj4.b + obj5.b;
-+}
-diff --git a/gdb/testsuite/gdb.base/type-and-typedef.exp b/gdb/testsuite/gdb.base/type-and-typedef.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/type-and-typedef.exp
-@@ -0,0 +1,65 @@
-+# Copyright 2025 Free Software Foundation, Inc.
-+#
-+# 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 .
-+
-+# Compile a single CU containing a type and a typedef with the same
-+# name (think C's "typedef struct foo { ... } foo;"). Check that
-+# 'info types' shows both types.
-+
-+standard_testfile
-+
-+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
-+ return
-+}
-+
-+# Line numbers needed by the test.
-+set struct_foo_lineno [gdb_get_line_number "struct foo defined here"]
-+set typedef_foo_lineno [gdb_get_line_number "typedef foo defined here"]
-+set struct_bar_lineno [gdb_get_line_number "struct bar defined here"]
-+set typedef_bar_lineno [gdb_get_line_number "typedef bar defined here"]
-+set baz_lineno [gdb_get_line_number "baz defined here"]
-+
-+# Check that the expected two types show up in global SRCFILE.
-+proc check_types { testname } {
-+ gdb_test "info types foo" \
-+ [multi_line \
-+ "File (?:\[^\r\n\]+/)?[string_to_regexp $::srcfile]:" \
-+ "${::struct_foo_lineno}:\\s+struct foo;" \
-+ "${::typedef_foo_lineno}:\\s+typedef struct foo foo;"] \
-+ "$testname, check foo"
-+
-+ gdb_test "info types bar" \
-+ [multi_line \
-+ "File (?:\[^\r\n\]+/)?[string_to_regexp $::srcfile]:" \
-+ "${::struct_bar_lineno}:\\s+struct bar;" \
-+ "${::typedef_bar_lineno}:\\s+typedef struct foo bar;"] \
-+ "$testname, check bar"
-+
-+ gdb_test "info types baz" \
-+ [multi_line \
-+ "File (?:\[^\r\n\]+/)?[string_to_regexp $::srcfile]:" \
-+ "${::baz_lineno}:\\s+struct baz;" \
-+ "${::baz_lineno}:\\s+typedef struct baz baz;"] \
-+ "$testname, check baz"
-+}
-+
-+check_types "before inferior is started"
-+
-+clean_restart $testfile
-+
-+if {![runto_main]} {
-+ return
-+}
-+
-+check_types "after starting the inferior"
diff --git a/gdb-rhel-50069-support-z17.patch b/gdb-rhel-50069-support-z17.patch
deleted file mode 100644
index 7c3504e..0000000
--- a/gdb-rhel-50069-support-z17.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Jens Remus
-Date: Wed, 9 Apr 2025 08:59:24 +0200
-Subject: gdb-rhel-50069-support-z17.patch
-
-;; Backport "s390: Add support for z17 as CPU name"
-;; (Jens Remus, RHEL-50069)
-
-So far IBM z17 was identified as arch15. Add the real name, as it has
-been announced. [1]
-
-[1]: IBM z17 announcement letter, AD25-0015,
- https://www.ibm.com/docs/en/announcements/z17-makes-more-possible
-
-gas/
- * config/tc-s390.c (s390_parse_cpu): Add z17 as alternate CPU
- name for arch15.
- * doc/c-s390.texi: Likewise.
- * doc/as.texi: Likewise.
-
-opcodes/
- * s390-mkopc.c (main): Add z17 as alternate CPU name for arch15.
-
-Signed-off-by: Jens Remus
-
-diff --git a/opcodes/s390-mkopc.c b/opcodes/s390-mkopc.c
---- a/opcodes/s390-mkopc.c
-+++ b/opcodes/s390-mkopc.c
-@@ -443,7 +443,8 @@ main (void)
- else if (strcmp (cpu_string, "z16") == 0
- || strcmp (cpu_string, "arch14") == 0)
- min_cpu = S390_OPCODE_ARCH14;
-- else if (strcmp (cpu_string, "arch15") == 0)
-+ else if (strcmp (cpu_string, "z17") == 0
-+ || strcmp (cpu_string, "arch15") == 0)
- min_cpu = S390_OPCODE_ARCH15;
- else {
- print_error ("Mnemonic \"%s\": Couldn't parse CPU string: %s\n",
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch
deleted file mode 100644
index f3e9017..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-1-of-13.patch
-
-;; [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 1
-;; (Tom de Vries, RHEL-7329)
-
-While reading amd64_get_unused_input_int_reg, I noticed that it first asserts,
-then throws an internal_error if no unused register can be found.
-
-Looking at the documentation of gdbarch_displaced_step_copy_insn, it seems
-that a failure can be indicated less abruptly, by returning a nullptr.
-
-Fix this by:
-- returning -1 in case of failure to find an unused register in
- amd64_get_unused_input_int_reg, and
-- propagating this to amd64_displaced_step_copy_insn.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1211,7 +1211,7 @@ amd64_skip_prefixes (gdb_byte *insn)
- In order to not require adding a rex prefix if the insn doesn't already
- have one, the result is restricted to RAX ... RDI, sans RSP.
- The register numbering of the result follows architecture ordering,
-- e.g. RDI = 7. */
-+ e.g. RDI = 7. Return -1 if no register can be found. */
-
- static int
- amd64_get_unused_input_int_reg (const struct amd64_insn *details)
-@@ -1263,7 +1263,6 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details)
- }
-
- gdb_assert (used_regs_mask < 256);
-- gdb_assert (used_regs_mask != 255);
-
- /* Finally, find a free reg. */
- {
-@@ -1274,10 +1273,9 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details)
- if (! (used_regs_mask & (1 << i)))
- return i;
- }
--
-- /* We shouldn't get here. */
-- internal_error (_("unable to find free reg"));
- }
-+
-+ return -1;
- }
-
- /* Extract the details of INSN that we need. */
-@@ -1361,9 +1359,10 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- 32 bits is not enough to be guaranteed to cover the distance between where
- the real instruction is and where its copy is.
- Convert the insn to use base+disp addressing.
-- We set base = pc + insn_length so we can leave disp unchanged. */
-+ We set base = pc + insn_length so we can leave disp unchanged.
-+ Return true if successful, false otherwise. */
-
--static void
-+static bool
- fixup_riprel (struct gdbarch *gdbarch,
- amd64_displaced_step_copy_insn_closure *dsc,
- CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
-@@ -1384,6 +1383,9 @@ fixup_riprel (struct gdbarch *gdbarch,
- Pick one not used in the insn.
- NOTE: arch_tmp_regno uses architecture ordering, e.g. RDI = 7. */
- arch_tmp_regno = amd64_get_unused_input_int_reg (insn_details);
-+ if (arch_tmp_regno == -1)
-+ return false;
-+
- tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
-
- /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
-@@ -1418,9 +1420,13 @@ fixup_riprel (struct gdbarch *gdbarch,
- displaced_debug_printf ("using temp reg %d, old value %s, new value %s",
- dsc->tmp_regno, paddress (gdbarch, dsc->tmp_save),
- paddress (gdbarch, rip_base));
-+ return true;
- }
-
--static void
-+/* Fixup the insn in DSC->insn_buf, which was copied from address FROM to TO.
-+ Return true if successful, false otherwise. */
-+
-+static bool
- fixup_displaced_copy (struct gdbarch *gdbarch,
- amd64_displaced_step_copy_insn_closure *dsc,
- CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
-@@ -1435,9 +1441,11 @@ fixup_displaced_copy (struct gdbarch *gdbarch,
- {
- /* The insn uses rip-relative addressing.
- Deal with it. */
-- fixup_riprel (gdbarch, dsc, from, to, regs);
-+ return fixup_riprel (gdbarch, dsc, from, to, regs);
- }
- }
-+
-+ return true;
- }
-
- displaced_step_copy_insn_closure_up
-@@ -1475,7 +1483,8 @@ amd64_displaced_step_copy_insn (struct gdbarch *gdbarch,
-
- /* Modify the insn to cope with the address where it will be executed from.
- In particular, handle any rip-relative addressing. */
-- fixup_displaced_copy (gdbarch, dsc.get (), from, to, regs);
-+ if (!fixup_displaced_copy (gdbarch, dsc.get (), from, to, regs))
-+ return nullptr;
-
- write_memory (to, buf, len);
-
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch
deleted file mode 100644
index 97e5f47..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-10-of-13.patch
-
-;; [gdb/tdep] Add vzeroupper and vzeroall in amd64-insn-decode selftest
-;; (Tom de Vries, RHEL-7329)
-
-After I posted a tentative patch for PR31952, Alexander Monakov pointed out
-that the patch broke instruction decoding for instructions vzeroall and
-vzeroupper.
-
-Add selftests for these two instructions in amd64-insn-decode, both using
-vex2 and vex3 prefixes.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -3512,6 +3512,40 @@ test_amd64_get_insn_details (void)
- gdb::byte_vector updated_insn = { 0x48, 0x8d, 0xb9, 0x1e, 0x00, 0x00, 0x00 };
- fixup_riprel (details, insn.data (), ECX_REG_NUM);
- SELF_CHECK (insn == updated_insn);
-+
-+ gdb::byte_vector vex2, vex3;
-+
-+ /* INSN: vzeroall, vex2 prefix. */
-+ vex2 = { 0xc5, 0xfc, 0x77 };
-+ amd64_get_insn_details (vex2.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.opcode_offset == 2);
-+ SELF_CHECK (details.modrm_offset == -1);
-+
-+ /* INSN: vzeroall, vex3 prefix. */
-+ vex2_to_vex3 (vex2, vex3);
-+ amd64_get_insn_details (vex3.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 3);
-+ SELF_CHECK (details.modrm_offset == -1);
-+
-+ /* INSN: vzeroupper, vex2 prefix. */
-+ vex2 = { 0xc5, 0xf8, 0x77 };
-+ amd64_get_insn_details (vex2.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.opcode_offset == 2);
-+ SELF_CHECK (details.modrm_offset == -1);
-+
-+ /* INSN: vzeroupper, vex3 prefix. */
-+ vex2_to_vex3 (vex2, vex3);
-+ amd64_get_insn_details (vex3.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 3);
-+ SELF_CHECK (details.modrm_offset == -1);
- }
-
- static void
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch
deleted file mode 100644
index 55d3b91..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-11-of-13.patch
-
-;; [gdb/tdep] Make amd64_get_insn_details more regular
-;; (Tom de Vries, RHEL-7329)
-
-In amd64_get_insn_details, I found this code with a comment explaining why
-enc_prefix_offset is not set:
-...
- else if (vex2_prefix_p (*insn))
- {
- /* Don't record the offset in this case because this prefix has
- no REX.B equivalent. */
- insn += 2;
- }
-...
-which I didn't understand until I looked at the only use of enc_prefix_offset,
-in fixup_riprel:
-...
- /* REX.B should be unset (VEX.!B set) as we were using rip-relative
- addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
- is not r8-r15. */
- if (insn_details->enc_prefix_offset != -1)
- {
- gdb_byte *pfx = &dsc->insn_buf[insn_details->enc_prefix_offset];
- if (rex_prefix_p (pfx[0]))
- pfx[0] &= ~REX_B;
- else if (vex3_prefix_p (pfx[0]))
- pfx[1] |= VEX3_NOT_B;
- else
- gdb_assert_not_reached ("unhandled prefix");
- }
-...
-
-Fix this by:
-- setting enc_prefix_offset for the vex2 case in amd64_get_insn_details,
- making the function more regular and easier to understand, and
-- handling the vex2 case in the "enc_prefix_offset != -1" clause in
- fixup_riprel.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1328,8 +1328,7 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- }
- else if (vex2_prefix_p (*insn))
- {
-- /* Don't record the offset in this case because this prefix has
-- no REX.B equivalent. */
-+ details->enc_prefix_offset = insn - start;
- insn += 2;
- }
- else if (vex3_prefix_p (*insn))
-@@ -1395,6 +1394,10 @@ fixup_riprel (const struct amd64_insn &details, gdb_byte *insn,
- gdb_byte *pfx = &insn[details.enc_prefix_offset];
- if (rex_prefix_p (pfx[0]))
- pfx[0] &= ~REX_B;
-+ else if (vex2_prefix_p (pfx[0]))
-+ {
-+ /* VEX.!B is set implicitly. */
-+ }
- else if (vex3_prefix_p (pfx[0]))
- pfx[1] |= VEX3_NOT_B;
- else
-@@ -3519,7 +3522,7 @@ test_amd64_get_insn_details (void)
- vex2 = { 0xc5, 0xfc, 0x77 };
- amd64_get_insn_details (vex2.data (), &details);
- SELF_CHECK (details.opcode_len == 1);
-- SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 2);
- SELF_CHECK (details.modrm_offset == -1);
-
-@@ -3535,7 +3538,7 @@ test_amd64_get_insn_details (void)
- vex2 = { 0xc5, 0xf8, 0x77 };
- amd64_get_insn_details (vex2.data (), &details);
- SELF_CHECK (details.opcode_len == 1);
-- SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 2);
- SELF_CHECK (details.modrm_offset == -1);
-
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch
deleted file mode 100644
index 90498bb..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-12-of-13.patch
-
-;; [gdb/tdep] Fix vmovdqu decoding
-;; (Tom de Vries, RHEL-7329)
-
-PR tdep/31952 reports that displaced stepping over an instruction pointer
-relative insn "vmovdqu 0x20(%rip),%ymm1" gives the wrong results.
-
-This is caused by misclassification of the insn in amd64_get_insn_details,
-which results in details.modrm_offset == -1, while the instruction in fact
-does have a modrm byte.
-
-The instruction is encoded as follows:
-...
- 400557: c5 fe 6f 0d 20 00 00 00 vmovdqu 0x20(%rip),%ymm1
-...
-where:
-- "0xc5 0xfe" is the vex2 prefix,
-- "0x6f" is the opcode,
-- "0x0d" is the modrm byte, and
-- "0x20 0x00 0x00 0x00" is a 32-bit displacement.
-
-The problem is related to details.opcode_len, which is 1.
-
-While it is true that the length of the opcode in the insn (0x6f) is 1 byte,
-the vex2 prefix implies that we're encoding an 2-byte opcode beginnning
-with 0x0f [1].
-
-Consequently, we should be using the twobyte_has_modrm map rather than the
-onebyte_has_modrm map.
-
-Fix this in amd64_get_insn_details, and add a selftest to check this.
-
-Tested on x86_64-linux.
-
-Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31952
-
-[1] https://en.wikipedia.org/wiki/VEX_prefix
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1336,10 +1336,49 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- details->enc_prefix_offset = insn - start;
- insn += 3;
- }
-+ gdb_byte *prefix = (details->enc_prefix_offset == -1
-+ ? nullptr
-+ : &start[details->enc_prefix_offset]);
-
- details->opcode_offset = insn - start;
-
-- if (*insn == TWO_BYTE_OPCODE_ESCAPE)
-+ if (prefix != nullptr && vex2_prefix_p (*prefix))
-+ {
-+ need_modrm = twobyte_has_modrm[*insn];
-+ details->opcode_len = 2;
-+ }
-+ else if (prefix != nullptr && vex3_prefix_p (*prefix))
-+ {
-+ need_modrm = twobyte_has_modrm[*insn];
-+
-+ gdb_byte m = prefix[1] & 0x1f;
-+ if (m == 0)
-+ {
-+ /* Todo: Xeon Phi-specific JKZD/JKNZD. */
-+ return;
-+ }
-+ else if (m == 1)
-+ {
-+ /* Escape 0x0f. */
-+ details->opcode_len = 2;
-+ }
-+ else if (m == 2 || m == 3)
-+ {
-+ /* Escape 0x0f 0x38 or 0x0f 0x3a. */
-+ details->opcode_len = 3;
-+ }
-+ else if (m == 7)
-+ {
-+ /* Todo: URDMSR/UWRMSR instructions. */
-+ return;
-+ }
-+ else
-+ {
-+ /* Unknown opcode map. */
-+ return;
-+ }
-+ }
-+ else if (*insn == TWO_BYTE_OPCODE_ESCAPE)
- {
- /* Two or three-byte opcode. */
- ++insn;
-@@ -1513,6 +1552,8 @@ amd64_displaced_step_copy_insn (struct gdbarch *gdbarch,
- memset (buf + len, 0, fixup_sentinel_space);
-
- amd64_get_insn_details (buf, details);
-+ if (details->opcode_len == -1)
-+ return nullptr;
-
- /* GDB may get control back after the insn after the syscall.
- Presumably this is a kernel bug.
-@@ -3475,7 +3516,7 @@ static void
- test_amd64_get_insn_details (void)
- {
- struct amd64_insn details;
-- gdb::byte_vector insn;
-+ gdb::byte_vector insn, tmp;
-
- /* INSN: add %eax,(%rcx). */
- insn = { 0x01, 0x01 };
-@@ -3521,7 +3562,7 @@ test_amd64_get_insn_details (void)
- /* INSN: vzeroall, vex2 prefix. */
- vex2 = { 0xc5, 0xfc, 0x77 };
- amd64_get_insn_details (vex2.data (), &details);
-- SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.opcode_len == 2);
- SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 2);
- SELF_CHECK (details.modrm_offset == -1);
-@@ -3529,7 +3570,7 @@ test_amd64_get_insn_details (void)
- /* INSN: vzeroall, vex3 prefix. */
- vex2_to_vex3 (vex2, vex3);
- amd64_get_insn_details (vex3.data (), &details);
-- SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.opcode_len == 2);
- SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 3);
- SELF_CHECK (details.modrm_offset == -1);
-@@ -3537,7 +3578,7 @@ test_amd64_get_insn_details (void)
- /* INSN: vzeroupper, vex2 prefix. */
- vex2 = { 0xc5, 0xf8, 0x77 };
- amd64_get_insn_details (vex2.data (), &details);
-- SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.opcode_len == 2);
- SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 2);
- SELF_CHECK (details.modrm_offset == -1);
-@@ -3545,10 +3586,40 @@ test_amd64_get_insn_details (void)
- /* INSN: vzeroupper, vex3 prefix. */
- vex2_to_vex3 (vex2, vex3);
- amd64_get_insn_details (vex3.data (), &details);
-- SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.opcode_len == 2);
- SELF_CHECK (details.enc_prefix_offset == 0);
- SELF_CHECK (details.opcode_offset == 3);
- SELF_CHECK (details.modrm_offset == -1);
-+
-+ /* INSN: vmovdqu 0x9(%rip),%ymm3, vex2 prefix. */
-+ vex2 = { 0xc5, 0xfe, 0x6f, 0x1d, 0x09, 0x00, 0x00, 0x00 };
-+ amd64_get_insn_details (vex2.data (), &details);
-+ SELF_CHECK (details.opcode_len == 2);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 2);
-+ SELF_CHECK (details.modrm_offset == 3);
-+
-+ /* INSN: vmovdqu 0x9(%rcx),%ymm3, vex2 prefix. */
-+ gdb::byte_vector updated_vex2
-+ = { 0xc5, 0xfe, 0x6f, 0x99, 0x09, 0x00, 0x00, 0x00 };
-+ tmp = vex2;
-+ fixup_riprel (details, tmp.data (), ECX_REG_NUM);
-+ SELF_CHECK (tmp == updated_vex2);
-+
-+ /* INSN: vmovdqu 0x9(%rip),%ymm3, vex3 prefix. */
-+ vex2_to_vex3 (vex2, vex3);
-+ amd64_get_insn_details (vex3.data (), &details);
-+ SELF_CHECK (details.opcode_len == 2);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 3);
-+ SELF_CHECK (details.modrm_offset == 4);
-+
-+ /* INSN: vmovdqu 0x9(%rcx),%ymm3, vex3 prefix. */
-+ gdb::byte_vector updated_vex3;
-+ vex2_to_vex3 (updated_vex2, updated_vex3);
-+ tmp = vex3;
-+ fixup_riprel (details, tmp.data (), ECX_REG_NUM);
-+ SELF_CHECK (tmp == updated_vex3);
- }
-
- static void
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch
deleted file mode 100644
index 0d1fc91..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch
+++ /dev/null
@@ -1,212 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-13-of-13.patch
-
-;; [gdb/tdep] Support REX2 and EVEX prefix
-;; (Tom de Vries, RHEL-7329)
-
-The following amd64 insn:
-...
- 0: 67 d5 44 8d 3d 00 00 00 00 lea 0x0(%eip),%r31d
-...
-uses the REX2 prefix [1], which is currently not supported in
-amd64_get_insn_details.
-
-Add the missing support in amd64_get_insn_details, as well as a corresponding
-unit test.
-
-Likewise for an amd64 insn using an EVEX prefix [2]:
-...
- 0: 62 f1 7c 48 28 05 00 fc ff ff vmovaps -0x400(%rip),%zmm0
-...
-
-Tested on x86_64-linux.
-
-PR tdep/32725
-Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32725
-
-[1] https://en.wikipedia.org/wiki/VEX_prefix
-[2] https://en.wikipedia.org/wiki/EVEX_prefix
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1158,6 +1158,14 @@ rex_prefix_p (gdb_byte pfx)
- return REX_PREFIX_P (pfx);
- }
-
-+/* True if PFX is the start of the 2-byte REX2 prefix. */
-+
-+static bool
-+rex2_prefix_p (gdb_byte pfx)
-+{
-+ return pfx == REX2_OPCODE;
-+}
-+
- /* True if PFX is the start of the 2-byte VEX prefix. */
-
- static bool
-@@ -1174,6 +1182,14 @@ vex3_prefix_p (gdb_byte pfx)
- return pfx == 0xc4;
- }
-
-+/* Return true if PFX is the start of the 4-byte EVEX prefix. */
-+
-+static bool
-+evex_prefix_p (gdb_byte pfx)
-+{
-+ return pfx == 0x62;
-+}
-+
- /* Skip the legacy instruction prefixes in INSN.
- We assume INSN is properly sentineled so we don't have to worry
- about falling off the end of the buffer. */
-@@ -1326,6 +1342,11 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- details->enc_prefix_offset = insn - start;
- ++insn;
- }
-+ else if (rex2_prefix_p (*insn))
-+ {
-+ details->enc_prefix_offset = insn - start;
-+ insn += 2;
-+ }
- else if (vex2_prefix_p (*insn))
- {
- details->enc_prefix_offset = insn - start;
-@@ -1336,13 +1357,32 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- details->enc_prefix_offset = insn - start;
- insn += 3;
- }
-+ else if (evex_prefix_p (*insn))
-+ {
-+ details->enc_prefix_offset = insn - start;
-+ insn += 4;
-+ }
- gdb_byte *prefix = (details->enc_prefix_offset == -1
- ? nullptr
- : &start[details->enc_prefix_offset]);
-
- details->opcode_offset = insn - start;
-
-- if (prefix != nullptr && vex2_prefix_p (*prefix))
-+ if (prefix != nullptr && rex2_prefix_p (*prefix))
-+ {
-+ bool m = (prefix[1] & (REX2_M << 4)) != 0;
-+ if (!m)
-+ {
-+ need_modrm = onebyte_has_modrm[*insn];
-+ details->opcode_len = 1;
-+ }
-+ else
-+ {
-+ need_modrm = twobyte_has_modrm[*insn];
-+ details->opcode_len = 2;
-+ }
-+ }
-+ else if (prefix != nullptr && vex2_prefix_p (*prefix))
- {
- need_modrm = twobyte_has_modrm[*insn];
- details->opcode_len = 2;
-@@ -1378,6 +1418,27 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- return;
- }
- }
-+ else if (prefix != nullptr && evex_prefix_p (*prefix))
-+ {
-+ need_modrm = twobyte_has_modrm[*insn];
-+
-+ gdb_byte m = prefix[1] & 0x7;
-+ if (m == 1)
-+ {
-+ /* Escape 0x0f. */
-+ details->opcode_len = 2;
-+ }
-+ else if (m == 2 || m == 3)
-+ {
-+ /* Escape 0x0f 0x38 or 0x0f 0x3a. */
-+ details->opcode_len = 3;
-+ }
-+ else
-+ {
-+ /* Unknown opcode map. */
-+ return;
-+ }
-+ }
- else if (*insn == TWO_BYTE_OPCODE_ESCAPE)
- {
- /* Two or three-byte opcode. */
-@@ -1425,6 +1486,15 @@ fixup_riprel (const struct amd64_insn &details, gdb_byte *insn,
- /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
- static constexpr gdb_byte VEX3_NOT_B = 0x20;
-
-+ /* Position of the B3 and B4 bits in the REX2 prefix (in byte 1). */
-+ static constexpr gdb_byte REX2_B = 0x11;
-+
-+ /* Position of the not-B3 bit in the EVEX prefix (in byte 1). */
-+ static constexpr gdb_byte EVEX_NOT_B = VEX3_NOT_B;
-+
-+ /* Position of the B4 bit in the EVEX prefix (in byte 1). */
-+ static constexpr gdb_byte EVEX_B = 0x08;
-+
- /* REX.B should be unset (VEX.!B set) as we were using rip-relative
- addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
- is not r8-r15. */
-@@ -1433,12 +1503,19 @@ fixup_riprel (const struct amd64_insn &details, gdb_byte *insn,
- gdb_byte *pfx = &insn[details.enc_prefix_offset];
- if (rex_prefix_p (pfx[0]))
- pfx[0] &= ~REX_B;
-+ else if (rex2_prefix_p (pfx[0]))
-+ pfx[1] &= ~REX2_B;
- else if (vex2_prefix_p (pfx[0]))
- {
- /* VEX.!B is set implicitly. */
- }
- else if (vex3_prefix_p (pfx[0]))
- pfx[1] |= VEX3_NOT_B;
-+ else if (evex_prefix_p (pfx[0]))
-+ {
-+ pfx[1] |= EVEX_NOT_B;
-+ pfx[1] &= ~EVEX_B;
-+ }
- else
- gdb_assert_not_reached ("unhandled prefix");
- }
-@@ -3620,6 +3697,37 @@ test_amd64_get_insn_details (void)
- tmp = vex3;
- fixup_riprel (details, tmp.data (), ECX_REG_NUM);
- SELF_CHECK (tmp == updated_vex3);
-+
-+ /* INSN: lea 0x0(%eip),%r31d, rex2 prefix. */
-+ insn = { 0x67, 0xd5, 0x44, 0x8d, 0x3d, 0x00, 0x00, 0x00, 0x00 };
-+ amd64_get_insn_details (insn.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == 1);
-+ SELF_CHECK (details.opcode_offset == 3);
-+ SELF_CHECK (details.modrm_offset == 4);
-+ /* This is incorrect, r31 is used instead of rdi, but currently that doesn't
-+ matter. */
-+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
-+ == (1 << EDI_REG_NUM));
-+
-+ /* INSN: lea 0x0(%ecx),%r31d, rex2 prefix. */
-+ updated_insn = { 0x67, 0xd5, 0x44, 0x8d, 0xb9, 0x00, 0x00, 0x00, 0x00 };
-+ fixup_riprel (details, insn.data (), ECX_REG_NUM);
-+ SELF_CHECK (insn == updated_insn);
-+
-+ /* INSN: vmovaps -0x400(%rip),%zmm0, evex prefix. */
-+ insn = { 0x62, 0xf1, 0x7c, 0x48, 0x28, 0x05, 0x00, 0xfc, 0xff, 0xff };
-+ amd64_get_insn_details (insn.data (), &details);
-+ SELF_CHECK (details.opcode_len == 2);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 4);
-+ SELF_CHECK (details.modrm_offset == 5);
-+
-+ /* INSN: vmovaps -0x400(%rcx),%zmm0, evex prefix. */
-+ updated_insn
-+ = { 0x62, 0xf1, 0x7c, 0x48, 0x28, 0x81, 0x00, 0xfc, 0xff, 0xff };
-+ fixup_riprel (details, insn.data (), ECX_REG_NUM);
-+ SELF_CHECK (insn == updated_insn);
- }
-
- static void
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch
deleted file mode 100644
index d9037d3..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-2-of-13.patch
-
-;; [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 2
-;; (Tom de Vries, RHEL-7329)
-
-I noticed that amd64_get_unused_input_int_reg uses a signed int for a bit
-mask:
-...
- /* 1 bit for each reg */
- int used_regs_mask = 0;
-...
-
-There's an assert:
-...
- gdb_assert (used_regs_mask < 256);
-...
-which is meant to assert on register numbers >= 8, but if for instance
-sizeof (used_regs_mask) == 4 and used_regs_mask == (1 << 31), then that is not
-caught because of the signedness.
-
-We could fix this by changing the type to unsigned int, but that only
-guarantees 16 bits in the reg mask. Intel CPUs with the APX extension support
-32 int registers.
-
-The implementation of amd64_get_unused_input_int_reg doesn't support analyzing
-registers with register number >= 8 yet, but now that we're changing the type,
-it seems like a good idea to anticipate this.
-
-Fix this by using uint32_t.
-
-Likewise, update the loop over the reg mask:
-...
- for (i = 0; i < 8; ++i)
- {
- if (! (used_regs_mask & (1 << i)))
- return i;
-...
-to handle any used_regs_mask value rather than just those for
-register number < 8.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1217,7 +1217,7 @@ static int
- amd64_get_unused_input_int_reg (const struct amd64_insn *details)
- {
- /* 1 bit for each reg */
-- int used_regs_mask = 0;
-+ uint32_t used_regs_mask = 0;
-
- /* There can be at most 3 int regs used as inputs in an insn, and we have
- 7 to choose from (RAX ... RDI, sans RSP).
-@@ -1268,7 +1268,7 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details)
- {
- int i;
-
-- for (i = 0; i < 8; ++i)
-+ for (i = 0; i < 32; ++i)
- {
- if (! (used_regs_mask & (1 << i)))
- return i;
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch
deleted file mode 100644
index a28e03a..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-3-of-13.patch
-
-;; [gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 3
-;; (Tom de Vries, RHEL-7329)
-
-While reading amd64_get_unused_input_int_reg, I noticed that it avoids picking
-RSP, which has to do with how the result of the only call to it is going to be
-used.
-
-Likewise for picking a register in the RAX ... RDI range.
-
-Fix this by:
-- adding an allowed_regs_mask parameter to amd64_get_unused_input_int_reg, and
-- properly documenting the value of the corresponding argument in fixup_riprel.
-
-No functional changes.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1206,31 +1206,23 @@ amd64_skip_prefixes (gdb_byte *insn)
- return insn;
- }
-
--/* Return an integer register (other than RSP) that is unused as an input
-- operand in INSN.
-- In order to not require adding a rex prefix if the insn doesn't already
-- have one, the result is restricted to RAX ... RDI, sans RSP.
-- The register numbering of the result follows architecture ordering,
-- e.g. RDI = 7. Return -1 if no register can be found. */
-+/* Return an integer register in ALLOWED_REGS_MASK that is unused as an input
-+ operand in INSN. The register numbering of the result follows architecture
-+ ordering, e.g. RDI = 7. Return -1 if no register can be found. */
-
- static int
--amd64_get_unused_input_int_reg (const struct amd64_insn *details)
-+amd64_get_unused_input_int_reg (const struct amd64_insn *details,
-+ uint32_t allowed_regs_mask)
- {
- /* 1 bit for each reg */
- uint32_t used_regs_mask = 0;
-
-- /* There can be at most 3 int regs used as inputs in an insn, and we have
-- 7 to choose from (RAX ... RDI, sans RSP).
-- This allows us to take a conservative approach and keep things simple.
-- E.g. By avoiding RAX, we don't have to specifically watch for opcodes
-- that implicitly specify RAX. */
--
-- /* Avoid RAX. */
-+ /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
-+ use RAX. */
- used_regs_mask |= 1 << EAX_REG_NUM;
-- /* Similarly avoid RDX, implicit operand in divides. */
-+ /* Assume RDX is used. If not, we'd have to detect opcodes that implicitly
-+ use RDX, like divides. */
- used_regs_mask |= 1 << EDX_REG_NUM;
-- /* Avoid RSP. */
-- used_regs_mask |= 1 << ESP_REG_NUM;
-
- /* If the opcode is one byte long and there's no ModRM byte,
- assume the opcode specifies a register. */
-@@ -1270,6 +1262,9 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details)
-
- for (i = 0; i < 32; ++i)
- {
-+ if (! (allowed_regs_mask & (1 << i)))
-+ continue;
-+
- if (! (used_regs_mask & (1 << i)))
- return i;
- }
-@@ -1379,13 +1374,19 @@ fixup_riprel (struct gdbarch *gdbarch,
- dsc->insn_buf.size (), from);
- rip_base = from + insn_length;
-
-- /* We need a register to hold the address.
-- Pick one not used in the insn.
-- NOTE: arch_tmp_regno uses architecture ordering, e.g. RDI = 7. */
-- arch_tmp_regno = amd64_get_unused_input_int_reg (insn_details);
-+ /* We need a register to hold the address. Pick one not used in the insn.
-+ In order to not require adding a rex prefix if the insn doesn't already
-+ have one, the range is restricted to RAX ... RDI, without RSP.
-+ We avoid RSP, because when patched into in the modrm byte, it doesn't
-+ indicate the use of the register, but instead the use of a SIB byte. */
-+ uint32_t allowed_regs_mask = 0xff & ~(1 << ESP_REG_NUM);
-+ arch_tmp_regno
-+ = amd64_get_unused_input_int_reg (insn_details, allowed_regs_mask);
- if (arch_tmp_regno == -1)
- return false;
-
-+ /* Convert arch_tmp_regno, which uses architecture ordering (e.g. RDI = 7),
-+ to GDB regnum. */
- tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
-
- /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch
deleted file mode 100644
index 37159e1..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-4-of-13.patch
-
-;; [gdb/tdep] Factor out amd64_get_used_input_int_regs
-;; (Tom de Vries, RHEL-7329)
-
-The function amd64_get_unused_input_int_reg consists of two parts:
-- finding the used int registers in an insn, and
-- picking an unused int register.
-
-Factor out the first part as new function amd64_get_used_input_int_regs.
-
-No functional changes.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1206,13 +1206,11 @@ amd64_skip_prefixes (gdb_byte *insn)
- return insn;
- }
-
--/* Return an integer register in ALLOWED_REGS_MASK that is unused as an input
-- operand in INSN. The register numbering of the result follows architecture
-- ordering, e.g. RDI = 7. Return -1 if no register can be found. */
-+/* Return a register mask for the integer registers that are used as an input
-+ operand in INSN. */
-
--static int
--amd64_get_unused_input_int_reg (const struct amd64_insn *details,
-- uint32_t allowed_regs_mask)
-+static uint32_t
-+amd64_get_used_input_int_regs (const struct amd64_insn *details)
- {
- /* 1 bit for each reg */
- uint32_t used_regs_mask = 0;
-@@ -1255,6 +1253,19 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details,
- }
-
- gdb_assert (used_regs_mask < 256);
-+ return used_regs_mask;
-+}
-+
-+/* Return an integer register in ALLOWED_REGS_MASK that is unused as an input
-+ operand in INSN. The register numbering of the result follows architecture
-+ ordering, e.g. RDI = 7. Return -1 if no register can be found. */
-+
-+static int
-+amd64_get_unused_input_int_reg (const struct amd64_insn *details,
-+ uint32_t allowed_regs_mask)
-+{
-+ /* 1 bit for each reg */
-+ uint32_t used_regs_mask = amd64_get_used_input_int_regs (details);
-
- /* Finally, find a free reg. */
- {
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch
deleted file mode 100644
index 10f8046..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-5-of-13.patch
-
-;; [gdb/tdep] Add amd64-insn-decode selftest
-;; (Tom de Vries, RHEL-7329)
-
-Add a selftest that checks the results of amd64_get_insn_details and related
-functions for two basic instructions.
-
-Add a parameter assumptions to amd64_get_used_input_int_regs, to make sure
-that this selftest:
-...
- /* INSN: add %eax,(%rcx). */
- ...
- SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
- == ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM)));
-...
-passes because it found the "%eax" in the insn, rather than passing because of
-this assumption:
-...
- /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
- use RAX. */
- used_regs_mask |= 1 << EAX_REG_NUM;
-...
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -50,6 +50,7 @@
- #include "osabi.h"
- #include "x86-tdep.h"
- #include "amd64-ravenscar-thread.h"
-+#include "gdbsupport/selftest.h"
-
- /* Note that the AMD64 architecture was previously known as x86-64.
- The latter is (forever) engraved into the canonical system name as
-@@ -1207,20 +1208,25 @@ amd64_skip_prefixes (gdb_byte *insn)
- }
-
- /* Return a register mask for the integer registers that are used as an input
-- operand in INSN. */
-+ operand in INSN. If !ASSUMPTIONS, only return the registers we actually
-+ found, for the benefit of self tests. */
-
- static uint32_t
--amd64_get_used_input_int_regs (const struct amd64_insn *details)
-+amd64_get_used_input_int_regs (const struct amd64_insn *details,
-+ bool assumptions = true)
- {
- /* 1 bit for each reg */
- uint32_t used_regs_mask = 0;
-
-- /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
-- use RAX. */
-- used_regs_mask |= 1 << EAX_REG_NUM;
-- /* Assume RDX is used. If not, we'd have to detect opcodes that implicitly
-- use RDX, like divides. */
-- used_regs_mask |= 1 << EDX_REG_NUM;
-+ if (assumptions)
-+ {
-+ /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
-+ use RAX. */
-+ used_regs_mask |= 1 << EAX_REG_NUM;
-+ /* Assume RDX is used. If not, we'd have to detect opcodes that implicitly
-+ use RDX, like divides. */
-+ used_regs_mask |= 1 << EDX_REG_NUM;
-+ }
-
- /* If the opcode is one byte long and there's no ModRM byte,
- assume the opcode specifies a register. */
-@@ -3395,6 +3401,51 @@ amd64_target_description (uint64_t xcr0, bool segments)
- return *tdesc;
- }
-
-+#if GDB_SELF_TEST
-+
-+namespace selftests {
-+
-+/* Test amd64_get_insn_details. */
-+
-+static void
-+test_amd64_get_insn_details (void)
-+{
-+ struct amd64_insn details;
-+ gdb::byte_vector insn;
-+
-+ /* INSN: add %eax,(%rcx). */
-+ insn = { 0x01, 0x01 };
-+ amd64_get_insn_details (insn.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.opcode_offset == 0);
-+ SELF_CHECK (details.modrm_offset == 1);
-+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
-+ == ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM)));
-+ SELF_CHECK (rip_relative_offset (&details) == 0);
-+
-+ /* INSN: push %rax. This exercises the "opcode specifies register" case in
-+ amd64_get_used_input_int_regs. */
-+ insn = { 0x50 };
-+ amd64_get_insn_details (insn.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == -1);
-+ SELF_CHECK (details.opcode_offset == 0);
-+ SELF_CHECK (details.modrm_offset == -1);
-+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
-+ == ((1 << EAX_REG_NUM)));
-+ SELF_CHECK (rip_relative_offset (&details) == 0);
-+}
-+
-+static void
-+amd64_insn_decode (void)
-+{
-+ test_amd64_get_insn_details ();
-+}
-+
-+} // namespace selftests
-+#endif /* GDB_SELF_TEST */
-+
- void _initialize_amd64_tdep ();
- void
- _initialize_amd64_tdep ()
-@@ -3403,6 +3454,10 @@ _initialize_amd64_tdep ()
- amd64_none_init_abi);
- gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32, GDB_OSABI_NONE,
- amd64_x32_none_init_abi);
-+#if GDB_SELF_TEST
-+ selftests::register_test ("amd64-insn-decode",
-+ selftests::amd64_insn_decode);
-+#endif
- }
-
-
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch
deleted file mode 100644
index 9bb4b87..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-6-of-13.patch
-
-;; [gdb/tdep] Factor out rip_relative_p
-;; (Tom de Vries, RHEL-7329)
-
-Factor out rip_relative_p, and rewrite it to use MODRM_MOD_FIELD and
-MODRM_RM_FIELD.
-
-No functional changes.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1207,6 +1207,18 @@ amd64_skip_prefixes (gdb_byte *insn)
- return insn;
- }
-
-+/* Return true if the MODRM byte of an insn indicates that the insn is
-+ rip-relative. */
-+
-+static bool
-+rip_relative_p (gdb_byte modrm)
-+{
-+ gdb_byte mod = MODRM_MOD_FIELD (modrm);
-+ gdb_byte rm = MODRM_RM_FIELD (modrm);
-+
-+ return mod == 0 && rm == 0x05;
-+}
-+
- /* Return a register mask for the integer registers that are used as an input
- operand in INSN. If !ASSUMPTIONS, only return the registers we actually
- found, for the benefit of self tests. */
-@@ -1455,7 +1467,7 @@ fixup_displaced_copy (struct gdbarch *gdbarch,
- {
- gdb_byte modrm = details->raw_insn[details->modrm_offset];
-
-- if ((modrm & 0xc7) == 0x05)
-+ if (rip_relative_p (modrm))
- {
- /* The insn uses rip-relative addressing.
- Deal with it. */
-@@ -1789,7 +1801,7 @@ rip_relative_offset (struct amd64_insn *insn)
- {
- gdb_byte modrm = insn->raw_insn[insn->modrm_offset];
-
-- if ((modrm & 0xc7) == 0x05)
-+ if (rip_relative_p (modrm))
- {
- /* The displacement is found right after the ModRM byte. */
- return insn->modrm_offset + 1;
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch
deleted file mode 100644
index 9a04e2e..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-7-of-13.patch
-
-;; [gdb/tdep] Fix rip-relative insn handling in amd64_get_used_input_int_reg
-;; (Tom de Vries, RHEL-7329)
-
-I wanted to add a unit test for an an rip-relative amd64 insn, so I did:
-...
-$ gcc -fPIE hello.c
-...
-and used an rip-relative insn from main:
-...
- 4005db: 48 8d 3d 1e 00 00 00 lea 0x1e(%rip),%rdi
-...
-
-While writing the unit test, I found that amd64_get_used_input_int_reg returns
-rbp as input register.
-
-Fix this by using rip_relative_p in amd64_get_used_input_int_reg to handle
-this case.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1264,7 +1264,7 @@ amd64_get_used_input_int_regs (const struct amd64_insn *details,
- used_regs_mask |= 1 << base;
- used_regs_mask |= 1 << idx;
- }
-- else
-+ else if (!rip_relative_p (modrm))
- {
- used_regs_mask |= 1 << rm;
- }
-@@ -3447,6 +3447,17 @@ test_amd64_get_insn_details (void)
- SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
- == ((1 << EAX_REG_NUM)));
- SELF_CHECK (rip_relative_offset (&details) == 0);
-+
-+ /* INSN: lea 0x1e(%rip),%rdi, rex prefix. */
-+ insn = { 0x48, 0x8d, 0x3d, 0x1e, 0x00, 0x00, 0x00 };
-+ amd64_get_insn_details (insn.data (), &details);
-+ SELF_CHECK (details.opcode_len == 1);
-+ SELF_CHECK (details.enc_prefix_offset == 0);
-+ SELF_CHECK (details.opcode_offset == 1);
-+ SELF_CHECK (details.modrm_offset == 2);
-+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
-+ == (1 << EDI_REG_NUM));
-+ SELF_CHECK (rip_relative_offset (&details) == 3);
- }
-
- static void
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch
deleted file mode 100644
index 4b75b0e..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-8-of-13.patch
-
-;; [gdb/tdep] Factor out part of fixup_riprel
-;; (Tom de Vries, RHEL-7329)
-
-Factor out the part of fixup_riprel that patches the insn, and use it in a
-unit test.
-
-Tested on x86_64-linux.
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -1377,6 +1377,36 @@ amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
- }
- }
-
-+/* Convert a %rip-relative INSN to use BASEREG+disp addressing, leaving
-+ displacement unchanged. */
-+
-+static void
-+fixup_riprel (const struct amd64_insn &details, gdb_byte *insn,
-+ int basereg)
-+{
-+ /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
-+ static constexpr gdb_byte VEX3_NOT_B = 0x20;
-+
-+ /* REX.B should be unset (VEX.!B set) as we were using rip-relative
-+ addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
-+ is not r8-r15. */
-+ if (details.enc_prefix_offset != -1)
-+ {
-+ gdb_byte *pfx = &insn[details.enc_prefix_offset];
-+ if (rex_prefix_p (pfx[0]))
-+ pfx[0] &= ~REX_B;
-+ else if (vex3_prefix_p (pfx[0]))
-+ pfx[1] |= VEX3_NOT_B;
-+ else
-+ gdb_assert_not_reached ("unhandled prefix");
-+ }
-+
-+ int modrm_offset = details.modrm_offset;
-+ /* Convert the ModRM field to be base+disp. */
-+ insn[modrm_offset] &= ~0xc7;
-+ insn[modrm_offset] |= 0x80 + basereg;
-+}
-+
- /* Update %rip-relative addressing in INSN.
-
- %rip-relative addressing only uses a 32-bit displacement.
-@@ -1392,7 +1422,6 @@ fixup_riprel (struct gdbarch *gdbarch,
- CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
- {
- const struct amd64_insn *insn_details = &dsc->insn_details;
-- int modrm_offset = insn_details->modrm_offset;
- CORE_ADDR rip_base;
- int insn_length;
- int arch_tmp_regno, tmp_regno;
-@@ -1414,36 +1443,17 @@ fixup_riprel (struct gdbarch *gdbarch,
- if (arch_tmp_regno == -1)
- return false;
-
-+ fixup_riprel (dsc->insn_details, dsc->insn_buf.data (), arch_tmp_regno);
-+
- /* Convert arch_tmp_regno, which uses architecture ordering (e.g. RDI = 7),
- to GDB regnum. */
- tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
-
-- /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
-- static constexpr gdb_byte VEX3_NOT_B = 0x20;
--
-- /* REX.B should be unset (VEX.!B set) as we were using rip-relative
-- addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
-- is not r8-r15. */
-- if (insn_details->enc_prefix_offset != -1)
-- {
-- gdb_byte *pfx = &dsc->insn_buf[insn_details->enc_prefix_offset];
-- if (rex_prefix_p (pfx[0]))
-- pfx[0] &= ~REX_B;
-- else if (vex3_prefix_p (pfx[0]))
-- pfx[1] |= VEX3_NOT_B;
-- else
-- gdb_assert_not_reached ("unhandled prefix");
-- }
--
- regcache_cooked_read_unsigned (regs, tmp_regno, &orig_value);
- dsc->tmp_regno = tmp_regno;
- dsc->tmp_save = orig_value;
- dsc->tmp_used = 1;
-
-- /* Convert the ModRM field to be base+disp. */
-- dsc->insn_buf[modrm_offset] &= ~0xc7;
-- dsc->insn_buf[modrm_offset] |= 0x80 + arch_tmp_regno;
--
- regcache_cooked_write_unsigned (regs, tmp_regno, rip_base);
-
- displaced_debug_printf ("%%rip-relative addressing used.");
-@@ -3458,6 +3468,11 @@ test_amd64_get_insn_details (void)
- SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
- == (1 << EDI_REG_NUM));
- SELF_CHECK (rip_relative_offset (&details) == 3);
-+
-+ /* INSN: lea 0x1e(%ecx),%rdi, rex prefix. */
-+ gdb::byte_vector updated_insn = { 0x48, 0x8d, 0xb9, 0x1e, 0x00, 0x00, 0x00 };
-+ fixup_riprel (details, insn.data (), ECX_REG_NUM);
-+ SELF_CHECK (insn == updated_insn);
- }
-
- static void
diff --git a/gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch b/gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch
deleted file mode 100644
index 3c61905..0000000
--- a/gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Tom de Vries
-Date: Fri, 7 Mar 2025 09:25:33 +0100
-Subject: gdb-rhel-7329-vandps-clobbers-registers-9-of-13.patch
-
-;; [gdb/tdep] Add vex2_to_vex3
-;; (Tom de Vries, RHEL-7329)
-
-I noticed here [1] that the vex2 prefix is essentially a special case of the
-vex3 prefix, meaning it's possible to rewrite any insn with a vex2 prefix into
-an equivalent one with a vex3 prefix.
-
-Add function vex2_to_vex3 that does precisely that, in the selftests
-namespace.
-
-Add a selftest that exercises this function.
-
-Tested on x86_64-linux.
-
-[1] https://en.wikipedia.org/wiki/VEX_prefix
-
-diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
---- a/gdb/amd64-tdep.c
-+++ b/gdb/amd64-tdep.c
-@@ -3427,6 +3427,45 @@ amd64_target_description (uint64_t xcr0, bool segments)
-
- namespace selftests {
-
-+/* Recode a vex2 instruction into a vex3 instruction. */
-+
-+static void
-+vex2_to_vex3 (gdb::byte_vector &vex2, gdb::byte_vector &vex3)
-+{
-+ gdb_assert (vex2.size () >= 2);
-+ gdb_assert (vex2[0] == 0xc5);
-+
-+ unsigned char r = vex2[1] >> 7;
-+ unsigned char b = 0x1;
-+ unsigned char x = 0x1;
-+ unsigned char m = 0x1;
-+ unsigned char w = 0x0;
-+
-+ vex3.resize (3);
-+ vex3[0] = 0xc4;
-+ vex3[1] = (r << 7) | (x << 6) | (b << 5) | m;
-+ vex3[2] = (vex2[1] & ~0x80) | (w << 7);
-+
-+ std::copy (vex2.begin () + 2, vex2.end (),
-+ std::back_inserter (vex3));
-+}
-+
-+/* Test vex2 to vex3. */
-+
-+static void
-+test_vex2_to_vex3 (void)
-+{
-+ /* INSN: vzeroall, vex2 prefix. */
-+ gdb::byte_vector vex2 = { 0xc5, 0xfc, 0x77 };
-+
-+ gdb::byte_vector vex3;
-+ vex2_to_vex3 (vex2, vex3);
-+
-+ /* INSN: vzeroall, vex3 prefix. */
-+ gdb::byte_vector vex3_ref = { 0xc4, 0xe1, 0x7c, 0x77 };
-+ SELF_CHECK (vex3 == vex3_ref);
-+}
-+
- /* Test amd64_get_insn_details. */
-
- static void
-@@ -3478,6 +3517,7 @@ test_amd64_get_insn_details (void)
- static void
- amd64_insn_decode (void)
- {
-+ test_vex2_to_vex3 ();
- test_amd64_get_insn_details ();
- }
-
diff --git a/gdb-add-rpm-suggestion-script.patch b/gdb-rpm-suggestion-script.patch
similarity index 99%
rename from gdb-add-rpm-suggestion-script.patch
rename to gdb-rpm-suggestion-script.patch
index 1eccb30..28df14b 100644
--- a/gdb-add-rpm-suggestion-script.patch
+++ b/gdb-rpm-suggestion-script.patch
@@ -1,7 +1,7 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Andrew Burgess
Date: Thu, 7 Mar 2024 15:14:23 +0000
-Subject: gdb-add-rpm-suggestion-script.patch
+Subject: gdb-rpm-suggestion-script.patch
;; Not a backport. Add a new script which hooks into GDB and suggests
;; RPMs to install when GDB finds an objfile with no debug info.
@@ -33,7 +33,7 @@ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
* Man Pages:: Manual pages
* Copying:: GNU General Public License says
how you can copy and share @value{GDBN}
-@@ -50588,6 +50589,111 @@ Show the current verbosity setting.
+@@ -50986,6 +50987,111 @@ Show the current verbosity setting.
@end table
@@ -149,7 +149,7 @@ diff --git a/gdb/python/lib/gdb/command/rpm-suggestions.py b/gdb/python/lib/gdb/
new file mode 100644
--- /dev/null
+++ b/gdb/python/lib/gdb/command/rpm-suggestions.py
-@@ -0,0 +1,525 @@
+@@ -0,0 +1,527 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
@@ -655,7 +655,9 @@ new file mode 100644
+
+# The 'info rpm-suggestions' command.
+class rpm_suggestion_info(gdb.Command):
-+ """Relist any RPM installation suggestions that have been made
++ """Relist RPM suggestions.
++
++ Relist any RPM installation suggestions that have been made
+ since the executable was last changed."""
+ def __init__(self):
+ super().__init__("info rpm-suggestions", gdb.COMMAND_NONE, gdb.COMPLETE_NONE)
@@ -967,7 +969,7 @@ diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
# If DEBUGINFOD_URLS is set, gdb will try to download sources and
# debug info for f.i. system libraries. Prevent this.
-@@ -2610,6 +2611,18 @@ proc default_gdb_start { } {
+@@ -2850,6 +2851,18 @@ proc default_gdb_start { } {
}
}
diff --git a/gdb-tcl9-utf8-encoding-fix.patch b/gdb-tcl9-utf8-encoding-fix.patch
new file mode 100644
index 0000000..9383e17
--- /dev/null
+++ b/gdb-tcl9-utf8-encoding-fix.patch
@@ -0,0 +1,157 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Kevin Buettner
+Date: Sun, 24 May 2026 21:02:34 -0700
+Subject: gdb-tcl9-utf8-encoding-fix.patch
+
+;; Fix EILSEQ problems for UTF8 related tests when using expect
+;; enabled with Tcl 9 and full set of Tcl 9 compatibility fixes
+;; from upstream PR80674 branch. Required for testing GDB on
+;; Fedora 44 and rawhide (Fedora 45).
+;;
+;; At the time of this Fedora commit, this patch was not upstream yet.
+;; For its status, see:
+;;
+;; https://inbox.sourceware.org/gdb-patches/20260526192701.3835262-2-kevinb@redhat.com/T/#u
+
+Fix EILSEQ problems for UTF8 related tests
+
+On Fedora 44 and Rawhide (Fedora 45), these tests...
+
+ gdb.ada/non-ascii-utf-8.exp
+ gdb.base/utf8-identifiers.exp
+ gdb.rust/unicode.exp
+
+...all die due to these errors:
+
+ Running ...gdb/testsuite/gdb.base/utf8-identifiers.exp ...
+ ERROR: tcl error sourcing .../gdb/testsuite/gdb.base/utf8-identifiers.exp.
+ ERROR: tcl error code POSIX EILSEQ {invalid or incomplete multibyte or wide character}
+ error writing "file6": invalid or incomplete multibyte or wide character
+ ...
+
+(I've shortened some of the pathnames for brevity.)
+
+These Fedora systems are using Tcl 9 and also an updated version of
+dejagnu with this change applied:
+
+ * Thu Apr 16 2026 Jakub Jelinek - 1:1.6.3-17
+ - Apply full set of Tcl 9 compatibility fixes from upstream PR80674 branch
+ (#2448542)
+
+That runtest change is responsible for the POSIX EILSEQ errors on
+machines with that change. The change to runtest causing the change
+in behavior for GDB is the addition of these lines near the top of
+the runtest script:
+
+ # Ensure that DejaGnu will be run in the POSIX locale
+ LC_ALL=C
+ export LC_ALL
+
+Tcl 8 used a permissive encoding strategy: bytes that could not be
+represented in the current encoding were silently mangled or
+substituted. Tcl 9 changed this default to a strict profile, which
+means that any attempt to write a character that cannot be expressed
+in the channel's encoding raises a POSIX EILSEQ error ("invalid or
+incomplete multibyte or wide character").
+
+So, together, this Tcl 9 behavior combined with the dejagnu change
+to runtest causes the EILSEQ error for the tests mentioned earlier.
+
+Fix it by using "fconfigure $handle -encoding utf-8 -profile replace"
+in proc spawn_capture_tty_name, and proc gdb_stdin_log_init. Also,
+the open_logs wrapper has been changed to invoke fconfigure using only
+"-encoding utf-8". Testing showed that "-profile replace" wasn't
+necessary there.
+
+Tested on Fedora 28 (Tcl 8.6.8), Fedora 43 (Tcl 9.0.2 / 8.6.16; expect
+uses 8.6.16), Fedora 44 (Tcl 9.0.2 / 8.6.17; expect uses 9.0.2), and
+Rawhide / Fedora 45 (Tcl 9.0.3 / 8.6.18; expect uses 9.0.3).
+
+With regard to the Bug noted below, I haven't been able to reproduce
+the failures in gdb.ada/lazy-string.exp, but I've been informed that
+this commit fixes it.
+
+Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34146
+Reviewed-By: Tom de Vries
+
+diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
+--- a/gdb/testsuite/lib/gdb.exp
++++ b/gdb/testsuite/lib/gdb.exp
+@@ -152,6 +152,35 @@ proc load_lib { file } {
+ return $result
+ }
+
++# Tcl 9.0 changed the default channel encoding profile to "strict".
++# When runtest sets LC_ALL=C the system encoding is iso8859-1, so file
++# channels opened by DejaGNU (gdb.sum, gdb.log) and spawn channels
++# (for GDB and subprocesses) default to iso8859-1 with strict profile.
++# Writing non-Latin-1 characters in test names then raises EILSEQ, and
++# sending them to GDB truncates the command at the unrepresentable
++# character.
++#
++# Fix this by:
++# 1. Overriding open_logs to reconfigure gdb.sum to UTF-8 after
++# DejaGNU opens it with the system (iso8859-1) encoding. Only
++# "-encoding utf-8" is needed here, not "-profile replace". The
++# test names written to gdb.sum are Unicode strings, and since
++# UTF-8 can represent every Unicode character, the encode
++# operation cannot fail. This use of "fconfigure" lacks a Tcl
++# version guard since "-encoding utf-8" works in both Tcl 8 and
++# Tcl 9. (Use of "-profile replace" requires a guard, as that
++# option did not exist before Tcl 9.)
++# 2. Reconfiguring each new spawn channel to UTF-8 and to also use
++# "-profile replace" in spawn_capture_tty_name, which wraps every
++# spawn call.
++# 3. Likewise for gdb_stdin_log_init.
++
++rename open_logs saved_open_logs
++proc open_logs {} {
++ saved_open_logs
++ fconfigure $::sum_file -encoding utf-8
++}
++
+ load_lib libgloss.exp
+ load_lib cache.exp
+ load_lib gdb-utils.exp
+@@ -2685,6 +2714,7 @@ proc gdb_file_cmd { arg {kill_flag 1} } {
+ proc spawn_capture_tty_name { args } {
+ set result [uplevel builtin_spawn $args]
+ upvar spawn_out spawn_out
++ upvar spawn_id spawn_id
+ if { [info exists spawn_out(slave,name)] } {
+ set ::last_spawn_tty_name $spawn_out(slave,name)
+ } else {
+@@ -2700,6 +2730,21 @@ proc spawn_capture_tty_name { args } {
+ # use -nocomplain here we would otherwise get an error.
+ unset -nocomplain ::last_spawn_tty_name
+ }
++ # Tcl 9.0 defaults spawn channels to iso8859-1/strict, which
++ # raises EILSEQ when non-Latin-1 characters (e.g. identifiers
++ # with UTF-8 letters) are written to or read from the channel.
++ # Use utf-8 instead.
++ #
++ # "catch" is used here because, unlike the other sites in this
++ # file where fconfigure is used, this use of fconfigure could
++ # attempt to modify channels which do not support these options.
++ # Those other sites use "fconfigure" on recently opened files
++ # where it will almost certainly work. (And, for those other sites,
++ # if it doesn't work, we want to be notified of that fact via the
++ # normal Tcl error reporting mechanisms.)
++ if {[tcl_version_at_least 9 0 0]} {
++ catch {fconfigure $spawn_id -encoding utf-8 -profile replace}
++ }
+ return $result
+ }
+
+@@ -10387,6 +10432,11 @@ proc gdb_stdin_log_init { } {
+ set logfile [standard_output_file_with_gdb_instance gdb.in]
+ set in_file [open $logfile w]
+
++ if {[tcl_version_at_least 9 0 0]} {
++ # Tcl 9 strict profile: gdb.in must accept UTF-8 command strings.
++ fconfigure $in_file -encoding utf-8 -profile replace
++ }
++
+ verbose -log ""
+ verbose -log "Starting logfile: $logfile"
+ verbose -log ""
diff --git a/gdb-6.3-rh-testversion-20041202.patch b/gdb-test-show-version.patch
similarity index 96%
rename from gdb-6.3-rh-testversion-20041202.patch
rename to gdb-test-show-version.patch
index 59132bf..feee38e 100644
--- a/gdb-6.3-rh-testversion-20041202.patch
+++ b/gdb-test-show-version.patch
@@ -1,7 +1,7 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Andrew Burgess
Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.3-rh-testversion-20041202.patch
+Subject: gdb-test-show-version.patch
;; Check distro name is included in the version output.
diff --git a/gdb.spec b/gdb.spec
index 64c477d..80770cb 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -41,11 +41,11 @@ Name: %{?scl_prefix}gdb
# See timestamp of source gnulib installed into gnulib/ .
%global snapgnulib 20220501
%global tarname gdb-%{version}
-Version: 16.3
+Version: 17.2
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 3%{?dist}
+Release: 1%{?dist}
License: GPL-3.0-or-later AND BSD-3-Clause AND FSFAP AND LGPL-2.1-or-later AND GPL-2.0-or-later AND LGPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND GFDL-1.3-or-later AND LGPL-2.0-or-later WITH GCC-exception-2.0 AND GPL-3.0-or-later WITH GCC-exception-3.1 AND GPL-2.0-or-later WITH GNU-compiler-exception AND MIT
# Do not provide URL for snapshots as the file lasts there only for 2 days.
@@ -135,10 +135,6 @@ BuildRequires: gcc-c++
#=push+jan
Source2: gdb-orphanripper.c
-# Man page for gstack(1).
-#=push+jan
-Source3: gdb-gstack.man
-
# /etc/gdbinit (from Debian but with Fedora compliant location).
#=fedora
Source4: gdbinit
@@ -146,7 +142,6 @@ Source4: gdbinit
# Include the auto-generated file containing the "Patch:" directives.
# See README.local-patches for more details.
Source9998: _gdb.spec.Patch.include
-Source9999: _gdb.spec.patch.include
%include %{SOURCE9998}
BuildRequires: readline-devel%{buildisa} >= 7.0
@@ -224,11 +219,6 @@ BuildRequires: %{?scl_testing_prefix}gcc %{?scl_testing_prefix}gcc-c++ %{?scl_te
BuildRequires: gcc-objc
%endif
-# We don't support gcc-gdb-plugin on RHEL anymore.
-%if 0%{!?rhel:1}
-BuildRequires: gcc-gdb-plugin%{?_isa}
-%endif
-
BuildRequires: systemtap-sdt-devel
BuildRequires: opencl-headers ocl-icd-devel%{bits_local} ocl-icd-devel%{bits_other}
@@ -313,7 +303,7 @@ machine than the one which is running the program being debugged.
%package doc
Summary: Documentation for GDB (the GNU source-level debugger)
-License: GFDL
+License: GFDL-1.3-or-later
BuildArch: noarch
%if 0%{?scl:1}
# As of F-28, packages won't need to call /sbin/install-info by hand
@@ -331,7 +321,7 @@ and printing their data.
This package provides INFO, HTML and PDF user manual for GDB.
%prep
-%setup -q -n %{gdb_src}
+%autosetup -p1 -n %{gdb_src}
# Files have `# ' statements breaking VPATH / find-debuginfo.sh .
(cd gdb;rm -fv $(perl -pe 's/\\\n/ /' - 16.3-3.el10
-- Include gdb-index-generation-fixes.patch (renamed).
- (Tom Tromey and Andrew Burgess, RHEL-150992)
+* Mon Jul 13 2026 Guinevere Larsen 17.2-1
+- Rebased to Fedora's GDB 17.2.
+ Resolves: RHEL-126216
-* Mon Jun 02 2025 Guinevere Larsen - 16.3-2.el10
-- Backport fixes to decoding AMD64 instructions
- Resolves: RHEL-93581
+* Wed Jul 8 2026 Andrew Burgess
+- Backport upstream commit 93f536d813c41527 to fix RHBZ 2498034. This
+ commit will drop out when we rebase to GDB 18.
-* Fri May 30 2025 Guinevere Larsen - 16.3-1.el10
-- Rebase RHEL10 GDB to 16.3
- Resolves: RHEL-56897
- Resolves: RHEL-91382
+* Wed Jul 8 2026 Andrew Burgess
+- Backport upstream commit be3a9405ceb4d6d6 to fix and issue with the
+ D demangler (RHBZ 2368350). This commit will drop out when we
+ rebase to GDB 18.
+
+* Wed Jul 8 2026 Andrew Burgess
+- Adjust commit message in gdb-backport-dap-core-file-support.patch to
+ remove '---' string which confuses git.
+
+* Wed Jun 24 2026 Michal Kolar
+- Rebase to FSF GDB 17.2.
+ Deleted: gdb-rhbz2435950-skip-revert.patch
+ Backport e492fb22b70, gdb: backport DAP core file support
+ Replace manual, multi-file patch inclusion with modern autosetup
+ Add rpminspect.yaml to define package-specific testing policy
+
+* Wed May 27 2026 Kevin Buettner
+- Applied proposed patch "[gdb/testsuite, Tcl 9] Fix EILSEQ problems for
+ UTF8 related tests". This is required in order to complete a build
+ with testing.
+
+* Sat May 16 2026 Andrew Burgess
+- Backport the following upstream commits in order to address RHBZ
+ 2467251: d980317c7f1, 958d06262a7, 7d1d7386561, 8915de0883c,
+ 8f65ab7b71f. These commits will all drop out when we rebase to GDB
+ 18.
+
+* Tue May 5 2026 Keith Seitz
+- Backport upstream commit ef7727ae from Tom de Vries to
+ fix the test suite for newer Tcl releases.
+
+* Tue Apr 21 2026 Andrew Burgess
+- Backport upstream commits 8bd08ee92c4 and cd289df068e to address
+ rhbz2366461. These backports will not be needed once we rebase to
+ GDB 18.
+
+* Wed Feb 25 2026 Kevin Buettner
+- Backport upstream commit c1da013915e from Kevin Buettner to fix
+ gcore failures caused by glibc 2.42 guard page changes (RHBZ 2413405).
+- Backport upstream commit d2cc16cd7fc from Jan Vrany to fix
+ FAILs in gdb.base/fileio.exp caused by macro expansion of
+ path components in OUTDIR.
+
+* Mon Feb 16 2026 Guinevere Larsen
+- Backport upstream commit f08ffbbf269 to fix RHBZ 2435950
+ This reverts a new feature that was never properly approved
+ for merging in upstream GDB.
+
+* Wed Feb 4 2026 Andrew Burgess
+- Backport upstream commit 70b66cf338b14336 to fix RH BZ 2402580.
+ This backport will not be needed once we rebase to GDB 18.
+
+* Tue Feb 3 2026 Kevin Buettner
+- Remove gcc-gdb-plugin BuildRequires and build with --disable-gdb-compile
+ due to this feature's brokenness. Tests using this feature skip cleanly
+ without timeouts. Reduces binary size and attack surface.
+
+* Fri Jan 16 2026 Fedora Release Engineering
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
+
+* Thu Jan 8 2026 Kevin Buettner - 17.1-1
+- Rebase to FSF GDB 17.1.
+ Deleted: gdb-fix-bg-execution-repeat.patch
+ Backport 919ba8ce158e, "bfd: fix build with C23", from Guinevere Larsen,
+ fixing RH BZ 2424325.
+ Backport "Fix some more C23 const-correctness issues", from Keith Seitz,
+ fixing same class of problem described by RH BZ 2424325.
+ Backport 777079c67c81, "[gdb/build, c++20] Fix deprecated implicit
+ capture in cooked_index::set_contents", from Tom de Vries, fixing more
+ FTBS problems.
+
+* Fri Sep 19 2025 Python Maint
+- Rebuilt for Python 3.14.0rc3 bytecode
+
+* Fri Aug 15 2025 Python Maint
+- Rebuilt for Python 3.14.0rc2 bytecode
+
+* Wed Jul 23 2025 Fedora Release Engineering
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
+
+* Tue Jun 03 2025 Andrew Burgess
+- Rename 'gdb-add-rpm-suggestion-script.patch' to
+ 'gdb-rpm-suggestion-script.patch' and
+ 'gdb-6.3-rh-testversion-20041202.patch' to
+ 'gdb-test-show-version.patch'. The new names better reflect the
+ patch contents.
+
+* Tue Jun 03 2025 Andrew Burgess
+- Remove gdb-archer-next-over-throw-cxx-exec.patch, we now have
+ upstream commit d462550c91c.
+
+* Tue Jun 03 2025 Andrew Burgess
+- Remove gdb-6.3-mapping-zero-inode-test.patch, we now have upstream
+ commit fcfd8a4f239.
+
+* Tue Jun 03 2025 Python Maint
+- Rebuilt for Python 3.14
+
+* Mon Jun 02 2025 Python Maint - 16.3-2
+- Bootstrap for Python 3.14
* Wed May 28 2025 Andrew Burgess
- Remove 32-bit ARM support for RHEL 10+. This is not a RHEL
supported target, so lets drop this target. Retain for older RHEL
versions, as well as Fedora.
-* Tue May 13 2025 Alexandra Hájková - 16.3-1
+* Mon May 12 2025 Keith Seitz
+- Remove gdb-rhbz1149205-catch-syscall-after-fork-test.patch
+ in favor of upstream commit.
+
+* Wed May 07 2025 Andrew Burgess
+- Remove gdb-6.8-bz466901-backtrace-full-prelinked.patch. Prelinking
+ is no longer supported, there seems little point keeping this test.
+
+* Fri Apr 25 2025 Alexandra Hájková
+- Backport "Fix another timeout in gdb.base/bg-execution-repeat.exp"
+ (Tom de Vries)
+
+* Wed Apr 23 2025 Alexandra Hájková - 16.3-1
- Rebase to FSF GDB 16.3.
- Deleted: gdb-rhbz2354997-gstack-drop-readnever.patch
+ Deleted: core-target-open-segfault.patch
+ gdb-rhbz2354997-gstack-drop-readnever.patch
+ tui-wrefresh-issue.patch
+
+* Wed Apr 02 2025 Alexandra Hájková
+- Remove upstreamed gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch.
* Fri Mar 28 2025 Keith Seitz - 16.2-3
- Backport "Fix gstack issues" from upstream.
(Keith Seitz, RH BZ 2354997)
-* Thu Feb 13 2025 Alexandra Hájková - 16.2-2
-- Bump the release number.
+* Thu Mar 06 2025 Kevin Buettner
+- Remove gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch.
+ The upstream test 'gdb.arch/amd64-prologue-skip.exp' should be
+ sufficient for testing an upstream fix which was pushed in 2015.
-* Tue Feb 11 2025 Alexandra Hájková - 16.2-1
+* Wed Mar 05 2025 Guinevere Larsen
+- Remove gdb-6.5-gcore-buffer-limit-test.patch. A similar test has been
+ added upstream, which will trickle down soon.
+
+* Thu Feb 27 2025 Keith Seitz
+- Remove gdb-6.6-bz237572-ppc-atomic-sequence-test.patch. This is covered
+ by gdb.arch/ppc64-isa207-atomic-inst.exp.
+
+* Mon Feb 10 2025 Andrew Burgess
+- Add core-target-open-segfault.patch and tui-wrefresh-issue.patch,
+ these backport upstream commits 2fc56106422 and 2b646bb8767
+ respectively, both fix regressiosn in GDB 16 vs GDB 15.
+
+* Fri Feb 07 2025 Andrew Burgess
+- Remove gdb-6.5-bz218379-ppc-solib-trampoline-test.patch. There must
+ be upstream tests that 'next' over a libc call. Additionally, it is
+ not clear to me exactly what bug is being tested for here.
+
+* Fri Feb 07 2025 Andrew Burgess
+- Remove gdb-gstack.man file. This is no longer used. There is an
+ upstream version of gstack which provides its own man page.
+
+* Tue Feb 04 2025 Alexandra Hájková - 16.2-1
- Rebase to FSF GDB 16.2.
- Dropped: gdb-backport-buildid-related-changes.patch
- gdb-catchpoint-re-set.patch
- gdb-remove-qnx-neutrino-support.patch
Modified: gdb-add-rpm-suggestion-script.patch
+* Thu Jan 23 2025 Alexandra Hájková - 16.1-1
+- Rebase to FSF GDB 16.1.
+ Dropped:
+ gdb-backport-buildid-related-changes.patch
+ gdb-catchpoint-re-set.patch
+ gdb-remove-qnx-neutrino-support.patch
+
* Thu Jan 23 2025 Alexandra Hájková
- Remove upstreamed gdb-6.3-gstack-20050411.patch.
diff --git a/gdbtui b/gdbtui
deleted file mode 100755
index 88f9d55..0000000
--- a/gdbtui
+++ /dev/null
@@ -1,2 +0,0 @@
-#! /bin/sh
-exec gdb -tui "$@"
diff --git a/generate-patches-from-git-repo.sh b/generate-patches-from-git-repo.sh
index 1937a3c..6003008 100755
--- a/generate-patches-from-git-repo.sh
+++ b/generate-patches-from-git-repo.sh
@@ -69,10 +69,9 @@ common_ancestor=`git merge-base HEAD $commit_or_tag`
test -z "$common_ancestor" && die "Could not find common ancestor between HEAD and $commit_or_tag."
temp_PATCH_file=/tmp/_gdb.spec.Patch.include
-temp_patch_file=/tmp/_gdb.spec.patch.include
temp_patch_order_file=/tmp/_patch_order
-rm -f $temp_PATCH_file $temp_patch_file $temp_patch_order_file
+rm -f $temp_PATCH_file $temp_patch_order_file
for c in `git rev-list --reverse ${common_ancestor}..HEAD` ; do
fname=`git log -1 --pretty='format:%s' $c`
@@ -100,13 +99,11 @@ for c in `git rev-list --reverse ${common_ancestor}..HEAD` ; do
`git log -1 --pretty='format:%b' $c | sed -n 's/^;;/#/p'`
EOF
printf "Patch%03d: %s\n\n" $idx $fname >> $temp_PATCH_file
- printf "%%patch -p1 -P%03d\n" $idx >> $temp_patch_file
echo $fname >> $temp_patch_order_file
idx=`expr $idx + 1`
done
cd $orig_dir
mv $temp_PATCH_file _gdb.spec.Patch.include
-mv $temp_patch_file _gdb.spec.patch.include
mv $temp_patch_order_file _patch_order
echo "$common_ancestor" > _git_upstream_commit
diff --git a/gnu-keyring.gpg b/gnu-keyring.gpg
new file mode 100644
index 0000000..8997652
Binary files /dev/null and b/gnu-keyring.gpg differ
diff --git a/rpminspect.yaml b/rpminspect.yaml
new file mode 100644
index 0000000..84451eb
--- /dev/null
+++ b/rpminspect.yaml
@@ -0,0 +1,7 @@
+---
+
+# Disable Link-Time Optimization checks
+# Upstream GDB is not fully compatible with LTO
+annocheck:
+ jobs:
+ - hardened: --skip-lto
diff --git a/sources b/sources
index a86cf9b..f76e77c 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (gdb-16.3.tar.xz) = fffd6689c3405466a179670b04720dc825e4f210a761f63dd2b33027432f8cd5d1c059c431a5ec9e165eedd1901220b5329d73c522f9a444788888c731b29e9c
+SHA512 (gdb-17.2.tar.xz) = 7794c5a185be7ed5e7ad1000c4ff7d8497c80425a1bc108aab8fd3dd8ecdde034e294dfd65b25c6b0dcd8ed2a240caf07293f3e73791b6cfc890d580d0af4581
diff --git a/tests/debug-toolset-binary/Makefile b/tests/debug-toolset-binary/Makefile
index 1453d76..9a7ecfd 100644
--- a/tests/debug-toolset-binary/Makefile
+++ b/tests/debug-toolset-binary/Makefile
@@ -54,7 +54,7 @@ $(METADATA): Makefile
@echo "Type: Sanity" >> $(METADATA)
@echo "TestTime: 5m" >> $(METADATA)
@echo "RunFor: gdb" >> $(METADATA)
- @echo "Requires: gdb coreutils binutils binutils-debuginfo glibc glibc-debuginfo gcc gcc-debuginfo zlib zlib-debuginfo" >> $(METADATA)
+ @echo "Requires: gdb coreutils binutils binutils-debuginfo glibc glibc-debuginfo gcc gcc-debuginfo zlib-ng zlib-ng-debuginfo" >> $(METADATA)
@echo "Priority: Normal" >> $(METADATA)
@echo "License: GPLv2" >> $(METADATA)
@echo "Confidential: no" >> $(METADATA)
diff --git a/tests/debug-toolset-binary/main.fmf b/tests/debug-toolset-binary/main.fmf
index 04b7702..eb6d8e7 100644
--- a/tests/debug-toolset-binary/main.fmf
+++ b/tests/debug-toolset-binary/main.fmf
@@ -15,8 +15,8 @@ recommend:
- glibc-debuginfo
- gcc
- gcc-debuginfo
-- zlib
-- zlib-debuginfo
+- zlib-ng
+- zlib-ng-debuginfo
duration: 5m
extra-summary: /tools/gdb/Sanity/debug-toolset-binary
extra-task: /tools/gdb/Sanity/debug-toolset-binary
diff --git a/tests/debug-toolset-binary/runtest.sh b/tests/debug-toolset-binary/runtest.sh
index 65cc2c7..f2a339f 100755
--- a/tests/debug-toolset-binary/runtest.sh
+++ b/tests/debug-toolset-binary/runtest.sh
@@ -38,7 +38,7 @@ CMD="gdb"
BIN="$(which $CMD)"
export PACKAGE="${PACKAGE:-$(rpm -qf --qf='%{name}\n' $BIN)}"
-PACKAGES="coreutils binutils binutils-debuginfo glibc glibc-debuginfo gcc gcc-debuginfo zlib zlib-debuginfo"
+PACKAGES="coreutils binutils binutils-debuginfo glibc glibc-debuginfo gcc gcc-debuginfo zlib-ng zlib-ng-debuginfo"
rlJournalStart
rlPhaseStartSetup