From e836eae49c827d0f8e990c1683c8f292ae2b68b5 Mon Sep 17 00:00:00 2001 From: Keith Seitz Date: Thu, 30 Jul 2026 11:55:52 -0700 Subject: [PATCH] Rebase to 17.2. Resolves: RHEL-221050 --- .gitignore | 1 + README.local-patches.md | 2 - _gdb.spec.Patch.include | 68 +- _gdb.spec.patch.include | 15 - _git_upstream_commit | 2 +- _patch_order | 11 +- gating.yaml | 11 +- ...backport-corefile-use-after-free-fix.patch | 77 + gdb-backport-dap-core-file-support.patch | 2956 +++++++++++++++++ gdb-backport-libiberty-sync.patch | 616 ++++ gdb-backport-s390x-return-crash.patch | 435 +++ ...ort-tom-32688-thread-specific-bp-fix.patch | 80 + ...uild-warnings.patch => gdb-c23-fixes.patch | 135 +- gdb-fileio-test-fixes.patch | 6 +- gdb-fix-odr-violations.patch | 66 + gdb-fix-testsuite-newer-tcl.patch | 46 - gdb-rhbz2403580-misplaced-symtabs.patch | 12 +- gdb-rhbz2413405-gcore-unreadable-pages.patch | 2 +- ...424325-c++20-implicit-lambda-capture.patch | 27 - gdb-rhbz2424325-c23-more-const-fixes.patch | 175 - gdb-rhbz2435950-skip-revert.patch | 138 - gdb-rpm-suggestion-script.patch | 2 +- gdb-tcl9-utf8-encoding-fix.patch | 157 - gdb.spec | 49 +- generate-patches-from-git-repo.sh | 5 +- rpminspect.yaml | 14 + sources | 2 +- 27 files changed, 4464 insertions(+), 646 deletions(-) delete mode 100644 _gdb.spec.patch.include create mode 100644 gdb-backport-corefile-use-after-free-fix.patch create mode 100644 gdb-backport-dap-core-file-support.patch create mode 100644 gdb-backport-libiberty-sync.patch create mode 100644 gdb-backport-s390x-return-crash.patch create mode 100644 gdb-backport-tom-32688-thread-specific-bp-fix.patch rename gdb-rhbz2424325-c23-const-build-warnings.patch => gdb-c23-fixes.patch (60%) create mode 100644 gdb-fix-odr-violations.patch delete mode 100644 gdb-fix-testsuite-newer-tcl.patch delete mode 100644 gdb-rhbz2424325-c++20-implicit-lambda-capture.patch delete mode 100644 gdb-rhbz2424325-c23-more-const-fixes.patch delete mode 100644 gdb-rhbz2435950-skip-revert.patch delete mode 100644 gdb-tcl9-utf8-encoding-fix.patch create mode 100644 rpminspect.yaml diff --git a/.gitignore b/.gitignore index aca6c18..980fa75 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /gdb-17.1.tar.xz +/gdb-17.2.tar.xz diff --git a/README.local-patches.md b/README.local-patches.md index fc2eb90..b9ef2c6 100644 --- a/README.local-patches.md +++ b/README.local-patches.md @@ -84,8 +84,6 @@ control files. These control files are: - `_gdb.spec.Patch.include`: This file contains the `Patch:` directives. - - `_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. diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include index 127de30..4f73fbb 100644 --- a/_gdb.spec.Patch.include +++ b/_gdb.spec.Patch.include @@ -19,63 +19,59 @@ Patch002: gdb-add-index.patch # RPMs to install when GDB finds an objfile with no debug info. Patch003: gdb-rpm-suggestion-script.patch -# Backport Guinevere Larsen's build warning fixes (RH BZ 2424325). -Patch004: gdb-rhbz2424325-c23-const-build-warnings.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 - -# Backport Tom de Vries fix regarding implicit lambda captures -# (RH BZ 2424325). -Patch006: gdb-rhbz2424325-c++20-implicit-lambda-capture.patch +# Backport test fix for flaky thread-specific-bp.exp (Tom de Vries). +Patch004: gdb-backport-tom-32688-thread-specific-bp-fix.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 - -# Backport of upstream commit f08ffbbf2691bad2d5df660ee644647687775f0c -# Can be dropped on a rebase to gdb 17.2 or 18.1 -Patch008: gdb-rhbz2435950-skip-revert.patch +Patch005: gdb-rhbz2403580-misplaced-symtabs.patch # Backport of upstream commit c1da013915e from Kevin Buettner # (RHBZ 2413405). -Patch009: gdb-rhbz2413405-gcore-unreadable-pages.patch +Patch006: gdb-rhbz2413405-gcore-unreadable-pages.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 -Patch010: gdb-fileio-test-fixes.patch +# path components in OUTDIR. +Patch007: gdb-fileio-test-fixes.patch # Backport upstream commit 8bd08ee92c4 to address rhbz2366461. This # commit will drop out with GDB 18. -Patch011: gdb-rhbz2366461-missing-thread.patch +Patch008: gdb-rhbz2366461-missing-thread.patch # Backport upstream commit cd289df068e to address rhbz2366461. This # commit will drop out with GDB 18. -Patch012: gdb-rhbz2366461-bad-solib-entry-addr.patch - -# Fix use of deprecated trace variable subcommand -# (Tom de Vries) -Patch013: gdb-fix-testsuite-newer-tcl.patch +Patch009: gdb-rhbz2366461-bad-solib-entry-addr.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. -Patch014: gdb-rhbz2467251-computed-location-synthetic-pointers.patch +Patch010: gdb-rhbz2467251-computed-location-synthetic-pointers.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 -Patch015: gdb-tcl9-utf8-encoding-fix.patch +# Backport of upstream commit e492fb22b70 +# gdb: backport DAP core file support +Patch011: 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. +Patch012: gdb-backport-libiberty-sync.patch + +# Backport of upstream commit 93f536d813c41527e8c939a5f8a90a4 to fix +# RHBZ2498034. +Patch013: gdb-backport-corefile-use-after-free-fix.patch + +# Backporting upstream commit f3ce0ce31fb3f0563510b9af0ae49aff96a72057 +# to fix a rebase regression. +Patch018: gdb-backport-s390x-return-crash.patch diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include deleted file mode 100644 index f630fc2..0000000 --- a/_gdb.spec.patch.include +++ /dev/null @@ -1,15 +0,0 @@ -%patch -p1 -P001 -%patch -p1 -P002 -%patch -p1 -P003 -%patch -p1 -P004 -%patch -p1 -P005 -%patch -p1 -P006 -%patch -p1 -P007 -%patch -p1 -P008 -%patch -p1 -P009 -%patch -p1 -P010 -%patch -p1 -P011 -%patch -p1 -P012 -%patch -p1 -P013 -%patch -p1 -P014 -%patch -p1 -P015 diff --git a/_git_upstream_commit b/_git_upstream_commit index 452ca53..da4c92e 100644 --- a/_git_upstream_commit +++ b/_git_upstream_commit @@ -1 +1 @@ -631a49c452a4a456dd9889d172541ea789f8bcae +7adf9fa6b1ccb3c70f86cb630368b9d3dffcf3aa diff --git a/_patch_order b/_patch_order index 04f732f..9956ca5 100644 --- a/_patch_order +++ b/_patch_order @@ -1,15 +1,14 @@ gdb-test-show-version.patch gdb-add-index.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-backport-tom-32688-thread-specific-bp-fix.patch gdb-rhbz2403580-misplaced-symtabs.patch -gdb-rhbz2435950-skip-revert.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 +gdb-backport-s390x-return-crash.patch diff --git a/gating.yaml b/gating.yaml index a1a0c2c..8daf6e5 100644 --- a/gating.yaml +++ b/gating.yaml @@ -7,8 +7,13 @@ rules: - !PassingTestCaseRule {test_case_name: fedora-ci.koji-build.tier0.functional} --- !Policy product_versions: - - rhel-* + - rhel-8 decision_context: osci_compose_gate rules: - - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.gate-build-fast-lane.functional} - - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.gate-build-slow-lane.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} 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..e487b32 --- /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: Fri, 3 Jul 2026 22:18:32 +0200 +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-backport-s390x-return-crash.patch b/gdb-backport-s390x-return-crash.patch new file mode 100644 index 0000000..1899677 --- /dev/null +++ b/gdb-backport-s390x-return-crash.patch @@ -0,0 +1,435 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Kevin Buettner +Date: Fri, 11 Jul 2025 16:18:13 -0700 +Subject: gdb-backport-s390x-return-crash.patch + +;; Backporting upstream commit f3ce0ce31fb3f0563510b9af0ae49aff96a72057 +;; to fix a rebase regression. + +Fix unwinding when restoring a register from one of a greater size + +When debugging functions where a callee-saved register is moved to a +register of a larger size (e.g., a 64-bit general-purpose register to +a 128-bit vector register), GDB would crash when the user issued the +"return" command. For example: + + ldgr %f0, %r11 ; Move 64-bit general-purpose register (r11) + ; to 128-bit vector register (f0) + .cfi_register r11, f0 ; DW_CFA_register: r11 is stored in f0 + ... + lgdr %r11, %f0 ; Restore r11 from f0 + .cfi_restore r11 ; DW_CFA_restore: r11 is restored to its original + ; register + +(This example uses instructions and registers for the S390x architecture, +where this bug was originally found.) + +If GDB is stopped in the "..." section and the user issues the +"return" command, GDB crashes due to a buffer size mismatch during +unwinding. Specifically, in frame_register_unwind in frame.c, a +buffer the size of the original register (the 64-bit r11 in this +example) has been allocated and GDB would like to use memcpy to copy +the contents of the register where the original register was saved +(the 128-bit f0) to the buffer for the original register. But, +fortunately, GDB has an assertion which prevents this from happening: + + gdb_assert (buffer.size () >= value->type ()->length ()); + +This patch ensures that GDB uses the original register's type (e.g., +r11's type) when unwinding, even if it was marked as saved to a differently +typed/sized register (e.g., f0) via .cfi_register (DW_CFA_register). + +The fix adds a 'struct type *' parameter to value_of_register_lazy() to +explicitly track the original register's type. The function +frame_unwind_got_register is updated to pass the correct type for the +original register. + +The call chain from frame_register_unwind to frame_unwind_got_register +is shown by this backtrace: + + #0 frame_unwind_got_register (frame=..., regnum=13, new_regnum=128) + at gdb/frame-unwind.c:300 + #1 0x000000000135d894 in dwarf2_frame_prev_register (this_frame=..., + this_cache=0x2204528, regnum=13) + at gdb/dwarf2/frame.c:1187 + #2 0x00000000014d9186 in frame_unwind_legacy::prev_register ( + this=0x211f428 , this_frame=..., + this_prologue_cache=0x2204528, regnum=13) at gdb/frame-unwind.c:401 + #3 0x00000000014e1d12 in frame_unwind_register_value (next_frame=..., + regnum=13) at gdb/frame.c:1263 + #4 0x00000000014e16b8 in frame_register_unwind (next_frame=..., regnum=13, + optimizedp=0x3ffffff813c, unavailablep=0x3ffffff8138, + lvalp=0x3ffffff8134, addrp=0x3ffffff8128, realnump=0x3ffffff8124, + buffer=...) at gdb/frame.c:1189 + +The register numbers shown above are for s390x. On s390x, +S390_R11_REGNUM has value 13. Vector registers (like f0) are numbered +differently from floating-point registers of the same name, leading to +regnum 128 for f0 despite S390_F0_REGNUM being assigned a different +value in s390-tdep.h. + +New test cases for aarch64 and x86_64 check for this on more popular +architectures and also without dependency on a particular compiler to +generate an unusual prologue in which a general purpose register is +being moved to a vector register. In both cases, the test simulates +the bug found on s390x where a 64-bit frame pointer was being moved to +a much wider vector register. These test cases will cause an internal +error on their respective architecture, but will pass with this fix in +place. + +When tested on s390x linux (native), this change fixes 59 GDB internal +errors and around 200 failures overall. This is the list of internal +errors that no longer occur on s390x: + +FAIL: gdb.base/call-sc.exp: tc: return foo; return call-sc-tc (GDB internal error) +FAIL: gdb.base/call-sc.exp: td: return foo; return call-sc-td (GDB internal error) +FAIL: gdb.base/call-sc.exp: te: return foo; return call-sc-te (GDB internal error) +FAIL: gdb.base/call-sc.exp: tf: return foo; return call-sc-tf (GDB internal error) +FAIL: gdb.base/call-sc.exp: ti: return foo; return call-sc-ti (GDB internal error) +FAIL: gdb.base/call-sc.exp: tl: return foo; return call-sc-tl (GDB internal error) +FAIL: gdb.base/call-sc.exp: tld: return foo; return call-sc-tld (GDB internal error) +FAIL: gdb.base/call-sc.exp: tll: return foo; return call-sc-tll (GDB internal error) +FAIL: gdb.base/call-sc.exp: ts: return foo; return call-sc-ts (GDB internal error) +FAIL: gdb.base/gnu_vector.exp: return from vector-valued function (GDB internal error) +FAIL: gdb.base/return-3.exp: in foo: return (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: double: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: float: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: int: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: long-long: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: long: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: short: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return-nodebug.exp: signed-char: return from function with no debug info with a cast (GDB internal error) +FAIL: gdb.base/return.exp: return value 5 (GDB internal error) +FAIL: gdb.base/return.exp: return value 5.0 (GDB internal error) +FAIL: gdb.base/return2.exp: return from char_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from double_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from float_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from int_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from long_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from long_long_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from short_func (GDB internal error) +FAIL: gdb.base/return2.exp: return from void_func (GDB internal error) +FAIL: gdb.base/sigstep.exp: return from handleri: leave handler (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc-ti: return foo; return 2 structs-tc-ti (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc-tl: return foo; return 2 structs-tc-tl (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc-ts: return foo; return 2 structs-tc-ts (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 1 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 2 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 3 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 4 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 5 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 6 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 7 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tc: return foo; return 8 structs-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=td-tf: return foo; return 2 structs-td-tf (GDB internal error) +FAIL: gdb.base/structs.exp: types=td: return foo; return 1 structs-td (GDB internal error) +FAIL: gdb.base/structs.exp: types=tf-tc: return foo; return 2 structs-tf-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tf-td: return foo; return 2 structs-tf-td (GDB internal error) +FAIL: gdb.base/structs.exp: types=tf: return foo; return 1 structs-tf (GDB internal error) +FAIL: gdb.base/structs.exp: types=tf: return foo; return 2 structs-tf (GDB internal error) +FAIL: gdb.base/structs.exp: types=ti-tc: return foo; return 2 structs-ti-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=ti: return foo; return 1 structs-ti (GDB internal error) +FAIL: gdb.base/structs.exp: types=ti: return foo; return 2 structs-ti (GDB internal error) +FAIL: gdb.base/structs.exp: types=tl-tc: return foo; return 2 structs-tl-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=tl: return foo; return 1 structs-tl (GDB internal error) +FAIL: gdb.base/structs.exp: types=tl: return foo; return 2 structs-tl (GDB internal error) +FAIL: gdb.base/structs.exp: types=tld: return foo; return 1 structs-tld (GDB internal error) +FAIL: gdb.base/structs.exp: types=tll: return foo; return 1 structs-tll (GDB internal error) +FAIL: gdb.base/structs.exp: types=ts-tc: return foo; return 2 structs-ts-tc (GDB internal error) +FAIL: gdb.base/structs.exp: types=ts: return foo; return 1 structs-ts (GDB internal error) +FAIL: gdb.base/structs.exp: types=ts: return foo; return 2 structs-ts (GDB internal error) +FAIL: gdb.base/structs.exp: types=ts: return foo; return 3 structs-ts (GDB internal error) +FAIL: gdb.base/structs.exp: types=ts: return foo; return 4 structs-ts (GDB internal error) + +I have tested this commit on Fedora Linux, with architectures s390x, +x86_64, x86_64/-m32, aarch64, ppc64le, and riscv64, with no +regressions found. + +This v2 version makes some changes suggested by Andrew Burgess: It +adds an assert to frame_unwind_got_register() and always passes the +type of REGNUM to value_of_register_lazy(). It also updates value.h's +comment describing value_of_register_lazy(). + +In his approval message, Andrew requested some changes to the tests. +Those have been made exactly as requested. + +Approved-By: Andrew Burgess + +diff --git a/gdb/findvar.c b/gdb/findvar.c +--- a/gdb/findvar.c ++++ b/gdb/findvar.c +@@ -65,14 +65,15 @@ value_of_register (int regnum, const frame_info_ptr &next_frame) + /* See value.h. */ + + value * +-value_of_register_lazy (const frame_info_ptr &next_frame, int regnum) ++value_of_register_lazy (const frame_info_ptr &next_frame, int regnum, ++ struct type *type) + { + gdbarch *gdbarch = frame_unwind_arch (next_frame); + + gdb_assert (regnum < gdbarch_num_cooked_regs (gdbarch)); + gdb_assert (next_frame != nullptr); + +- return value::allocate_register_lazy (next_frame, regnum); ++ return value::allocate_register_lazy (next_frame, regnum, type); + } + + /* Given a pointer of type TYPE in target form in BUF, return the +diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c +--- a/gdb/frame-unwind.c ++++ b/gdb/frame-unwind.c +@@ -297,8 +297,16 @@ struct value * + frame_unwind_got_register (const frame_info_ptr &frame, + int regnum, int new_regnum) + { ++ struct gdbarch *gdbarch = frame_unwind_arch (frame); ++ struct type *regnum_type = register_type (gdbarch, regnum); ++ struct type *new_regnum_type = register_type (gdbarch, new_regnum); ++ ++ /* REGNUM has been copied into NEW_REGNUM, therefore, the former ++ must be smaller or equal in size to the latter. */ ++ gdb_assert (regnum_type->length () <= new_regnum_type->length ()); ++ + return value_of_register_lazy (get_next_frame_sentinel_okay (frame), +- new_regnum); ++ new_regnum, regnum_type); + } + + /* Return a value which indicates that FRAME saved REGNUM in memory at +diff --git a/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.c b/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.c +new file mode 100644 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.c +@@ -0,0 +1,62 @@ ++/* 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 . */ ++ ++volatile void dummy () {} ++ ++long test_function(void) ++{ ++ __asm__ volatile ( ++ /* Zero d0 (64-bit vector register part of v0). */ ++ "movi d0, #0\n\t" ++ ++ /* Move the frame pointer (x29) to d0 using fmov. */ ++ "fmov d0, x29\n\t" ++ ++ /* Describe CFI: Frame pointer is now in d0. */ ++ ".cfi_register x29, d0\n\t" ++ ++ /* Clobber list: Specify all modified registers. */ ++ : /* No output operands. */ ++ : /* No input operands. */ ++ : "d0" ++ ); ++ ++ dummy (); /* break-here */ ++ ++ __asm__ volatile ( ++ /* Restore the frame pointer (x29) from d0 using fmov. */ ++ "fmov x29, d0\n\t" ++ ++ /* Describe CFI: Frame pointer is restored. */ ++ ".cfi_restore x29\n\t" ++ ++ /* Clobber list: Specify all modified registers. */ ++ : /* No output operands. */ ++ : /* No input operands. */ ++ : "x29", "d0" ++ ); ++ ++ return 0; ++} ++ ++int ++main () ++{ ++ long result = test_function (); ++ dummy (); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.exp b/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.exp +new file mode 100644 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-frameptr-vecreg-unwind.exp +@@ -0,0 +1,33 @@ ++# 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 . ++ ++require is_aarch64_target ++ ++standard_testfile ++ ++if { [prepare_for_testing "failed to prepare" ${testfile} \ ++ "${srcfile}" {debug}] } { ++ return -1 ++} ++ ++if {![runto_main]} { ++ return ++} ++ ++gdb_breakpoint [gdb_get_line_number "break-here"] ++gdb_continue_to_breakpoint "break-here" ++gdb_test "with confirm off --return -1" "result = test_function \\(\\);" ++gdb_test "step" "dummy \\(\\);" ++gdb_test "print result" "= -1" +diff --git a/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.c b/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.c +new file mode 100644 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.c +@@ -0,0 +1,63 @@ ++/* 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 . */ ++ ++volatile void dummy () {} ++ ++long test_function(void) ++{ ++ __asm__ volatile ( ++ /* Clear xmm0. */ ++ "vxorps %%xmm0, %%xmm0, %%xmm0\n\t" ++ ++ /* Move the frame pointer (rbp) to xmm0. */ ++ "movq %%rbp, %%xmm0\n\t" ++ ++ /* CFI: Frame pointer is in xmm0. */ ++ ".cfi_register %%rbp, %%xmm0\n\t" ++ ++ /* Clobber list: Specify all modified registers */ ++ : // No output operands ++ : // No input operands ++ : "xmm0" ++ ); ++ ++ dummy (); /* break-here */ ++ ++ /* Pseudo-epilogue: Restore rbp from xmm0. */ ++ __asm__ volatile ( ++ /* Restore rbp. */ ++ "movq %%xmm0, %%rbp\n\t" ++ ++ /* Describe CFI: Frame pointer is restored. */ ++ ".cfi_restore %%rbp\n\t" ++ ++ /* Clobber list: Specify all modified registers */ ++ : /* No output operands. */ ++ : /* No input operands. */ ++ : /* Despite clobbering rbp, gcc doesn't let us list it here. */ ++ ); ++ ++ return 0; ++} ++ ++int ++main () ++{ ++ long result = test_function (); ++ dummy (); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.exp b/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.exp +new file mode 100644 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/amd64-frameptr-vecreg-unwind.exp +@@ -0,0 +1,40 @@ ++# 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 verifies that we can read and write the value of a pseudo register ++# in unwound frames. For the test, we choose one raw register, rbx, and one ++# pseudo register that is backed by rbx, ebx. We have two frames (the inner one, ++# #0 and the outer one, #1) that each set a value for rbx. We verify that we ++# can read both rbx and ebx correctly for each frame, and that when we write to ++# ebx, rbx for that frame is correctly updated. ++ ++require is_x86_64_m64_target ++ ++standard_testfile ++ ++if { [prepare_for_testing "failed to prepare" ${testfile} \ ++ "${srcfile}" {debug}] } { ++ return -1 ++} ++ ++if {![runto_main]} { ++ return ++} ++ ++gdb_breakpoint [gdb_get_line_number "break-here"] ++gdb_continue_to_breakpoint "break-here" ++gdb_test "with confirm off --return -1" "result = test_function \\(\\);" ++gdb_test "step" "dummy \\(\\);" ++gdb_test "print result" "= -1" +diff --git a/gdb/value.h b/gdb/value.h +--- a/gdb/value.h ++++ b/gdb/value.h +@@ -1156,9 +1156,12 @@ extern struct value *address_of_variable (struct symbol *var, + + extern value *value_of_register (int regnum, const frame_info_ptr &next_frame); + +-/* Same as the above, but the value is not fetched. */ ++/* Same as the above, but the value is not fetched. If TYPE is ++ non-nullptr, use it as the value type. Otherwise, 'register_type' ++ will be used to obtain the type. */ + +-extern value *value_of_register_lazy (const frame_info_ptr &next_frame, int regnum); ++extern value *value_of_register_lazy (const frame_info_ptr &next_frame, ++ int regnum, struct type *type = nullptr); + + /* Return the symbol's reading requirement. */ + diff --git a/gdb-backport-tom-32688-thread-specific-bp-fix.patch b/gdb-backport-tom-32688-thread-specific-bp-fix.patch new file mode 100644 index 0000000..91bc30d --- /dev/null +++ b/gdb-backport-tom-32688-thread-specific-bp-fix.patch @@ -0,0 +1,80 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Kevin Buettner +Date: Wed, 21 Jan 2026 00:46:23 -0700 +Subject: gdb-backport-tom-32688-thread-specific-bp-fix.patch + +;; Backport test fix for flaky thread-specific-bp.exp (Tom de Vries). + +[gdb/testsuite] Yet another attempt to fix gdb.threads/thread-specific-bp.exp + +When running test-case gdb.threads/thread-specific-bp.exp using taskset to +select an Efficient-core in a loop, it fails 19 out of 100 runs. + +For example, like this: +... +(gdb) continue -a^M +Continuing.^M +^M +Thread 1 "thread-specific" hit Breakpoint 4, end () at thread-specific-bp.c:29^M +29 }^M +(gdb) FAIL: $exp: non_stop=on: continue to end +[Thread 0x7ffff7cbe6c0 (LWP 2348848) exited]^M +Thread-specific breakpoint 3 deleted - thread 2 no longer in the thread list.^M +... + +The way we're trying to match this gdb output is: +... + gdb_test_multiple "$cmd" "continue to end" { + -re "$\r\n${gdb_prompt} .*${msg_re}\r\n" { + pass $gdb_test_name + } + -re "\r\n${msg_re}\r\n.*$gdb_prompt " { + pass $gdb_test_name + } + } +... + +The problem is that the two -re clauses above do not match the output ending +in a prompt, so the default fail in gdb_test_multiple triggers. + +Fix this by splitting this up in two gdb_test_multiple calls: +- the first matches a prompt (with or without preceding $msg_re), making sure + that the default fail doesn't trigger, and +- the second matches $msg_re, if that was not already matched by the first call. + +Using this approach, the test-case passes 100 out of 100 runs. + +Tested on x86_64-linux, also with make-check-all.sh. + +PR testsuite/32688 +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32688 + +diff --git a/gdb/testsuite/gdb.threads/thread-specific-bp.exp b/gdb/testsuite/gdb.threads/thread-specific-bp.exp +--- a/gdb/testsuite/gdb.threads/thread-specific-bp.exp ++++ b/gdb/testsuite/gdb.threads/thread-specific-bp.exp +@@ -95,12 +95,21 @@ proc check_thread_specific_breakpoint {non_stop} { + "-" \ + "thread 2 no longer in the thread list\\."]] + +- gdb_test_multiple "$cmd" "continue to end" { +- -re "$\r\n${gdb_prompt} .*${msg_re}\r\n" { ++ set test "continue to end" ++ set try_again 0 ++ gdb_test_multiple $cmd $test -no-prompt-anchor { ++ -re -wrap "\r\n${msg_re}(?=\r\n).*" { + pass $gdb_test_name + } +- -re "\r\n${msg_re}\r\n.*$gdb_prompt " { +- pass $gdb_test_name ++ -re -wrap "" { ++ set try_again 1 ++ } ++ } ++ if { $try_again } { ++ gdb_test_multiple "" $test { ++ -re "\r\n${msg_re}(?=\r\n)" { ++ pass $gdb_test_name ++ } + } + } + diff --git a/gdb-rhbz2424325-c23-const-build-warnings.patch b/gdb-c23-fixes.patch similarity index 60% rename from gdb-rhbz2424325-c23-const-build-warnings.patch rename to gdb-c23-fixes.patch index 517ee6e..44328cd 100644 --- a/gdb-rhbz2424325-c23-const-build-warnings.patch +++ b/gdb-c23-fixes.patch @@ -1,23 +1,26 @@ 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 +From: Keith Seitz +Date: Thu, 14 May 2026 10:15:24 -0700 +Subject: gdb-c23-fixes.patch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -;; Backport Guinevere Larsen's build warning fixes (RH BZ 2424325). +Fix even more -Wdiscarded-qualifers issues -bfd: fix build with C23 +Fedora Rawhide is failing to build due to new glibc header changes +enforcing const-correctness in functions like strchr and memchr. +For example: -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 *. +../../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 -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. +This patch addresses all the discovered issues with --enable-targets=all +and regenerates a few cgen files along the way. diff --git a/bfd/bfd.c b/bfd/bfd.c --- a/bfd/bfd.c @@ -207,3 +210,105 @@ diff --git a/bfd/targets.c b/bfd/targets.c if (_bfd_find_arch_match (new_tname, arches, def_target_arch)) break; +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-fileio-test-fixes.patch b/gdb-fileio-test-fixes.patch index 045cb38..742ef44 100644 --- a/gdb-fileio-test-fixes.patch +++ b/gdb-fileio-test-fixes.patch @@ -1,11 +1,13 @@ From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 From: Kevin Buettner -Date: Wed, 25 Feb 2026 20:02:22 -0700 +Date: Wed, 25 Feb 2026 23:38:21 -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 +;; path components in OUTDIR. + +gdb/testsuite: fix FAILs in fileio.exp I'm experiencing intermittent FAILs in fileio.exp when running on (my) CI: diff --git a/gdb-fix-odr-violations.patch b/gdb-fix-odr-violations.patch new file mode 100644 index 0000000..dd13d1b --- /dev/null +++ b/gdb-fix-odr-violations.patch @@ -0,0 +1,66 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Keith Seitz +Date: Thu, 14 May 2026 06:54:25 -0700 +Subject: gdb-fix-odr-violations.patch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +regdat.sh: generate target_desc_up for register descriptions + +Update regdat.sh so that generated init_registers_* code matches this +newer const-unique_ptr-based target description API. This fixes recent ODR +violations that have appeared (at least) on ppc64le: + + CXXLD gdbserver +../../src/gdbserver/../gdb/arch/ppc-linux-tdesc.h:46:29: error: ‘tdesc_powerpc_isa207_htm_vsx64l’ violates the C++ One Definition Rule [-Werror=odr] + 46 | extern const_target_desc_up tdesc_powerpc_isa207_htm_vsx64l; + | ^ +powerpc-isa207-htm-vsx64l-generated.cc:26:27: note: ‘tdesc_powerpc_isa207_htm_vsx64l’ was previously declared here + 26 | const struct target_desc *tdesc_powerpc_isa207_htm_vsx64l; + | ^ +powerpc-isa207-htm-vsx64l-generated.cc:26:27: note: code may be misoptimized unless ‘-fno-strict-aliasing’ is used +[snip] + +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28444 + +diff --git a/gdb/regformats/regdat.sh b/gdb/regformats/regdat.sh +--- a/gdb/regformats/regdat.sh ++++ b/gdb/regformats/regdat.sh +@@ -125,7 +125,7 @@ do + if test "${type}" = "name"; then + name="${entry}" + +- echo "const struct target_desc *tdesc_${name};" ++ echo "const_target_desc_up tdesc_${name};" + echo "" + + # This is necessary for -Wmissing-declarations. +@@ -134,9 +134,8 @@ do + echo "void" + echo "init_registers_${name} (void)" + echo "{" +- echo " static struct target_desc tdesc_${name}_s;" +- echo " struct target_desc *result = &tdesc_${name}_s;" +- echo " struct tdesc_feature *feature = tdesc_create_feature (result, \"${name}\");" ++ echo " target_desc_up result = allocate_target_description ();" ++ echo " struct tdesc_feature *feature = tdesc_create_feature (result.get (), \"${name}\");" + continue + elif test "${type}" = "xmltarget"; then + xmltarget="${entry}" +@@ -195,12 +194,12 @@ echo + osabi_enum=$(grep "${osabi}" "$2" | sed 's/.*(\([^,]\+\),.*/GDB_OSABI_\1/') + + cat <xmltarget = xmltarget_${name}; ++ result.get ()->xmltarget = xmltarget_${name}; + #endif + +- init_target_desc (result, expedite_regs_${name}, ${osabi_enum}); ++ init_target_desc (result.get (), expedite_regs_${name}, ${osabi_enum}); + +- tdesc_${name} = result; ++ tdesc_${name} = std::move (result); + } + EOF + diff --git a/gdb-fix-testsuite-newer-tcl.patch b/gdb-fix-testsuite-newer-tcl.patch deleted file mode 100644 index 5e0e16c..0000000 --- a/gdb-fix-testsuite-newer-tcl.patch +++ /dev/null @@ -1,46 +0,0 @@ -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-rhbz2403580-misplaced-symtabs.patch b/gdb-rhbz2403580-misplaced-symtabs.patch index 7996d82..35fdaad 100644 --- a/gdb-rhbz2403580-misplaced-symtabs.patch +++ b/gdb-rhbz2403580-misplaced-symtabs.patch @@ -92,7 +92,7 @@ diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c -@@ -6222,8 +6222,8 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die) +@@ -6227,8 +6227,8 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die) sf->symtab = allocate_symtab (cust, name, name_for_id); } @@ -103,7 +103,7 @@ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c } } else -@@ -6241,7 +6241,7 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die) +@@ -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]; @@ -112,7 +112,7 @@ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c } } -@@ -11584,7 +11584,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) +@@ -11589,7 +11589,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) { /* Any related symtab will do. */ symtab @@ -121,7 +121,7 @@ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c } else { -@@ -16587,6 +16587,9 @@ dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, +@@ -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); @@ -131,7 +131,7 @@ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c /* Make sure a symtab is created for every file, even files which contain only variables (i.e. no code with associated line numbers). */ -@@ -16602,7 +16605,7 @@ dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, +@@ -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 ()); @@ -140,7 +140,7 @@ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c } } -@@ -16879,7 +16882,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, +@@ -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 diff --git a/gdb-rhbz2413405-gcore-unreadable-pages.patch b/gdb-rhbz2413405-gcore-unreadable-pages.patch index 9dd5847..e81cd41 100644 --- a/gdb-rhbz2413405-gcore-unreadable-pages.patch +++ b/gdb-rhbz2413405-gcore-unreadable-pages.patch @@ -1,6 +1,6 @@ From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 From: Kevin Buettner -Date: Wed, 25 Feb 2026 19:58:50 -0700 +Date: Wed, 25 Feb 2026 23:34:29 -0700 Subject: gdb-rhbz2413405-gcore-unreadable-pages.patch ;; Backport of upstream commit c1da013915e from Kevin Buettner diff --git a/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch b/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch deleted file mode 100644 index 90473a1..0000000 --- a/gdb-rhbz2424325-c++20-implicit-lambda-capture.patch +++ /dev/null @@ -1,27 +0,0 @@ -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-more-const-fixes.patch b/gdb-rhbz2424325-c23-more-const-fixes.patch deleted file mode 100644 index 6655e73..0000000 --- a/gdb-rhbz2424325-c23-more-const-fixes.patch +++ /dev/null @@ -1,175 +0,0 @@ -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-rhbz2435950-skip-revert.patch b/gdb-rhbz2435950-skip-revert.patch deleted file mode 100644 index 931d063..0000000 --- a/gdb-rhbz2435950-skip-revert.patch +++ /dev/null @@ -1,138 +0,0 @@ -From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 -From: Andrew Burgess -Date: Mon, 9 Feb 2026 16:31:23 +0000 -Subject: gdb-rhbz2435950-skip-revert.patch - -;; Backport of upstream commit f08ffbbf2691bad2d5df660ee644647687775f0c -;; Can be dropped on a rebase to gdb 17.2 or 18.1 - -Revert "skip -gfile: call fnmatch without FNM_FILE_NAME" - -This reverts commit 02646a4c561ec88491114b87950cbb827c7d614c. See: - - https://inbox.sourceware.org/gdb-patches/20260203185528.946918-1-guinevere@redhat.com - -This commit introduced a non backward compatible change to how GDB -handled skip files. Something like: - - skip -gfile dir/*.c - -no longer matches every file within 'dir/', but now matches every file -in 'dir/' and within every sub-directory of 'dir/', which might not be -what the user wanted. - -The original intention behind the commit is solid, we just need to -find a better implementation. - -Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33872 - -diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo ---- a/gdb/doc/gdb.texinfo -+++ b/gdb/doc/gdb.texinfo -@@ -6825,9 +6825,7 @@ Functions in @var{file} will be skipped over when stepping. - @itemx -gfi @var{file-glob-pattern} - @cindex skipping over files via glob-style patterns - Functions in files matching @var{file-glob-pattern} will be skipped --over when stepping. The directory separator character @file{/} is treated as a --regular character, so it can be matched by wildcard characters @file{*} and --@file{?}. -+over when stepping. - - @smallexample - (@value{GDBP}) skip -gfi utils/*.c -diff --git a/gdb/skip.c b/gdb/skip.c ---- a/gdb/skip.c -+++ b/gdb/skip.c -@@ -531,7 +531,7 @@ skiplist_entry::do_skip_gfile_p (const symtab_and_line &function_sal) const - /* Check first sole SYMTAB->FILENAME. It may not be a substring of - symtab_to_fullname as it may contain "./" etc. */ - if (gdb_filename_fnmatch (m_file.c_str (), function_sal.symtab->filename, -- FNM_NOESCAPE) == 0) -+ FNM_FILE_NAME | FNM_NOESCAPE) == 0) - result = true; - - /* Before we invoke symtab_to_fullname, which is expensive, do a quick -@@ -542,14 +542,14 @@ skiplist_entry::do_skip_gfile_p (const symtab_and_line &function_sal) const - else if (!basenames_may_differ - && gdb_filename_fnmatch (lbasename (m_file.c_str ()), - lbasename (function_sal.symtab->filename), -- FNM_NOESCAPE) != 0) -+ FNM_FILE_NAME | FNM_NOESCAPE) != 0) - result = false; - else - { - /* Note: symtab_to_fullname caches its result, thus we don't have to. */ - const char *fullname = symtab_to_fullname (function_sal.symtab); - -- result = gdb_filename_fnmatch (m_file.c_str (), fullname, FNM_NOESCAPE); -+ result = compare_glob_filenames_for_search (fullname, m_file.c_str ()); - } - - if (debug_skip) -diff --git a/gdb/symtab.c b/gdb/symtab.c ---- a/gdb/symtab.c -+++ b/gdb/symtab.c -@@ -698,6 +698,40 @@ iterate_over_some_symtabs (const char *name, - return false; - } - -+/* Same as compare_filenames_for_search, but for glob-style patterns. -+ Heads up on the order of the arguments. They match the order of -+ compare_filenames_for_search, but it's the opposite of the order of -+ arguments to gdb_filename_fnmatch. */ -+ -+bool -+compare_glob_filenames_for_search (const char *filename, -+ const char *search_name) -+{ -+ /* We rely on the property of glob-style patterns with FNM_FILE_NAME that -+ all /s have to be explicitly specified. */ -+ int file_path_elements = count_path_elements (filename); -+ int search_path_elements = count_path_elements (search_name); -+ -+ if (search_path_elements > file_path_elements) -+ return false; -+ -+ if (IS_ABSOLUTE_PATH (search_name)) -+ { -+ return (search_path_elements == file_path_elements -+ && gdb_filename_fnmatch (search_name, filename, -+ FNM_FILE_NAME | FNM_NOESCAPE) == 0); -+ } -+ -+ { -+ const char *file_to_compare -+ = strip_leading_path_elements (filename, -+ file_path_elements - search_path_elements); -+ -+ return gdb_filename_fnmatch (search_name, file_to_compare, -+ FNM_FILE_NAME | FNM_NOESCAPE) == 0; -+ } -+} -+ - /* See symtab.h. */ - - void -diff --git a/gdb/utils.c b/gdb/utils.c ---- a/gdb/utils.c -+++ b/gdb/utils.c -@@ -3466,8 +3466,8 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout) - - #endif /* HAVE_WAITPID */ - --/* Provide fnmatch compatible function for matching of host files. -- FNM_NOESCAPE must be set in FLAGS. -+/* Provide fnmatch compatible function for FNM_FILE_NAME matching of host files. -+ Both FNM_FILE_NAME and FNM_NOESCAPE must be set in FLAGS. - - It handles correctly HAVE_DOS_BASED_FILE_SYSTEM and - HAVE_CASE_INSENSITIVE_FILE_SYSTEM. */ -@@ -3475,6 +3475,8 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout) - int - gdb_filename_fnmatch (const char *pattern, const char *string, int flags) - { -+ gdb_assert ((flags & FNM_FILE_NAME) != 0); -+ - /* It is unclear how '\' escaping vs. directory separator should coexist. */ - gdb_assert ((flags & FNM_NOESCAPE) != 0); - diff --git a/gdb-rpm-suggestion-script.patch b/gdb-rpm-suggestion-script.patch index 07a68d5..28df14b 100644 --- a/gdb-rpm-suggestion-script.patch +++ b/gdb-rpm-suggestion-script.patch @@ -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} -@@ -50988,6 +50989,111 @@ Show the current verbosity setting. +@@ -50986,6 +50987,111 @@ Show the current verbosity setting. @end table diff --git a/gdb-tcl9-utf8-encoding-fix.patch b/gdb-tcl9-utf8-encoding-fix.patch deleted file mode 100644 index 9383e17..0000000 --- a/gdb-tcl9-utf8-encoding-fix.patch +++ /dev/null @@ -1,157 +0,0 @@ -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.spec b/gdb.spec index c89875f..fab17b3 100644 --- a/gdb.spec +++ b/gdb.spec @@ -51,7 +51,7 @@ Name: %{?scl_prefix}gdb # See timestamp of source gnulib installed into gnulib/ . %global snapgnulib 20220501 %global tarname gdb-%{version} -Version: 17.1 +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. @@ -152,7 +152,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 @@ -230,6 +229,14 @@ 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. +# Note: kevinb disabled this entirely, but we should probably just get rid of it. +%if 0 +%if 0%{!?rhel:1} +BuildRequires: gcc-gdb-plugin%{?_isa} +%endif +%endif + BuildRequires: systemtap-sdt-devel BuildRequires: opencl-headers ocl-icd-devel%{bits_local} ocl-icd-devel%{bits_other} @@ -314,7 +321,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-1.3-or-later +License: GFDL BuildArch: noarch %if 0%{?scl:1} # As of F-28, packages won't need to call /sbin/install-info by hand @@ -332,7 +339,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/ /' - 17.2-1.el8 +- Rebase to 17.2. + (Keith Seitz, RHEL-221050) + +* Wed Jul 22 2026 Guinevere Larsen - 17.2-3 +- Backport upstream commit f3ce0ce31fb3f056 to fix a regression on + s390x. + +* 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. + +* 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. + +* Fri Jul 03 2026 Michal Kolar - 17.2-1 +- 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 + * Tue Jun 09 2026 Guinevere Larsen - 17.1-1 - Initial import of sources Resolves: RHELMISC-29064 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/rpminspect.yaml b/rpminspect.yaml new file mode 100644 index 0000000..2bfe7c0 --- /dev/null +++ b/rpminspect.yaml @@ -0,0 +1,14 @@ +--- + +annocheck: + jobs: + + # --skip-lto + # Disable Link-Time Optimization checks + # Upstream GDB is not fully compatible with LTO + # + # --skip-stack-realign + # Skip stack-realign test for i686 + # GDB code is compiled with -mstackrealign, but the binary links + # against static code which was compiled without this flag + - hardened: --skip-lto --skip-stack-realign diff --git a/sources b/sources index fd3c204..f76e77c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gdb-17.1.tar.xz) = f1a6751e439a2128fecf3eae8b57c1608a0dc7cfe79b4356a937874e5a42bb2df0aba36eb6a9452c41966908b9a59076c7cad9720f684688ab956b65080f1d7c +SHA512 (gdb-17.2.tar.xz) = 7794c5a185be7ed5e7ad1000c4ff7d8497c80425a1bc108aab8fd3dd8ecdde034e294dfd65b25c6b0dcd8ed2a240caf07293f3e73791b6cfc890d580d0af4581