public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/gdb] gdb-17.2-rebase-f44: switch rpm suggestion feature to a Python extension
Date: Sun, 28 Jun 2026 00:01:34 GMT	[thread overview]
Message-ID: <178260489465.1.5364622496640306165.rpms-gdb-08bfd0a4a7fe@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : rpms/gdb
            Branch : gdb-17.2-rebase-f44
            Commit : 08bfd0a4a7fe8241b1f63780ff25978aa0da8c9d
            Author : Andrew Burgess <aburgess@redhat.com>
            Date   : 2024-03-15T14:04:11+00:00
            Stats  : +2891/-2022 in 26 file(s)
            URL    : https://src.fedoraproject.org/rpms/gdb/c/08bfd0a4a7fe8241b1f63780ff25978aa0da8c9d?branch=gdb-17.2-rebase-f44

            Log:
            switch rpm suggestion feature to a Python extension

This commit backports several patches from upstream GDB:

  7d21600b31f
  dd5516bf98f
  e8c3dafa5f5
  1146d27749f
  7db795bc67a
  8f6c452b5a4
  661d98a3331
  6234ba17598
  27807da5849
  7628a997f27

These commits provide a new Python API which allows users to catch the
case where GDB tries to load an objfile, but can't find any debug
information.

I've then added a new patch which uses this Python API to hook into
GDB and make suggestions about RPMs to install that could provide
missing debug information, this should replace some of the rpm
suggestion functionality that is currently implemented within GDB's
C++ code, as such I've deleted all of the code related to opening
librpm and querying the RPM database.

There is still code in GDB which will make suggestions about
installing RPMs based on the path to the build-id symlink for the
file.  This code is hit when a user tries to open a core-file and the
corresponding executable can't be found, or if a shared library
required by the core-file isn't found.

In these cases the librpm lookup would always fail anyway and we'd
just suggest that the user try to install the required package based
on the path to the build-id symlink, e.g.:

  Missing separate debuginfo for the main executable file.
  Try: yum --enablerepo='*debug*' install /usr/local/lib/debug/.build-id/bf/c9fbd13046db58c28ba332e6c991240e775c96

This should still work just as it did before.

Now GDB no longer links against librpm I'm able to remove all the
librpm related stuff from the configure scripts, which is a nice
cleanup.

There are a couple of patches:

  gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
  gdb-6.6-buildid-locate-rpm.patch

which deal exclusively with updating code (added in earlier patches)
related to the use of librpm from GDB's C++ code, these patches are
removed by this commit.  Other patches are changed either by the
removal of the librpm code, or as a consequence of that code having
been removed.

I've also taken the opportunity to fix up some of the test cases which
only exist in the Fedora tree so that they will run again.  This is
mostly just updating the tests to match upstream GDB's current
testsuite infrastructure, these are all pretty minor fixes.

---
diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include
index 7a222d6..ae6c4af 100644
--- a/_gdb.spec.Patch.include
+++ b/_gdb.spec.Patch.include
@@ -44,110 +44,103 @@ Patch010: gdb-6.6-buildid-locate.patch
 #=push+jan
 Patch011: gdb-6.6-buildid-locate-solib-missing-ids.patch
 
-#=push+jan
-Patch012: gdb-6.6-buildid-locate-rpm.patch
-
 # Test PPC hiding of call-volatile parameter register.
 #=fedoratest
-Patch013: gdb-6.7-ppc-clobbered-registers-O2-test.patch
+Patch012: gdb-6.7-ppc-clobbered-registers-O2-test.patch
 
 # Test gcore memory and time requirements for large inferiors.
 #=fedoratest
-Patch014: gdb-6.5-gcore-buffer-limit-test.patch
+Patch013: gdb-6.5-gcore-buffer-limit-test.patch
 
 # Test GCORE for shmid 0 shared memory mappings.
 #=fedoratest: But it is broken anyway, sometimes the case being tested is not reproducible.
-Patch015: gdb-6.3-mapping-zero-inode-test.patch
+Patch014: gdb-6.3-mapping-zero-inode-test.patch
 
 # Test a crash on libraries missing the .text section.
 #=fedoratest
-Patch016: gdb-6.5-section-num-fixup-test.patch
+Patch015: gdb-6.5-section-num-fixup-test.patch
 
 # Fix resolving of variables at locations lists in prelinked libs (BZ 466901).
 #=fedoratest
-Patch017: gdb-6.8-bz466901-backtrace-full-prelinked.patch
+Patch016: gdb-6.8-bz466901-backtrace-full-prelinked.patch
 
 # New test for step-resume breakpoint placed in multiple threads at once.
 #=fedoratest
-Patch018: gdb-simultaneous-step-resume-breakpoint-test.patch
+Patch017: gdb-simultaneous-step-resume-breakpoint-test.patch
 
 # Fix GNU/Linux core open: Can't read pathname for load map: Input/output error.
 # Fix regression of undisplayed missing shared libraries caused by a fix for.
 #=fedoratest: It should be in glibc: libc-alpha: <20091004161706.GA27450@.*>
-Patch019: gdb-core-open-vdso-warning.patch
+Patch018: gdb-core-open-vdso-warning.patch
 
 # Fix follow-exec for C++ programs (bugreported by Martin Stransky).
 #=fedoratest
-Patch020: gdb-archer-next-over-throw-cxx-exec.patch
-
-# Workaround librpm BZ 643031 due to its unexpected exit() calls (BZ 642879).
-#=push+jan
-Patch021: gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
+Patch019: gdb-archer-next-over-throw-cxx-exec.patch
 
 # [delayed-symfile] Test a backtrace regression on CFIs without DIE (BZ 614604).
 #=fedoratest
-Patch022: gdb-test-bt-cfi-without-die.patch
+Patch020: gdb-test-bt-cfi-without-die.patch
 
 # Verify GDB Python built-in function gdb.solib_address exists (BZ # 634108).
 #=fedoratest
-Patch023: gdb-bz634108-solib_address.patch
+Patch021: gdb-bz634108-solib_address.patch
 
 # [archer-tromey-delayed-symfile] New test gdb.dwarf2/dw2-aranges.exp.
 #=fedoratest
-Patch024: gdb-test-dw2-aranges.patch
+Patch022: gdb-test-dw2-aranges.patch
 
 # Workaround PR libc/14166 for inferior calls of strstr.
 #=fedoratest: Compatibility with RHELs (unchecked which ones).
-Patch025: gdb-glibc-strstr-workaround.patch
+Patch023: gdb-glibc-strstr-workaround.patch
 
 # Testcase for `Setting solib-absolute-prefix breaks vDSO' (BZ 818343).
 #=fedoratest
-Patch026: gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
+Patch024: gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
 
 # Import regression test for `gdb/findvar.c:417: internal-error:
 # read_var_value: Assertion `frame' failed.' (RH BZ 947564) from RHEL 6.5.
 #=fedoratest
-Patch027: gdb-rhbz947564-findvar-assertion-frame-failed-testcase.patch
+Patch025: gdb-rhbz947564-findvar-assertion-frame-failed-testcase.patch
 
 # Fix 'memory leak in infpy_read_memory()' (RH BZ 1007614)
 #=fedoratest
-Patch028: gdb-rhbz1007614-memleak-infpy_read_memory-test.patch
+Patch026: gdb-rhbz1007614-memleak-infpy_read_memory-test.patch
 
 # Fix 'gdb gives highly misleading error when debuginfo pkg is present,
 # but not corresponding binary pkg' (RH BZ 981154).
 #=push+jan
-Patch029: gdb-6.6-buildid-locate-misleading-warning-missing-debuginfo-rhbz981154.patch
+Patch027: gdb-6.6-buildid-locate-misleading-warning-missing-debuginfo-rhbz981154.patch
 
 # Testcase for '[SAP] Recursive dlopen causes SAP HANA installer to
 # crash.' (RH BZ 1156192).
 #=fedoratest
-Patch030: gdb-rhbz1156192-recursive-dlopen-test.patch
+Patch028: gdb-rhbz1156192-recursive-dlopen-test.patch
 
 # Fix '`catch syscall' doesn't work for parent after `fork' is called'
 # (Philippe Waroquiers, RH BZ 1149205).
 #=fedoratest
-Patch031: gdb-rhbz1149205-catch-syscall-after-fork-test.patch
+Patch029: gdb-rhbz1149205-catch-syscall-after-fork-test.patch
 
 # Fix '[ppc64] and [s390x] wrong prologue skip on -O2 -g code' (Jan
 # Kratochvil, RH BZ 1084404).
 #=fedoratest
-Patch032: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
+Patch030: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
 
 # Force libncursesw over libncurses to match the includes (RH BZ 1270534).
 #=push+jan
-Patch033: gdb-fedora-libncursesw.patch
+Patch031: gdb-fedora-libncursesw.patch
 
 # [aarch64] Fix hardware watchpoints (RH BZ 1261564).
 #=fedoratest
-Patch034: gdb-rhbz1261564-aarch64-hw-watchpoint-test.patch
+Patch032: gdb-rhbz1261564-aarch64-hw-watchpoint-test.patch
 
 # Add messages suggesting more recent RHEL gdbserver (RH BZ 1321114).
 #=fedora
-Patch035: gdb-container-rh-pkg.patch
+Patch033: gdb-container-rh-pkg.patch
 
 # [dts+el7] [x86*] Bundle linux_perf.h for libipt (RH BZ 1256513).
 #=fedora
-Patch036: gdb-linux_perf-bundle.patch
+Patch034: gdb-linux_perf-bundle.patch
 
 # Update gdb-add-index.sh such that, when the GDB environment
 # variable is not set, the script is smarter than just looking for
@@ -161,38 +154,72 @@ Patch036: gdb-linux_perf-bundle.patch
 #   https://fedoraproject.org/wiki/Changes/Minimal_GDB_in_buildroot
 #
 #=fedora
-Patch037: gdb-add-index.patch
+Patch035: gdb-add-index.patch
 
 # Back-port upstream commit 1f0fab7ff86 as part of a fix for
 # non-deterministic gdb-index generation (RH BZ 2232086).
-Patch038: gdb-rhbz2232086-refactor-selftest-support.patch
+Patch036: gdb-rhbz2232086-refactor-selftest-support.patch
 
 # Back-port upstream commit aa19bc1d259 as part of a fix for
 # non-deterministic gdb-index generation (RH BZ 2232086).
-Patch039: gdb-rhbz-2232086-reduce-size-of-gdb-index.patch
+Patch037: gdb-rhbz-2232086-reduce-size-of-gdb-index.patch
 
 # Back-port upstream commit acc117b57f7 as part of a fix for
 # non-deterministic gdb-index generation (RH BZ 2232086).
-Patch040: gdb-rhbz-2232086-cpp-ify-mapped-symtab.patch
+Patch038: gdb-rhbz-2232086-cpp-ify-mapped-symtab.patch
 
 # Back-port upstream commit aff250145af as part of a fix for
 # non-deterministic gdb-index generation (RH BZ 2232086).
-Patch041: gdb-rhbz-2232086-generate-gdb-index-consistently.patch
+Patch039: gdb-rhbz-2232086-generate-gdb-index-consistently.patch
 
 # Back-port upstream commit 3644f41dc80 as part of a fix for
 # non-deterministic gdb-index generation (RH BZ 2232086).
-Patch042: gdb-rhbz-2232086-generate-dwarf-5-index-consistently.patch
+Patch040: gdb-rhbz-2232086-generate-dwarf-5-index-consistently.patch
 
 
-Patch043: gdb-rhbz2250652-gdbpy_gil.patch
+Patch041: gdb-rhbz2250652-gdbpy_gil.patch
 
 
-Patch044: gdb-rhbz2250652-avoid-PyOS_ReadlineTState.patch
+Patch042: gdb-rhbz2250652-avoid-PyOS_ReadlineTState.patch
 
 
-Patch045: gdb-ftbs-swapped-calloc-args.patch
+Patch043: gdb-ftbs-swapped-calloc-args.patch
 
 # Backport upstream workaround for GCC 14 problem which cause assertion
 # failures in GDB.
-Patch046: gdb-rhbz2261580-intrusive_list-assertion-fix.patch
+Patch044: gdb-rhbz2261580-intrusive_list-assertion-fix.patch
+
+# Backport upstream commit 7628a997f27.
+Patch045: gdb-sync-coffread-with-elfread.patch
+
+# Backport upstream commit 27807da5849.
+Patch046: gdb-merge-debug-symbol-lookup.patch
+
+# Backport upstream commit 6234ba17598.
+Patch047: gdb-refactor-find-and-add-separate-symbol-file.patch
+
+# Backport upstream commit 661d98a3331.
+Patch048: gdb-add-missing-debug-ext-lang-hook.patch
+
+# Backport upstream commit 8f6c452b5a4.
+Patch049: gdb-add-missing-debug-info-python-hook.patch
+
+# Backport upstream commit 7db795bc67a.
+Patch050: gdb-remove-use-of-py-isascii
+
+# Backport upstream commit 1146d27749f.
+Patch051: gdb-remove-path-in-test-name.patch
+
+# Backport upstream commit e8c3dafa5f5.
+Patch052: gdb-do-not-import-py-curses-ascii-module.patch
+
+# Backport upstream commit dd5516bf98f.
+Patch053: gdb-reformat-missing-debug-py-file.patch
+
+# Backport upstream commit 7d21600b31fe.
+Patch054: gdb-handle-no-python-gdb-module.patch
+
+# Not a backport.  Add a new script which hooks into GDB and suggests
+# RPMs to install when GDB finds an objfile with no debug info.
+Patch055: gdb-add-rpm-suggestion-script.patch
 

diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include
index 80df31a..b72c412 100644
--- a/_gdb.spec.patch.include
+++ b/_gdb.spec.patch.include
@@ -44,3 +44,12 @@
 %patch -p1 -P044
 %patch -p1 -P045
 %patch -p1 -P046
+%patch -p1 -P047
+%patch -p1 -P048
+%patch -p1 -P049
+%patch -p1 -P050
+%patch -p1 -P051
+%patch -p1 -P052
+%patch -p1 -P053
+%patch -p1 -P054
+%patch -p1 -P055

diff --git a/_patch_order b/_patch_order
index 77122be..7f94e21 100644
--- a/_patch_order
+++ b/_patch_order
@@ -9,7 +9,6 @@ gdb-6.3-attach-see-vdso-test.patch
 gdb-6.5-bz243845-stale-testing-zombie-test.patch
 gdb-6.6-buildid-locate.patch
 gdb-6.6-buildid-locate-solib-missing-ids.patch
-gdb-6.6-buildid-locate-rpm.patch
 gdb-6.7-ppc-clobbered-registers-O2-test.patch
 gdb-6.5-gcore-buffer-limit-test.patch
 gdb-6.3-mapping-zero-inode-test.patch
@@ -18,7 +17,6 @@ gdb-6.8-bz466901-backtrace-full-prelinked.patch
 gdb-simultaneous-step-resume-breakpoint-test.patch
 gdb-core-open-vdso-warning.patch
 gdb-archer-next-over-throw-cxx-exec.patch
-gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
 gdb-test-bt-cfi-without-die.patch
 gdb-bz634108-solib_address.patch
 gdb-test-dw2-aranges.patch
@@ -44,3 +42,14 @@ gdb-rhbz2250652-gdbpy_gil.patch
 gdb-rhbz2250652-avoid-PyOS_ReadlineTState.patch
 gdb-ftbs-swapped-calloc-args.patch
 gdb-rhbz2261580-intrusive_list-assertion-fix.patch
+gdb-sync-coffread-with-elfread.patch
+gdb-merge-debug-symbol-lookup.patch
+gdb-refactor-find-and-add-separate-symbol-file.patch
+gdb-add-missing-debug-ext-lang-hook.patch
+gdb-add-missing-debug-info-python-hook.patch
+gdb-remove-use-of-py-isascii
+gdb-remove-path-in-test-name.patch
+gdb-do-not-import-py-curses-ascii-module.patch
+gdb-reformat-missing-debug-py-file.patch
+gdb-handle-no-python-gdb-module.patch
+gdb-add-rpm-suggestion-script.patch

diff --git a/gdb-6.3-gstack-20050411.patch b/gdb-6.3-gstack-20050411.patch
index 01e8ffa..3285686 100644
--- a/gdb-6.3-gstack-20050411.patch
+++ b/gdb-6.3-gstack-20050411.patch
@@ -226,7 +226,7 @@ new file mode 100644
 +# exiting the function.  Still we could retry the gstack command if we fail.
 +
 +set test "spawn gstack"
-+set command "sh -c GDB=$GDB\\ GDBARGS=-data-directory\\\\\\ $BUILD_DATA_DIRECTORY\\ sh\\ ${srcdir}/../gstack.sh\\ $pid\\;echo\\ GSTACK-END"
++set command "sh -c GDB=$GDB\\ GDBARGS=-data-directory\\\\\\ $GDB_DATA_DIRECTORY\\ sh\\ ${srcdir}/../gstack.sh\\ $pid\\;echo\\ GSTACK-END"
 +set res [remote_spawn host $command];
 +if { $res < 0 || $res == "" } {
 +    perror "Spawning $command failed."

diff --git a/gdb-6.6-buildid-locate-rpm-librpm-workaround.patch b/gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
deleted file mode 100644
index 2b862a0..0000000
--- a/gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Fedora GDB patches <invalid@email.com>
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.6-buildid-locate-rpm-librpm-workaround.patch
-
-;; Workaround librpm BZ 643031 due to its unexpected exit() calls (BZ 642879).
-;;=push+jan
-
-diff --git a/gdb/proc-service.list b/gdb/proc-service.list
---- a/gdb/proc-service.list
-+++ b/gdb/proc-service.list
-@@ -37,4 +37,7 @@
-   ps_pstop;
-   ps_ptread;
-   ps_ptwrite;
-+
-+  /* gdb-6.6-buildid-locate-rpm.patch */
-+  rpmsqEnable;
- };

diff --git a/gdb-6.6-buildid-locate-rpm.patch b/gdb-6.6-buildid-locate-rpm.patch
deleted file mode 100644
index 14013ef..0000000
--- a/gdb-6.6-buildid-locate-rpm.patch
+++ /dev/null
@@ -1,1084 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Kevin Buettner <kevinb@redhat.com>
-Date: Wed, 22 Feb 2023 22:30:40 -0700
-Subject: gdb-6.6-buildid-locate-rpm.patch
-
-;;=push+jan
-
-diff --git a/gdb/aclocal.m4 b/gdb/aclocal.m4
---- a/gdb/aclocal.m4
-+++ b/gdb/aclocal.m4
-@@ -11,7 +11,223 @@
- # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- # PARTICULAR PURPOSE.
- 
-+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
-+# serial 1 (pkg-config-0.24)
-+#
-+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful, but
-+# WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+# General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+#
-+# As a special exception to the GNU General Public License, if you
-+# distribute this file as part of a program that contains a
-+# configuration script generated by Autoconf, you may include it under
-+# the same distribution terms that you use for the rest of that program.
-+
-+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-+# ----------------------------------
-+AC_DEFUN([PKG_PROG_PKG_CONFIG],
-+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
-+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
-+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
-+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
-+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
-+
-+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-+fi
-+if test -n "$PKG_CONFIG"; then
-+	_pkg_min_version=m4_default([$1], [0.9.0])
-+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
-+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-+		AC_MSG_RESULT([yes])
-+	else
-+		AC_MSG_RESULT([no])
-+		PKG_CONFIG=""
-+	fi
-+fi[]dnl
-+])# PKG_PROG_PKG_CONFIG
-+
-+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-+#
-+# Check to see whether a particular set of modules exists.  Similar
-+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-+#
-+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-+# only at the first occurence in configure.ac, so if the first place
-+# it's called might be skipped (such as if it is within an "if", you
-+# have to call PKG_CHECK_EXISTS manually
-+# --------------------------------------------------------------
-+AC_DEFUN([PKG_CHECK_EXISTS],
-+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-+if test -n "$PKG_CONFIG" && \
-+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
-+  m4_default([$2], [:])
-+m4_ifvaln([$3], [else
-+  $3])dnl
-+fi])
-+
-+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-+# ---------------------------------------------
-+m4_define([_PKG_CONFIG],
-+[if test -n "$$1"; then
-+    pkg_cv_[]$1="$$1"
-+ elif test -n "$PKG_CONFIG"; then
-+    PKG_CHECK_EXISTS([$3],
-+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
-+		      test "x$?" != "x0" && pkg_failed=yes ],
-+		     [pkg_failed=yes])
-+ else
-+    pkg_failed=untried
-+fi[]dnl
-+])# _PKG_CONFIG
-+
-+# _PKG_SHORT_ERRORS_SUPPORTED
-+# -----------------------------
-+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-+        _pkg_short_errors_supported=yes
-+else
-+        _pkg_short_errors_supported=no
-+fi[]dnl
-+])# _PKG_SHORT_ERRORS_SUPPORTED
-+
-+
-+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-+# [ACTION-IF-NOT-FOUND])
-+#
-+#
-+# Note that if there is a possibility the first call to
-+# PKG_CHECK_MODULES might not happen, you should be sure to include an
-+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-+#
-+#
-+# --------------------------------------------------------------
-+AC_DEFUN([PKG_CHECK_MODULES],
-+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-+
-+pkg_failed=no
-+AC_MSG_CHECKING([for $1])
-+
-+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-+
-+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-+and $1[]_LIBS to avoid the need to call pkg-config.
-+See the pkg-config man page for more details.])
-+
-+if test $pkg_failed = yes; then
-+        AC_MSG_RESULT([no])
-+        _PKG_SHORT_ERRORS_SUPPORTED
-+        if test $_pkg_short_errors_supported = yes; then
-+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
-+        else
-+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
-+        fi
-+	# Put the nasty error message in config.log where it belongs
-+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-+
-+	m4_default([$4], [AC_MSG_ERROR(
-+[Package requirements ($2) were not met:
-+
-+$$1_PKG_ERRORS
-+
-+Consider adjusting the PKG_CONFIG_PATH environment variable if you
-+installed software in a non-standard prefix.
-+
-+_PKG_TEXT])[]dnl
-+        ])
-+elif test $pkg_failed = untried; then
-+        AC_MSG_RESULT([no])
-+	m4_default([$4], [AC_MSG_FAILURE(
-+[The pkg-config script could not be found or is too old.  Make sure it
-+is in your PATH or set the PKG_CONFIG environment variable to the full
-+path to pkg-config.
-+
-+_PKG_TEXT
-+
-+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
-+        ])
-+else
-+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
-+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
-+        AC_MSG_RESULT([yes])
-+	$3
-+fi[]dnl
-+])# PKG_CHECK_MODULES
-+
-+
-+# PKG_INSTALLDIR(DIRECTORY)
-+# -------------------------
-+# Substitutes the variable pkgconfigdir as the location where a module
-+# should install pkg-config .pc files. By default the directory is
-+# $libdir/pkgconfig, but the default can be changed by passing
-+# DIRECTORY. The user can override through the --with-pkgconfigdir
-+# parameter.
-+AC_DEFUN([PKG_INSTALLDIR],
-+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
-+m4_pushdef([pkg_description],
-+    [pkg-config installation directory @<:@]pkg_default[@:>@])
-+AC_ARG_WITH([pkgconfigdir],
-+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
-+    [with_pkgconfigdir=]pkg_default)
-+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
-+m4_popdef([pkg_default])
-+m4_popdef([pkg_description])
-+]) dnl PKG_INSTALLDIR
-+
-+
-+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
-+# -------------------------
-+# Substitutes the variable noarch_pkgconfigdir as the location where a
-+# module should install arch-independent pkg-config .pc files. By
-+# default the directory is $datadir/pkgconfig, but the default can be
-+# changed by passing DIRECTORY. The user can override through the
-+# --with-noarch-pkgconfigdir parameter.
-+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
-+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
-+m4_pushdef([pkg_description],
-+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
-+AC_ARG_WITH([noarch-pkgconfigdir],
-+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
-+    [with_noarch_pkgconfigdir=]pkg_default)
-+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
-+m4_popdef([pkg_default])
-+m4_popdef([pkg_description])
-+]) dnl PKG_NOARCH_INSTALLDIR
-+
-+
-+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
-+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-+# -------------------------------------------
-+# Retrieves the value of the pkg-config variable for the given module.
-+AC_DEFUN([PKG_CHECK_VAR],
-+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
-+
-+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
-+AS_VAR_COPY([$1], [pkg_cv_][$1])
-+
-+AS_VAR_IF([$1], [""], [$5], [$4])dnl
-+])# PKG_CHECK_VAR
-+
- m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-+
- # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
- 
- # Copyright (C) 2001-2017 Free Software Foundation, Inc.
-diff --git a/gdb/build-id.c b/gdb/build-id.c
---- a/gdb/build-id.c
-+++ b/gdb/build-id.c
-@@ -780,10 +780,10 @@ missing_rpm_enlist_1 (const char *filename, int verify_vendor)
-   static rpmts (*rpmtsCreate_p) (void);
-   extern rpmts rpmtsFree(rpmts ts);
-   static rpmts (*rpmtsFree_p) (rpmts ts);
--  extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
-+  extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
-                                               const void * keyp, size_t keylen);
-   static rpmdbMatchIterator (*rpmtsInitIterator_p) (const rpmts ts,
--						    rpmTag rpmtag,
-+						    rpmDbiTagVal rpmtag,
- 						    const void *keyp,
- 						    size_t keylen);
- #else	/* !DLOPEN_LIBRPM */
-@@ -838,7 +838,7 @@ missing_rpm_enlist_1 (const char *filename, int verify_vendor)
- 	      && (rpmdbNextIterator_p = (Header (*) (rpmdbMatchIterator mi)) dlsym (h, "rpmdbNextIterator"))
- 	      && (rpmtsCreate_p = (rpmts (*) (void)) dlsym (h, "rpmtsCreate"))
- 	      && (rpmtsFree_p = (rpmts (*) (rpmts ts)) dlsym (h, "rpmtsFree"))
--	      && (rpmtsInitIterator_p = (rpmdbMatchIterator (*) (const rpmts ts, rpmTag rpmtag, const void *keyp, size_t keylen)) dlsym (h, "rpmtsInitIterator"))))
-+	      && (rpmtsInitIterator_p = (rpmdbMatchIterator (*) (const rpmts ts, rpmDbiTagVal rpmtag, const void *keyp, size_t keylen)) dlsym (h, "rpmtsInitIterator"))))
- 	  {
- 	    warning (_("Opened library \"%s\" is incompatible (%s), "
- 		      "missing debuginfos notifications will not be displayed"),
-@@ -926,7 +926,7 @@ missing_rpm_enlist_1 (const char *filename, int verify_vendor)
- 
- 	  /* RPMDBI_PACKAGES requires keylen == sizeof (int).  */
- 	  /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel().  */
--	  mi_debuginfo = rpmtsInitIterator_p (ts, (rpmTag) RPMDBI_LABEL, debuginfo, 0);
-+	  mi_debuginfo = rpmtsInitIterator_p (ts, (rpmDbiTagVal) RPMDBI_LABEL, debuginfo, 0);
- 	  xfree (debuginfo);
- 	  if (mi_debuginfo)
- 	    {
-diff --git a/gdb/config.in b/gdb/config.in
---- a/gdb/config.in
-+++ b/gdb/config.in
-@@ -42,6 +42,9 @@
- /* Handle .ctf type-info sections */
- #undef ENABLE_LIBCTF
- 
-+/* librpm version specific library name to dlopen. */
-+#undef DLOPEN_LIBRPM
-+
- /* Define to 1 if translation of program messages to the user's native
-    language is requested. */
- #undef ENABLE_NLS
-@@ -265,6 +268,9 @@
- /* Define to 1 if you have the `m' library (-lm). */
- #undef HAVE_LIBM
- 
-+/* Define if librpm library is being used. */
-+#undef HAVE_LIBRPM
-+
- /* Define to 1 if you have the <libunwind-ia64.h> header file. */
- #undef HAVE_LIBUNWIND_IA64_H
- 
-diff --git a/gdb/configure b/gdb/configure
---- a/gdb/configure
-+++ b/gdb/configure
-@@ -778,6 +778,11 @@ AMD_DBGAPI_CFLAGS
- ENABLE_BFD_64_BIT_FALSE
- ENABLE_BFD_64_BIT_TRUE
- subdirs
-+RPM_LIBS
-+RPM_CFLAGS
-+PKG_CONFIG_LIBDIR
-+PKG_CONFIG_PATH
-+PKG_CONFIG
- GDB_DATADIR
- DEBUGDIR
- MAKEINFO_EXTRA_FLAGS
-@@ -911,6 +916,7 @@ with_gdb_datadir
- with_relocated_sources
- with_auto_load_dir
- with_auto_load_safe_path
-+with_rpm
- enable_targets
- enable_64_bit_bfd
- with_amd_dbgapi
-@@ -988,6 +994,8 @@ AMD_DBGAPI_CFLAGS
- AMD_DBGAPI_LIBS
- DEBUGINFOD_CFLAGS
- DEBUGINFOD_LIBS
-+RPM_CFLAGS
-+RPM_LIBS
- YACC
- YFLAGS
- ZSTD_CFLAGS
-@@ -1679,6 +1687,8 @@ Optional Packages:
-   --with-amd-dbgapi       support for the amd-dbgapi target (yes / no / auto)
-   --with-debuginfod       Enable debuginfo lookups with debuginfod
-                           (auto/yes/no)
-+  --with-rpm              query rpm database for missing debuginfos (yes/no,
-+                          def. auto=librpm.so)
-   --with-libunwind-ia64   use libunwind frame unwinding for ia64 targets
-   --with-curses           use the curses library instead of the termcap
-                           library
-@@ -1759,6 +1769,8 @@ Some influential environment variables:
-               C compiler flags for DEBUGINFOD, overriding pkg-config
-   DEBUGINFOD_LIBS
-               linker flags for DEBUGINFOD, overriding pkg-config
-+  RPM_CFLAGS  C compiler flags for RPM, overriding pkg-config
-+  RPM_LIBS    linker flags for RPM, overriding pkg-config
-   YACC        The `Yet Another Compiler Compiler' implementation to use.
-               Defaults to the first program found out of: `bison -y', `byacc',
-               `yacc'.
-@@ -18039,6 +18051,495 @@ _ACEOF
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_auto_load_safe_path" >&5
- $as_echo "$with_auto_load_safe_path" >&6; }
- 
-+# Integration with rpm library to support missing debuginfo suggestions.
-+# --without-rpm: Disable any rpm support.
-+# --with-rpm=libname.so: Try to dynamically open `libname.so' during runtime.
-+#   Even with runtime missing `libname.so' GDB will still other run correctly.
-+#   Missing `libname.so' during ./configure will abort the configuration.
-+# --with-rpm=librpm.so: Like `--with-rpm=libname.so' but try to find specific
-+#   minor version first such as `librpm-4.6.so' as minor version differences
-+#   mean API+ABI incompatibility.  If the specific match versioned library name
-+#   could not be found still open dynamically at least `librpm.so'.
-+# --with-rpm: Like `--with-rpm=librpm.so' but if any of its detection fails try
-+#   to find librpm for compilation-time linking by pkg-config.  GDB binary will
-+#   be probably linked with the version specific library (as `librpm-4.6.so').
-+#   Failure to find librpm by pkg-config will abort the configuration.
-+# (default) --with-rpm=auto: Like `--with-rpm=librpm.so' but if even pkg-config
-+#   cannot find librpm use to the rpmless compilation (like `--without-rpm').
-+
-+
-+# Check whether --with-rpm was given.
-+if test "${with_rpm+set}" = set; then :
-+  withval=$with_rpm;
-+else
-+  with_rpm="auto"
-+fi
-+
-+
-+
-+
-+if test "x$with_rpm" != "xno"; then
-+  if test "x$with_rpm" = "xyes"; then
-+    LIBRPM="librpm.so"
-+    RPM_REQUIRE=true
-+    DLOPEN_REQUIRE=false
-+  elif test "x$with_rpm" = "xauto"; then
-+    LIBRPM="librpm.so"
-+    RPM_REQUIRE=false
-+    DLOPEN_REQUIRE=false
-+  else
-+    LIBRPM="$with_rpm"
-+    RPM_REQUIRE=true
-+    DLOPEN_REQUIRE=true
-+  fi
-+  LIBRPM_STRING='"'"$LIBRPM"'"'
-+
-+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking specific librpm version" >&5
-+$as_echo_n "checking specific librpm version... " >&6; }
-+  HAVE_DLOPEN_LIBRPM=false
-+  save_LIBS="$LIBS"
-+  LIBS="$LIBS -ldl"
-+  if test "$cross_compiling" = yes; then :
-+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-+as_fn_error "cannot run test program while cross compiling
-+See \`config.log' for more details." "$LINENO" 5; }
-+else
-+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+#include <rpm/rpmlib.h>
-+#include <dlfcn.h>
-+#include <errno.h>
-+#include <string.h>
-+
-+int
-+main ()
-+{
-+
-+    void *h;
-+    const char *const *rpmverp;
-+    FILE *f;
-+
-+    f = fopen ("conftest.out", "w");
-+    if (!f)
-+      {
-+	fprintf (stderr, "Cannot write \"%s\": %s\n", "conftest.out",
-+		 strerror (errno));
-+	return 1;
-+      }
-+    h = dlopen ($LIBRPM_STRING, RTLD_LAZY);
-+    if (!h)
-+      {
-+	fprintf (stderr, "dlopen (\"%s\"): %s\n", $LIBRPM_STRING, dlerror ());
-+	return 1;
-+      }
-+    rpmverp = dlsym (h, "RPMVERSION");
-+    if (!rpmverp)
-+      {
-+	fprintf (stderr, "dlsym (\"RPMVERSION\"): %s\n", dlerror ());
-+	return 1;
-+      }
-+    fprintf (stderr, "RPMVERSION is: \"");
-+    fprintf (stderr, "%s\"\n", *rpmverp);
-+
-+    /* Try to find the specific librpm version only for "librpm.so" as we do
-+       not know how to assemble the version string otherwise.  */
-+
-+    if (strcmp ("librpm.so", $LIBRPM_STRING) != 0)
-+      {
-+	fprintf (f, "%s\n", $LIBRPM_STRING);
-+	return 0;
-+      }
-+    else
-+      {
-+	char *h2_name;
-+	void *h2;
-+	int major, minor;
-+
-+	if (sscanf (*rpmverp, "%d.%d", &major, &minor) != 2)
-+	  {
-+	    fprintf (stderr, "Unable to parse RPMVERSION.\n");
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	/* Avoid the square brackets by malloc.  */
-+	h2_name = malloc (64);
-+	sprintf (h2_name, "librpm-%d.%d.so", major, minor);
-+	h2 = dlopen (h2_name, RTLD_LAZY);
-+	if (!h2)
-+	  {
-+	    fprintf (stderr, "dlopen (\"%s\"): %s\n", h2_name, dlerror ());
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	if (h2 != h)
-+	  {
-+	    fprintf (stderr, "dlopen of \"%s\" and \"%s\" are different.\n",
-+		     $LIBRPM_STRING, h2_name);
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	/* Found the valid .so name with a specific version.  */
-+	fprintf (f, "%s\n", h2_name);
-+	return 0;
-+      }
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_run "$LINENO"; then :
-+
-+    DLOPEN_LIBRPM="`cat conftest.out`"
-+    if test "x$DLOPEN_LIBRPM" != "x"; then
-+      HAVE_DLOPEN_LIBRPM=true
-+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLOPEN_LIBRPM" >&5
-+$as_echo "$DLOPEN_LIBRPM" >&6; }
-+    fi
-+
-+fi
-+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-+  conftest.$ac_objext conftest.beam conftest.$ac_ext
-+fi
-+
-+  rm -f conftest.out
-+
-+
-+
-+  if $HAVE_DLOPEN_LIBRPM; then
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking rpm library API compatibility" >&5
-+$as_echo_n "checking rpm library API compatibility... " >&6; }
-+    # The compilation requires -Werror to verify anything.
-+    save_CFLAGS="$CFLAGS"
-+    CFLAGS="$CFLAGS -Werror"
-+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+/* Duplicate here the declarations to verify they match "elfread.c".  */
-+#include <rpm/rpmlib.h>
-+#include <rpm/rpmts.h>
-+#include <rpm/rpmdb.h>
-+#include <rpm/header.h>
-+extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg);
-+extern int rpmReadConfigFiles(const char * file, const char * target);
-+extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi);
-+extern Header rpmdbNextIterator(rpmdbMatchIterator mi);
-+extern rpmts rpmtsCreate(void);
-+extern rpmts rpmtsFree(rpmts ts);
-+extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
-+					    const void * keyp, size_t keylen);
-+
-+int
-+main ()
-+{
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_compile "$LINENO"; then :
-+
-+      LIBRPM_COMPAT=true
-+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+
-+else
-+
-+      LIBRPM_COMPAT=false
-+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+
-+fi
-+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-+    CFLAGS="$save_CFLAGS"
-+
-+    if ! $LIBRPM_COMPAT; then
-+      HAVE_DLOPEN_LIBRPM=false
-+    fi
-+  fi
-+
-+  if $HAVE_DLOPEN_LIBRPM; then
-+    DLOPEN_LIBRPM_STRING='"'"$DLOPEN_LIBRPM"'"'
-+
-+cat >>confdefs.h <<_ACEOF
-+#define DLOPEN_LIBRPM $DLOPEN_LIBRPM_STRING
-+_ACEOF
-+
-+
-+$as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
-+
-+  else
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+    LIBS="$save_LIBS"
-+    if $DLOPEN_REQUIRE; then
-+      as_fn_error "Specific name $LIBRPM was requested but it could not be opened." "$LINENO" 5
-+    fi
-+
-+
-+
-+
-+
-+
-+
-+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-+	if test -n "$ac_tool_prefix"; then
-+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-+$as_echo_n "checking for $ac_word... " >&6; }
-+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then :
-+  $as_echo_n "(cached) " >&6
-+else
-+  case $PKG_CONFIG in
-+  [\\/]* | ?:[\\/]*)
-+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-+  ;;
-+  *)
-+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-+for as_dir in $PATH
-+do
-+  IFS=$as_save_IFS
-+  test -z "$as_dir" && as_dir=.
-+    for ac_exec_ext in '' $ac_executable_extensions; do
-+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-+    break 2
-+  fi
-+done
-+  done
-+IFS=$as_save_IFS
-+
-+  ;;
-+esac
-+fi
-+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-+if test -n "$PKG_CONFIG"; then
-+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-+$as_echo "$PKG_CONFIG" >&6; }
-+else
-+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+fi
-+
-+
-+fi
-+if test -z "$ac_cv_path_PKG_CONFIG"; then
-+  ac_pt_PKG_CONFIG=$PKG_CONFIG
-+  # Extract the first word of "pkg-config", so it can be a program name with args.
-+set dummy pkg-config; ac_word=$2
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-+$as_echo_n "checking for $ac_word... " >&6; }
-+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then :
-+  $as_echo_n "(cached) " >&6
-+else
-+  case $ac_pt_PKG_CONFIG in
-+  [\\/]* | ?:[\\/]*)
-+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-+  ;;
-+  *)
-+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-+for as_dir in $PATH
-+do
-+  IFS=$as_save_IFS
-+  test -z "$as_dir" && as_dir=.
-+    for ac_exec_ext in '' $ac_executable_extensions; do
-+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-+    break 2
-+  fi
-+done
-+  done
-+IFS=$as_save_IFS
-+
-+  ;;
-+esac
-+fi
-+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-+if test -n "$ac_pt_PKG_CONFIG"; then
-+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-+else
-+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+fi
-+
-+  if test "x$ac_pt_PKG_CONFIG" = x; then
-+    PKG_CONFIG=""
-+  else
-+    case $cross_compiling:$ac_tool_warned in
-+yes:)
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-+ac_tool_warned=yes ;;
-+esac
-+    PKG_CONFIG=$ac_pt_PKG_CONFIG
-+  fi
-+else
-+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-+fi
-+
-+fi
-+if test -n "$PKG_CONFIG"; then
-+	_pkg_min_version=0.9.0
-+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+	else
-+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+		PKG_CONFIG=""
-+	fi
-+fi
-+
-+pkg_failed=no
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RPM" >&5
-+$as_echo_n "checking for RPM... " >&6; }
-+
-+if test -n "$RPM_CFLAGS"; then
-+    pkg_cv_RPM_CFLAGS="$RPM_CFLAGS"
-+ elif test -n "$PKG_CONFIG"; then
-+    if test -n "$PKG_CONFIG" && \
-+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"rpm\""; } >&5
-+  ($PKG_CONFIG --exists --print-errors "rpm") 2>&5
-+  ac_status=$?
-+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-+  test $ac_status = 0; }; then
-+  pkg_cv_RPM_CFLAGS=`$PKG_CONFIG --cflags "rpm" 2>/dev/null`
-+		      test "x$?" != "x0" && pkg_failed=yes
-+else
-+  pkg_failed=yes
-+fi
-+ else
-+    pkg_failed=untried
-+fi
-+if test -n "$RPM_LIBS"; then
-+    pkg_cv_RPM_LIBS="$RPM_LIBS"
-+ elif test -n "$PKG_CONFIG"; then
-+    if test -n "$PKG_CONFIG" && \
-+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"rpm\""; } >&5
-+  ($PKG_CONFIG --exists --print-errors "rpm") 2>&5
-+  ac_status=$?
-+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-+  test $ac_status = 0; }; then
-+  pkg_cv_RPM_LIBS=`$PKG_CONFIG --libs "rpm" 2>/dev/null`
-+		      test "x$?" != "x0" && pkg_failed=yes
-+else
-+  pkg_failed=yes
-+fi
-+ else
-+    pkg_failed=untried
-+fi
-+
-+
-+
-+if test $pkg_failed = yes; then
-+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+
-+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-+        _pkg_short_errors_supported=yes
-+else
-+        _pkg_short_errors_supported=no
-+fi
-+        if test $_pkg_short_errors_supported = yes; then
-+	        RPM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "rpm" 2>&1`
-+        else
-+	        RPM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "rpm" 2>&1`
-+        fi
-+	# Put the nasty error message in config.log where it belongs
-+	echo "$RPM_PKG_ERRORS" >&5
-+
-+	HAVE_LIBRPM=false
-+elif test $pkg_failed = untried; then
-+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+	HAVE_LIBRPM=false
-+else
-+	RPM_CFLAGS=$pkg_cv_RPM_CFLAGS
-+	RPM_LIBS=$pkg_cv_RPM_LIBS
-+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+	HAVE_LIBRPM=true
-+fi
-+
-+    if $HAVE_LIBRPM; then
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking rpm library API compatibility" >&5
-+$as_echo_n "checking rpm library API compatibility... " >&6; }
-+    # The compilation requires -Werror to verify anything.
-+    save_CFLAGS="$CFLAGS"
-+    CFLAGS="$CFLAGS -Werror"
-+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+/* Duplicate here the declarations to verify they match "elfread.c".  */
-+#include <rpm/rpmlib.h>
-+#include <rpm/rpmts.h>
-+#include <rpm/rpmdb.h>
-+#include <rpm/header.h>
-+extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg);
-+extern int rpmReadConfigFiles(const char * file, const char * target);
-+extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi);
-+extern Header rpmdbNextIterator(rpmdbMatchIterator mi);
-+extern rpmts rpmtsCreate(void);
-+extern rpmts rpmtsFree(rpmts ts);
-+extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
-+					    const void * keyp, size_t keylen);
-+
-+int
-+main ()
-+{
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_compile "$LINENO"; then :
-+
-+      LIBRPM_COMPAT=true
-+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+
-+else
-+
-+      LIBRPM_COMPAT=false
-+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+
-+fi
-+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-+    CFLAGS="$save_CFLAGS"
-+
-+      if ! $LIBRPM_COMPAT; then
-+	HAVE_LIBRPM=false
-+	RPM_PKG_ERRORS="Found $LIBRPM API is incompatibile with this GDB"
-+      fi
-+    fi
-+
-+    if $HAVE_LIBRPM; then
-+
-+$as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
-+
-+      CFLAGS="$CFLAGS $RPM_CFLAGS"
-+      LIBS="$LIBS $RPM_LIBS"
-+    else
-+      if $RPM_REQUIRE; then
-+	as_fn_error "$RPM_PKG_ERRORS" "$LINENO" 5
-+      else
-+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $RPM_PKG_ERRORS" >&5
-+$as_echo "$as_me: WARNING: $RPM_PKG_ERRORS" >&2;}
-+      fi
-+    fi
-+  fi
-+fi
-+
- 
- 
- subdirs="$subdirs testsuite"
-diff --git a/gdb/configure.ac b/gdb/configure.ac
---- a/gdb/configure.ac
-+++ b/gdb/configure.ac
-@@ -173,6 +173,200 @@ AC_DEFINE_DIR(AUTO_LOAD_SAFE_PATH, escape_dir,
- 	      [Directories safe to hold auto-loaded files.])
- AC_MSG_RESULT([$with_auto_load_safe_path])
- 
-+# Integration with rpm library to support missing debuginfo suggestions.
-+# --without-rpm: Disable any rpm support.
-+# --with-rpm=libname.so: Try to dynamically open `libname.so' during runtime.
-+#   Even with runtime missing `libname.so' GDB will still other run correctly.
-+#   Missing `libname.so' during ./configure will abort the configuration.
-+# --with-rpm=librpm.so: Like `--with-rpm=libname.so' but try to find specific
-+#   minor version first such as `librpm-4.6.so' as minor version differences
-+#   mean API+ABI incompatibility.  If the specific match versioned library name
-+#   could not be found still open dynamically at least `librpm.so'.
-+# --with-rpm: Like `--with-rpm=librpm.so' but if any of its detection fails try
-+#   to find librpm for compilation-time linking by pkg-config.  GDB binary will
-+#   be probably linked with the version specific library (as `librpm-4.6.so').
-+#   Failure to find librpm by pkg-config will abort the configuration.
-+# (default) --with-rpm=auto: Like `--with-rpm=librpm.so' but if even pkg-config
-+#   cannot find librpm use to the rpmless compilation (like `--without-rpm').
-+
-+AC_ARG_WITH([rpm],
-+  [AS_HELP_STRING([--with-rpm],
-+                  [query rpm database for missing debuginfos (yes/no, def. auto=librpm.so)])], [], [with_rpm="auto"])
-+
-+m4_pattern_allow([^AC_MSG_ERROR$])
-+m4_pattern_allow([^AC_MSG_WARN$])
-+if test "x$with_rpm" != "xno"; then
-+  if test "x$with_rpm" = "xyes"; then
-+    LIBRPM="librpm.so"
-+    RPM_REQUIRE=true
-+    DLOPEN_REQUIRE=false
-+  elif test "x$with_rpm" = "xauto"; then
-+    LIBRPM="librpm.so"
-+    RPM_REQUIRE=false
-+    DLOPEN_REQUIRE=false
-+  else
-+    LIBRPM="$with_rpm"
-+    RPM_REQUIRE=true
-+    DLOPEN_REQUIRE=true
-+  fi
-+  LIBRPM_STRING='"'"$LIBRPM"'"'
-+
-+  AC_MSG_CHECKING([specific librpm version])
-+  HAVE_DLOPEN_LIBRPM=false
-+  save_LIBS="$LIBS"
-+  LIBS="$LIBS -ldl"
-+  AC_RUN_IFELSE(AC_LANG_PROGRAM([[
-+#include <rpm/rpmlib.h>
-+#include <dlfcn.h>
-+#include <errno.h>
-+#include <string.h>
-+  ]], [[
-+    void *h;
-+    const char *const *rpmverp;
-+    FILE *f;
-+
-+    f = fopen ("conftest.out", "w");
-+    if (!f)
-+      {
-+	fprintf (stderr, "Cannot write \"%s\": %s\n", "conftest.out",
-+		 strerror (errno));
-+	return 1;
-+      }
-+    h = dlopen ($LIBRPM_STRING, RTLD_LAZY);
-+    if (!h)
-+      {
-+	fprintf (stderr, "dlopen (\"%s\"): %s\n", $LIBRPM_STRING, dlerror ());
-+	return 1;
-+      }
-+    rpmverp = dlsym (h, "RPMVERSION");
-+    if (!rpmverp)
-+      {
-+	fprintf (stderr, "dlsym (\"RPMVERSION\"): %s\n", dlerror ());
-+	return 1;
-+      }
-+    fprintf (stderr, "RPMVERSION is: \"");
-+    fprintf (stderr, "%s\"\n", *rpmverp);
-+
-+    /* Try to find the specific librpm version only for "librpm.so" as we do
-+       not know how to assemble the version string otherwise.  */
-+
-+    if (strcmp ("librpm.so", $LIBRPM_STRING) != 0)
-+      {
-+	fprintf (f, "%s\n", $LIBRPM_STRING);
-+	return 0;
-+      }
-+    else
-+      {
-+	char *h2_name;
-+	void *h2;
-+	int major, minor;
-+
-+	if (sscanf (*rpmverp, "%d.%d", &major, &minor) != 2)
-+	  {
-+	    fprintf (stderr, "Unable to parse RPMVERSION.\n");
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	/* Avoid the square brackets by malloc.  */
-+	h2_name = malloc (64);
-+	sprintf (h2_name, "librpm-%d.%d.so", major, minor);
-+	h2 = dlopen (h2_name, RTLD_LAZY);
-+	if (!h2)
-+	  {
-+	    fprintf (stderr, "dlopen (\"%s\"): %s\n", h2_name, dlerror ());
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	if (h2 != h)
-+	  {
-+	    fprintf (stderr, "dlopen of \"%s\" and \"%s\" are different.\n",
-+		     $LIBRPM_STRING, h2_name);
-+	    fprintf (f, "%s\n", $LIBRPM_STRING);
-+	    return 0;
-+	  }
-+	/* Found the valid .so name with a specific version.  */
-+	fprintf (f, "%s\n", h2_name);
-+	return 0;
-+      }
-+  ]]), [
-+    DLOPEN_LIBRPM="`cat conftest.out`"
-+    if test "x$DLOPEN_LIBRPM" != "x"; then
-+      HAVE_DLOPEN_LIBRPM=true
-+      AC_MSG_RESULT($DLOPEN_LIBRPM)
-+    fi
-+  ])
-+  rm -f conftest.out
-+
-+  m4_define([CHECK_LIBRPM_COMPAT], [
-+    AC_MSG_CHECKING([rpm library API compatibility])
-+    # The compilation requires -Werror to verify anything.
-+    save_CFLAGS="$CFLAGS"
-+    CFLAGS="$CFLAGS -Werror"
-+    AC_COMPILE_IFELSE(AC_LANG_PROGRAM([[
-+/* Duplicate here the declarations to verify they match "elfread.c".  */
-+#include <rpm/rpmlib.h>
-+#include <rpm/rpmts.h>
-+#include <rpm/rpmdb.h>
-+#include <rpm/header.h>
-+extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg);
-+extern int rpmReadConfigFiles(const char * file, const char * target);
-+extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi);
-+extern Header rpmdbNextIterator(rpmdbMatchIterator mi);
-+extern rpmts rpmtsCreate(void);
-+extern rpmts rpmtsFree(rpmts ts);
-+extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
-+					    const void * keyp, size_t keylen);
-+    ]]), [
-+      LIBRPM_COMPAT=true
-+      AC_MSG_RESULT(yes)
-+    ], [
-+      LIBRPM_COMPAT=false
-+      AC_MSG_RESULT(no)
-+    ])
-+    CFLAGS="$save_CFLAGS"
-+  ])
-+
-+  if $HAVE_DLOPEN_LIBRPM; then
-+    CHECK_LIBRPM_COMPAT
-+    if ! $LIBRPM_COMPAT; then
-+      HAVE_DLOPEN_LIBRPM=false
-+    fi
-+  fi
-+
-+  if $HAVE_DLOPEN_LIBRPM; then
-+    DLOPEN_LIBRPM_STRING='"'"$DLOPEN_LIBRPM"'"'
-+    AC_DEFINE_UNQUOTED(DLOPEN_LIBRPM, $DLOPEN_LIBRPM_STRING, [librpm version specific library name to dlopen.])
-+    AC_DEFINE(HAVE_LIBRPM, 1, [Define if librpm library is being used.])
-+  else
-+    AC_MSG_RESULT(no)
-+    LIBS="$save_LIBS"
-+    if $DLOPEN_REQUIRE; then
-+      AC_MSG_ERROR([Specific name $LIBRPM was requested but it could not be opened.])
-+    fi
-+    PKG_CHECK_MODULES(RPM, rpm, [HAVE_LIBRPM=true], [HAVE_LIBRPM=false])
-+
-+    if $HAVE_LIBRPM; then
-+      CHECK_LIBRPM_COMPAT
-+      if ! $LIBRPM_COMPAT; then
-+	HAVE_LIBRPM=false
-+	RPM_PKG_ERRORS="Found $LIBRPM API is incompatibile with this GDB"
-+      fi
-+    fi
-+
-+    if $HAVE_LIBRPM; then
-+      AC_DEFINE(HAVE_LIBRPM, 1, [Define if librpm library is being used.])
-+      CFLAGS="$CFLAGS $RPM_CFLAGS"
-+      LIBS="$LIBS $RPM_LIBS"
-+    else
-+      if $RPM_REQUIRE; then
-+	AC_MSG_ERROR($RPM_PKG_ERRORS)
-+      else
-+	AC_MSG_WARN($RPM_PKG_ERRORS)
-+      fi
-+    fi
-+  fi
-+fi
-+
- AC_CONFIG_SUBDIRS(testsuite)
- 
- # Check whether to support alternative target configurations
-diff --git a/gdb/event-top.c b/gdb/event-top.c
---- a/gdb/event-top.c
-+++ b/gdb/event-top.c
-@@ -43,6 +43,7 @@
- #include "async-event.h"
- #include "bt-utils.h"
- #include "pager.h"
-+#include "symfile.h"
- 
- /* readline include files.  */
- #include "readline/readline.h"
-@@ -404,6 +405,8 @@ display_gdb_prompt (const char *new_prompt)
-   /* Reset the nesting depth used when trace-commands is set.  */
-   reset_command_nest_depth ();
- 
-+  debug_flush_missing ();
-+
-   /* Do not call the python hook on an explicit prompt change as
-      passed to this function, as this forms a secondary/local prompt,
-      IE, displayed but not set.  */
-@@ -788,7 +791,10 @@ command_line_handler (gdb::unique_xmalloc_ptr<char> &&rl)
-       command_handler (cmd);
- 
-       if (ui->prompt_state != PROMPTED)
--	display_gdb_prompt (0);
-+	{
-+	  debug_flush_missing ();
-+	  display_gdb_prompt (0);
-+	}
-     }
- }
- 
-diff --git a/gdb/symfile.h b/gdb/symfile.h
---- a/gdb/symfile.h
-+++ b/gdb/symfile.h
-@@ -366,6 +366,7 @@ extern void generic_load (const char *args, int from_tty);
- /* build-id support.  */
- extern struct bfd_build_id *build_id_addr_get (CORE_ADDR addr);
- extern void debug_print_missing (const char *binary, const char *debug);
-+extern void debug_flush_missing (void);
- #define BUILD_ID_MAIN_EXECUTABLE_FILENAME _("the main executable file")
- 
- /* From minidebug.c.  */

diff --git a/gdb-6.6-buildid-locate-solib-missing-ids.patch b/gdb-6.6-buildid-locate-solib-missing-ids.patch
index e9ec7b5..5847c2e 100644
--- a/gdb-6.6-buildid-locate-solib-missing-ids.patch
+++ b/gdb-6.6-buildid-locate-solib-missing-ids.patch
@@ -130,7 +130,7 @@ diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp b/gdb/t
 new file mode 100644
 --- /dev/null
 +++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp
-@@ -0,0 +1,105 @@
+@@ -0,0 +1,104 @@
 +# Copyright 2016 Free Software Foundation, Inc.
 +
 +# This program is free software; you can redistribute it and/or modify
@@ -146,9 +146,7 @@ new file mode 100644
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
-+if {[skip_shlib_tests]} {
-+    return 0
-+}
++require allow_shlib_tests
 +
 +set testfile "gcore-buildid-exec-but-not-solib"
 +set srcmainfile ${testfile}-main.c
@@ -226,7 +224,8 @@ new file mode 100644
 +remote_exec build "ln -s /lib64     ${debugdir}/"
 +# /usr is not needed, all the libs are in /lib64: libm.so.6 libc.so.6 ld-linux-x86-64.so.2
 +
-+gdb_test "set solib-absolute-prefix $debugdir"
++gdb_test_no_output "set solib-absolute-prefix $debugdir" \
++    "set solib-absolute-prefix"
 +
 +gdb_test_no_output "set debug-file-directory $debugdir" "set debug-file-directory"
 +

diff --git a/gdb-6.6-buildid-locate.patch b/gdb-6.6-buildid-locate.patch
index 833eb70..c4e6ff9 100644
--- a/gdb-6.6-buildid-locate.patch
+++ b/gdb-6.6-buildid-locate.patch
@@ -553,13 +553,13 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 +
 +      /* We expect to be silent on the non-existing files.  */
 +      gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget);
-+
+ 
+-      return {};
 +      if (debug_bfd == NULL)
 +	{
 +	  if (separate_debug_file_debug)
 +	    gdb_printf (gdb_stdlog, _(" no, unable to open.\n"));
- 
--      return {};
++
 +	  continue;
 +	}
 +
@@ -583,6 +583,8 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
      {
        if (separate_debug_file_debug)
 -	gdb_printf (gdb_stdlog, _(" no, build-id does not match.\n"));
+-
+-      return {};
 +	gdb_printf (gdb_stdlog, _(" yes!\n"));
 +    }
 +  else
@@ -590,8 +592,7 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 +      /* If none of the real files is found report as missing file
 +	 always the non-.%u-suffixed file.  */
 +      std::string link0 = orig_link;
- 
--      return {};
++
 +      /* If the symlink has target request to install the target.
 +	 BASE-debuginfo.rpm contains the symlink but BASE.rpm may be missing.
 +	 https://bugzilla.redhat.com/show_bug.cgi?id=981154  */
@@ -665,7 +666,7 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
  	  if (debug_bfd != NULL)
  	    return debug_bfd;
  	}
-@@ -190,30 +694,662 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
+@@ -190,20 +694,178 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
    return {};
  }
  
@@ -683,446 +684,6 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 +  return result;
 +}
 +
-+void debug_flush_missing (void);
-+
-+#ifdef HAVE_LIBRPM
-+
-+#include <rpm/rpmlib.h>
-+#include <rpm/rpmts.h>
-+#include <rpm/rpmdb.h>
-+#include <rpm/header.h>
-+#ifdef DLOPEN_LIBRPM
-+#include <dlfcn.h>
-+#endif
-+
-+/* Workarodun https://bugzilla.redhat.com/show_bug.cgi?id=643031
-+   librpm must not exit() an application on SIGINT
-+
-+   Enable or disable a signal handler.  SIGNUM: signal to enable (or disable
-+   if negative).  HANDLER: sa_sigaction handler (or NULL to use
-+   rpmsqHandler()).  Returns: no. of refs, -1 on error.  */
-+extern int rpmsqEnable (int signum, /* rpmsqAction_t handler */ void *handler);
-+int
-+rpmsqEnable (int signum, /* rpmsqAction_t handler */ void *handler)
-+{
-+  return 0;
-+}
-+
-+/* This MISSING_RPM_HASH tracker is used to collect all the missing rpm files
-+   and avoid their duplicities during a single inferior run.  */
-+
-+static struct htab *missing_rpm_hash;
-+
-+/* This MISSING_RPM_LIST tracker is used to collect and print as a single line
-+   all the rpms right before the nearest GDB prompt.  It gets cleared after
-+   each such print (it is questionable if we should clear it after the print).
-+   */
-+
-+struct missing_rpm
-+  {
-+    struct missing_rpm *next;
-+    char rpm[1];
-+  };
-+static struct missing_rpm *missing_rpm_list;
-+static int missing_rpm_list_entries;
-+
-+/* Returns the count of newly added rpms.  */
-+
-+static int
-+#ifndef GDB_INDEX_VERIFY_VENDOR
-+missing_rpm_enlist (const char *filename)
-+#else
-+missing_rpm_enlist_1 (const char *filename, int verify_vendor)
-+#endif
-+{
-+  static int rpm_init_done = 0;
-+  rpmts ts;
-+  rpmdbMatchIterator mi;
-+  int count = 0;
-+
-+#ifdef DLOPEN_LIBRPM
-+  /* Duplicate here the declarations to verify they match.  The same sanity
-+     check is present also in `configure.ac'.  */
-+  extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg);
-+  static char *(*headerFormat_p) (Header h, const char * fmt, errmsg_t *errmsg);
-+  extern int rpmReadConfigFiles(const char * file, const char * target);
-+  static int (*rpmReadConfigFiles_p) (const char * file, const char * target);
-+  extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi);
-+  static rpmdbMatchIterator (*rpmdbFreeIterator_p) (rpmdbMatchIterator mi);
-+  extern Header rpmdbNextIterator(rpmdbMatchIterator mi);
-+  static Header (*rpmdbNextIterator_p) (rpmdbMatchIterator mi);
-+  extern rpmts rpmtsCreate(void);
-+  static rpmts (*rpmtsCreate_p) (void);
-+  extern rpmts rpmtsFree(rpmts ts);
-+  static rpmts (*rpmtsFree_p) (rpmts ts);
-+  extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
-+                                              const void * keyp, size_t keylen);
-+  static rpmdbMatchIterator (*rpmtsInitIterator_p) (const rpmts ts,
-+						    rpmTag rpmtag,
-+						    const void *keyp,
-+						    size_t keylen);
-+#else	/* !DLOPEN_LIBRPM */
-+# define headerFormat_p headerFormat
-+# define rpmReadConfigFiles_p rpmReadConfigFiles
-+# define rpmdbFreeIterator_p rpmdbFreeIterator
-+# define rpmdbNextIterator_p rpmdbNextIterator
-+# define rpmtsCreate_p rpmtsCreate
-+# define rpmtsFree_p rpmtsFree
-+# define rpmtsInitIterator_p rpmtsInitIterator
-+#endif	/* !DLOPEN_LIBRPM */
-+
-+  gdb_assert (filename != NULL);
-+
-+  if (strcmp (filename, BUILD_ID_MAIN_EXECUTABLE_FILENAME) == 0)
-+    return 0;
-+
-+  if (is_target_filename (filename))
-+    return 0;
-+
-+  if (filename[0] != '/')
-+    {
-+      warning (_("Ignoring non-absolute filename: <%s>"), filename);
-+      return 0;
-+    }
-+
-+  if (!rpm_init_done)
-+    {
-+      static int init_tried;
-+
-+      /* Already failed the initialization before?  */
-+      if (init_tried)
-+        return 0;
-+      init_tried = 1;
-+
-+#ifdef DLOPEN_LIBRPM
-+      {
-+	void *h;
-+
-+	h = dlopen (DLOPEN_LIBRPM, RTLD_LAZY);
-+	if (!h)
-+	  {
-+	    warning (_("Unable to open \"%s\" (%s), "
-+		      "missing debuginfos notifications will not be displayed"),
-+		     DLOPEN_LIBRPM, dlerror ());
-+	    return 0;
-+	  }
-+
-+	if (!((headerFormat_p = (char *(*) (Header h, const char * fmt, errmsg_t *errmsg)) dlsym (h, "headerFormat"))
-+	      && (rpmReadConfigFiles_p = (int (*) (const char * file, const char * target)) dlsym (h, "rpmReadConfigFiles"))
-+	      && (rpmdbFreeIterator_p = (rpmdbMatchIterator (*) (rpmdbMatchIterator mi)) dlsym (h, "rpmdbFreeIterator"))
-+	      && (rpmdbNextIterator_p = (Header (*) (rpmdbMatchIterator mi)) dlsym (h, "rpmdbNextIterator"))
-+	      && (rpmtsCreate_p = (rpmts (*) (void)) dlsym (h, "rpmtsCreate"))
-+	      && (rpmtsFree_p = (rpmts (*) (rpmts ts)) dlsym (h, "rpmtsFree"))
-+	      && (rpmtsInitIterator_p = (rpmdbMatchIterator (*) (const rpmts ts, rpmTag rpmtag, const void *keyp, size_t keylen)) dlsym (h, "rpmtsInitIterator"))))
-+	  {
-+	    warning (_("Opened library \"%s\" is incompatible (%s), "
-+		      "missing debuginfos notifications will not be displayed"),
-+		     DLOPEN_LIBRPM, dlerror ());
-+	    if (dlclose (h))
-+	      warning (_("Error closing library \"%s\": %s\n"), DLOPEN_LIBRPM,
-+		       dlerror ());
-+	    return 0;
-+	  }
-+      }
-+#endif	/* DLOPEN_LIBRPM */
-+
-+      if (rpmReadConfigFiles_p (NULL, NULL) != 0)
-+	{
-+	  warning (_("Error reading the rpm configuration files"));
-+	  return 0;
-+	}
-+
-+      rpm_init_done = 1;
-+    }
-+
-+  ts = rpmtsCreate_p ();
-+
-+  mi = rpmtsInitIterator_p (ts, RPMTAG_BASENAMES, filename, 0);
-+  if (mi != NULL)
-+    {
-+#ifndef GDB_INDEX_VERIFY_VENDOR
-+      for (;;)
-+#else
-+      if (!verify_vendor) for (;;)
-+#endif
-+	{
-+	  Header h;
-+	  char *debuginfo, **slot, *s, *s2;
-+	  errmsg_t err;
-+	  size_t srcrpmlen = sizeof (".src.rpm") - 1;
-+	  size_t debuginfolen = sizeof ("-debuginfo") - 1;
-+	  rpmdbMatchIterator mi_debuginfo;
-+
-+	  h = rpmdbNextIterator_p (mi);
-+	  if (h == NULL)
-+	    break;
-+
-+	  /* Verify the debuginfo file is not already installed.  */
-+
-+	  debuginfo = headerFormat_p (h, "%{sourcerpm}-debuginfo.%{arch}",
-+				      &err);
-+	  if (!debuginfo)
-+	    {
-+	      warning (_("Error querying the rpm file `%s': %s"), filename,
-+	               err);
-+	      continue;
-+	    }
-+	  /* s = `.src.rpm-debuginfo.%{arch}' */
-+	  s = strrchr (debuginfo, '-') - srcrpmlen;
-+	  s2 = NULL;
-+	  if (s > debuginfo && memcmp (s, ".src.rpm", srcrpmlen) == 0)
-+	    {
-+	      /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */
-+	      s2 = (char *) memrchr (debuginfo, '-', s - debuginfo);
-+	    }
-+	  if (s2)
-+	    {
-+	      /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */
-+	      s2 = (char *) memrchr (debuginfo, '-', s2 - debuginfo);
-+	    }
-+	  if (!s2)
-+	    {
-+	      warning (_("Error querying the rpm file `%s': %s"), filename,
-+	               debuginfo);
-+	      xfree (debuginfo);
-+	      continue;
-+	    }
-+	  /* s = `.src.rpm-debuginfo.%{arch}' */
-+	  /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */
-+	  memmove (s2 + debuginfolen, s2, s - s2);
-+	  memcpy (s2, "-debuginfo", debuginfolen);
-+	  /* s = `XXXX.%{arch}' */
-+	  /* strlen ("XXXX") == srcrpmlen + debuginfolen */
-+	  /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */
-+	  /* strlen ("XX") == srcrpmlen */
-+	  memmove (s + debuginfolen, s + srcrpmlen + debuginfolen,
-+		   strlen (s + srcrpmlen + debuginfolen) + 1);
-+	  /* s = `-debuginfo-%{version}-%{release}.%{arch}' */
-+
-+	  /* RPMDBI_PACKAGES requires keylen == sizeof (int).  */
-+	  /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel().  */
-+	  mi_debuginfo = rpmtsInitIterator_p (ts, (rpmTag) RPMDBI_LABEL, debuginfo, 0);
-+	  xfree (debuginfo);
-+	  if (mi_debuginfo)
-+	    {
-+	      rpmdbFreeIterator_p (mi_debuginfo);
-+	      count = 0;
-+	      break;
-+	    }
-+
-+	  /* The allocated memory gets utilized below for MISSING_RPM_HASH.  */
-+	  debuginfo = headerFormat_p (h,
-+				      "%{name}-%{version}-%{release}.%{arch}",
-+				      &err);
-+	  if (!debuginfo)
-+	    {
-+	      warning (_("Error querying the rpm file `%s': %s"), filename,
-+	               err);
-+	      continue;
-+	    }
-+
-+	  /* Base package name for `debuginfo-install'.  We do not use the
-+	     `yum' command directly as the line
-+		 yum --enablerepo='*debug*' install NAME-debuginfo.ARCH
-+	     would be more complicated than just:
-+		 debuginfo-install NAME-VERSION-RELEASE.ARCH
-+	     Do not supply the rpm base name (derived from .src.rpm name) as
-+	     debuginfo-install is unable to install the debuginfo package if
-+	     the base name PKG binary rpm is not installed while for example
-+	     PKG-libs would be installed (RH Bug 467901).
-+	     FUTURE: After multiple debuginfo versions simultaneously installed
-+	     get supported the support for the VERSION-RELEASE tags handling
-+	     may need an update.  */
-+
-+	  if (missing_rpm_hash == NULL)
-+	    {
-+	      /* DEL_F is passed NULL as MISSING_RPM_LIST's HTAB_DELETE
-+		 should not deallocate the entries.  */
-+
-+	      missing_rpm_hash = htab_create_alloc (64, htab_hash_string,
-+			       (int (*) (const void *, const void *)) streq,
-+						    NULL, xcalloc, xfree);
-+	    }
-+	  slot = (char **) htab_find_slot (missing_rpm_hash, debuginfo, INSERT);
-+	  /* XCALLOC never returns NULL.  */
-+	  gdb_assert (slot != NULL);
-+	  if (*slot == NULL)
-+	    {
-+	      struct missing_rpm *missing_rpm;
-+
-+	      *slot = debuginfo;
-+
-+	      missing_rpm = (struct missing_rpm *) xmalloc (sizeof (*missing_rpm) + strlen (debuginfo));
-+	      strcpy (missing_rpm->rpm, debuginfo);
-+	      missing_rpm->next = missing_rpm_list;
-+	      missing_rpm_list = missing_rpm;
-+	      missing_rpm_list_entries++;
-+	    }
-+	  else
-+	    xfree (debuginfo);
-+	  count++;
-+	}
-+#ifdef GDB_INDEX_VERIFY_VENDOR
-+      else /* verify_vendor */
-+	{
-+	  int vendor_pass = 0, vendor_fail = 0;
-+
-+	  for (;;)
-+	    {
-+	      Header h;
-+	      errmsg_t err;
-+	      char *vendor;
-+
-+	      h = rpmdbNextIterator_p (mi);
-+	      if (h == NULL)
-+		break;
-+
-+	      vendor = headerFormat_p (h, "%{vendor}", &err);
-+	      if (!vendor)
-+		{
-+		  warning (_("Error querying the rpm file `%s': %s"), filename,
-+			   err);
-+		  continue;
-+		}
-+	      if (strcmp (vendor, "Red Hat, Inc.") == 0)
-+		vendor_pass = 1;
-+	      else
-+		vendor_fail = 1;
-+	      xfree (vendor);
-+	    }
-+	  count = vendor_pass != 0 && vendor_fail == 0;
-+	}
-+#endif
-+
-+      rpmdbFreeIterator_p (mi);
-+    }
-+
-+  rpmtsFree_p (ts);
-+
-+  return count;
-+}
-+
-+#ifdef GDB_INDEX_VERIFY_VENDOR
-+missing_rpm_enlist (const char *filename)
-+{
-+  return missing_rpm_enlist_1 (filename, 0);
-+}
-+
-+extern int rpm_verify_vendor (const char *filename);
-+int
-+rpm_verify_vendor (const char *filename)
-+{
-+  return missing_rpm_enlist_1 (filename, 1);
-+}
-+#endif
-+
-+static bool
-+missing_rpm_list_compar (const char *ap, const char *bp)
-+{
-+  return strcoll (ap, bp) < 0;
-+}
-+
-+/* It returns a NULL-terminated array of strings needing to be FREEd.  It may
-+   also return only NULL.  */
-+
-+static void
-+missing_rpm_list_print (void)
-+{
-+  struct missing_rpm *list_iter;
-+
-+  if (missing_rpm_list_entries == 0)
-+    return;
-+
-+  std::vector<const char *> array (missing_rpm_list_entries);
-+  size_t idx = 0;
-+
-+  for (list_iter = missing_rpm_list; list_iter != NULL;
-+       list_iter = list_iter->next)
-+    {
-+      array[idx++] = list_iter->rpm;
-+    }
-+  gdb_assert (idx == missing_rpm_list_entries);
-+
-+  std::sort (array.begin (), array.end (), missing_rpm_list_compar);
-+
-+  /* We zero out the number of missing RPMs here because of a nasty
-+     bug (see RHBZ 1801974).
-+
-+     When we call 'puts_unfiltered' below, if pagination is on and if
-+     the number of missing RPMs is big enough to trigger pagination,
-+     we will end up in an infinite recursion.  The call chain looks
-+     like this:
-+
-+     missing_rpm_list_print -> puts_unfiltered -> fputs_maybe_filtered
-+     -> prompt_for_continue -> display_gdb_prompt ->
-+     debug_flush_missing -> missing_rpm_list_print ...
-+
-+     For this reason, we make sure MISSING_RPM_LIST_ENTRIES is zero
-+     *before* calling any print function.
-+     
-+     Note: kevinb/2023-02-22: The code below used to call
-+     puts_unfiltered() and printf_unfiltered(), but calls to these
-+     functions have been replaced by calls to gdb_printf().  The call
-+     chain shown above (probably) used to be the case at one time and
-+     hopefully something similar is still the case now that
-+     gdb_printf() is being used instead.  */
-+  missing_rpm_list_entries = 0;
-+
-+  gdb_printf (_("Missing separate debuginfos, use: %s"),
-+#ifdef DNF_DEBUGINFO_INSTALL
-+		     "dnf "
-+#endif
-+		     "debuginfo-install");
-+  for (const char *el : array)
-+    {
-+      gdb_printf (" %s", el);
-+    }
-+  gdb_printf ("\n");
-+
-+  while (missing_rpm_list != NULL)
-+    {
-+      list_iter = missing_rpm_list;
-+      missing_rpm_list = list_iter->next;
-+      xfree (list_iter);
-+    }
-+}
-+
-+static void
-+missing_rpm_change (void)
-+{
-+  debug_flush_missing ();
-+
-+  gdb_assert (missing_rpm_list == NULL);
-+  if (missing_rpm_hash != NULL)
-+    {
-+      htab_delete (missing_rpm_hash);
-+      missing_rpm_hash = NULL;
-+    }
-+}
-+
-+enum missing_exec
-+  {
-+    /* Init state.  EXEC_BFD also still could be NULL.  */
-+    MISSING_EXEC_NOT_TRIED,
-+    /* We saw a non-NULL EXEC_BFD but RPM has no info about it.  */
-+    MISSING_EXEC_NOT_FOUND,
-+    /* We found EXEC_BFD by RPM and we either have its symbols (either embedded
-+       or separate) or the main executable's RPM is now contained in
-+       MISSING_RPM_HASH.  */
-+    MISSING_EXEC_ENLISTED
-+  };
-+static enum missing_exec missing_exec = MISSING_EXEC_NOT_TRIED;
-+
-+#endif	/* HAVE_LIBRPM */
-+
-+void
-+debug_flush_missing (void)
-+{
-+#ifdef HAVE_LIBRPM
-+  missing_rpm_list_print ();
-+#endif
-+}
-+
 +/* This MISSING_FILEPAIR_HASH tracker is used only for the duplicite messages
 +     yum --enablerepo='*debug*' install ...
 +   avoidance.  */
@@ -1178,17 +739,11 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 +      /* All their memory came just from missing_filepair_OBSTACK.  */
 +      missing_filepair_hash = NULL;
 +    }
-+#ifdef HAVE_LIBRPM
-+  missing_exec = MISSING_EXEC_NOT_TRIED;
-+#endif
 +}
 +
 +static void
 +debug_print_executable_changed (struct program_space *pspace, bool reload_p)
 +{
-+#ifdef HAVE_LIBRPM
-+  missing_rpm_change ();
-+#endif
 +  missing_filepair_change ();
 +}
 +
@@ -1255,55 +810,30 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 +
 +  *slot = missing_filepair;
 +
-+#ifdef HAVE_LIBRPM
-+  if (missing_exec == MISSING_EXEC_NOT_TRIED)
-+    {
-+      const char *execfilename = get_exec_file (0);
++  /* We do not collect and flush these messages as each such message
++     already requires its own separate lines.  */
 +
-+      if (execfilename != NULL)
-+	{
-+	  if (missing_rpm_enlist (execfilename) == 0)
-+	    missing_exec = MISSING_EXEC_NOT_FOUND;
-+	  else
-+	    missing_exec = MISSING_EXEC_ENLISTED;
-+	}
-+    }
-+  if (missing_exec != MISSING_EXEC_ENLISTED)
-+    if ((binary[0] == 0 || missing_rpm_enlist (binary) == 0)
-+	&& (debug == NULL || missing_rpm_enlist (debug) == 0))
-+#endif	/* HAVE_LIBRPM */
-+      {
-+	/* We do not collect and flush these messages as each such message
-+	   already requires its own separate lines.  */
-+
-+	gdb_printf (gdb_stdlog,
-+		    _("Missing separate debuginfo for %s.\n"), binary);
-+	if (debug != NULL)
-+	{
-+	  if (access (debug, F_OK) == 0) {
-+	    gdb_printf (gdb_stdlog, _("Try: %s %s\n"),
++  gdb_printf (gdb_stdlog,
++	      _("Missing separate debuginfo for %s.\n"), binary);
++  if (debug != NULL)
++    {
++      gdb_printf (gdb_stdlog, _("Try: %s %s\n"),
 +#ifdef DNF_DEBUGINFO_INSTALL
-+			"dnf"
++		  "dnf"
 +#else
-+			"yum"
++		  "yum"
 +#endif
-+			" --enablerepo='*debug*' install", debug);
-+	  } else
-+	    gdb_printf (gdb_stdlog, _("The debuginfo package for this file is probably broken.\n"));
-+	}
-+      }
++		  " --enablerepo='*debug*' install", debug);
++    }
 +}
 +
  /* See build-id.h.  */
  
  gdb_bfd_ref_ptr
--build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
-+build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id,
-+		       char **link_return)
+ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
  {
 -  return build_id_to_bfd_suffix (build_id_len, build_id, ".debug");
-+  return build_id_to_bfd_suffix (build_id_len, build_id, ".debug",
-+				 link_return);
++  return build_id_to_bfd_suffix (build_id_len, build_id, ".debug", nullptr);
  }
  
  /* See build-id.h.  */
@@ -1318,45 +848,15 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
  }
  
  /* See build-id.h.  */
+@@ -224,6 +886,7 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
  
- std::string
- find_separate_debug_file_by_buildid (struct objfile *objfile,
--				     deferred_warnings *warnings)
-+				     deferred_warnings *warnings,
-+				     gdb::unique_xmalloc_ptr<char> *build_id_filename_return)
- {
-   const struct bfd_build_id *build_id;
- 
-+  if (build_id_filename_return)
-+    *build_id_filename_return = NULL;
-+
-   build_id = build_id_bfd_get (objfile->obfd.get ());
-   if (build_id != NULL)
-     {
-@@ -222,8 +1358,21 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
- 		    _("\nLooking for separate debug info (build-id) for "
- 		      "%s\n"), objfile_name (objfile));
- 
-+      char *build_id_filename_cstr = NULL;
        gdb_bfd_ref_ptr abfd (build_id_to_debug_bfd (build_id->size,
--						   build_id->data));
-+						   build_id->data,
-+	      (!build_id_filename_return ? NULL : &build_id_filename_cstr)));
-+      if (build_id_filename_return)
-+	{
-+	  if (!build_id_filename_cstr)
-+	    gdb_assert (!*build_id_filename_return);
-+	  else
-+	    {
-+	      *build_id_filename_return = gdb::unique_xmalloc_ptr<char> (build_id_filename_cstr);
-+	      build_id_filename_cstr = NULL;
-+	    }
-+	}
+ 						   build_id->data));
 +
        /* Prevent looping on a stripped .debug file.  */
        if (abfd != NULL
  	  && filename_cmp (bfd_get_filename (abfd.get ()),
-@@ -243,3 +1392,22 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
+@@ -243,3 +906,22 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
  
    return std::string ();
  }
@@ -1382,17 +882,13 @@ diff --git a/gdb/build-id.c b/gdb/build-id.c
 diff --git a/gdb/build-id.h b/gdb/build-id.h
 --- a/gdb/build-id.h
 +++ b/gdb/build-id.h
-@@ -38,14 +38,19 @@ extern int build_id_verify (bfd *abfd,
-    can be found, return NULL.  */
- 
+@@ -40,12 +40,16 @@ extern int build_id_verify (bfd *abfd,
  extern gdb_bfd_ref_ptr build_id_to_debug_bfd (size_t build_id_len,
--					      const bfd_byte *build_id);
-+					      const bfd_byte *build_id,
-+					      char **link_return = NULL);
-+
+ 					      const bfd_byte *build_id);
+ 
 +extern char *build_id_to_filename (const struct bfd_build_id *build_id,
 +				   char **link_return);
- 
++
  /* Find and open a BFD for an executable file given a build-id.  If no BFD
     can be found, return NULL.  The returned reference to the BFD must be
     released by the caller.  */
@@ -1404,28 +900,6 @@ diff --git a/gdb/build-id.h b/gdb/build-id.h
  
  /* Find the separate debug file for OBJFILE, by using the build-id
     associated with OBJFILE's BFD.  If successful, returns the file name for the
-@@ -58,7 +63,8 @@ extern gdb_bfd_ref_ptr build_id_to_exec_bfd (size_t build_id_len,
-    will be printed.  */
- 
- extern std::string find_separate_debug_file_by_buildid
--  (struct objfile *objfile, deferred_warnings *warnings);
-+  (struct objfile *objfile, deferred_warnings *warnings,
-+   gdb::unique_xmalloc_ptr<char> *build_id_filename_return);
- 
- /* Return an hex-string representation of BUILD_ID.  */
- 
-diff --git a/gdb/coffread.c b/gdb/coffread.c
---- a/gdb/coffread.c
-+++ b/gdb/coffread.c
-@@ -729,7 +729,7 @@ coff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
-     {
-       deferred_warnings warnings;
-       std::string debugfile
--	= find_separate_debug_file_by_buildid (objfile, &warnings);
-+	= find_separate_debug_file_by_buildid (objfile, &warnings, NULL);
- 
-       if (debugfile.empty ())
- 	debugfile
 diff --git a/gdb/corelow.c b/gdb/corelow.c
 --- a/gdb/corelow.c
 +++ b/gdb/corelow.c
@@ -1517,33 +991,6 @@ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
  @cindex @code{.gnu_debuglink} sections
  @cindex debug link sections
  A debug link is a special section of the executable file named
-diff --git a/gdb/elfread.c b/gdb/elfread.c
---- a/gdb/elfread.c
-+++ b/gdb/elfread.c
-@@ -1220,8 +1220,10 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
-     {
-       deferred_warnings warnings;
- 
-+      gdb::unique_xmalloc_ptr<char> build_id_filename;
-       std::string debugfile
--	= find_separate_debug_file_by_buildid (objfile, &warnings);
-+	= find_separate_debug_file_by_buildid (objfile, &warnings,
-+					       &build_id_filename);
- 
-       if (debugfile.empty ())
- 	debugfile = find_separate_debug_file_by_debuglink (objfile, &warnings);
-@@ -1265,6 +1267,11 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
- 		      has_dwarf2 = true;
- 		    }
- 		}
-+		/* Check if any separate debug info has been extracted out.  */
-+		else if (bfd_get_section_by_name (objfile->obfd.get (),
-+		                                  ".gnu_debuglink")
-+			 != NULL)
-+		  debug_print_missing (objfile_name (objfile), build_id_filename.get ());
- 	    }
- 	}
-       /* If all the methods to collect the debuginfo failed, print the
 diff --git a/gdb/objfiles.h b/gdb/objfiles.h
 --- a/gdb/objfiles.h
 +++ b/gdb/objfiles.h

diff --git a/gdb-add-missing-debug-ext-lang-hook.patch b/gdb-add-missing-debug-ext-lang-hook.patch
new file mode 100644
index 0000000..f3a3405
--- /dev/null
+++ b/gdb-add-missing-debug-ext-lang-hook.patch
@@ -0,0 +1,314 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Fri, 13 Oct 2023 16:48:36 +0100
+Subject: gdb-add-missing-debug-ext-lang-hook.patch
+
+;; Backport upstream commit 661d98a3331.
+
+gdb: add an extension language hook for missing debug info
+
+This commit adds a new extension_language_ops hook which allows an
+extension to handle the case where GDB can't find a separate debug
+information file for a particular objfile.
+
+This commit doesn't actually implement the hook for any of GDB's
+extension languages, the next commit will do that.  This commit just
+adds support for the hook to extension-priv.h and extension.[ch], and
+then reworks symfile-debug.c to call the hook.
+
+Right now the hook will always return its default value, which means
+GDB should do nothing different.  As such, there should be no user
+visible changes after this commit.
+
+I'll give a brief description of what the hook does here so that we
+can understand the changes in symfile-debug.c.  The next commit adds a
+Python implementation for this new hook, and gives a fuller
+description of the new functionality.
+
+Currently, when looking for separate debug information GDB tries three
+things, in this order:
+
+  1. Use the build-id to find the required debug information,
+
+  2. Check for .gnu_debuglink section and use that to look up the
+  required debug information,
+
+  3. Check with debuginfod to see if it can supply the required
+  information.
+
+The new extension_language_ops::handle_missing_debuginfo hook is
+called if all three steps fail to find any debug information.  The
+hook has three possible return values:
+
+  a. Nothing, no debug information is found, GDB continues without the
+  debug information for this objfile.  This matches the current
+  behaviour of GDB, and is the default if nothing is implementing this
+  new hook,
+
+  b. Install debug information into a location that step #1 or #2
+  above would normally check, and then request that GDB repeats steps
+  #1 and #2 in the hope that GDB will now find the debug information.
+  If the debug information is still not found then GDB carries on
+  without the debug information.  If the debug information is found
+  the GDB loads it and carries on,
+
+  c. Return a filename for a file containing the required debug
+  information.  GDB loads the contents of this file and carries on.
+
+The changes in this commit mostly involve placing the core of
+objfile::find_and_add_separate_symbol_file into a loop which allows
+for steps #1 and #2 to be repeated.
+
+We take care to ensure that debuginfod is only queried once, the first
+time through.  The assumption is that no extension is going to be able
+to control the replies from debuginfod, so there's no point making a
+second request -- and as these requests go over the network, they
+could potentially be slow.
+
+The warnings that find_and_add_separate_symbol_file collects are
+displayed only once assuming that no debug information is found.  If
+debug information is found, even after the extension has operated,
+then the warnings are not shown; remember, these are warnings from GDB
+about failure to find any suitable debug information, so it makes
+sense to hide these if debug information is found.
+
+Approved-By: Tom Tromey <tom@tromey.com>
+
+diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
+--- a/gdb/extension-priv.h
++++ b/gdb/extension-priv.h
+@@ -279,6 +279,13 @@ struct extension_language_ops
+   gdb::optional<int> (*print_insn) (struct gdbarch *gdbarch,
+ 				    CORE_ADDR address,
+ 				    struct disassemble_info *info);
++
++  /* Give extension languages a chance to deal with missing debug
++     information.  OBJFILE is the file for which GDB was unable to find
++     any debug information.  */
++  ext_lang_missing_debuginfo_result
++    (*handle_missing_debuginfo) (const struct extension_language_defn *,
++				 struct objfile *objfile);
+ };
+ 
+ /* State necessary to restore a signal handler to its previous value.  */
+diff --git a/gdb/extension.c b/gdb/extension.c
+--- a/gdb/extension.c
++++ b/gdb/extension.c
+@@ -997,6 +997,25 @@ ext_lang_print_insn (struct gdbarch *gdbarch, CORE_ADDR address,
+   return {};
+ }
+ 
++/* See extension.h.  */
++
++ext_lang_missing_debuginfo_result
++ext_lang_handle_missing_debuginfo (struct objfile *objfile)
++{
++  for (const struct extension_language_defn *extlang : extension_languages)
++    {
++      if (extlang->ops == nullptr
++	  || extlang->ops->handle_missing_debuginfo == nullptr)
++	continue;
++      ext_lang_missing_debuginfo_result result
++	= extlang->ops->handle_missing_debuginfo (extlang, objfile);
++      if (!result.filename ().empty () || result.try_again ())
++	return result;
++    }
++
++  return {};
++}
++
+ /* Called via an observer before gdb prints its prompt.
+    Iterate over the extension languages giving them a chance to
+    change the prompt.  The first one to change the prompt wins,
+diff --git a/gdb/extension.h b/gdb/extension.h
+--- a/gdb/extension.h
++++ b/gdb/extension.h
+@@ -337,6 +337,68 @@ extern gdb::optional<std::string> ext_lang_colorize_disasm
+ extern gdb::optional<int> ext_lang_print_insn
+   (struct gdbarch *gdbarch, CORE_ADDR address, struct disassemble_info *info);
+ 
++/* When GDB calls into an extension language because an objfile was
++   discovered for which GDB couldn't find any debug information, this
++   structure holds the result that the extension language returns.
++
++   There are three possible actions that might be returned by an extension;
++   first an extension can return a filename, this is the path to the file
++   containing the required debug  information.  The second possibility is
++   to return a flag indicating that GDB should check again for the missing
++   debug information, this would imply that the extension has installed
++   the debug information into a location where GDB can be expected to find
++   it.  And the third option is for the extension to just return a null
++   result, indication there is nothing the extension can do to provide the
++   missing debug information.  */
++struct ext_lang_missing_debuginfo_result
++{
++  /* Default result.  The extension was unable to provide the missing debug
++     info.  */
++  ext_lang_missing_debuginfo_result ()
++  { /* Nothing.  */ }
++
++  /* When TRY_AGAIN is true GDB should try searching again, the extension
++     may have installed the missing debug info into a suitable location.
++     When TRY_AGAIN is false this is equivalent to the default, no
++     argument, constructor.  */
++  ext_lang_missing_debuginfo_result (bool try_again)
++    : m_try_again (try_again)
++  { /* Nothing.  */ }
++
++  /* Look in FILENAME for the missing debug info.  */
++  ext_lang_missing_debuginfo_result (std::string &&filename)
++    : m_filename (std::move (filename))
++  { /* Nothing.  */ }
++
++  /* The filename where GDB can find the missing debuginfo.  This is empty
++     if the extension didn't suggest a file that can be used.  */
++  const std::string &
++  filename () const
++  {
++    return m_filename;
++  }
++
++  /* Returns true if GDB should look again for the debug information.  */
++  const bool
++  try_again () const
++  {
++    return m_try_again;
++  }
++
++private:
++  /* The filename where the missing debuginfo can now be found.  */
++  std::string m_filename;
++
++  /* When true GDB will search again for the debuginfo using its standard
++     techniques.  When false GDB will not search again.  */
++  bool m_try_again = false;
++};
++
++/* Called when GDB failed to find any debug information for OBJFILE.  */
++
++extern ext_lang_missing_debuginfo_result ext_lang_handle_missing_debuginfo
++  (struct objfile *objfile);
++
+ #if GDB_SELF_TEST
+ namespace selftests {
+ extern void (*hook_set_active_ext_lang) ();
+diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
+--- a/gdb/symfile-debug.c
++++ b/gdb/symfile-debug.c
+@@ -631,38 +631,88 @@ debuginfod_find_and_open_separate_symbol_file (struct objfile * objfile)
+ bool
+ objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
+ {
+-  bool has_dwarf = false;
+-
+-  deferred_warnings warnings;
+-
+-  gdb_bfd_ref_ptr debug_bfd;
+-  std::string filename;
+-
+-  std::tie (debug_bfd, filename) = simple_find_and_open_separate_symbol_file
+-    (this, find_separate_debug_file_by_buildid, &warnings);
+-
+-  if (debug_bfd == nullptr)
+-    std::tie (debug_bfd, filename)
+-      = simple_find_and_open_separate_symbol_file
+-	  (this, find_separate_debug_file_by_debuglink, &warnings);
++  bool has_dwarf2 = false;
++
++  /* Usually we only make a single pass when looking for separate debug
++     information.  However, it is possible for an extension language hook
++     to request that GDB make a second pass, in which case max_attempts
++     will be updated, and the loop restarted.  */
++  for (unsigned attempt = 0, max_attempts = 1;
++       attempt < max_attempts && !has_dwarf2;
++       ++attempt)
++    {
++      gdb_assert (max_attempts <= 2);
++
++      deferred_warnings warnings;
++      gdb_bfd_ref_ptr debug_bfd;
++      std::string filename;
++
++      std::tie (debug_bfd, filename)
++	= simple_find_and_open_separate_symbol_file
++	    (this, find_separate_debug_file_by_buildid, &warnings);
++
++      if (debug_bfd == nullptr)
++	std::tie (debug_bfd, filename)
++	  = simple_find_and_open_separate_symbol_file
++	      (this, find_separate_debug_file_by_debuglink, &warnings);
++
++      /* Only try debuginfod on the first attempt.  Sure, we could imagine
++	 an extension that somehow adds the required debug info to the
++	 debuginfod server but, at least for now, we don't support this
++	 scenario.  Better for the extension to return new debug info
++	 directly to GDB.  Plus, going to the debuginfod server might be
++	 slow, so that's a good argument for only doing this once.  */
++      if (debug_bfd == nullptr && attempt == 0)
++	std::tie (debug_bfd, filename)
++	  = debuginfod_find_and_open_separate_symbol_file (this);
++
++      if (debug_bfd != nullptr)
++	{
++	  /* We found a separate debug info symbol file.  If this is our
++	     first attempt then setting HAS_DWARF2 will cause us to break
++	     from the attempt loop.  */
++	  symbol_file_add_separate (debug_bfd, filename.c_str (),
++				    symfile_flags, this);
++	  has_dwarf2 = true;
++	}
++      else if (attempt == 0)
++	{
++	  /* Failed to find a separate debug info symbol file.  Call out to
++	     the extension languages.  The user might have registered an
++	     extension that can find the debug info for us, or maybe give
++	     the user a system specific message that guides them to finding
++	     the missing debug info.  */
++
++	  ext_lang_missing_debuginfo_result ext_result
++	    = ext_lang_handle_missing_debuginfo (this);
++	  if (!ext_result.filename ().empty ())
++	    {
++	      /* Extension found a suitable debug file for us.  */
++	      debug_bfd
++		= symfile_bfd_open_no_error (ext_result.filename ().c_str ());
+ 
+-  if (debug_bfd == nullptr)
+-    std::tie (debug_bfd, filename)
+-      = debuginfod_find_and_open_separate_symbol_file (this);
++	      if (debug_bfd != nullptr)
++		{
++		  symbol_file_add_separate (debug_bfd,
++					    ext_result.filename ().c_str (),
++					    symfile_flags, this);
++		  has_dwarf2 = true;
++		}
++	    }
++	  else if (ext_result.try_again ())
++	    {
++	      max_attempts = 2;
++	      continue;
++	    }
++	}
+ 
+-  if (debug_bfd != nullptr)
+-    {
+-      symbol_file_add_separate (debug_bfd, filename.c_str (), symfile_flags,
+-				this);
+-      has_dwarf = true;
++      /* If we still have not got a separate debug symbol file, then
++	 emit any warnings we've collected so far.  */
++      if (!has_dwarf2)
++	warnings.emit ();
+     }
+ 
+-  /* If we still have not got a separate debug symbol file, then
+-     emit any warnings we've collected so far.  */
+-  if (!has_dwarf)
+-    warnings.emit ();
+-
+-  return has_dwarf;
++  return has_dwarf2;
+ }
+ 
+ \f

diff --git a/gdb-add-missing-debug-info-python-hook.patch b/gdb-add-missing-debug-info-python-hook.patch
new file mode 100644
index 0000000..6617bf8
--- /dev/null
+++ b/gdb-add-missing-debug-info-python-hook.patch
@@ -0,0 +1,1556 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Sun, 15 Oct 2023 22:48:42 +0100
+Subject: gdb-add-missing-debug-info-python-hook.patch
+
+;; Backport upstream commit 8f6c452b5a4.
+
+gdb: implement missing debug handler hook for Python
+
+This commit builds on the previous commit, and implements the
+extension_language_ops::handle_missing_debuginfo function for Python.
+This hook will give user supplied Python code a chance to help find
+missing debug information.
+
+The implementation of the new hook is pretty minimal within GDB's C++
+code; most of the work is out-sourced to a Python implementation which
+is modelled heavily on how GDB's Python frame unwinders are
+implemented.
+
+The following new commands are added as commands implemented in
+Python, this is similar to how the Python unwinder commands are
+implemented:
+
+  info missing-debug-handlers
+  enable missing-debug-handler LOCUS HANDLER
+  disable missing-debug-handler LOCUS HANDLER
+
+To make use of this extension hook a user will create missing debug
+information handler objects, and registers these handlers with GDB.
+When GDB encounters an objfile that is missing debug information, each
+handler is called in turn until one is able to help.  Here is a
+minimal handler that does nothing useful:
+
+  import gdb
+  import gdb.missing_debug
+
+  class MyFirstHandler(gdb.missing_debug.MissingDebugHandler):
+      def __init__(self):
+          super().__init__("my_first_handler")
+
+      def __call__(self, objfile):
+          # This handler does nothing useful.
+          return None
+
+  gdb.missing_debug.register_handler(None, MyFirstHandler())
+
+Returning None from the __call__ method tells GDB that this handler
+was unable to find the missing debug information, and GDB should ask
+any other registered handlers.
+
+By extending the __call__ method it is possible for the Python
+extension to locate the debug information for objfile and return a
+value that tells GDB how to use the information that has been located.
+
+Possible return values from a handler:
+
+  - None: This means the handler couldn't help.  GDB will call other
+          registered handlers to see if they can help instead.
+
+  - False: The handler has done all it can, but the debug information
+           for the objfile still couldn't be found.  GDB will not call
+	   any other handlers, and will continue without the debug
+	   information for objfile.
+
+  - True: The handler has installed the debug information into a
+          location where GDB would normally expect to find it.  GDB
+	  should look again for the debug information.
+
+  - A string: The handler can return a filename, which is the file
+              containing the missing debug information.  GDB will load
+	      this file.
+
+When a handler returns True, GDB will look again for the debug
+information, but only using the standard built-in build-id and
+.gnu_debuglink based lookup strategies.  It is not possible for an
+extension to trigger another debuginfod lookup; the assumption is that
+the debuginfod server is remote, and out of the control of extensions
+running within GDB.
+
+Handlers can be registered globally, or per program space.  GDB checks
+the handlers for the current program space first, and then all of the
+global handles.  The first handler that returns a value that is not
+None, has "handled" the objfile, at which point GDB continues.
+
+Reviewed-By: Eli Zaretskii <eliz@gnu.org>
+Approved-By: Tom Tromey <tom@tromey.com>
+
+diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
+--- a/gdb/data-directory/Makefile.in
++++ b/gdb/data-directory/Makefile.in
+@@ -73,6 +73,7 @@ PYTHON_FILE_LIST = \
+ 	gdb/FrameDecorator.py \
+ 	gdb/FrameIterator.py \
+ 	gdb/frames.py \
++	gdb/missing_debug.py \
+ 	gdb/printing.py \
+ 	gdb/prompt.py \
+ 	gdb/styling.py \
+@@ -82,6 +83,7 @@ PYTHON_FILE_LIST = \
+ 	gdb/command/__init__.py \
+ 	gdb/command/explore.py \
+ 	gdb/command/frame_filters.py \
++	gdb/command/missing_debug.py \
+ 	gdb/command/pretty_printers.py \
+ 	gdb/command/prompt.py \
+ 	gdb/command/type_printers.py \
+diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
+--- a/gdb/doc/python.texi
++++ b/gdb/doc/python.texi
+@@ -229,6 +229,7 @@
+ * Connections In Python::       Python representation of connections.
+ * TUI Windows In Python::       Implementing new TUI windows.
+ * Disassembly In Python::       Instruction Disassembly In Python
++* Missing Debug Info In Python:: Handle missing debug info from Python.
+ @end menu
+ 
+ @node Basic Python
+@@ -5191,6 +5192,12 @@
+ objects.  @xref{Frame Filter API}, for more information.
+ @end defvar
+ 
++@defvar Progspace.missing_debug_handlers
++The @code{missing_debug_handlers} attribute is a list of the missing
++debug handler objects for this program space.  @xref{Missing Debug
++Info In Python}, for more information.
++@end defvar
++
+ A program space has the following methods:
+ 
+ @defun Progspace.block_for_pc (pc)
+@@ -7770,6 +7777,139 @@
+ gdb.disassembler.register_disassembler(NibbleSwapDisassembler())
+ @end smallexample
+ 
++@node Missing Debug Info In Python
++@subsubsection Missing Debug Info In Python
++@cindex python, handle missing debug information
++
++When @value{GDBN} encounters a new objfile (@pxref{Objfiles In
++Python}), e.g.@: the primary executable, or any shared libraries used
++by the inferior, @value{GDBN} will attempt to load the corresponding
++debug information for that objfile.  The debug information might be
++found within the objfile itself, or within a separate objfile which
++@value{GDBN} will automatically locate and load.
++
++Sometimes though, @value{GDBN} might not find any debug information
++for an objfile, in this case the debugging experience will be
++restricted.
++
++If @value{GDBN} fails to locate any debug information for a particular
++objfile, there is an opportunity for a Python extension to step in.  A
++Python extension can potentially locate the missing debug information
++using some platform- or project-specific steps, and inform
++@value{GDBN} of its location.  Or a Python extension might provide
++some platform- or project-specific advice to the user about how to
++obtain the missing debug information.
++
++A missing debug information Python extension consists of a handler
++object which has the @code{name} and @code{enabled} attributes, and
++implements the @code{__call__} method.  When @value{GDBN} encounters
++an objfile for which it is unable to find any debug information, it
++invokes the @code{__call__} method.  Full details of how handlers are
++written can be found below.
++
++@subheading The @code{gdb.missing_debug} Module
++
++@value{GDBN} comes with a @code{gdb.missing_debug} module which
++contains the following class and global function:
++
++@deftp{class} gdb.missing_debug.MissingDebugHandler
++
++@code{MissingDebugHandler} is a base class from which user-created
++handlers can derive, though it is not required that handlers derive
++from this class, so long as any user created handler has the
++@code{name} and @code{enabled} attributes, and implements the
++@code{__call__} method.
++
++@defun MissingDebugHandler.__init__ (name)
++The @var{name} is a string used to reference this missing debug
++handler within some @value{GDBN} commands.  Valid names consist of the
++characters @code{[-_a-zA-Z0-9]}, creating a handler with an invalid
++name raises a @code{ValueError} exception.
++@end defun
++
++@defun MissingDebugHandler.__call__ (objfile)
++Sub-classes must override the @code{__call__} method.  The
++@var{objfile} argument will be a @code{gdb.Objfile}, this is the
++objfile for which @value{GDBN} was unable to find any debug
++information.
++
++The return value from the @code{__call__} method indicates what
++@value{GDBN} should do next.  The possible return values are:
++
++@itemize @bullet
++@item @code{None}
++
++This indicates that this handler could not help with @var{objfile},
++@value{GDBN} should call any other registered handlers.
++
++@item @code{True}
++
++This indicates that this handler has installed the debug information
++into a location where @value{GDBN} would normally expect to find it
++when looking for separate debug information files (@pxref{Separate
++Debug Files}).  @value{GDBN} will repeat the normal lookup process,
++which should now find the separate debug file.
++
++If @value{GDBN} still doesn't find the separate debug information file
++after this second attempt, then the Python missing debug information
++handlers are not invoked a second time, this prevents a badly behaved
++handler causing @value{GDBN} to get stuck in a loop.  @value{GDBN}
++will continue without any debug information for @var{objfile}.
++
++@item @code{False}
++
++This indicates that this handler has done everything that it intends
++to do with @var{objfile}, but no separate debug information can be
++found.  @value{GDBN} will not call any other registered handlers for
++@var{objfile}.  @value{GDBN} will continue without debugging
++information for @var{objfile}.
++
++@item A string
++
++The returned string should contain a filename.  @value{GDBN} will not
++call any further registered handlers, and will instead load the debug
++information from the file identified by the returned filename.
++@end itemize
++
++Invoking the @code{__call__} method from this base class will raise a
++@code{NotImplementedError} exception.
++@end defun
++
++@defvar MissingDebugHandler.name
++A read-only attribute which is a string, the name of this handler
++passed to the @code{__init__} method.
++@end defvar
++
++@defvar MissingDebugHandler.enabled
++A modifiable attribute containing a boolean; when @code{True}, the
++handler is enabled, and will be used by @value{GDBN}.  When
++@code{False}, the handler has been disabled, and will not be used.
++@end defvar
++@end deftp
++
++@defun gdb.missing_debug.register_handler (locus, handler, replace=@code{False})
++Register a new missing debug handler with @value{GDBN}.
++
++@var{handler} is an instance of a sub-class of
++@code{MissingDebugHandler}, or at least an instance of an object that
++has the same attributes and methods as @code{MissingDebugHandler}.
++
++@var{locus} specifies to which handler list to prepend @var{handler}.
++It can be either a @code{gdb.Progspace} (@pxref{Progspaces In Python})
++or @code{None}, in which case the handler is registered globally.  The
++newly registered @var{handler} will be called before any other handler
++from the same locus.  Two handlers in the same locus cannot have the
++same name, an attempt to add a handler with an already existing name
++raises an exception unless @var{replace} is @code{True}, in which case
++the old handler is deleted and the new handler is prepended to the
++selected handler list.
++
++@value{GDBN} first calls the handlers for the current program space,
++and then the globally registered handlers.  As soon as a handler
++returns a value other than @code{None}, no further handlers are called
++for this objfile.
++@end defun
++
+ @node Python Auto-loading
+ @subsection Python Auto-loading
+ @cindex Python auto-loading
+diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
+--- a/gdb/python/lib/gdb/__init__.py
++++ b/gdb/python/lib/gdb/__init__.py
+@@ -84,6 +84,8 @@ xmethods = []
+ frame_filters = {}
+ # Initial frame unwinders.
+ frame_unwinders = []
++# Initial missing debug handlers.
++missing_debug_handlers = []
+ 
+ 
+ def _execute_unwinders(pending_frame):
+@@ -291,3 +293,42 @@ class Thread(threading.Thread):
+         # threads.
+         with blocked_signals():
+             super().start()
++
++
++def _handle_missing_debuginfo(objfile):
++    """Internal function called from GDB to execute missing debug
++    handlers.
++
++    Run each of the currently registered, and enabled missing debug
++    handler objects for the current program space and then from the
++    global list.  Stop after the first handler that returns a result
++    other than None.
++
++    Arguments:
++        objfile: A gdb.Objfile for which GDB could not find any debug
++                 information.
++
++    Returns:
++        None: No debug information could be found for objfile.
++        False: A handler has done all it can with objfile, but no
++               debug information could be found.
++        True: Debug information might have been installed by a
++              handler, GDB should check again.
++        A string: This is the filename of a file containing the
++                  required debug information.
++    """
++    pspace = objfile.progspace
++
++    for handler in pspace.missing_debug_handlers:
++        if handler.enabled:
++            result = handler(objfile)
++            if result is not None:
++                return result
++
++    for handler in missing_debug_handlers:
++        if handler.enabled:
++            result = handler(objfile)
++            if result is not None:
++                return result
++
++    return None
+diff --git a/gdb/python/lib/gdb/command/missing_debug.py b/gdb/python/lib/gdb/command/missing_debug.py
+new file mode 100644
+--- /dev/null
++++ b/gdb/python/lib/gdb/command/missing_debug.py
+@@ -0,0 +1,226 @@
++# Missing debug related commands.
++#
++# Copyright 2023 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 <http://www.gnu.org/licenses/>.
++
++import gdb
++import re
++
++
++def validate_regexp(exp, idstring):
++    """Compile exp into a compiler regular expression object.
++
++    Arguments:
++        exp: The string to compile into a re.Pattern object.
++        idstring: A string, what exp is a regexp for.
++
++    Returns:
++        A re.Pattern object representing exp.
++
++    Raises:
++        SyntaxError: If exp is an invalid regexp.
++    """
++    try:
++        return re.compile(exp)
++    except SyntaxError:
++        raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp))
++
++
++def parse_missing_debug_command_args(arg):
++    """Internal utility to parse missing debug handler command argv.
++
++    Arguments:
++        arg: The arguments to the command. The format is:
++             [locus-regexp [name-regexp]]
++
++    Returns:
++        A 2-tuple of compiled regular expressions.
++
++    Raises:
++        SyntaxError: an error processing ARG
++    """
++    argv = gdb.string_to_argv(arg)
++    argc = len(argv)
++    if argc > 2:
++        raise SyntaxError("Too many arguments.")
++    locus_regexp = ""
++    name_regexp = ""
++    if argc >= 1:
++        locus_regexp = argv[0]
++        if argc >= 2:
++            name_regexp = argv[1]
++    return (
++        validate_regexp(locus_regexp, "locus"),
++        validate_regexp(name_regexp, "handler"),
++    )
++
++
++class InfoMissingDebugHanders(gdb.Command):
++    """GDB command to list missing debug handlers.
++
++    Usage: info missing-debug-handlers [LOCUS-REGEXP [NAME-REGEXP]]
++
++    LOCUS-REGEXP is a regular expression matching the location of the
++    handler.  If it is omitted, all registered handlers from all
++    loci are listed.  A locus can be 'global', 'progspace' to list
++    the handlers from the current progspace, or a regular expression
++    matching filenames of progspaces.
++
++    NAME-REGEXP is a regular expression to filter missing debug
++    handler names.  If this omitted for a specified locus, then all
++    registered handlers in the locus are listed.
++    """
++
++    def __init__(self):
++        super().__init__("info missing-debug-handlers", gdb.COMMAND_FILES)
++
++    def list_handlers(self, title, handlers, name_re):
++        """Lists the missing debug handlers whose name matches regexp.
++
++        Arguments:
++            title: The line to print before the list.
++            handlers: The list of the missing debug handlers.
++            name_re: handler name filter.
++        """
++        if not handlers:
++            return
++        print(title)
++        for handler in handlers:
++            if name_re.match(handler.name):
++                print(
++                    "  %s%s" % (handler.name, "" if handler.enabled else " [disabled]")
++                )
++
++    def invoke(self, arg, from_tty):
++        locus_re, name_re = parse_missing_debug_command_args(arg)
++
++        if locus_re.match("progspace") and locus_re.pattern != "":
++            cp = gdb.current_progspace()
++            self.list_handlers(
++                "Progspace %s:" % cp.filename, cp.missing_debug_handlers, name_re
++            )
++
++        for progspace in gdb.progspaces():
++            filename = progspace.filename or ""
++            if locus_re.match(filename):
++                if filename == "":
++                    if progspace == gdb.current_progspace():
++                        msg = "Current Progspace:"
++                    else:
++                        msg = "Progspace <no-file>:"
++                else:
++                    msg = "Progspace %s:" % filename
++                self.list_handlers(
++                    msg,
++                    progspace.missing_debug_handlers,
++                    name_re,
++                )
++
++        # Print global handlers last, as these are invoked last.
++        if locus_re.match("global"):
++            self.list_handlers("Global:", gdb.missing_debug_handlers, name_re)
++
++
++def do_enable_handler1(handlers, name_re, flag):
++    """Enable/disable missing debug handlers whose names match given regex.
++
++    Arguments:
++        handlers: The list of missing debug handlers.
++        name_re: Handler name filter.
++        flag: A boolean indicating if we should enable or disable.
++
++    Returns:
++        The number of handlers affected.
++    """
++    total = 0
++    for handler in handlers:
++        if name_re.match(handler.name) and handler.enabled != flag:
++            handler.enabled = flag
++            total += 1
++    return total
++
++
++def do_enable_handler(arg, flag):
++    """Enable or disable missing debug handlers."""
++    (locus_re, name_re) = parse_missing_debug_command_args(arg)
++    total = 0
++    if locus_re.match("global"):
++        total += do_enable_handler1(gdb.missing_debug_handlers, name_re, flag)
++    if locus_re.match("progspace") and locus_re.pattern != "":
++        total += do_enable_handler1(
++            gdb.current_progspace().missing_debug_handlers, name_re, flag
++        )
++    for progspace in gdb.progspaces():
++        filename = progspace.filename or ""
++        if locus_re.match(filename):
++            total += do_enable_handler1(progspace.missing_debug_handlers, name_re, flag)
++    print(
++        "%d missing debug handler%s %s"
++        % (total, "" if total == 1 else "s", "enabled" if flag else "disabled")
++    )
++
++
++class EnableMissingDebugHandler(gdb.Command):
++    """GDB command to enable missing debug handlers.
++
++    Usage: enable missing-debug-handler [LOCUS-REGEXP [NAME-REGEXP]]
++
++    LOCUS-REGEXP is a regular expression specifying the handlers to
++    enable.  It can be 'global', 'progspace' for the current
++    progspace, or the filename for a file associated with a progspace.
++
++    NAME_REGEXP is a regular expression to filter handler names.  If
++    this omitted for a specified locus, then all registered handlers
++    in the locus are affected.
++    """
++
++    def __init__(self):
++        super().__init__("enable missing-debug-handler", gdb.COMMAND_FILES)
++
++    def invoke(self, arg, from_tty):
++        """GDB calls this to perform the command."""
++        do_enable_handler(arg, True)
++
++
++class DisableMissingDebugHandler(gdb.Command):
++    """GDB command to disable missing debug handlers.
++
++    Usage: disable missing-debug-handler [LOCUS-REGEXP [NAME-REGEXP]]
++
++    LOCUS-REGEXP is a regular expression specifying the handlers to
++    enable.  It can be 'global', 'progspace' for the current
++    progspace, or the filename for a file associated with a progspace.
++
++    NAME_REGEXP is a regular expression to filter handler names.  If
++    this omitted for a specified locus, then all registered handlers
++    in the locus are affected.
++    """
++
++    def __init__(self):
++        super().__init__("disable missing-debug-handler", gdb.COMMAND_FILES)
++
++    def invoke(self, arg, from_tty):
++        """GDB calls this to perform the command."""
++        do_enable_handler(arg, False)
++
++
++def register_missing_debug_handler_commands():
++    """Installs the missing debug handler commands."""
++    InfoMissingDebugHanders()
++    EnableMissingDebugHandler()
++    DisableMissingDebugHandler()
++
++
++register_missing_debug_handler_commands()
+diff --git a/gdb/python/lib/gdb/missing_debug.py b/gdb/python/lib/gdb/missing_debug.py
+new file mode 100644
+--- /dev/null
++++ b/gdb/python/lib/gdb/missing_debug.py
+@@ -0,0 +1,169 @@
++# Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
++
++"""
++MissingDebugHandler base class, and register_handler function.
++"""
++
++import gdb
++
++
++def _validate_name(name):
++    """Validate a missing debug handler name string.
++
++    If name is valid as a missing debug handler name, then this
++    function does nothing.  If name is not valid then an exception is
++    raised.
++
++    Arguments:
++        name: A string, the name of a missing debug handler.
++
++    Returns:
++        Nothing.
++
++    Raises:
++        ValueError: If name is invalid as a missing debug handler
++                    name.
++    """
++    for ch in name:
++        if not ch.isascii() or not (ch.isalnum() or ch in "_-"):
++            raise ValueError("invalid character '%s' in handler name: %s" % (ch, name))
++
++
++class MissingDebugHandler(object):
++    """Base class for missing debug handlers written in Python.
++
++    A missing debug handler has a single method __call__ along with
++    the read/write attribute enabled, and a read-only attribute name.
++
++    Attributes:
++        name: Read-only attribute, the name of this handler.
++        enabled: When true this handler is enabled.
++    """
++
++    def __init__(self, name):
++        """Constructor.
++
++        Args:
++            name: An identifying name for this handler.
++
++        Raises:
++            TypeError: name is not a string.
++            ValueError: name contains invalid characters.
++        """
++
++        if not isinstance(name, str):
++            raise TypeError("incorrect type for name: %s" % type(name))
++
++        _validate_name(name)
++
++        self._name = name
++        self._enabled = True
++
++    @property
++    def name(self):
++        return self._name
++
++    @property
++    def enabled(self):
++        return self._enabled
++
++    @enabled.setter
++    def enabled(self, value):
++        if not isinstance(value, bool):
++            raise TypeError("incorrect type for enabled attribute: %s" % type(value))
++        self._enabled = value
++
++    def __call__(self, objfile):
++        """GDB handle missing debug information for an objfile.
++
++        Arguments:
++            objfile: A gdb.Objfile for which GDB could not find any
++                debug information.
++
++        Returns:
++            True: GDB should try again to locate the debug information
++                for objfile, the handler may have installed the
++                missing information.
++            False: GDB should move on without the debug information
++                for objfile.
++            A string: GDB should load the file at the given path; it
++                contains the debug information for objfile.
++            None: This handler can't help with objfile.  GDB should
++                try any other registered handlers.
++        """
++        raise NotImplementedError("MissingDebugHandler.__call__()")
++
++
++def register_handler(locus, handler, replace=False):
++    """Register handler in given locus.
++
++    The handler is prepended to the locus's missing debug handlers
++    list. The name of handler should be unique (or replace must be
++    True).
++
++    Arguments:
++        locus: Either a progspace, or None (in which case the unwinder
++               is registered globally).
++        handler: An object of a gdb.MissingDebugHandler subclass.
++
++        replace: If True, replaces existing handler with the same name
++                 within locus.  Otherwise, raises RuntimeException if
++                 unwinder with the same name already exists.
++
++    Returns:
++        Nothing.
++
++    Raises:
++        RuntimeError: The name of handler is not unique.
++        TypeError: Bad locus type.
++        AttributeError: Required attributes of handler are missing.
++    """
++
++    if locus is None:
++        if gdb.parameter("verbose"):
++            gdb.write("Registering global %s handler ...\n" % handler.name)
++        locus = gdb
++    elif isinstance(locus, gdb.Progspace):
++        if gdb.parameter("verbose"):
++            gdb.write(
++                "Registering %s handler for %s ...\n" % (handler.name, locus.filename)
++            )
++    else:
++        raise TypeError("locus should be gdb.Progspace or None")
++
++    # Some sanity checks on HANDLER.  Calling getattr will raise an
++    # exception if the attribute doesn't exist, which is what we want.
++    # These checks are not exhaustive; we don't check the attributes
++    # have the correct types, or the method has the correct signature,
++    # but this should catch some basic mistakes.
++    getattr(handler, "name")
++    getattr(handler, "enabled")
++    call_method = getattr(handler, "__call__")
++    if not callable(call_method):
++        raise AttributeError(
++            "'%s' object's '__call__' attribute is not callable"
++            % type(handler).__name__
++        )
++
++    i = 0
++    for needle in locus.missing_debug_handlers:
++        if needle.name == handler.name:
++            if replace:
++                del locus.missing_debug_handlers[i]
++            else:
++                raise RuntimeError("Handler %s already exists." % handler.name)
++        i += 1
++    locus.missing_debug_handlers.insert(0, handler)
+diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
+--- a/gdb/python/py-progspace.c
++++ b/gdb/python/py-progspace.c
+@@ -54,6 +54,9 @@ struct pspace_object
+ 
+   /* The debug method list.  */
+   PyObject *xmethods;
++
++  /* The missing debug handler list.  */
++  PyObject *missing_debug_handlers;
+ };
+ 
+ extern PyTypeObject pspace_object_type
+@@ -163,6 +166,7 @@ pspy_dealloc (PyObject *self)
+   Py_XDECREF (ps_self->frame_unwinders);
+   Py_XDECREF (ps_self->type_printers);
+   Py_XDECREF (ps_self->xmethods);
++  Py_XDECREF (ps_self->missing_debug_handlers);
+   Py_TYPE (self)->tp_free (self);
+ }
+ 
+@@ -198,6 +202,10 @@ pspy_initialize (pspace_object *self)
+   if (self->xmethods == NULL)
+     return 0;
+ 
++  self->missing_debug_handlers = PyList_New (0);
++  if (self->missing_debug_handlers == nullptr)
++    return 0;
++
+   return 1;
+ }
+ 
+@@ -352,6 +360,47 @@ pspy_get_xmethods (PyObject *o, void *ignore)
+   return self->xmethods;
+ }
+ 
++/* Return the list of missing debug handlers for this program space.  */
++
++static PyObject *
++pspy_get_missing_debug_handlers (PyObject *o, void *ignore)
++{
++  pspace_object *self = (pspace_object *) o;
++
++  Py_INCREF (self->missing_debug_handlers);
++  return self->missing_debug_handlers;
++}
++
++/* Set this program space's list of missing debug handlers to HANDLERS.  */
++
++static int
++pspy_set_missing_debug_handlers (PyObject *o, PyObject *handlers,
++				 void *ignore)
++{
++  pspace_object *self = (pspace_object *) o;
++
++  if (handlers == nullptr)
++    {
++      PyErr_SetString (PyExc_TypeError,
++		       "cannot delete the missing debug handlers list");
++      return -1;
++    }
++
++  if (!PyList_Check (handlers))
++    {
++      PyErr_SetString (PyExc_TypeError,
++		       "the missing debug handlers attribute must be a list");
++      return -1;
++    }
++
++  /* Take care in case the LHS and RHS are related somehow.  */
++  gdbpy_ref<> tmp (self->missing_debug_handlers);
++  Py_INCREF (handlers);
++  self->missing_debug_handlers = handlers;
++
++  return 0;
++}
++
+ /* Set the 'type_printers' attribute.  */
+ 
+ static int
+@@ -744,6 +793,8 @@ static gdb_PyGetSetDef pspace_getset[] =
+     "Type printers.", NULL },
+   { "xmethods", pspy_get_xmethods, NULL,
+     "Debug methods.", NULL },
++  { "missing_debug_handlers", pspy_get_missing_debug_handlers,
++    pspy_set_missing_debug_handlers, "Missing debug handlers.", NULL },
+   { NULL }
+ };
+ 
+diff --git a/gdb/python/python.c b/gdb/python/python.c
+--- a/gdb/python/python.c
++++ b/gdb/python/python.c
+@@ -124,7 +124,9 @@ static enum ext_lang_rc gdbpy_before_prompt_hook
+ static gdb::optional<std::string> gdbpy_colorize
+   (const std::string &filename, const std::string &contents);
+ static gdb::optional<std::string> gdbpy_colorize_disasm
+-  (const std::string &content, gdbarch *gdbarch);
++(const std::string &content, gdbarch *gdbarch);
++static ext_lang_missing_debuginfo_result gdbpy_handle_missing_debuginfo
++  (const struct extension_language_defn *extlang, struct objfile *objfile);
+ 
+ /* The interface between gdb proper and loading of python scripts.  */
+ 
+@@ -170,6 +172,8 @@ static const struct extension_language_ops python_extension_ops =
+   gdbpy_colorize_disasm,
+ 
+   gdbpy_print_insn,
++
++  gdbpy_handle_missing_debuginfo
+ };
+ 
+ #endif /* HAVE_PYTHON */
+@@ -1661,6 +1665,83 @@ gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2)
+   return objfile_to_objfile_object (gdbpy_current_objfile).release ();
+ }
+ 
++/* Implement the 'handle_missing_debuginfo' hook for Python.  GDB has
++   failed to find any debug information for OBJFILE.  The extension has a
++   chance to record this, or even install the required debug information.
++   See the description of ext_lang_missing_debuginfo_result in
++   extension-priv.h for details of the return value.  */
++
++static ext_lang_missing_debuginfo_result
++gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
++				struct objfile *objfile)
++{
++  /* Early exit if Python is not initialised.  */
++  if (!gdb_python_initialized)
++    return {};
++
++  struct gdbarch *gdbarch = objfile->arch ();
++
++  gdbpy_enter enter_py (gdbarch);
++
++  /* Convert OBJFILE into the corresponding Python object.  */
++  gdbpy_ref<> pyo_objfile = objfile_to_objfile_object (objfile);
++  if (pyo_objfile == nullptr)
++    {
++      gdbpy_print_stack ();
++      return {};
++    }
++
++  /* Lookup the helper function within the GDB module.  */
++  gdbpy_ref<> pyo_handler
++    (PyObject_GetAttrString (gdb_python_module, "_handle_missing_debuginfo"));
++  if (pyo_handler == nullptr)
++    {
++      gdbpy_print_stack ();
++      return {};
++    }
++
++  /* Call the function, passing in the Python objfile object.  */
++  gdbpy_ref<> pyo_execute_ret
++    (PyObject_CallFunctionObjArgs (pyo_handler.get (), pyo_objfile.get (),
++				   nullptr));
++  if (pyo_execute_ret == nullptr)
++    {
++      /* If the handler is cancelled due to a Ctrl-C, then propagate
++	 the Ctrl-C as a GDB exception instead of swallowing it.  */
++      gdbpy_print_stack_or_quit ();
++      return {};
++    }
++
++  /* Parse the result, and convert it back to the C++ object.  */
++  if (pyo_execute_ret == Py_None)
++    return {};
++
++  if (PyBool_Check (pyo_execute_ret.get ()))
++    {
++      bool try_again = PyObject_IsTrue (pyo_execute_ret.get ());
++      return ext_lang_missing_debuginfo_result (try_again);
++    }
++
++  if (!gdbpy_is_string (pyo_execute_ret.get ()))
++    {
++      PyErr_SetString (PyExc_ValueError,
++		       "return value from _handle_missing_debuginfo should "
++		       "be None, a Bool, or a String");
++      gdbpy_print_stack ();
++      return {};
++    }
++
++  gdb::unique_xmalloc_ptr<char> filename
++    = python_string_to_host_string (pyo_execute_ret.get ());
++  if (filename == nullptr)
++    {
++      gdbpy_print_stack ();
++      return {};
++    }
++
++  return ext_lang_missing_debuginfo_result (std::string (filename.get ()));
++}
++
+ /* Compute the list of active python type printers and store them in
+    EXT_PRINTERS->py_type_printers.  The product of this function is used by
+    gdbpy_apply_type_printers, and freed by gdbpy_free_type_printers.
+diff --git a/gdb/testsuite/gdb.python/py-missing-debug.c b/gdb/testsuite/gdb.python/py-missing-debug.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-missing-debug.c
+@@ -0,0 +1,22 @@
++/* This test program is part of GDB, the GNU debugger.
++
++   Copyright 2023 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 <http://www.gnu.org/licenses/>.  */
++
++int
++main ()
++{
++  return 0;
++}
+diff --git a/gdb/testsuite/gdb.python/py-missing-debug.exp b/gdb/testsuite/gdb.python/py-missing-debug.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-missing-debug.exp
+@@ -0,0 +1,473 @@
++# Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
++
++load_lib gdb-python.exp
++
++require allow_python_tests
++
++standard_testfile
++
++if {[build_executable "failed to prepare" ${testfile} ${srcfile}]} {
++    return -1
++}
++
++# Remove debug information from BINFILE and place it into
++# BINFILE.debug.
++if {[gdb_gnu_strip_debug $binfile]} {
++    unsupported "cannot produce separate debug info files"
++    return -1
++}
++
++set remote_python_file \
++    [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
++
++set debug_filename ${binfile}.debug
++set hidden_filename ${binfile}.hidden
++
++# Start GDB.
++clean_restart
++
++# Some initial sanity checks; initially, we can find the debug information
++# (this will use the .gnu_debuglink), then after we move the debug
++# information, reload the executable, now the debug can't be found.
++with_test_prefix "initial checks" {
++    # Load BINFILE, we should find the separate debug information.
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "debug"} \
++	"debug info is found"
++
++    # Rename the debug information file, re-load BINFILE, GDB should fail
++    # to find the debug information
++    remote_exec build "mv $debug_filename $hidden_filename"
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
++	"debug info no longer found"
++}
++
++# Load the Python script into GDB.
++gdb_test "source $remote_python_file" "^Success" \
++    "source python script"
++
++# Setup the separate debug info directory.  This isn't actually needed until
++# some of the later tests, but might as well get this done now.
++set debug_directory [standard_output_file "debug-dir"]
++remote_exec build "mkdir -p $debug_directory"
++gdb_test_no_output "set debug-file-directory $debug_directory" \
++    "set debug-file-directory"
++
++# Initially the missing debug handler we install is in a mode where it
++# returns None, indicating that it can't help locate the debug information.
++# Check this works as expected.
++with_test_prefix "handler returning None" {
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(None, handler_obj)" \
++	"register the initial handler"
++
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
++	"debug info not found"
++
++    # Check the handler was only called once.
++    gdb_test "python print(handler_obj.call_count)" "^1" \
++	"check handler was only called once"
++}
++
++# Now configure the handler to move the debug file back to the
++# .gnu_debuglink location and then return True, this will cause GDB to
++# recheck, at which point it should find the debug info.
++with_test_prefix "handler in gnu_debuglink mode" {
++    gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \
++						    \"$hidden_filename\", \
++						    \"$debug_filename\")" \
++	"confirgure handler"
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found"
++
++    # Check the handler was only called once.
++    gdb_test "python print(handler_obj.call_count)" "^1" \
++	"check handler was only called once"
++}
++
++# Setup a directory structure based on the build-id of BINFILE, but don't
++# move the debug information into place just yet.
++#
++# Instead, configure the handler to move the debug info into the build-id
++# directory.
++#
++# Reload BINFILE, at which point the handler will move the debug info into
++# the build-id directory and return True, GDB will then recheck for the
++# debug information, and should find it.
++with_test_prefix "handler in build-id mode" {
++    # Move the debug file out of the way once more.
++    remote_exec build "mv $debug_filename $hidden_filename"
++
++    # Create the build-id based directory in which the debug information
++    # will be placed.
++    set build_id_filename \
++	$debug_directory/[build_id_debug_filename_get $binfile]
++    remote_exec build "mkdir -p [file dirname $build_id_filename]"
++
++    # Configure the handler to move the debug info into the build-id dir.
++    gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \
++						    \"$hidden_filename\", \
++						    \"$build_id_filename\")" \
++	"confirgure handler"
++
++    # Reload the binary and check the debug information is found.
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found"
++
++    # Check the handler was only called once.
++    gdb_test "python print(handler_obj.call_count)" "^1" \
++	"check handler was only called once"
++}
++
++# Move the debug information back to a hidden location and configure the
++# handler to return the filename of the hidden debug info location.  GDB
++# should immediately use this file as the debug information.
++with_test_prefix "handler returning a string" {
++    remote_exec build "mv $build_id_filename $hidden_filename"
++
++    # Configure the handler return a filename string.
++    gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \
++						    \"$hidden_filename\")" \
++	"confirgure handler"
++
++    # Reload the binary and check the debug information is found.
++    gdb_file_cmd $binfile
++    gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found"
++
++    # Check the handler was only called once.
++    gdb_test "python print(handler_obj.call_count)" "^1" \
++	"check handler was only called once"
++}
++
++# Register another global handler, this one raises an exception.  Reload the
++# debug information, the bad handler should be invoked first, which raises
++# an excetption, at which point GDB should skip further Python handlers.
++with_test_prefix "handler raises an exception" {
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(None, rhandler)"
++
++    foreach_with_prefix exception_type {gdb.GdbError TypeError} {
++	gdb_test_no_output \
++	    "python rhandler.exception_type = $exception_type"
++
++	gdb_file_cmd $binfile
++	gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
++	    "debug info not found"
++
++	set re [string_to_regexp \
++		    "Python Exception <class '$exception_type'>: message"]
++	gdb_assert {[regexp $re $gdb_file_cmd_msg]} \
++	    "check for exception in file command output"
++
++	# Our original handler is still registered, but should not have been
++	# called again (as the exception occurs first).
++	gdb_test "python print(handler_obj.call_count)" "^1" \
++	    "check good handler hasn't been called again"
++    }
++}
++
++gdb_test "info missing-debug-handlers" \
++    [multi_line \
++	 "Global:" \
++	 "  exception_handler" \
++	 "  handler"] \
++    "check both handlers are visible"
++
++# Re-start GDB.
++clean_restart
++
++# Load the Python script into GDB.
++gdb_test "source $remote_python_file" "^Success" \
++    "source python script for bad handler name checks"
++
++# Attempt to register a missing-debug-handler with NAME.  The expectation is
++# that this should fail as NAME contains some invalid characters.
++proc check_bad_name {name} {
++    set name_re [string_to_regexp $name]
++    set re \
++	[multi_line \
++	     "ValueError: invalid character '.' in handler name: $name_re" \
++	     "Error while executing Python code\\."]
++
++    gdb_test "python register(\"$name\")" $re \
++	"check that '$name' is not accepted"
++}
++
++# We don't attempt to be exhaustive here, just check a few random examples
++# of invalid names.
++check_bad_name "!! Bad Name"
++check_bad_name "Bad Name"
++check_bad_name "(Bad Name)"
++check_bad_name "Bad \[Name\]"
++check_bad_name "Bad,Name"
++check_bad_name "Bad;Name"
++
++# Check that there are no handlers registered.
++gdb_test_no_output "info missing-debug-handlers" \
++    "check no handlers are registered"
++
++# Check we can use the enable/disable commands where there are no handlers
++# registered.
++gdb_test "enable missing-debug-handler foo" \
++    "^0 missing debug handlers enabled"
++gdb_test "disable missing-debug-handler foo" \
++    "^0 missing debug handlers disabled"
++
++# Grab the current program space object, used for registering handler later.
++gdb_test_no_output "python pspace = gdb.selected_inferior().progspace"
++
++# Now register some handlers.
++foreach hspec {{\"Foo\" None}
++    {\"-bar\" None}
++    {\"baz-\" pspace}
++    {\"abc-def\" pspace}} {
++    lassign $hspec name locus
++    gdb_test "python register($name, $locus)"
++}
++
++with_test_prefix "all handlers enabled" {
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Current Progspace:" \
++	     "  abc-def" \
++	     "  baz-" \
++	     "Global:" \
++	     "  -bar" \
++	     "  Foo"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def', 'baz-', '-bar', 'Foo']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "disable 'baz-'" {
++    gdb_test "disable missing-debug-handler progspace baz-" \
++	"^1 missing debug handler disabled"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def" \
++	     "  baz- \\\[disabled\\\]" \
++	     "Global:" \
++	     "  -bar" \
++	     "  Foo"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def', '-bar', 'Foo']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "disable 'Foo'" {
++    gdb_test "disable missing-debug-handler .* Foo" \
++	"^1 missing debug handler disabled"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def" \
++	     "  baz- \\\[disabled\\\]" \
++	     "Global:" \
++	     "  -bar" \
++	     "  Foo \\\[disabled\\\]"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def', '-bar']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "disable everything" {
++    gdb_test "disable missing-debug-handler .* .*" \
++	"^2 missing debug handlers disabled"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def \\\[disabled\\\]" \
++	     "  baz- \\\[disabled\\\]" \
++	     "Global:" \
++	     "  -bar \\\[disabled\\\]" \
++	     "  Foo \\\[disabled\\\]"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {[]}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "enable 'abc-def'" {
++    set re [string_to_regexp $binfile]
++
++    gdb_test "enable missing-debug-handler \"$re\" abc-def" \
++	"^1 missing debug handler enabled"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def" \
++	     "  baz- \\\[disabled\\\]" \
++	     "Global:" \
++	     "  -bar \\\[disabled\\\]" \
++	     "  Foo \\\[disabled\\\]"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "enable global handlers" {
++    set re [string_to_regexp $binfile]
++
++    gdb_test "enable missing-debug-handler global" \
++	"^2 missing debug handlers enabled"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def" \
++	     "  baz- \\\[disabled\\\]" \
++	     "Global:" \
++	     "  -bar" \
++	     "  Foo"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def', '-bar', 'Foo']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++# Add handler_obj to the global handler list, and configure it to
++# return False.  We should call all of the program space specific
++# handlers (which return None), and then call handler_obj from the
++# global list, which returns False, at which point we shouldn't call
++# anyone else.
++with_test_prefix "return False handler in progspace list" {
++    gdb_test "enable missing-debug-handler progspace" \
++	"^1 missing debug handler enabled"
++
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(None, handler_obj)" \
++	"register the initial handler"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  abc-def" \
++	     "  baz-" \
++	     "Global:" \
++	     "  handler" \
++	     "  -bar" \
++	     "  Foo"]
++
++    gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \
++	"confirgure handler"
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['abc-def', 'baz-', 'handler']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++# Now add handler_obj to the current program space's handler list.  We
++# use the same handler object here, that's fine.  We should only see a
++# call to the first handler object in the call log.
++with_test_prefix "return False handler in global list" {
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(pspace, handler_obj)" \
++	"register the initial handler"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  handler" \
++	     "  abc-def" \
++	     "  baz-" \
++	     "Global:" \
++	     "  handler" \
++	     "  -bar" \
++	     "  Foo"]
++
++    gdb_file_cmd $binfile
++    gdb_test "python print(handler_call_log)" \
++	[string_to_regexp {['handler']}]
++    gdb_test_no_output "python handler_call_log = \[\]" \
++	"reset call log"
++}
++
++with_test_prefix "check handler replacement" {
++    # First, check we can have the same name appear in both program
++    # space and global lists without giving an error.
++    gdb_test_no_output "python register(\"Foo\", pspace)"
++
++    gdb_test "info missing-debug-handlers" \
++	[multi_line \
++	     "Progspace \[^\r\n\]+:" \
++	     "  Foo" \
++	     "  handler" \
++	     "  abc-def" \
++	     "  baz-" \
++	     "Global:" \
++	     "  handler" \
++	     "  -bar" \
++	     "  Foo"]
++
++    # Now check that we get an error if we try to add a handler with
++    # the same name.
++    gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \
++	[multi_line \
++	     "RuntimeError: Handler Foo already exists\\." \
++	     "Error while executing Python code\\."]
++
++    gdb_test "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \
++	[multi_line \
++	     "RuntimeError: Handler Foo already exists\\." \
++	     "Error while executing Python code\\."]
++
++    # And now try again, but this time with 'replace=True', we
++    # shouldn't get an error in this case.
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)"
++
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)"
++
++    # Now disable a handler and check we still need to use 'replace=True'.
++    gdb_test "disable missing-debug-handler progspace Foo" \
++	"^1 missing debug handler disabled"
++
++    gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \
++	[multi_line \
++	     "RuntimeError: Handler Foo already exists\\." \
++	     "Error while executing Python code\\."] \
++	"still get an error when handler is disabled"
++
++    gdb_test_no_output \
++	"python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \
++	"can replace a disabled handler"
++}
+diff --git a/gdb/testsuite/gdb.python/py-missing-debug.py b/gdb/testsuite/gdb.python/py-missing-debug.py
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.python/py-missing-debug.py
+@@ -0,0 +1,120 @@
++# Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
++
++import gdb
++from gdb.missing_debug import MissingDebugHandler
++from enum import Enum
++import os
++
++# A global log that is filled in by instances of the LOG_HANDLER class
++# when they are called.
++handler_call_log = []
++
++
++class Mode(Enum):
++    RETURN_NONE = 0
++    RETURN_TRUE = 1
++    RETURN_FALSE = 2
++    RETURN_STRING = 3
++
++
++class handler(MissingDebugHandler):
++    def __init__(self):
++        super().__init__("handler")
++        self._call_count = 0
++        self._mode = Mode.RETURN_NONE
++
++    def __call__(self, objfile):
++        global handler_call_log
++        handler_call_log.append(self.name)
++        self._call_count += 1
++        if self._mode == Mode.RETURN_NONE:
++            return None
++
++        if self._mode == Mode.RETURN_TRUE:
++            os.rename(self._src, self._dest)
++            return True
++
++        if self._mode == Mode.RETURN_FALSE:
++            return False
++
++        if self._mode == Mode.RETURN_STRING:
++            return self._dest
++
++        assert False
++
++    @property
++    def call_count(self):
++        """Return a count, the number of calls to __call__ since the last
++        call to set_mode.
++        """
++        return self._call_count
++
++    def set_mode(self, mode, *args):
++        self._call_count = 0
++        self._mode = mode
++
++        if mode == Mode.RETURN_NONE:
++            assert len(args) == 0
++            return
++
++        if mode == Mode.RETURN_TRUE:
++            assert len(args) == 2
++            self._src = args[0]
++            self._dest = args[1]
++            return
++
++        if mode == Mode.RETURN_FALSE:
++            assert len(args) == 0
++            return
++
++        if mode == Mode.RETURN_STRING:
++            assert len(args) == 1
++            self._dest = args[0]
++            return
++
++        assert False
++
++
++class exception_handler(MissingDebugHandler):
++    def __init__(self):
++        super().__init__("exception_handler")
++        self.exception_type = None
++
++    def __call__(self, objfile):
++        global handler_call_log
++        handler_call_log.append(self.name)
++        assert self.exception_type is not None
++        raise self.exception_type("message")
++
++
++class log_handler(MissingDebugHandler):
++    def __call__(self, objfile):
++        global handler_call_log
++        handler_call_log.append(self.name)
++        return None
++
++
++# A basic helper function, this keeps lines shorter in the TCL script.
++def register(name, locus=None):
++    gdb.missing_debug.register_handler(locus, log_handler(name))
++
++
++# Create instances of the handlers, but don't install any.  We install
++# these as needed from the TCL script.
++rhandler = exception_handler()
++handler_obj = handler()
++
++print("Success")

diff --git a/gdb-add-rpm-suggestion-script.patch b/gdb-add-rpm-suggestion-script.patch
new file mode 100644
index 0000000..660bc58
--- /dev/null
+++ b/gdb-add-rpm-suggestion-script.patch
@@ -0,0 +1,157 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Thu, 7 Mar 2024 15:14:23 +0000
+Subject: gdb-add-rpm-suggestion-script.patch
+
+;; Not a backport.  Add a new script which hooks into GDB and suggests
+;; RPMs to install when GDB finds an objfile with no debug info.
+
+gdb: add script which will suggest debuginfo RPMs to install
+
+This script hooks into GDB's missing debug info Python API and
+suggests debuginfo RPMs to install.
+
+diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
+--- a/gdb/data-directory/Makefile.in
++++ b/gdb/data-directory/Makefile.in
+@@ -86,6 +86,7 @@ PYTHON_FILE_LIST = \
+ 	gdb/command/missing_debug.py \
+ 	gdb/command/pretty_printers.py \
+ 	gdb/command/prompt.py \
++	gdb/command/rpm-suggestions.py \
+ 	gdb/command/type_printers.py \
+ 	gdb/command/unwinders.py \
+ 	gdb/command/xmethods.py \
+diff --git a/gdb/python/lib/gdb/command/rpm-suggestions.py b/gdb/python/lib/gdb/command/rpm-suggestions.py
+new file mode 100644
+--- /dev/null
++++ b/gdb/python/lib/gdb/command/rpm-suggestions.py
+@@ -0,0 +1,111 @@
++# Copyright 2023 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 <http://www.gnu.org/licenses/>.
++
++import gdb
++import gdb.missing_debug
++import rpm
++
++# Track all the RPMs suggested during a single debug session so we
++# don't suggest the same RPM twice.  This is only cleared when the
++# main executable is changed.
++__missing_rpms = {}
++
++# Track any missing RPMs that have been discovered since the last time
++# the prompt was displayed.  RPMs in here are also present in the
++# __MISSING_RPMS dictionary, but this dictionary is cleared each time
++# the prompt is shown.
++__suggest_rpms = {}
++
++
++# Lookup RPMs that might provide the debug information for FILENAME,
++# which is a string containing the path to an object file GDB could
++# not find any debug information for.
++#
++# If a possible RPM is found then this is added to the globals
++# __MISSING_RPMS and __SUGGEST_RPMS, which are used elsewhere in this
++# script.
++def find_suggestions(filename):
++    ts = rpm.TransactionSet()
++
++    mi = ts.dbMatch(rpm.RPMDBI_BASENAMES, filename)
++    for h in mi:
++        # Build the debuginfo package name.
++        obj = h.format("%{name}-debuginfo-%{version}-%{release}.%{arch}")
++
++        # Check to see if the package is installed.
++        mi2 = ts.dbMatch(rpm.RPMDBI_LABEL, str(obj))
++        if len(mi2) > 0:
++            continue
++
++        # Now build the name of the package FILENAME came from.
++        obj = h.format("%{name}-%{version}-%{release}.%{arch}")
++        rpm_name = str(obj)
++        if not rpm_name in __missing_rpms:
++            __suggest_rpms[rpm_name] = True
++            __missing_rpms[rpm_name] = True
++
++
++# A missing debug handler class.  Just forwards the name of the
++# objfile for which we are missing debug information to
++# find_suggestions.
++class RPMSuggestionHandler(gdb.missing_debug.MissingDebugHandler):
++    def __init__(self):
++        super().__init__("rpm-suggestions")
++
++    def __call__(self, objfile):
++        # Traditionally the 'build-id-verbose' parameter is what
++        # controlled all RPM suggestion.  Maybe once all the RPM
++        # suggestion is performed via Python extensions then we might
++        # consider renaming this parameter to something else, but for
++        # now, for backward compatibility, I've retained this name.
++        if gdb.parameter("build-id-verbose") > 0:
++            find_suggestions(objfile.filename)
++            return False
++        return None
++
++
++# Called before GDB displays its prompt.  If the global __SUGGEST_RPMS
++# dictionary is not empty, then this hook prints treats the keys of
++# this dictionary as strings which are the names of RPMs.  This hook
++# formats each RPM name into a suggested debuginfo-install command and
++# suggests this to the user.
++def before_prompt():
++    global __suggest_rpms
++
++    if len(__suggest_rpms) > 0:
++        for p in __suggest_rpms.keys():
++            print("Missing debuginfo, try: dnf debuginfo-install " + p)
++        __suggest_rpms = {}
++
++
++# Called when the executable within a progrm space is changed.  Clear
++# the lists of RPM suggestions.  We only clear the previous suggestion
++# list when the executable really changes.  If the user simply
++# recompiles the executable, then we don't both clearing this list.
++def executable_changed_handler(event):
++    global __missing_rpms
++    global __suggest_rpms
++
++    if not event.reload:
++        __missing_rpms = {}
++        __suggest_rpms = {}
++
++
++# Attach to the required GDB events.
++gdb.events.executable_changed.connect(executable_changed_handler)
++gdb.events.before_prompt.connect(before_prompt)
++
++# Register the missing debug handler with GDB.
++gdb.missing_debug.register_handler(None, RPMSuggestionHandler())
+diff --git a/gdb/testsuite/gdb.python/py-missing-debug.py b/gdb/testsuite/gdb.python/py-missing-debug.py
+--- a/gdb/testsuite/gdb.python/py-missing-debug.py
++++ b/gdb/testsuite/gdb.python/py-missing-debug.py
+@@ -18,6 +18,13 @@ from gdb.missing_debug import MissingDebugHandler
+ from enum import Enum
+ import os
+ 
++# This is a RHEL/Fedora work around: There's already a
++# missing-debug-info handler registered for these versions of GDB.
++# Discard the handler now so that the tests will pass (the tests
++# assume no handler is currently registered).
++gdb.missing_debug_handlers = []
++
++
+ # A global log that is filled in by instances of the LOG_HANDLER class
+ # when they are called.
+ handler_call_log = []

diff --git a/gdb-archer-next-over-throw-cxx-exec.patch b/gdb-archer-next-over-throw-cxx-exec.patch
index ba71cd3..c5d58b3 100644
--- a/gdb-archer-next-over-throw-cxx-exec.patch
+++ b/gdb-archer-next-over-throw-cxx-exec.patch
@@ -59,7 +59,7 @@ new file mode 100644
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
-+if { [skip_cplus_tests] } { continue }
++require allow_cplus_tests
 +
 +set testfile cxxexec
 +if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.cc {c++ debug}] } {

diff --git a/gdb-bz634108-solib_address.patch b/gdb-bz634108-solib_address.patch
index 58b473f..131e1c1 100644
--- a/gdb-bz634108-solib_address.patch
+++ b/gdb-bz634108-solib_address.patch
@@ -14,7 +14,7 @@ diff --git a/gdb/testsuite/gdb.python/rh634108-solib_address.exp b/gdb/testsuite
 new file mode 100644
 --- /dev/null
 +++ b/gdb/testsuite/gdb.python/rh634108-solib_address.exp
-@@ -0,0 +1,24 @@
+@@ -0,0 +1,25 @@
 +# Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
 +
 +# This program is free software; you can redistribute it and/or modify
@@ -32,10 +32,11 @@ new file mode 100644
 +
 +# https://bugzilla.redhat.com/show_bug.cgi?id=634108
 +
++load_lib gdb-python.exp
++
++require allow_python_tests
++
 +gdb_exit
 +gdb_start
 +
-+# Skip all tests if Python scripting is not enabled.
-+if { [skip_python_tests] } { continue }
-+
 +gdb_test "python print (gdb.solib_name(-1))" "None" "gdb.solib_name exists"

diff --git a/gdb-do-not-import-py-curses-ascii-module.patch b/gdb-do-not-import-py-curses-ascii-module.patch
new file mode 100644
index 0000000..40e544b
--- /dev/null
+++ b/gdb-do-not-import-py-curses-ascii-module.patch
@@ -0,0 +1,64 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Tom de Vries <tdevries@suse.de>
+Date: Wed, 22 Nov 2023 19:02:34 +0100
+Subject: gdb-do-not-import-py-curses-ascii-module.patch
+
+;; Backport upstream commit e8c3dafa5f5.
+
+[gdb/python] Don't import curses.ascii module unless necessary
+
+I ran into a failure in test-case gdb.python/py-missing-debug.exp with python
+3.6, which was fixed by commit 7db795bc67a ("gdb/python: remove use of
+str.isascii()").
+
+However, I subsequently ran into a failure with python 3.11:
+...
+(gdb) PASS: $exp: initial checks: debug info no longer found
+source py-missing-debug.py^M
+Traceback (most recent call last):^M
+  File "py-missing-debug.py", line 17, in <module>^M
+    from gdb.missing_debug import MissingDebugHandler^M
+  File "missing_debug.py", line 21, in <module>^M
+    from curses.ascii import isascii, isalnum^M
+  File "/usr/lib64/python3.11/_import_failed/curses.py", line 16, in <module>^M
+    raise ImportError(f"""Module '{failed_name}' is not installed.^M
+ImportError: Module 'curses' is not installed.^M
+Use:^M
+  sudo zypper install python311-curses^M
+to install it.^M
+(gdb) FAIL: $exp: source python script
+...
+
+Apparently I have the curses module installed for 3.6, but not 3.11.
+
+I could just install it, but the test-case worked fine with 3.11 before commit
+7db795bc67a.
+
+Fix this by only using the curses module when necessary, for python <= 3.7.
+
+Tested on x86_64-linux, with both python 3.6 and 3.11.
+
+diff --git a/gdb/python/lib/gdb/missing_debug.py b/gdb/python/lib/gdb/missing_debug.py
+--- a/gdb/python/lib/gdb/missing_debug.py
++++ b/gdb/python/lib/gdb/missing_debug.py
+@@ -18,8 +18,18 @@ MissingDebugHandler base class, and register_handler function.
+ """
+ 
+ import gdb
+-from curses.ascii import isascii, isalnum
+-
++import sys
++if sys.version_info >= (3, 7):
++    # Functions str.isascii() and str.isalnum are available starting Python
++    # 3.7.
++    def isascii(ch):
++        return ch.isascii()
++    def isalnum(ch):
++        return ch.isalnum()
++else:
++    # Fall back to curses.ascii.isascii() and curses.ascii.isalnum() for
++    # earlier versions.
++    from curses.ascii import isascii, isalnum
+ 
+ def _validate_name(name):
+     """Validate a missing debug handler name string.

diff --git a/gdb-fedora-libncursesw.patch b/gdb-fedora-libncursesw.patch
index 1bb640d..3ee4ab6 100644
--- a/gdb-fedora-libncursesw.patch
+++ b/gdb-fedora-libncursesw.patch
@@ -12,269 +12,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1270534
 diff --git a/gdb/configure b/gdb/configure
 --- a/gdb/configure
 +++ b/gdb/configure
-@@ -780,9 +780,6 @@ ENABLE_BFD_64_BIT_TRUE
- subdirs
- RPM_LIBS
- RPM_CFLAGS
--PKG_CONFIG_LIBDIR
--PKG_CONFIG_PATH
--PKG_CONFIG
- GDB_DATADIR
- DEBUGDIR
- MAKEINFO_EXTRA_FLAGS
-@@ -990,12 +987,12 @@ PKG_CONFIG_PATH
- PKG_CONFIG_LIBDIR
- MAKEINFO
- MAKEINFOFLAGS
-+RPM_CFLAGS
-+RPM_LIBS
- AMD_DBGAPI_CFLAGS
- AMD_DBGAPI_LIBS
- DEBUGINFOD_CFLAGS
- DEBUGINFOD_LIBS
--RPM_CFLAGS
--RPM_LIBS
- YACC
- YFLAGS
- ZSTD_CFLAGS
-@@ -1684,11 +1681,11 @@ Optional Packages:
-                           [--with-auto-load-dir]
-   --without-auto-load-safe-path
-                           do not restrict auto-loaded files locations
-+  --with-rpm              query rpm database for missing debuginfos (yes/no,
-+                          def. auto=librpm.so)
-   --with-amd-dbgapi       support for the amd-dbgapi target (yes / no / auto)
-   --with-debuginfod       Enable debuginfo lookups with debuginfod
-                           (auto/yes/no)
--  --with-rpm              query rpm database for missing debuginfos (yes/no,
--                          def. auto=librpm.so)
-   --with-libunwind-ia64   use libunwind frame unwinding for ia64 targets
-   --with-curses           use the curses library instead of the termcap
-                           library
-@@ -1761,6 +1758,8 @@ Some influential environment variables:
-   MAKEINFO    Parent configure detects if it is of sufficient version.
-   MAKEINFOFLAGS
-               Parameters for MAKEINFO.
-+  RPM_CFLAGS  C compiler flags for RPM, overriding pkg-config
-+  RPM_LIBS    linker flags for RPM, overriding pkg-config
-   AMD_DBGAPI_CFLAGS
-               C compiler flags for AMD_DBGAPI, overriding pkg-config
-   AMD_DBGAPI_LIBS
-@@ -1769,8 +1768,6 @@ Some influential environment variables:
-               C compiler flags for DEBUGINFOD, overriding pkg-config
-   DEBUGINFOD_LIBS
-               linker flags for DEBUGINFOD, overriding pkg-config
--  RPM_CFLAGS  C compiler flags for RPM, overriding pkg-config
--  RPM_LIBS    linker flags for RPM, overriding pkg-config
-   YACC        The `Yet Another Compiler Compiler' implementation to use.
-               Defaults to the first program found out of: `bison -y', `byacc',
-               `yacc'.
-@@ -11495,7 +11492,7 @@ else
-   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-   lt_status=$lt_dlunknown
-   cat > conftest.$ac_ext <<_LT_EOF
--#line 11486 "configure"
-+#line 11495 "configure"
- #include "confdefs.h"
- 
- #if HAVE_DLFCN_H
-@@ -11601,7 +11598,7 @@ else
-   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-   lt_status=$lt_dlunknown
-   cat > conftest.$ac_ext <<_LT_EOF
--#line 11592 "configure"
-+#line 11601 "configure"
- #include "confdefs.h"
- 
- #if HAVE_DLFCN_H
-@@ -18102,8 +18099,8 @@ $as_echo_n "checking specific librpm version... " >&6; }
-   if test "$cross_compiling" = yes; then :
-   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
- $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
--as_fn_error "cannot run test program while cross compiling
--See \`config.log' for more details." "$LINENO" 5; }
-+as_fn_error $? "cannot run test program while cross compiling
-+See \`config.log' for more details" "$LINENO" 5; }
- else
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
- /* end confdefs.h.  */
-@@ -18275,132 +18272,12 @@ $as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
- $as_echo "no" >&6; }
-     LIBS="$save_LIBS"
-     if $DLOPEN_REQUIRE; then
--      as_fn_error "Specific name $LIBRPM was requested but it could not be opened." "$LINENO" 5
-+      as_fn_error $? "Specific name $LIBRPM was requested but it could not be opened." "$LINENO" 5
-     fi
- 
--
--
--
--
--
--
--if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
--	if test -n "$ac_tool_prefix"; then
--  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
--set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
--$as_echo_n "checking for $ac_word... " >&6; }
--if test "${ac_cv_path_PKG_CONFIG+set}" = set; then :
--  $as_echo_n "(cached) " >&6
--else
--  case $PKG_CONFIG in
--  [\\/]* | ?:[\\/]*)
--  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
--  ;;
--  *)
--  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
--for as_dir in $PATH
--do
--  IFS=$as_save_IFS
--  test -z "$as_dir" && as_dir=.
--    for ac_exec_ext in '' $ac_executable_extensions; do
--  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
--    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
--    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
--    break 2
--  fi
--done
--  done
--IFS=$as_save_IFS
--
--  ;;
--esac
--fi
--PKG_CONFIG=$ac_cv_path_PKG_CONFIG
--if test -n "$PKG_CONFIG"; then
--  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
--$as_echo "$PKG_CONFIG" >&6; }
--else
--  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
--$as_echo "no" >&6; }
--fi
--
--
--fi
--if test -z "$ac_cv_path_PKG_CONFIG"; then
--  ac_pt_PKG_CONFIG=$PKG_CONFIG
--  # Extract the first word of "pkg-config", so it can be a program name with args.
--set dummy pkg-config; ac_word=$2
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
--$as_echo_n "checking for $ac_word... " >&6; }
--if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then :
--  $as_echo_n "(cached) " >&6
--else
--  case $ac_pt_PKG_CONFIG in
--  [\\/]* | ?:[\\/]*)
--  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
--  ;;
--  *)
--  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
--for as_dir in $PATH
--do
--  IFS=$as_save_IFS
--  test -z "$as_dir" && as_dir=.
--    for ac_exec_ext in '' $ac_executable_extensions; do
--  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
--    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
--    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
--    break 2
--  fi
--done
--  done
--IFS=$as_save_IFS
--
--  ;;
--esac
--fi
--ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
--if test -n "$ac_pt_PKG_CONFIG"; then
--  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
--$as_echo "$ac_pt_PKG_CONFIG" >&6; }
--else
--  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
--$as_echo "no" >&6; }
--fi
--
--  if test "x$ac_pt_PKG_CONFIG" = x; then
--    PKG_CONFIG=""
--  else
--    case $cross_compiling:$ac_tool_warned in
--yes:)
--{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
--$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
--ac_tool_warned=yes ;;
--esac
--    PKG_CONFIG=$ac_pt_PKG_CONFIG
--  fi
--else
--  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
--fi
--
--fi
--if test -n "$PKG_CONFIG"; then
--	_pkg_min_version=0.9.0
--	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
--$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
--	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
--		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
--$as_echo "yes" >&6; }
--	else
--		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
--$as_echo "no" >&6; }
--		PKG_CONFIG=""
--	fi
--fi
--
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RPM" >&5
--$as_echo_n "checking for RPM... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rpm" >&5
-+$as_echo_n "checking for rpm... " >&6; }
- 
- if test -n "$RPM_CFLAGS"; then
-     pkg_cv_RPM_CFLAGS="$RPM_CFLAGS"
-@@ -18437,6 +18314,30 @@ fi
-     pkg_failed=untried
- fi
- 
-+if test $pkg_failed = no; then
-+  pkg_save_LDFLAGS="$LDFLAGS"
-+  LDFLAGS="$LDFLAGS $pkg_cv_RPM_LIBS"
-+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+int
-+main ()
-+{
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_link "$LINENO"; then :
-+
-+else
-+  pkg_failed=yes
-+fi
-+rm -f core conftest.err conftest.$ac_objext \
-+    conftest$ac_exeext conftest.$ac_ext
-+  LDFLAGS=$pkg_save_LDFLAGS
-+fi
-+
- 
- 
- if test $pkg_failed = yes; then
-@@ -18531,7 +18432,7 @@ $as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
-       LIBS="$LIBS $RPM_LIBS"
-     else
-       if $RPM_REQUIRE; then
--	as_fn_error "$RPM_PKG_ERRORS" "$LINENO" 5
-+	as_fn_error $? "$RPM_PKG_ERRORS" "$LINENO" 5
-       else
- 	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $RPM_PKG_ERRORS" >&5
- $as_echo "$as_me: WARNING: $RPM_PKG_ERRORS" >&2;}
-@@ -21164,6 +21065,7 @@ if test x"$prefer_curses" = xyes; then
+@@ -20663,6 +20663,7 @@ if test x"$prefer_curses" = xyes; then
    # search /usr/local/include, if ncurses is installed in /usr/local.  A
    # default installation of ncurses on alpha*-dec-osf* will lead to such
    # a situation.
@@ -282,7 +20,7 @@ diff --git a/gdb/configure b/gdb/configure
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing waddstr" >&5
  $as_echo_n "checking for library containing waddstr... " >&6; }
  if ${ac_cv_search_waddstr+:} false; then :
-@@ -21188,7 +21090,7 @@ return waddstr ();
+@@ -20687,7 +20688,7 @@ return waddstr ();
    return 0;
  }
  _ACEOF
@@ -291,7 +29,7 @@ diff --git a/gdb/configure b/gdb/configure
    if test -z "$ac_lib"; then
      ac_res="none required"
    else
-@@ -21260,6 +21162,7 @@ case $host_os in
+@@ -20759,6 +20760,7 @@ case $host_os in
  esac
  
  # These are the libraries checked by Readline.
@@ -299,7 +37,7 @@ diff --git a/gdb/configure b/gdb/configure
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
  $as_echo_n "checking for library containing tgetent... " >&6; }
  if ${ac_cv_search_tgetent+:} false; then :
-@@ -21284,7 +21187,7 @@ return tgetent ();
+@@ -20783,7 +20785,7 @@ return tgetent ();
    return 0;
  }
  _ACEOF
@@ -311,7 +49,7 @@ diff --git a/gdb/configure b/gdb/configure
 diff --git a/gdb/configure.ac b/gdb/configure.ac
 --- a/gdb/configure.ac
 +++ b/gdb/configure.ac
-@@ -749,7 +749,8 @@ if test x"$prefer_curses" = xyes; then
+@@ -555,7 +555,8 @@ if test x"$prefer_curses" = xyes; then
    # search /usr/local/include, if ncurses is installed in /usr/local.  A
    # default installation of ncurses on alpha*-dec-osf* will lead to such
    # a situation.
@@ -321,7 +59,7 @@ diff --git a/gdb/configure.ac b/gdb/configure.ac
                   [curses_found=yes
                    AC_DEFINE([HAVE_LIBCURSES], [1],
                              [Define to 1 if curses is enabled.])
-@@ -789,7 +790,8 @@ case $host_os in
+@@ -595,7 +596,8 @@ case $host_os in
  esac
  
  # These are the libraries checked by Readline.

diff --git a/gdb-glibc-strstr-workaround.patch b/gdb-glibc-strstr-workaround.patch
index da9c5de..ad0bd0f 100644
--- a/gdb-glibc-strstr-workaround.patch
+++ b/gdb-glibc-strstr-workaround.patch
@@ -10,7 +10,7 @@ diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-strstr-workaround.exp b/gdb/testsu
 new file mode 100644
 --- /dev/null
 +++ b/gdb/testsuite/gdb.base/gnu-ifunc-strstr-workaround.exp
-@@ -0,0 +1,119 @@
+@@ -0,0 +1,117 @@
 +# Copyright (C) 2012 Free Software Foundation, Inc.
 +
 +# This program is free software; you can redistribute it and/or modify
@@ -30,9 +30,7 @@ new file mode 100644
 +# invalid IFUNC DW_AT_linkage_name: memmove strstr time
 +# http://sourceware.org/bugzilla/show_bug.cgi?id=14166
 +
-+if {[skip_shlib_tests]} {
-+    return 0
-+}
++require allow_shlib_tests
 +
 +set testfile "gnu-ifunc-strstr-workaround"
 +set executable ${testfile}

diff --git a/gdb-handle-no-python-gdb-module.patch b/gdb-handle-no-python-gdb-module.patch
new file mode 100644
index 0000000..21966a5
--- /dev/null
+++ b/gdb-handle-no-python-gdb-module.patch
@@ -0,0 +1,30 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Tom Tromey <tromey@adacore.com>
+Date: Wed, 15 Nov 2023 06:48:55 -0700
+Subject: gdb-handle-no-python-gdb-module.patch
+
+;; Backport upstream commit 7d21600b31fe.
+
+Check gdb_python_module in gdbpy_handle_missing_debuginfo
+
+If you run gdb in the build tree without --data-directory, on a
+program that does not have debug info, it will crash, because
+gdbpy_handle_missing_debuginfo unconditionally uses gdb_python_module.
+
+Other code in gdb using gdb_python_module checks it first and it
+seemes harmless to do the same thing here.  (gdb_python_initialized
+does not cover this case so that python can be partially initialized
+and still somewhat work.)
+
+diff --git a/gdb/python/python.c b/gdb/python/python.c
+--- a/gdb/python/python.c
++++ b/gdb/python/python.c
+@@ -1676,7 +1676,7 @@ gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
+ 				struct objfile *objfile)
+ {
+   /* Early exit if Python is not initialised.  */
+-  if (!gdb_python_initialized)
++  if (!gdb_python_initialized || gdb_python_module == nullptr)
+     return {};
+ 
+   struct gdbarch *gdbarch = objfile->arch ();

diff --git a/gdb-merge-debug-symbol-lookup.patch b/gdb-merge-debug-symbol-lookup.patch
new file mode 100644
index 0000000..e9b5058
--- /dev/null
+++ b/gdb-merge-debug-symbol-lookup.patch
@@ -0,0 +1,265 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Fri, 13 Oct 2023 09:50:33 +0100
+Subject: gdb-merge-debug-symbol-lookup.patch
+
+;; Backport upstream commit 27807da5849.
+
+gdb: merge debug symbol file lookup code from coffread & elfread paths
+
+This commit merges the code that looks for and loads the separate
+debug symbol files from coffread.c and elfread.c.  The factored out
+code is moved into a new objfile::find_and_add_separate_symbol_file()
+method.
+
+For the elfread.c path there should be no user visible changes after
+this commit.
+
+For the coffread.c path GDB will now attempt to perform a debuginfod
+lookup for the missing debug information, assuming that GDB can find a
+build-id in the COFF file.
+
+I don't know if COFF files can include a build-id, but I the existing
+coffread.c code already includes a call to
+find_separate_debug_file_by_build-id, so I know that it is at least OK
+for GDB to ask a COFF file for a build-id.  If the COFF file doesn't
+include a build-id then the debuginfod lookup code will not trigger
+and the new code is harmless.
+
+If the COFF file does include a build-id, then we're going to end up
+asking debuginfod for the debug file.  As build-ids should be unique,
+this should be harmless, even if debuginfod doesn't contain any
+suitable debug data, it just costs us one debuginfod lookup, so I'm
+not too worried about this for now.
+
+As with the previous commit, I've done some minimal testing using the
+mingw toolchain on a Linux machine, GDB seems to still access the
+split debug information just fine.
+
+Approved-By: Tom Tromey <tom@tromey.com>
+
+diff --git a/gdb/coffread.c b/gdb/coffread.c
+--- a/gdb/coffread.c
++++ b/gdb/coffread.c
+@@ -40,8 +40,6 @@
+ 
+ #include "coff-pe-read.h"
+ 
+-#include "build-id.h"
+-
+ /* The objfile we are currently reading.  */
+ 
+ static struct objfile *coffread_objfile;
+@@ -729,26 +727,8 @@ coff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
+ 	   && objfile->separate_debug_objfile == NULL
+ 	   && objfile->separate_debug_objfile_backlink == NULL)
+     {
+-      deferred_warnings warnings;
+-      std::string debugfile
+-	= find_separate_debug_file_by_buildid (objfile, &warnings);
+-
+-      if (debugfile.empty ())
+-	debugfile
+-	  = find_separate_debug_file_by_debuglink (objfile, &warnings);
+-
+-      if (!debugfile.empty ())
+-	{
+-	  gdb_bfd_ref_ptr debug_bfd (symfile_bfd_open (debugfile.c_str ()));
+-
+-	  symbol_file_add_separate (debug_bfd, debugfile.c_str (),
+-				    symfile_flags, objfile);
+-	}
+-      /* If all the methods to collect the debuginfo failed, print any
+-	 warnings that were collected, this is a no-op if there are no
+-	 warnings.  */
+-      if (debugfile.empty ())
+-	warnings.emit ();
++      if (objfile->find_and_add_separate_symbol_file (symfile_flags))
++	gdb_assert (objfile->separate_debug_objfile != nullptr);
+     }
+ }
+ 
+diff --git a/gdb/elfread.c b/gdb/elfread.c
+--- a/gdb/elfread.c
++++ b/gdb/elfread.c
+@@ -41,14 +41,12 @@
+ #include "regcache.h"
+ #include "bcache.h"
+ #include "gdb_bfd.h"
+-#include "build-id.h"
+ #include "location.h"
+ #include "auxv.h"
+ #include "mdebugread.h"
+ #include "ctfread.h"
+ #include "gdbsupport/gdb_string_view.h"
+ #include "gdbsupport/scoped_fd.h"
+-#include "debuginfod-support.h"
+ #include "dwarf2/public.h"
+ #include "cli/cli-cmds.h"
+ 
+@@ -1218,59 +1216,10 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
+ 	   && objfile->separate_debug_objfile == NULL
+ 	   && objfile->separate_debug_objfile_backlink == NULL)
+     {
+-      deferred_warnings warnings;
+-
+-      std::string debugfile
+-	= find_separate_debug_file_by_buildid (objfile, &warnings);
+-
+-      if (debugfile.empty ())
+-	debugfile = find_separate_debug_file_by_debuglink (objfile, &warnings);
+-
+-      if (!debugfile.empty ())
+-	{
+-	  gdb_bfd_ref_ptr debug_bfd
+-	    (symfile_bfd_open_no_error (debugfile.c_str ()));
+-
+-	  if (debug_bfd != nullptr)
+-	    symbol_file_add_separate (debug_bfd, debugfile.c_str (),
+-				      symfile_flags, objfile);
+-	}
++      if (objfile->find_and_add_separate_symbol_file (symfile_flags))
++	gdb_assert (objfile->separate_debug_objfile != nullptr);
+       else
+-	{
+-	  has_dwarf2 = false;
+-	  const struct bfd_build_id *build_id
+-	    = build_id_bfd_get (objfile->obfd.get ());
+-	  const char *filename = bfd_get_filename (objfile->obfd.get ());
+-
+-	  if (build_id != nullptr)
+-	    {
+-	      gdb::unique_xmalloc_ptr<char> symfile_path;
+-	      scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
+-							build_id->size,
+-							filename,
+-							&symfile_path));
+-
+-	      if (fd.get () >= 0)
+-		{
+-		  /* File successfully retrieved from server.  */
+-		  gdb_bfd_ref_ptr debug_bfd
+-		    (symfile_bfd_open_no_error (symfile_path.get ()));
+-
+-		  if (debug_bfd != nullptr
+-		      && build_id_verify (debug_bfd.get (), build_id->size,
+-					  build_id->data))
+-		    {
+-		      symbol_file_add_separate (debug_bfd, symfile_path.get (),
+-						symfile_flags, objfile);
+-		      has_dwarf2 = true;
+-		    }
+-		}
+-	    }
+-	}
+-      /* If all the methods to collect the debuginfo failed, print the
+-	 warnings, this is a no-op if there are no warnings.  */
+-      if (debugfile.empty () && !has_dwarf2)
+-	warnings.emit ();
++	has_dwarf2 = false;
+     }
+ 
+   return has_dwarf2;
+diff --git a/gdb/objfiles.h b/gdb/objfiles.h
+--- a/gdb/objfiles.h
++++ b/gdb/objfiles.h
+@@ -513,6 +513,16 @@ struct objfile
+ 
+   bool has_partial_symbols ();
+ 
++  /* Look for a separate debug symbol file for this objfile, make use of
++     build-id, debug-link, and debuginfod as necessary.  If a suitable
++     separate debug symbol file is found then it is loaded using a call to
++     symbol_file_add_separate (SYMFILE_FLAGS is passed through unmodified
++     to this call) and this function returns true.  If no suitable separate
++     debug symbol file is found and loaded then this function returns
++     false.  */
++
++  bool find_and_add_separate_symbol_file (symfile_add_flags symfile_flags);
++
+   /* Return true if this objfile has any unexpanded symbols.  A return
+      value of false indicates either, that this objfile has all its
+      symbols fully expanded (i.e. fully read in), or that this objfile has
+diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
+--- a/gdb/symfile-debug.c
++++ b/gdb/symfile-debug.c
+@@ -35,6 +35,8 @@
+ #include "block.h"
+ #include "filenames.h"
+ #include "cli/cli-style.h"
++#include "build-id.h"
++#include "debuginfod-support.h"
+ 
+ /* We need to save a pointer to the real symbol functions.
+    Plus, the debug versions are malloc'd because we have to NULL out the
+@@ -558,6 +560,70 @@ objfile::require_partial_symbols (bool verbose)
+     }
+ }
+ 
++/* See objfiles.h.  */
++
++bool
++objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
++{
++  bool has_dwarf2 = true;
++
++  deferred_warnings warnings;
++
++  std::string debugfile
++    = find_separate_debug_file_by_buildid (this, &warnings);
++
++  if (debugfile.empty ())
++    debugfile = find_separate_debug_file_by_debuglink (this, &warnings);
++
++  if (!debugfile.empty ())
++    {
++      gdb_bfd_ref_ptr debug_bfd
++	(symfile_bfd_open_no_error (debugfile.c_str ()));
++
++      if (debug_bfd != nullptr)
++	symbol_file_add_separate (debug_bfd, debugfile.c_str (),
++				  symfile_flags, this);
++    }
++  else
++    {
++      has_dwarf2 = false;
++      const struct bfd_build_id *build_id
++	= build_id_bfd_get (this->obfd.get ());
++      const char *filename = bfd_get_filename (this->obfd.get ());
++
++      if (build_id != nullptr)
++	{
++	  gdb::unique_xmalloc_ptr<char> symfile_path;
++	  scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
++						    build_id->size,
++						    filename,
++						    &symfile_path));
++
++	  if (fd.get () >= 0)
++	    {
++	      /* File successfully retrieved from server.  */
++	      gdb_bfd_ref_ptr debug_bfd
++		(symfile_bfd_open_no_error (symfile_path.get ()));
++
++	      if (debug_bfd != nullptr
++		  && build_id_verify (debug_bfd.get (), build_id->size,
++				      build_id->data))
++		{
++		  symbol_file_add_separate (debug_bfd, symfile_path.get (),
++					    symfile_flags, this);
++		  has_dwarf2 = true;
++		}
++	    }
++	}
++    }
++  /* If all the methods to collect the debuginfo failed, print the
++     warnings, this is a no-op if there are no warnings.  */
++  if (debugfile.empty () && !has_dwarf2)
++    warnings.emit ();
++
++  return has_dwarf2;
++}
++
+ \f
+ /* Debugging version of struct sym_probe_fns.  */
+ 

diff --git a/gdb-refactor-find-and-add-separate-symbol-file.patch b/gdb-refactor-find-and-add-separate-symbol-file.patch
new file mode 100644
index 0000000..83ceabb
--- /dev/null
+++ b/gdb-refactor-find-and-add-separate-symbol-file.patch
@@ -0,0 +1,190 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Fri, 13 Oct 2023 16:17:20 +0100
+Subject: gdb-refactor-find-and-add-separate-symbol-file.patch
+
+;; Backport upstream commit 6234ba17598.
+
+gdb: refactor objfile::find_and_add_separate_symbol_file
+
+This is purely a refactoring commit.
+
+This commit splits objfile::find_and_add_separate_symbol_file into
+some separate helper functions.  My hope is that the steps for looking
+up separate debug information are now clearer.
+
+In a later commit I'm going to extend
+objfile::find_and_add_separate_symbol_file, with some additional
+logic, so starting with a simpler function will make the following
+changes easier.
+
+When reading objfile::find_and_add_separate_symbol_file after this
+commit, you might be tempted to think that removing the `has_dwarf`
+local variable would be a good additional cleanup.  After the next
+commit though it makes more sense to retain this local, so I've left
+this in place for now.
+
+There should be no user visible changes after this commit.
+
+Approved-By: Tom Tromey <tom@tromey.com>
+
+diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
+--- a/gdb/symfile-debug.c
++++ b/gdb/symfile-debug.c
+@@ -560,68 +560,109 @@ objfile::require_partial_symbols (bool verbose)
+     }
+ }
+ 
++/* Call LOOKUP_FUNC to find the filename of a file containing the separate
++   debug information matching OBJFILE.  If LOOKUP_FUNC does return a
++   filename then open this file and return a std::pair containing the
++   gdb_bfd_ref_ptr of the open file and the filename returned by
++   LOOKUP_FUNC, otherwise this function returns an empty pair; the first
++   item will be nullptr, and the second will be an empty string.
++
++   Any warnings generated by this function, or by calling LOOKUP_FUNC are
++   placed into WARNINGS, these warnings are only displayed to the user if
++   GDB is unable to find the separate debug information via any route.  */
++static std::pair<gdb_bfd_ref_ptr, std::string>
++simple_find_and_open_separate_symbol_file
++  (struct objfile *objfile,
++   std::string (*lookup_func) (struct objfile *, deferred_warnings *),
++   deferred_warnings *warnings)
++{
++  std::string filename = lookup_func (objfile, warnings);
++
++  if (!filename.empty ())
++    {
++      gdb_bfd_ref_ptr symfile_bfd
++	= symfile_bfd_open_no_error (filename.c_str ());
++      if (symfile_bfd != nullptr)
++	return { symfile_bfd, filename };
++    }
++
++  return {};
++}
++
++/* Lookup separate debug information for OBJFILE via debuginfod.  If
++   successful the debug information will be have been downloaded into the
++   debuginfod cache and this function will return a std::pair containing a
++   gdb_bfd_ref_ptr of the open debug information file and the filename for
++   the file within the debuginfod cache.  If no debug information could be
++   found then this function returns an empty pair; the first item will be
++   nullptr, and the second will be an empty string.  */
++
++static std::pair<gdb_bfd_ref_ptr, std::string>
++debuginfod_find_and_open_separate_symbol_file (struct objfile * objfile)
++{
++  const struct bfd_build_id *build_id
++    = build_id_bfd_get (objfile->obfd.get ());
++  const char *filename = bfd_get_filename (objfile->obfd.get ());
++
++  if (build_id != nullptr)
++    {
++      gdb::unique_xmalloc_ptr<char> symfile_path;
++      scoped_fd fd (debuginfod_debuginfo_query (build_id->data, build_id->size,
++						filename, &symfile_path));
++
++      if (fd.get () >= 0)
++	{
++	  /* File successfully retrieved from server.  */
++	  gdb_bfd_ref_ptr debug_bfd
++	    (symfile_bfd_open_no_error (symfile_path.get ()));
++
++	  if (debug_bfd != nullptr
++	      && build_id_verify (debug_bfd.get (),
++				  build_id->size, build_id->data))
++	    return { debug_bfd, std::string (symfile_path.get ()) };
++	}
++    }
++
++  return {};
++}
++
+ /* See objfiles.h.  */
+ 
+ bool
+ objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
+ {
+-  bool has_dwarf2 = true;
++  bool has_dwarf = false;
+ 
+   deferred_warnings warnings;
+ 
+-  std::string debugfile
+-    = find_separate_debug_file_by_buildid (this, &warnings);
+-
+-  if (debugfile.empty ())
+-    debugfile = find_separate_debug_file_by_debuglink (this, &warnings);
++  gdb_bfd_ref_ptr debug_bfd;
++  std::string filename;
+ 
+-  if (!debugfile.empty ())
+-    {
+-      gdb_bfd_ref_ptr debug_bfd
+-	(symfile_bfd_open_no_error (debugfile.c_str ()));
++  std::tie (debug_bfd, filename) = simple_find_and_open_separate_symbol_file
++    (this, find_separate_debug_file_by_buildid, &warnings);
+ 
+-      if (debug_bfd != nullptr)
+-	symbol_file_add_separate (debug_bfd, debugfile.c_str (),
+-				  symfile_flags, this);
+-    }
+-  else
+-    {
+-      has_dwarf2 = false;
+-      const struct bfd_build_id *build_id
+-	= build_id_bfd_get (this->obfd.get ());
+-      const char *filename = bfd_get_filename (this->obfd.get ());
+-
+-      if (build_id != nullptr)
+-	{
+-	  gdb::unique_xmalloc_ptr<char> symfile_path;
+-	  scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
+-						    build_id->size,
+-						    filename,
+-						    &symfile_path));
++  if (debug_bfd == nullptr)
++    std::tie (debug_bfd, filename)
++      = simple_find_and_open_separate_symbol_file
++	  (this, find_separate_debug_file_by_debuglink, &warnings);
+ 
+-	  if (fd.get () >= 0)
+-	    {
+-	      /* File successfully retrieved from server.  */
+-	      gdb_bfd_ref_ptr debug_bfd
+-		(symfile_bfd_open_no_error (symfile_path.get ()));
++  if (debug_bfd == nullptr)
++    std::tie (debug_bfd, filename)
++      = debuginfod_find_and_open_separate_symbol_file (this);
+ 
+-	      if (debug_bfd != nullptr
+-		  && build_id_verify (debug_bfd.get (), build_id->size,
+-				      build_id->data))
+-		{
+-		  symbol_file_add_separate (debug_bfd, symfile_path.get (),
+-					    symfile_flags, this);
+-		  has_dwarf2 = true;
+-		}
+-	    }
+-	}
++  if (debug_bfd != nullptr)
++    {
++      symbol_file_add_separate (debug_bfd, filename.c_str (), symfile_flags,
++				this);
++      has_dwarf = true;
+     }
+-  /* If all the methods to collect the debuginfo failed, print the
+-     warnings, this is a no-op if there are no warnings.  */
+-  if (debugfile.empty () && !has_dwarf2)
++
++  /* If we still have not got a separate debug symbol file, then
++     emit any warnings we've collected so far.  */
++  if (!has_dwarf)
+     warnings.emit ();
+ 
+-  return has_dwarf2;
++  return has_dwarf;
+ }
+ 
+ \f

diff --git a/gdb-reformat-missing-debug-py-file.patch b/gdb-reformat-missing-debug-py-file.patch
new file mode 100644
index 0000000..c988fa2
--- /dev/null
+++ b/gdb-reformat-missing-debug-py-file.patch
@@ -0,0 +1,38 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Tom de Vries <tdevries@suse.de>
+Date: Thu, 23 Nov 2023 07:37:19 +0100
+Subject: gdb-reformat-missing-debug-py-file.patch
+
+;; Backport upstream commit dd5516bf98f.
+
+[gdb/python] Reformat missing_debug.py using black
+
+Reformat gdb/python/lib/gdb/missing_debug.py with black after commit
+e8c3dafa5f5 ("[gdb/python] Don't import curses.ascii module unless necessary").
+
+diff --git a/gdb/python/lib/gdb/missing_debug.py b/gdb/python/lib/gdb/missing_debug.py
+--- a/gdb/python/lib/gdb/missing_debug.py
++++ b/gdb/python/lib/gdb/missing_debug.py
+@@ -19,18 +19,22 @@ MissingDebugHandler base class, and register_handler function.
+ 
+ import gdb
+ import sys
++
+ if sys.version_info >= (3, 7):
+     # Functions str.isascii() and str.isalnum are available starting Python
+     # 3.7.
+     def isascii(ch):
+         return ch.isascii()
++
+     def isalnum(ch):
+         return ch.isalnum()
++
+ else:
+     # Fall back to curses.ascii.isascii() and curses.ascii.isalnum() for
+     # earlier versions.
+     from curses.ascii import isascii, isalnum
+ 
++
+ def _validate_name(name):
+     """Validate a missing debug handler name string.
+ 

diff --git a/gdb-remove-path-in-test-name.patch b/gdb-remove-path-in-test-name.patch
new file mode 100644
index 0000000..f637ab9
--- /dev/null
+++ b/gdb-remove-path-in-test-name.patch
@@ -0,0 +1,29 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Tom Tromey <tromey@adacore.com>
+Date: Tue, 14 Nov 2023 11:47:27 -0700
+Subject: gdb-remove-path-in-test-name.patch
+
+;; Backport upstream commit 1146d27749f.
+
+Remove path name from test case
+
+'runtest' complains about a path in a test name, from the new test
+case py-missing-debug.exp.
+
+This patch fixes the problem by providing an explicit test name to
+gdb_test.  I chose something very basic because the block in question
+is already wrapped in with_test_prefix.
+
+diff --git a/gdb/testsuite/gdb.python/py-missing-debug.exp b/gdb/testsuite/gdb.python/py-missing-debug.exp
+--- a/gdb/testsuite/gdb.python/py-missing-debug.exp
++++ b/gdb/testsuite/gdb.python/py-missing-debug.exp
+@@ -321,7 +321,8 @@ with_test_prefix "enable 'abc-def'" {
+     set re [string_to_regexp $binfile]
+ 
+     gdb_test "enable missing-debug-handler \"$re\" abc-def" \
+-	"^1 missing debug handler enabled"
++	"^1 missing debug handler enabled" \
++	"enable missing-debug-handler"
+ 
+     gdb_test "info missing-debug-handlers" \
+ 	[multi_line \

diff --git a/gdb-remove-use-of-py-isascii b/gdb-remove-use-of-py-isascii
new file mode 100644
index 0000000..a605d1c
--- /dev/null
+++ b/gdb-remove-use-of-py-isascii
@@ -0,0 +1,46 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Thu, 16 Nov 2023 10:53:34 +0000
+Subject: gdb-remove-use-of-py-isascii
+
+;; Backport upstream commit 7db795bc67a.
+
+gdb/python: remove use of str.isascii()
+
+This commit:
+
+  commit 8f6c452b5a4e50fbb55ff1d13328b392ad1fd416
+  Date:   Sun Oct 15 22:48:42 2023 +0100
+
+      gdb: implement missing debug handler hook for Python
+
+introduced a use of str.isascii(), which was only added in Python 3.7.
+
+This commit switches to use curses.ascii.isascii(), as this was
+available in 3.6.
+
+The same is true for str.isalnum(), which is replaced with
+curses.ascii.isalnum().
+
+There should be no user visible changes after this commit.
+
+diff --git a/gdb/python/lib/gdb/missing_debug.py b/gdb/python/lib/gdb/missing_debug.py
+--- a/gdb/python/lib/gdb/missing_debug.py
++++ b/gdb/python/lib/gdb/missing_debug.py
+@@ -18,6 +18,7 @@ MissingDebugHandler base class, and register_handler function.
+ """
+ 
+ import gdb
++from curses.ascii import isascii, isalnum
+ 
+ 
+ def _validate_name(name):
+@@ -38,7 +39,7 @@ def _validate_name(name):
+                     name.
+     """
+     for ch in name:
+-        if not ch.isascii() or not (ch.isalnum() or ch in "_-"):
++        if not isascii(ch) or not (isalnum(ch) or ch in "_-"):
+             raise ValueError("invalid character '%s' in handler name: %s" % (ch, name))
+ 
+ 

diff --git a/gdb-rhbz1007614-memleak-infpy_read_memory-test.patch b/gdb-rhbz1007614-memleak-infpy_read_memory-test.patch
index 4d05ba5..555eefb 100644
--- a/gdb-rhbz1007614-memleak-infpy_read_memory-test.patch
+++ b/gdb-rhbz1007614-memleak-infpy_read_memory-test.patch
@@ -64,7 +64,7 @@ diff --git a/gdb/testsuite/gdb.python/py-gdb-rhbz1007614-memleak-infpy_read_memo
 new file mode 100644
 --- /dev/null
 +++ b/gdb/testsuite/gdb.python/py-gdb-rhbz1007614-memleak-infpy_read_memory.exp
-@@ -0,0 +1,68 @@
+@@ -0,0 +1,72 @@
 +# Copyright 2014 Free Software Foundation, Inc.
 +
 +# This program is free software; you can redistribute it and/or modify
@@ -80,6 +80,10 @@ new file mode 100644
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
++load_lib gdb-python.exp
++
++require allow_python_tests
++
 +set testfile py-gdb-rhbz1007614-memleak-infpy_read_memory
 +set srcfile ${testfile}.c
 +set binfile [standard_output_file ${testfile}]
@@ -88,8 +92,6 @@ new file mode 100644
 +    return -1
 +}
 +
-+if { [skip_python_tests] } { continue }
-+
 +set pid_of_gdb [exp_pid -i [board_info host fileid]]
 +
 +proc memory_v_pages_get {} {
@@ -111,12 +113,14 @@ new file mode 100644
 +
 +gdb_test "source ${remote_python_file}" ""
 +
-+gdb_test "hello-world" ""
++gdb_test "hello-world" "" \
++    "first hello-world test"
 +
 +set kbytes_before [memory_v_pages_get]
 +verbose -log "kbytes_before = $kbytes_before"
 +
-+gdb_test "hello-world" ""
++gdb_test "hello-world" "" \
++    "second hello-world test"
 +
 +set kbytes_after [memory_v_pages_get]
 +verbose -log "kbytes_after = $kbytes_after"

diff --git a/gdb-rhbz1156192-recursive-dlopen-test.patch b/gdb-rhbz1156192-recursive-dlopen-test.patch
index 96b93ae..e0a2270 100644
--- a/gdb-rhbz1156192-recursive-dlopen-test.patch
+++ b/gdb-rhbz1156192-recursive-dlopen-test.patch
@@ -211,7 +211,7 @@ diff --git a/gdb/testsuite/gdb.base/gdb-rhbz1156192-recursive-dlopen.exp b/gdb/t
 new file mode 100644
 --- /dev/null
 +++ b/gdb/testsuite/gdb.base/gdb-rhbz1156192-recursive-dlopen.exp
-@@ -0,0 +1,157 @@
+@@ -0,0 +1,152 @@
 +# Copyright 2014 Free Software Foundation, Inc.
 +#
 +# This program is free software; you can redistribute it and/or modify
@@ -227,13 +227,8 @@ new file mode 100644
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
-+if {[skip_shlib_tests]} {
-+    untested "skipping shlib tests"
-+    return 0
-+} elseif {[use_gdb_stub]} {
-+    untested "skipping tests because of stub"
-+    return 0
-+}
++require allow_shlib_tests
++require !use_gdb_stub
 +
 +# Library foo
 +set libname1 "gdb-rhbz1156192-recursive-dlopen-libfoo"

diff --git a/gdb-sync-coffread-with-elfread.patch b/gdb-sync-coffread-with-elfread.patch
new file mode 100644
index 0000000..92c9e6d
--- /dev/null
+++ b/gdb-sync-coffread-with-elfread.patch
@@ -0,0 +1,47 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Thu, 12 Oct 2023 19:42:19 +0100
+Subject: gdb-sync-coffread-with-elfread.patch
+
+;; Backport upstream commit 7628a997f27.
+
+gdb/coffread: bring separate debug file logic into line with elfread.c
+
+In this commit:
+
+  commit 8a92335bfca80cc9b4cd217505ea0dcbfdefbf07
+  Date:   Fri Feb 1 19:39:04 2013 +0000
+
+the logic for when we try to load a separate debug file in elfread.c
+was extended.  The new code checks that the objfile doesn't already
+have a separate debug objfile linked to it, and that the objfile isn't
+itself a separate debug objfile for some other objfile.
+
+The coffread code wasn't extended at the same time.
+
+I don't know if it's possible for the coffread code to get into the
+same state where these checks are needed, but I don't see why having
+these checks would be a problem.  In a later commit I plan to merge
+this part of the elfread and coffread code, so bringing these two
+pieces of code into line first makes that job easier.
+
+I've tested this with a simple test binary compiled with the mingw
+toolchain on a Linux host.  After compiling the binary and splitting
+out the debug info GDB still finds and loads the separate debug info.
+
+Approved-By: Tom Tromey <tom@tromey.com>
+
+diff --git a/gdb/coffread.c b/gdb/coffread.c
+--- a/gdb/coffread.c
++++ b/gdb/coffread.c
+@@ -725,7 +725,9 @@ coff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
+     }
+ 
+   /* Try to add separate debug file if no symbols table found.   */
+-  if (!objfile->has_partial_symbols ())
++  else if (!objfile->has_partial_symbols ()
++	   && objfile->separate_debug_objfile == NULL
++	   && objfile->separate_debug_objfile_backlink == NULL)
+     {
+       deferred_warnings warnings;
+       std::string debugfile

diff --git a/gdb.spec b/gdb.spec
index 19f8323..23b654f 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -57,7 +57,7 @@ Version: 14.2
 
 # The release always contains a leading reserved number, start it at 1.
 # `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 3%{?dist}
+Release: 4%{?dist}
 
 License: GPL-3.0-or-later AND BSD-3-Clause AND FSFAP AND LGPL-2.1-or-later AND GPL-2.0-or-later AND LGPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND GFDL-1.3-or-later AND LGPL-2.0-or-later WITH GCC-exception-2.0 AND GPL-3.0-or-later WITH GCC-exception-3.1 AND GPL-2.0-or-later WITH GNU-compiler-exception
 # Do not provide URL for snapshots as the file lasts there only for 2 days.
@@ -1250,6 +1250,15 @@ fi
 %endif
 
 %changelog
+* Wed Mar 13 2024 Andrew Burgess <aburgess@redhat.com>
+- Remove the use of librpm from GDB's C++ code, and instead provide
+  similar RPM suggestion feature using a Python extension.  The Python
+  extension feature that supports this is an upstream feature which
+  has been back-ported (along with several dependencies and related
+  fixes).  The actual RPM suggestion is now provided as a Python
+  script which is auto-loaded by GDB.  Removing the use of librpm from
+  the C++ code allows some cleanup of the configure scripts.
+
 * Fri Mar  8 2024 Andrew Burgess <aburgess@redhat.com>
 - Reduce gdb-6.6-buildid-locate.patch by removing some unnecessary
   casts added to bfd/ source files.

                 reply	other threads:[~2026-06-28  0:01 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178260489465.1.5364622496640306165.rpms-gdb-08bfd0a4a7fe@fedoraproject.org \
    --to=aburgess@redhat.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox