public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/gdb] gdb-17.2-rebase-f44: rename two of the patch files
@ 2026-06-28  0:02 Andrew Burgess
  0 siblings, 0 replies; only message in thread
From: Andrew Burgess @ 2026-06-28  0:02 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/gdb
            Branch : gdb-17.2-rebase-f44
            Commit : 152468cce99ebd78a392c2392a8334729e390e44
            Author : Andrew Burgess <aburgess@redhat.com>
            Date   : 2025-06-03T22:09:34+01:00
            Stats  : +1056/-1049 in 7 file(s)
            URL    : https://src.fedoraproject.org/rpms/gdb/c/152468cce99ebd78a392c2392a8334729e390e44?branch=gdb-17.2-rebase-f44

            Log:
            rename two of the patch files

Rename 'gdb-add-rpm-suggestion-script.patch' to
'gdb-rpm-suggestion-script.patch' and
'gdb-6.3-rh-testversion-20041202.patch' to
'gdb-test-show-version.patch'.  The new names better reflect the patch
contents.

None of the patch contents have changed.

There should be no changes in final GDB source tree after this commit.

---
diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include
index f725bb0..4005134 100644
--- a/_gdb.spec.Patch.include
+++ b/_gdb.spec.Patch.include
@@ -1,5 +1,5 @@
 # Check distro name is included in the version output.
-Patch001: gdb-6.3-rh-testversion-20041202.patch
+Patch001: gdb-test-show-version.patch
 
 # Update gdb-add-index.sh such that, when the GDB environment
 # variable is not set, the script is smarter than just looking for
@@ -17,7 +17,7 @@ Patch002: gdb-add-index.patch
 
 # Not a backport.  Add a new script which hooks into GDB and suggests
 # RPMs to install when GDB finds an objfile with no debug info.
-Patch003: gdb-add-rpm-suggestion-script.patch
+Patch003: gdb-rpm-suggestion-script.patch
 
 # Backport "Fix another timeout in gdb.base/bg-execution-repeat.exp"
 Patch004: gdb-fix-bg-execution-repeat.patch

diff --git a/_patch_order b/_patch_order
index 295d4ae..8103f66 100644
--- a/_patch_order
+++ b/_patch_order
@@ -1,4 +1,4 @@
-gdb-6.3-rh-testversion-20041202.patch
+gdb-test-show-version.patch
 gdb-add-index.patch
-gdb-add-rpm-suggestion-script.patch
+gdb-rpm-suggestion-script.patch
 gdb-fix-bg-execution-repeat.patch

diff --git a/gdb-6.3-rh-testversion-20041202.patch b/gdb-6.3-rh-testversion-20041202.patch
deleted file mode 100644
index 59132bf..0000000
--- a/gdb-6.3-rh-testversion-20041202.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Andrew Burgess <aburgess@redhat.com>
-Date: Fri, 27 Oct 2017 21:07:50 +0200
-Subject: gdb-6.3-rh-testversion-20041202.patch
-
-;; Check distro name is included in the version output.
-
-diff --git a/gdb/testsuite/gdb.base/fedora-version.exp b/gdb/testsuite/gdb.base/fedora-version.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/fedora-version.exp
-@@ -0,0 +1,22 @@
-+# 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/>.
-+
-+# Start with a fresh gdb
-+clean_restart
-+
-+# Check the version string contains either the Fedora or RHEL distro
-+# name, and that the version number looks roughly correct in format.
-+gdb_test "show version" \
-+    "GNU gdb \\((Fedora Linux|Red Hat Enterprise Linux)\\) \[0-9\]+\\.\[0-9\]+-\[0-9\]+.*"

diff --git a/gdb-add-rpm-suggestion-script.patch b/gdb-add-rpm-suggestion-script.patch
deleted file mode 100644
index 3010fb8..0000000
--- a/gdb-add-rpm-suggestion-script.patch
+++ /dev/null
@@ -1,1011 +0,0 @@
-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
-@@ -92,6 +92,7 @@ PYTHON_FILE_LIST = \
- 	gdb/command/missing_files.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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
---- a/gdb/doc/gdb.texinfo
-+++ b/gdb/doc/gdb.texinfo
-@@ -186,6 +186,7 @@ software in general.  We will miss him.
- * Trace File Format::		@value{GDBN} trace file format
- * Index Section Format::        .gdb_index section format
- * Debuginfod::                  Download debugging resources with @code{debuginfod}
-+* RPM Suggestions::		RPM Suggestions from GDB
- * Man Pages::                   Manual pages
- * Copying::                     GNU General Public License says
-                                 how you can copy and share @value{GDBN}
-@@ -50588,6 +50589,111 @@ Show the current verbosity setting.
- 
- @end table
- 
-+@node RPM Suggestions
-+@appendix Receiving RPM installation suggestions
-+@cindex rpm suggestions
-+
-+When @value{GDBN} loads an executable, or shared library, and cannot
-+find the corresponding debug information, @value{GDBN} will check to
-+see if an RPM is available which could provide the missing debug
-+information.  If a suitable RPM is found then @value{GDBN} will print
-+a hint before the next prompt is displayed:
-+
-+@smallexample
-+(@value{GDBP}) file /bin/ls
-+Reading symbols from /bin/ls...
-+Reading symbols from .gnu_debugdata for /usr/bin/ls...
-+(No debugging symbols found in .gnu_debugdata for /usr/bin/ls)
-+Missing rpms, try: dnf --enablerepo='*debug*' install coreutils-debuginfo-9.3-7.fc39.x86_64
-+(@value{GDBP})
-+@end smallexample
-+
-+In this case, installing @file{coreutils-debuginfo-9.3-7.fc39.x86_64}
-+will provide the missing debug information for @file{/bin/ls}.  It is
-+up to you to install the suggested package, if possible, and after
-+that reload the executable in @value{GDBN} so that the newly installed
-+debug information can be found.
-+
-+The RPM suggestion feature can be disabled:
-+
-+@table @code
-+@kindex set rpm-suggestion enabled
-+@kindex show rpm-suggestion enabled
-+@cindex rpm suggestions, disabling
-+@item set rpm-suggestion enabled @r{[}on@r{|}off@r{]}
-+@itemx show rpm-suggestion enabled
-+When @samp{on} @value{GDBN} will make RPM suggestions where possible.
-+When @samp{off} all RPM suggestion will be disabled.
-+@end table
-+
-+When opening a core file (@pxref{core-file command}), it may be the
-+case that not only is the debug information missing, but the
-+corresponding executable itself is missing.  For example, if a core
-+file is copied from one machine to another in order to debug.
-+
-+In this case @value{GDBN} is able to suggest a command which will
-+install the missing executable based on the build-id of the
-+executable.  For example:
-+
-+@smallexample
-+(@value{GDBP}) core-file /tmp/core.5489
-+warning: Can't open file /usr/bin/sl during file-backed mapping note processing
-+[New LWP 5489]
-+Core was generated by `sl'.
-+Program terminated with signal SIGQUIT, Quit.
-+#0  0x00007f1b41ced1a7 in ?? ()
-+Missing file(s), try: dnf --enablerepo='*debug*' install /usr/lib/.build-id/33/2f1a8e56693960e3beb2d70cd79ddfec451cc3 /usr/lib/debug/.build-id/33/2f1a8e56693960e3beb2d70cd79ddfec451cc3.debug
-+(@value{GDBP})
-+@end smallexample
-+
-+The core file was generated from the @file{/usr/bin/sl} binary, which
-+is not present on the machine opening the core file.  @value{GDBN} has
-+suggested a command, based on the build-id of the binary, which was
-+extracted from the core file, that would install both the missing
-+binary, and the corresponding debug information.
-+
-+Unfortunately, @value{GDBN} doesn't know if the suggested command will
-+actually find a matching RPM or not.  Querying the RPM database to see
-+which packages, if any, will provide a file with the given build-id,
-+is rather slow.  As @file{/usr/bin/sl} is available in an RPM, then
-+the above command will succeed.
-+
-+It is possible to have @value{GDBN} check to see if there is a package
-+available before making the suggestion, but this is significantly
-+slower.  To enable this mode use the following command:
-+
-+@table @code
-+@kindex set rpm-suggestion build-id-mode
-+@kindex show rpm-suggestion build-id-mode
-+@cindex rpm suggestions, build-id-mode
-+@item set rpm-suggestion build-id-mode @r{[}fast@r{|}slow@r{]}
-+@itemx show rpm-suggestion build-id-mode
-+When set to @samp{fast}, which is the default, @value{GDBN} will offer
-+suggestions based on the build-id of any missing executables or shared
-+libraries while opening a core file.  This is fast, but @value{GDBN}
-+has not checked if there is a package available that can supply the
-+required file, so running the suggested command might not install any
-+packages.
-+
-+When set to @samp{slow}, each time @value{GDBN} encounters an
-+executable, or shared library, that is missing, @value{GDBN} will
-+check to see if there is an RPM available that will supply the missing
-+binary.  If a suitable RPM is found then @value{GDBN} will offer a
-+command which will install the missing RPM.  If no suitable RPM is
-+found then @value{GDBN} will make no suggestions.
-+@end table
-+
-+It is possible to review all of the previous RPM suggestions that
-+@value{GDBN} has made using the following command:
-+
-+@table @code
-+@kindex info rpm-suggestions
-+@cindex rpm suggestions, listing
-+@item info rpm-suggestions
-+List all of the RPM suggestions @value{GDBN} has made since the
-+executable was last changed.
-+@end table
-+
- @node Man Pages
- @appendix Manual pages
- @cindex Man pages
-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,527 @@
-+# 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 gdb.missing_objfile
-+
-+# These modules are all system modules, and should be available on any
-+# correctly setup Python install.
-+import sys
-+import os
-+import subprocess
-+import re
-+from threading import Thread
-+import time
-+
-+try:
-+    import rpm
-+except ModuleNotFoundError:
-+    # The "RPM suggestions" mechanism will not work without the (python)
-+    # rpm module.  Inform the user of this, but wait to do so until
-+    # just prior to printing the GDB prompt.  If we do it right away,
-+    # the message typically appears before the version and copyright
-+    # info, which is easily missed by many users.  Additionally, it
-+    # seems that several other packages which parse GDB version info
-+    # are confused by an early error message regarding a missing
-+    # python3-rpm package, so waiting to print the error allows those
-+    # applications to work as they used to.
-+    def before_prompt():
-+        print(
-+            ("\nUnable to load the Python 'rpm' module.  Lack of this module disables\n"
-+             "the RPM suggestions mechanism which recommends shell commands for\n"
-+             "installing missing debuginfo packages.  To enable this functionality,\n"
-+             "please install the python3-rpm package."),
-+            file=sys.stderr
-+        )
-+        gdb.events.before_prompt.disconnect(before_prompt)
-+
-+    gdb.events.before_prompt.connect(before_prompt)
-+
-+    # Implement 'info rpm-suggestions' when the 'rpm' module is not
-+    # available.  Just throws an error.
-+    def info_rpm_suggestions():
-+        raise gdb.GdbError("rpm-suggestions are disabled as the Python 'rpm' module is not installed")
-+else:
-+    # 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 = {}
-+
-+    # Track all the build-ids suggested during a single debug session so we
-+    # don't suggest installing using the same build-id twice.  This is only
-+    # cleared when the main executable is changed.
-+    __missing_build_ids = {}
-+
-+    # Track any build-ids that have been discovered missing since the last
-+    # time the prompt was displayed.  Build-ids in here are also present in
-+    # the __MISSING_BUILD_IDS dictionary, but this dictionary is cleared
-+    # each time the prompt is shown.
-+    __suggest_build_ids = {}
-+
-+    # The build-id to RPM lookup is very slow.  This cache maps
-+    # build-ids to the set of RPM we can suggest installing.  The key
-+    # is the build-id string, and the value is a list of RPM names, or
-+    # None if there was an error with the build-id to RPM lookup.
-+    #
-+    # This cache is never cleared, even when the executable is
-+    # changed.  The build-ids should be unique, so a build-id lookup
-+    # should be good for the lifetime of the session.
-+    __build_id_lookup_cache = {}
-+
-+    # When searching for an RPM given a build-id, if the search takes
-+    # too long, then a message is printed to the user.  We only print
-+    # the message once between each GDB prompt.  This flag is set True
-+    # when the message is printed, and reset to False when a prompt is
-+    # displayed.
-+    __searching_message_printed = False
-+
-+    # Add a suggestion to install RPM_NAME (the full name of an RPM)
-+    # to the list of suggestions to make the next time a prompt is
-+    # displayed.
-+    def add_rpm_suggestion(rpm_name):
-+        global __missing_rpms
-+        global __suggest_rpms
-+
-+        if not rpm_name in __missing_rpms:
-+            __suggest_rpms[rpm_name] = True
-+            __missing_rpms[rpm_name] = True
-+
-+    # Return True if RPM_NAME is installed, where RPM_NAME is the full
-+    # name of an RPM.
-+    def is_rpm_installed(ts, rpm_name):
-+        res = ts.dbMatch(rpm.RPMDBI_LABEL, rpm_name)
-+        return len(res) > 0
-+
-+    # Add a suggestion to install RPMs based on BUILD_ID, a string
-+    # containing a build-id, to the list of suggestions to make the next
-+    # time a prompt is displayed.
-+    def add_build_id_suggestion(build_id):
-+        global __missing_build_ids
-+        global __suggest_build_ids
-+
-+        if not build_id in __missing_build_ids:
-+            __suggest_build_ids[build_id] = True
-+            __missing_build_ids[build_id] = True
-+
-+    # Return true if '/usr/lib' is in the debug-file-directory list.
-+    # System packages install their debug information into /usr/lib,
-+    # so if GDB isn't looking in that directory, then there's no
-+    # reason to try and figure out a suitable RPM to install.
-+    def using_suitable_debug_file_directory():
-+        debug_file_directories = gdb.parameter("debug-file-directory")
-+        for d in debug_file_directories.split(os.pathsep):
-+            if d[:8] == "/usr/lib":
-+                return True
-+        return False
-+
-+    # Return True if rpm-suggestion is disabled for any reason.
-+    def rpm_suggestion_is_disabled():
-+        # If /usr/lib/ is not being used to find debug information
-+        # then there's no point offering any RPMs as GDB would not
-+        # find the newly installed content.
-+        if not using_suitable_debug_file_directory():
-+            return True
-+
-+        # Is 'rpm-suggestion enabled' set to 'off'?
-+        if not param_rpm_suggestion_enabled.value:
-+            return True
-+
-+        return False
-+
-+
-+    # 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_debug_suggestions(filename):
-+        if rpm_suggestion_is_disabled():
-+            return
-+
-+        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}")
-+            rpm_name = str(obj)
-+
-+            # Check to see if the package is installed.
-+            if is_rpm_installed(ts, rpm_name):
-+                continue
-+
-+            add_rpm_suggestion(rpm_name)
-+
-+
-+    # Return a string which is the filename of the filename
-+    # corresponding to BUILD_ID in one of the two locations under
-+    # /usr/lib.
-+    #
-+    # When DEBUG_P is True, return a filename within:
-+    # /usr/lib/debug/.build-id/ and when DEBUG_P is False, return a
-+    # filename within: /usr/lib/.build-id/.
-+    #
-+    # The SUFFIX string is appended to the generated filename.
-+    def build_id_to_usr_lib_filename(build_id, debug_p, suffix = ""):
-+        key = build_id[:2]
-+        rst = build_id[2:]
-+
-+        filename = '/usr/lib'
-+        if debug_p:
-+            filename += '/debug'
-+        filename += '/.build-id/' + key + '/' + rst + suffix
-+
-+        return filename
-+
-+    # A regexp object used to match against the output of `dnf`.  This
-+    # is initialised the first time it is needed.
-+    find_objfile_suggestions_re = None
-+
-+    # Given BUILD_ID, a string containing a build-id, run a `dnf`
-+    # command to figure out if any RPMs can provide a file with that
-+    # build-id.
-+    #
-+    # If any suitable RPMs are found then `add_rpm_suggestion` is called
-+    # to register the suggestion.
-+    #
-+    # This function is pretty slow, which is a shame, as the results
-+    # returned are much nicer than just telling the user to try the
-+    # lookup command for themselves.
-+    def find_objfile_suggestions_in_thread(build_id):
-+        global find_objfile_suggestions_re
-+
-+        if find_objfile_suggestions_re is None:
-+            find_objfile_suggestions_re = re.compile("^(.*)-debuginfo-(.*) : Debug information for package (.*)$")
-+
-+        result = subprocess.run(['dnf', "--enablerepo=*debug*", '--nogpgcheck', '-C', 'provides',
-+                                 build_id_to_usr_lib_filename(build_id, True)],
-+                                capture_output=True, timeout=30)
-+
-+        lines = result.stdout.decode('utf-8').splitlines()
-+        ts = rpm.TransactionSet()
-+
-+        for l in lines:
-+            m = find_objfile_suggestions_re.match(l)
-+            if not m:
-+                continue
-+            if m.group(1) != m.group(3):
-+                return
-+
-+            main_rpm = m.group(1) + '-' + m.group(2)
-+            dbg_rpm = m.group(1) + '-debuginfo-' + m.group(2)
-+
-+            if not is_rpm_installed(ts, main_rpm):
-+                add_rpm_suggestion(main_rpm)
-+
-+            if not is_rpm_installed(ts, dbg_rpm):
-+                add_rpm_suggestion(dbg_rpm)
-+
-+        return
-+
-+    # Call `find_objfile_suggestions_in_thread` is a separate thread,
-+    # then wait for the thread to complete.  Don't touch any shared
-+    # state while waiting for the thread to complete.  There's no
-+    # locking on any of our caches, and the worker thread will add RPM
-+    # suggestions as it wants.
-+    #
-+    # If thre thread takes too long to complete then print a message
-+    # to the user telling them what's going on.
-+    def find_objfile_suggestions_slow_core(build_id):
-+        global __searching_message_printed
-+
-+        thread = Thread(target = find_objfile_suggestions_in_thread, args = (build_id, ))
-+        thread.start()
-+        start = time.time_ns()
-+
-+        while thread.is_alive ():
-+            time.sleep(0.05)
-+            now = time.time_ns ()
-+            if not __searching_message_printed and (now - start > 1000000000):
-+                print("Searching for packages to install that could improve debugging...")
-+                __searching_message_printed = True
-+
-+        thread.join()
-+
-+
-+    # Given BUILD_ID, a string containing a build-id, lookup suitable
-+    # RPMs that could be installed to provide a file with the required
-+    # build-id.
-+    #
-+    # Any suitable RPMs are recorded by calling `add_rpm_suggestion`, and
-+    # will be printed before the next prompt.
-+    def find_objfile_suggestions_slow(build_id):
-+        global __build_id_lookup_cache
-+        global __suggest_rpms
-+
-+        # The code to lookup an RPM given only a build-id is pretty
-+        # slow.  Cache the results to try and reduce the UI delays.
-+        if build_id in __build_id_lookup_cache:
-+            rpms = __build_id_lookup_cache[build_id]
-+            if rpms is not None:
-+                for r in rpms:
-+                    add_rpm_suggestion(r)
-+            return
-+
-+        # Make sure the cache entry exists before we do the lookup.
-+        # If, for any reason, the lookup raises an exception, then
-+        # having a cache entry will prevent us retrying this lookup in
-+        # the future.
-+        __build_id_lookup_cache[build_id] = None
-+
-+        # Now do the lookup.  This is the slow part.
-+        find_objfile_suggestions_slow_core(build_id)
-+
-+        # Fill in the cache, for a given build-id which RPMs were
-+        # suggested.
-+        rpms = []
-+        for r in __suggest_rpms:
-+            rpms.append(r)
-+        __build_id_lookup_cache[build_id] = rpms
-+
-+
-+    # Given BUILD_ID, a string containing a build-id, just record that we
-+    # should advise the user to try installing RPMs based on this build-id.
-+    def find_objfile_suggestions_fast(build_id):
-+        add_build_id_suggestion(build_id)
-+
-+    # Given BUILD_ID, a string containing a build-id, which GDB has failed
-+    # to find, possibly record some information so that we can, at the next
-+    # prompt, give some RPM installation advice to the user.
-+    #
-+    # We have two different strategies for RPM lookup based on a build-id,
-+    # one approach is that we actually lookup the RPMs and only suggest
-+    # something if there is a suitable RPM.  However, this is pretty slow,
-+    # and users will probably find this annoying.
-+    #
-+    # So we also have a fast way.  With this approach we just record the
-+    # build-id that was missing and tell the user to try installing based on
-+    # the build-id.  The downside with this is that if there is no RPM for
-+    # that build-id, then the user will try the command, but nothing will
-+    # install.
-+    def find_objfile_suggestions(build_id):
-+        if rpm_suggestion_is_disabled():
-+            return
-+
-+        if param_rpm_suggestion_build_id_mode.fast_mode():
-+            find_objfile_suggestions_fast(build_id)
-+        else:
-+            find_objfile_suggestions_slow(build_id)
-+
-+    # A missing debug handler class.  Just forwards the name of the
-+    # objfile for which we are missing debug information to
-+    # find_debug_suggestions.
-+    class RPM_MissingDebugHandler(gdb.missing_debug.MissingDebugHandler):
-+        def __init__(self):
-+            super().__init__("rpm-suggestions")
-+
-+        def __call__(self, objfile):
-+            find_debug_suggestions(objfile.filename)
-+            return False
-+
-+    # A missing objfile handler class.  Just forwards the build-id of
-+    # the objfile that is missing to find_objfile_suggestions.
-+    class RPM_MissingObjfileHandler(gdb.missing_objfile.MissingObjfileHandler):
-+        def __init__(self):
-+            super().__init__("rpm-suggestions")
-+
-+        def __call__(self, pspace, build_id, filename):
-+            find_objfile_suggestions(build_id)
-+            return False
-+
-+    # Take a non-empty list of RPM names and print a command line a
-+    # user could run to install these RPMs.
-+    def print_rpm_suggestions(rpm_name_list):
-+        print("Missing rpms, try: dnf --enablerepo='*debug*' install " + ' '.join(rpm_name_list))
-+
-+    # Take a non-empty list of build-id strings and print a series of
-+    # lines that a user could run to instll the RPMs that provide
-+    # files with this build-id.
-+    #
-+    # The printed commands will also install the corresponding debug
-+    # packages for the executable with the given build-id.
-+    def print_build_id_suggestions(build_id_list):
-+        for build_id in build_id_list:
-+            print("Missing file(s), try: dnf --enablerepo='*debug*' install "
-+                  + build_id_to_usr_lib_filename(build_id, False)
-+                  + ' '
-+                  + build_id_to_usr_lib_filename(build_id, True, ".debug"))
-+
-+    # Called before GDB displays its prompt.  If the global __SUGGEST_RPMS
-+    # dictionary is not empty, then this hook prints the keys of this
-+    # dictionary as strings which are the names of RPMs.  This hook formats
-+    # each RPM name into a suggested 'dnf install' command and suggests this
-+    # to the user.
-+    #
-+    # Additionally, if the global __SUGGEST_BUILD_IDS dictionary is not
-+    # empty, then this hook uses the keys of this dictionary as build-ids
-+    # that were found to be missing, and formats these into some file based
-+    # 'dnf install' suggestions to the user.
-+    def before_prompt():
-+        global __suggest_rpms
-+        global __suggest_build_ids
-+        global __searching_message_printed
-+
-+        # We allow the searching message to be printed just once
-+        # between prompts.
-+        __searching_message_printed = False
-+
-+        if len(__suggest_rpms) > 0:
-+            print_rpm_suggestions(__suggest_rpms.keys())
-+            __suggest_rpms = {}
-+
-+        if len(__suggest_build_ids) > 0:
-+            print_build_id_suggestions(__suggest_build_ids.keys())
-+            __suggest_build_ids = {}
-+
-+    # 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
-+        global __suggest_build_ids
-+        global __missing_build_ids
-+
-+        if not event.reload:
-+            __missing_rpms = {}
-+            __suggest_rpms = {}
-+            __missing_build_ids = {}
-+            __suggest_build_ids = {}
-+
-+
-+    # 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 and missing objfile handlers with GDB.
-+    gdb.missing_debug.register_handler(None, RPM_MissingDebugHandler())
-+    gdb.missing_objfile.register_handler(None, RPM_MissingObjfileHandler())
-+
-+    # Implement the core of 'info rpm-suggestions'.  Reprint all rpm
-+    # suggestions.
-+    def info_rpm_suggestions():
-+        global __missing_rpms
-+        global __missing_build_ids
-+
-+        if len(__missing_rpms) == 0 and len(__missing_build_ids) == 0:
-+            print("No RPM suggestions have been made so far.")
-+            return
-+
-+        if len(__missing_rpms) > 0:
-+            print_rpm_suggestions(__missing_rpms.keys())
-+        if len(__missing_build_ids) > 0:
-+            print_build_id_suggestions(__missing_build_ids.keys())
-+
-+####################################################################
-+# The following code is outside the 'else' block of the attempt to #
-+# load the 'rpm' module.  Nothing after this point depends on the  #
-+# 'rpm' module.                                                    #
-+####################################################################
-+
-+# The 'set rpm-suggestion' prefix command.
-+class rpm_suggestion_set_prefix(gdb.Command):
-+    """Prefix command for 'set' rpm-suggestion related commands."""
-+
-+    def __init__(self):
-+        super().__init__("set rpm-suggestion", gdb.COMMAND_NONE,
-+                         gdb.COMPLETE_NONE, True)
-+
-+# The 'show rpm-suggestion' prefix command.
-+class rpm_suggestion_show_prefix(gdb.Command):
-+    """Prefix command for 'show' rpm-suggestion related commands."""
-+
-+    def __init__(self):
-+        super().__init__("show rpm-suggestion", gdb.COMMAND_NONE,
-+                         gdb.COMPLETE_NONE, True)
-+
-+# The 'set/show rpm-suggestion enabled' command.
-+class rpm_suggestion_enabled(gdb.Parameter):
-+    """
-+    When 'on' GDB will search for RPMS that might provide additional
-+    debug information, or provide missing executables or shared
-+    libraries (when opening a core file), and will make suggestions
-+    about what should be installed.
-+
-+    When 'off' GDB will not make these suggestions.
-+    """
-+
-+    set_doc = "Set whether to perform rpm-suggestion."
-+    show_doc = "Show whether rpm-suggestion is enabled."
-+
-+    def __init__(self):
-+        super().__init__("rpm-suggestion enabled", gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)
-+        self.value = True
-+
-+# The 'set/show rpm-suggestion enabled' command.
-+class rpm_suggestion_build_id_mode(gdb.Parameter):
-+    """
-+    When set to 'fast' (the default), GDB doesn't try to map a build-id to
-+    an actual RPM, instead, GDB just suggests a command based on the
-+    build-id which might install some RPMs, if there are any RPMs that
-+    supply that build-id.  However, it is equally possible that there are no
-+    suitable RPMs, and nothing will install.  This approach has almost zero
-+    overhead.
-+
-+    When set to 'slow', GDB first does the build-id to RPM check itself, and
-+    only if something is found are RPMs installation commands suggested.
-+    The suggested command will include the name of the RPM to install.  This
-+    approach is considerably slower as querying the RPM database for the RPM
-+    that supplies a specific file is slow.
-+    """
-+
-+    set_doc = "Set how build-id based rpm suggestions should be performed."
-+    show_doc = "Show how build-id based rpm suggestions shoud be performed."
-+
-+    def __init__(self):
-+        super().__init__("rpm-suggestion build-id-mode",
-+                         gdb.COMMAND_NONE, gdb.PARAM_ENUM, ["fast", "slow"])
-+        self.value = "fast"
-+
-+    def fast_mode(self):
-+        return self.value == "fast"
-+
-+# The 'info rpm-suggestions' command.
-+class rpm_suggestion_info(gdb.Command):
-+    """Relist RPM suggestions.
-+
-+    Relist any RPM installation suggestions that have been made
-+    since the executable was last changed."""
-+    def __init__(self):
-+        super().__init__("info rpm-suggestions", gdb.COMMAND_NONE, gdb.COMPLETE_NONE)
-+
-+    def invoke(self, args, from_tty):
-+        if args != "":
-+            raise gdb.GdbError("unexpected arguments: %s" % args)
-+
-+        info_rpm_suggestions ()
-+
-+
-+# Create the 'set/show rpm-suggestion' commands.
-+rpm_suggestion_set_prefix()
-+rpm_suggestion_show_prefix()
-+param_rpm_suggestion_enabled = rpm_suggestion_enabled()
-+param_rpm_suggestion_build_id_mode = rpm_suggestion_build_id_mode()
-+
-+# Create the 'info rpm-suggestions' commands.
-+rpm_suggestion_info()
-diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c
-@@ -0,0 +1,21 @@
-+/* Copyright 2010 Free Software Foundation, Inc.
-+
-+   This file is part of GDB.
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; either version 3 of the License, or
-+   (at your option) any later version.
-+
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-+
-+void
-+lib (void)
-+{
-+}
-diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c
-@@ -0,0 +1,25 @@
-+/* Copyright 2010 Free Software Foundation, Inc.
-+
-+   This file is part of GDB.
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; either version 3 of the License, or
-+   (at your option) any later version.
-+
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-+
-+extern void lib (void);
-+
-+int
-+main (void)
-+{
-+  lib ();
-+  return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp
-@@ -0,0 +1,104 @@
-+# Copyright 2016 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/>.
-+
-+require allow_shlib_tests
-+
-+set testfile "gcore-buildid-exec-but-not-solib"
-+set srcmainfile ${testfile}-main.c
-+set srclibfile ${testfile}-lib.c
-+set libfile [standard_output_file ${testfile}-lib.so]
-+set objfile [standard_output_file ${testfile}-main.o]
-+set executable ${testfile}-main
-+set binfile [standard_output_file ${executable}]
-+set gcorefile [standard_output_file ${executable}.gcore]
-+set outdir [file dirname $binfile]
-+
-+if { [gdb_compile_shlib ${srcdir}/${subdir}/${srclibfile} ${libfile} "debug additional_flags=-Wl,--build-id"] != ""
-+     || [gdb_compile ${srcdir}/${subdir}/${srcmainfile} ${objfile} object {debug}] != "" } {
-+     unsupported "-Wl,--build-id compilation failed"
-+     return -1
-+}
-+set opts [list debug shlib=${libfile} "additional_flags=-Wl,--build-id"]
-+if { [gdb_compile ${objfile} ${binfile} executable $opts] != "" } {
-+     unsupported "-Wl,--build-id compilation failed"
-+     return -1
-+}
-+
-+clean_restart $executable
-+gdb_load_shlib $libfile
-+
-+# Does this gdb support gcore?
-+set test "help gcore"
-+gdb_test_multiple $test $test {
-+    -re "Undefined command: .gcore.*\r\n$gdb_prompt $" {
-+	# gcore command not supported -- nothing to test here.
-+	unsupported "gdb does not support gcore on this target"
-+	return -1;
-+    }
-+    -re "Save a core file .*\r\n$gdb_prompt $" {
-+	pass $test
-+    }
-+}
-+
-+if { ![runto lib] } then {
-+    return -1
-+}
-+
-+set escapedfilename [string_to_regexp ${gcorefile}]
-+
-+set test "save a corefile"
-+gdb_test_multiple "gcore ${gcorefile}" $test {
-+    -re "Saved corefile ${escapedfilename}\r\n$gdb_prompt $" {
-+	pass $test
-+    }
-+    -re "Can't create a corefile\r\n$gdb_prompt $" {
-+	unsupported $test
-+	return -1
-+    }
-+}
-+
-+# Now restart gdb and load the corefile.
-+
-+clean_restart $executable
-+gdb_load_shlib $libfile
-+
-+set buildid [build_id_debug_filename_get $libfile]
-+
-+regsub {\.debug$} $buildid {} buildid
-+
-+set debugdir [standard_output_file ${testfile}-debugdir]
-+file delete -force -- $debugdir
-+
-+file mkdir $debugdir/[file dirname $libfile]
-+file copy $libfile $debugdir/${libfile}
-+
-+file mkdir $debugdir/[file dirname $buildid]
-+file copy $libfile $debugdir/${buildid}
-+
-+remote_exec build "ln -s /lib       ${debugdir}/"
-+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_no_output "set solib-absolute-prefix $debugdir" \
-+    "set solib-absolute-prefix"
-+
-+gdb_test_no_output "set debug-file-directory $debugdir" "set debug-file-directory"
-+
-+gdb_test "core ${gcorefile}" "Core was generated by .*" "re-load generated corefile"
-+
-+gdb_test "frame" "#0 \[^\r\n\]* lib .*" "library got loaded"
-+
-+gdb_test "bt"
-+gdb_test "info shared"
-diff --git a/gdb/testsuite/gdb.base/gdbinit-history.exp b/gdb/testsuite/gdb.base/gdbinit-history.exp
---- a/gdb/testsuite/gdb.base/gdbinit-history.exp
-+++ b/gdb/testsuite/gdb.base/gdbinit-history.exp
-@@ -179,7 +179,8 @@ proc test_empty_history_filename { } {
-     global env
-     global gdb_prompt
- 
--    set common_history [list "set height 0" "set width 0"]
-+    set common_history [list "set height 0" "set width 0" \
-+			    "set rpm-suggestion enabled off"]
- 
-     set test_dir [standard_output_file history_test]
-     remote_exec host "mkdir -p $test_dir"
-diff --git a/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp b/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp
-@@ -0,0 +1,60 @@
-+# Copyright (C) 2014  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/>.
-+
-+# Create a core file, then hide the executable.  Restart GDB and load
-+# the core file.  Check GDB gives a message suggesting a 'dnf' command
-+# to try and install the executable based on its build-id.
-+
-+standard_testfile "normal.c"
-+
-+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
-+    return -1
-+}
-+
-+# Get the build-id of the file.
-+set build_id_debug_file [build_id_debug_filename_get $binfile]
-+regsub -all ".debug$" $build_id_debug_file "" build_id_without_debug
-+
-+# Run to main.
-+if { ![runto_main] } {
-+    return -1
-+}
-+
-+# We first need to generate a corefile.
-+set corefilename "[standard_output_file gcore.test]"
-+if { ![gdb_gcore_cmd "$corefilename" "save corefile"] } {
-+    untested "could not generate a corefile"
-+    return -1
-+}
-+
-+# Move the binfile to a temporary name.
-+remote_exec build "mv $binfile ${binfile}.old"
-+
-+# Reinitialize GDB and see if we get a dnf suggestion.
-+clean_restart
-+
-+gdb_test "set rpm-suggestion enabled on" "" \
-+    "turn on rpm-suggestion feature"
-+
-+# GDB only makes build-id based RPM suggestions if /usr/lib is in
-+# the debug-file-directory list, the reason being that system RPMs
-+# will always install under this location.  If GDB is not looking
-+# here then there's no point making suggestions.
-+gdb_test "set debug-file-directory /usr/lib/" "" \
-+    "set debug-file-directory"
-+
-+gdb_test "core-file [standard_output_file gcore.test]" \
-+    "Missing file\\(s\\), try: dnf --enablerepo='\\*debug\\*' install [string_to_regexp /usr/lib/$build_id_without_debug] [string_to_regexp /usr/lib/debug/$build_id_debug_file]" \
-+    "test first yum/dnf warning"
-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
-@@ -19,6 +19,13 @@ from enum import Enum
- import gdb
- from gdb.missing_debug import MissingDebugHandler
- 
-+# 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 = []
-@@ -118,4 +125,7 @@ def register(name, locus=None):
- rhandler = exception_handler()
- handler_obj = handler()
- 
-+# Discard the rpm-suggestion handler.
-+gdb.missing_file_handlers = []
-+
- print("Success")
-diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.python/py-missing-objfile.py
---- a/gdb/testsuite/gdb.python/py-missing-objfile.py
-+++ b/gdb/testsuite/gdb.python/py-missing-objfile.py
-@@ -164,4 +164,7 @@ def register(name, locus=None):
- rhandler = exception_handler()
- handler_obj = handler()
- 
-+# Discard the rpm-suggestion handler.
-+gdb.missing_file_handlers = []
-+
- print("Success")
-diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
---- a/gdb/testsuite/lib/gdb.exp
-+++ b/gdb/testsuite/lib/gdb.exp
-@@ -255,7 +255,8 @@ if ![info exists INTERNAL_GDBFLAGS] {
- 		   "-nx" \
- 		   "-q" \
- 		   {-iex "set height 0"} \
--		   {-iex "set width 0"}]]
-+		   {-iex "set width 0"} \
-+		   {-iex "set rpm-suggestion enabled off"}]]
- 
-     # If DEBUGINFOD_URLS is set, gdb will try to download sources and
-     # debug info for f.i. system libraries.  Prevent this.
-@@ -2610,6 +2611,18 @@ proc default_gdb_start { } {
- 	}
-     }
- 
-+    # Turn off the missing debug info messages as the testsuite does
-+    # not expect them.
-+    send_gdb "set rpm-suggestion enabled off\n"
-+    gdb_expect 10 {
-+	-re "$gdb_prompt $" {
-+	    verbose "Disabled the missing debug info messages." 2
-+	}
-+	timeout {
-+	    warning "Could not disable the missing debug info messages."
-+	}
-+    }
-+
-     gdb_debug_init
-     return 0
- }
-diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
---- a/gdb/testsuite/lib/mi-support.exp
-+++ b/gdb/testsuite/lib/mi-support.exp
-@@ -321,6 +321,17 @@ proc default_mi_gdb_start { { flags {} } } {
- 	    warning "Couldn't set the width to 0."
- 	}
-     }
-+    # Turn off the missing debug info messages as the testsuite does
-+    # not expect them.
-+    send_gdb "190-gdb-set rpm-suggestion enabled off\n"
-+    gdb_expect 10 {
-+	-re ".*190-gdb-set rpm-suggestion enabled off\r\n190\\\^done\r\n$mi_gdb_prompt$" {
-+	    verbose "Disabled the missing debug info messages." 2
-+	}
-+	timeout {
-+	    warning "Could not disable the missing debug info messages."
-+	}
-+    }
- 
-     if { $separate_inferior_pty } {
- 	mi_create_inferior_pty

diff --git a/gdb-rpm-suggestion-script.patch b/gdb-rpm-suggestion-script.patch
new file mode 100644
index 0000000..c7ecf91
--- /dev/null
+++ b/gdb-rpm-suggestion-script.patch
@@ -0,0 +1,1011 @@
+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-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
+@@ -92,6 +92,7 @@ PYTHON_FILE_LIST = \
+ 	gdb/command/missing_files.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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
+--- a/gdb/doc/gdb.texinfo
++++ b/gdb/doc/gdb.texinfo
+@@ -186,6 +186,7 @@ software in general.  We will miss him.
+ * Trace File Format::		@value{GDBN} trace file format
+ * Index Section Format::        .gdb_index section format
+ * Debuginfod::                  Download debugging resources with @code{debuginfod}
++* RPM Suggestions::		RPM Suggestions from GDB
+ * Man Pages::                   Manual pages
+ * Copying::                     GNU General Public License says
+                                 how you can copy and share @value{GDBN}
+@@ -50588,6 +50589,111 @@ Show the current verbosity setting.
+ 
+ @end table
+ 
++@node RPM Suggestions
++@appendix Receiving RPM installation suggestions
++@cindex rpm suggestions
++
++When @value{GDBN} loads an executable, or shared library, and cannot
++find the corresponding debug information, @value{GDBN} will check to
++see if an RPM is available which could provide the missing debug
++information.  If a suitable RPM is found then @value{GDBN} will print
++a hint before the next prompt is displayed:
++
++@smallexample
++(@value{GDBP}) file /bin/ls
++Reading symbols from /bin/ls...
++Reading symbols from .gnu_debugdata for /usr/bin/ls...
++(No debugging symbols found in .gnu_debugdata for /usr/bin/ls)
++Missing rpms, try: dnf --enablerepo='*debug*' install coreutils-debuginfo-9.3-7.fc39.x86_64
++(@value{GDBP})
++@end smallexample
++
++In this case, installing @file{coreutils-debuginfo-9.3-7.fc39.x86_64}
++will provide the missing debug information for @file{/bin/ls}.  It is
++up to you to install the suggested package, if possible, and after
++that reload the executable in @value{GDBN} so that the newly installed
++debug information can be found.
++
++The RPM suggestion feature can be disabled:
++
++@table @code
++@kindex set rpm-suggestion enabled
++@kindex show rpm-suggestion enabled
++@cindex rpm suggestions, disabling
++@item set rpm-suggestion enabled @r{[}on@r{|}off@r{]}
++@itemx show rpm-suggestion enabled
++When @samp{on} @value{GDBN} will make RPM suggestions where possible.
++When @samp{off} all RPM suggestion will be disabled.
++@end table
++
++When opening a core file (@pxref{core-file command}), it may be the
++case that not only is the debug information missing, but the
++corresponding executable itself is missing.  For example, if a core
++file is copied from one machine to another in order to debug.
++
++In this case @value{GDBN} is able to suggest a command which will
++install the missing executable based on the build-id of the
++executable.  For example:
++
++@smallexample
++(@value{GDBP}) core-file /tmp/core.5489
++warning: Can't open file /usr/bin/sl during file-backed mapping note processing
++[New LWP 5489]
++Core was generated by `sl'.
++Program terminated with signal SIGQUIT, Quit.
++#0  0x00007f1b41ced1a7 in ?? ()
++Missing file(s), try: dnf --enablerepo='*debug*' install /usr/lib/.build-id/33/2f1a8e56693960e3beb2d70cd79ddfec451cc3 /usr/lib/debug/.build-id/33/2f1a8e56693960e3beb2d70cd79ddfec451cc3.debug
++(@value{GDBP})
++@end smallexample
++
++The core file was generated from the @file{/usr/bin/sl} binary, which
++is not present on the machine opening the core file.  @value{GDBN} has
++suggested a command, based on the build-id of the binary, which was
++extracted from the core file, that would install both the missing
++binary, and the corresponding debug information.
++
++Unfortunately, @value{GDBN} doesn't know if the suggested command will
++actually find a matching RPM or not.  Querying the RPM database to see
++which packages, if any, will provide a file with the given build-id,
++is rather slow.  As @file{/usr/bin/sl} is available in an RPM, then
++the above command will succeed.
++
++It is possible to have @value{GDBN} check to see if there is a package
++available before making the suggestion, but this is significantly
++slower.  To enable this mode use the following command:
++
++@table @code
++@kindex set rpm-suggestion build-id-mode
++@kindex show rpm-suggestion build-id-mode
++@cindex rpm suggestions, build-id-mode
++@item set rpm-suggestion build-id-mode @r{[}fast@r{|}slow@r{]}
++@itemx show rpm-suggestion build-id-mode
++When set to @samp{fast}, which is the default, @value{GDBN} will offer
++suggestions based on the build-id of any missing executables or shared
++libraries while opening a core file.  This is fast, but @value{GDBN}
++has not checked if there is a package available that can supply the
++required file, so running the suggested command might not install any
++packages.
++
++When set to @samp{slow}, each time @value{GDBN} encounters an
++executable, or shared library, that is missing, @value{GDBN} will
++check to see if there is an RPM available that will supply the missing
++binary.  If a suitable RPM is found then @value{GDBN} will offer a
++command which will install the missing RPM.  If no suitable RPM is
++found then @value{GDBN} will make no suggestions.
++@end table
++
++It is possible to review all of the previous RPM suggestions that
++@value{GDBN} has made using the following command:
++
++@table @code
++@kindex info rpm-suggestions
++@cindex rpm suggestions, listing
++@item info rpm-suggestions
++List all of the RPM suggestions @value{GDBN} has made since the
++executable was last changed.
++@end table
++
+ @node Man Pages
+ @appendix Manual pages
+ @cindex Man pages
+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,527 @@
++# 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 gdb.missing_objfile
++
++# These modules are all system modules, and should be available on any
++# correctly setup Python install.
++import sys
++import os
++import subprocess
++import re
++from threading import Thread
++import time
++
++try:
++    import rpm
++except ModuleNotFoundError:
++    # The "RPM suggestions" mechanism will not work without the (python)
++    # rpm module.  Inform the user of this, but wait to do so until
++    # just prior to printing the GDB prompt.  If we do it right away,
++    # the message typically appears before the version and copyright
++    # info, which is easily missed by many users.  Additionally, it
++    # seems that several other packages which parse GDB version info
++    # are confused by an early error message regarding a missing
++    # python3-rpm package, so waiting to print the error allows those
++    # applications to work as they used to.
++    def before_prompt():
++        print(
++            ("\nUnable to load the Python 'rpm' module.  Lack of this module disables\n"
++             "the RPM suggestions mechanism which recommends shell commands for\n"
++             "installing missing debuginfo packages.  To enable this functionality,\n"
++             "please install the python3-rpm package."),
++            file=sys.stderr
++        )
++        gdb.events.before_prompt.disconnect(before_prompt)
++
++    gdb.events.before_prompt.connect(before_prompt)
++
++    # Implement 'info rpm-suggestions' when the 'rpm' module is not
++    # available.  Just throws an error.
++    def info_rpm_suggestions():
++        raise gdb.GdbError("rpm-suggestions are disabled as the Python 'rpm' module is not installed")
++else:
++    # 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 = {}
++
++    # Track all the build-ids suggested during a single debug session so we
++    # don't suggest installing using the same build-id twice.  This is only
++    # cleared when the main executable is changed.
++    __missing_build_ids = {}
++
++    # Track any build-ids that have been discovered missing since the last
++    # time the prompt was displayed.  Build-ids in here are also present in
++    # the __MISSING_BUILD_IDS dictionary, but this dictionary is cleared
++    # each time the prompt is shown.
++    __suggest_build_ids = {}
++
++    # The build-id to RPM lookup is very slow.  This cache maps
++    # build-ids to the set of RPM we can suggest installing.  The key
++    # is the build-id string, and the value is a list of RPM names, or
++    # None if there was an error with the build-id to RPM lookup.
++    #
++    # This cache is never cleared, even when the executable is
++    # changed.  The build-ids should be unique, so a build-id lookup
++    # should be good for the lifetime of the session.
++    __build_id_lookup_cache = {}
++
++    # When searching for an RPM given a build-id, if the search takes
++    # too long, then a message is printed to the user.  We only print
++    # the message once between each GDB prompt.  This flag is set True
++    # when the message is printed, and reset to False when a prompt is
++    # displayed.
++    __searching_message_printed = False
++
++    # Add a suggestion to install RPM_NAME (the full name of an RPM)
++    # to the list of suggestions to make the next time a prompt is
++    # displayed.
++    def add_rpm_suggestion(rpm_name):
++        global __missing_rpms
++        global __suggest_rpms
++
++        if not rpm_name in __missing_rpms:
++            __suggest_rpms[rpm_name] = True
++            __missing_rpms[rpm_name] = True
++
++    # Return True if RPM_NAME is installed, where RPM_NAME is the full
++    # name of an RPM.
++    def is_rpm_installed(ts, rpm_name):
++        res = ts.dbMatch(rpm.RPMDBI_LABEL, rpm_name)
++        return len(res) > 0
++
++    # Add a suggestion to install RPMs based on BUILD_ID, a string
++    # containing a build-id, to the list of suggestions to make the next
++    # time a prompt is displayed.
++    def add_build_id_suggestion(build_id):
++        global __missing_build_ids
++        global __suggest_build_ids
++
++        if not build_id in __missing_build_ids:
++            __suggest_build_ids[build_id] = True
++            __missing_build_ids[build_id] = True
++
++    # Return true if '/usr/lib' is in the debug-file-directory list.
++    # System packages install their debug information into /usr/lib,
++    # so if GDB isn't looking in that directory, then there's no
++    # reason to try and figure out a suitable RPM to install.
++    def using_suitable_debug_file_directory():
++        debug_file_directories = gdb.parameter("debug-file-directory")
++        for d in debug_file_directories.split(os.pathsep):
++            if d[:8] == "/usr/lib":
++                return True
++        return False
++
++    # Return True if rpm-suggestion is disabled for any reason.
++    def rpm_suggestion_is_disabled():
++        # If /usr/lib/ is not being used to find debug information
++        # then there's no point offering any RPMs as GDB would not
++        # find the newly installed content.
++        if not using_suitable_debug_file_directory():
++            return True
++
++        # Is 'rpm-suggestion enabled' set to 'off'?
++        if not param_rpm_suggestion_enabled.value:
++            return True
++
++        return False
++
++
++    # 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_debug_suggestions(filename):
++        if rpm_suggestion_is_disabled():
++            return
++
++        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}")
++            rpm_name = str(obj)
++
++            # Check to see if the package is installed.
++            if is_rpm_installed(ts, rpm_name):
++                continue
++
++            add_rpm_suggestion(rpm_name)
++
++
++    # Return a string which is the filename of the filename
++    # corresponding to BUILD_ID in one of the two locations under
++    # /usr/lib.
++    #
++    # When DEBUG_P is True, return a filename within:
++    # /usr/lib/debug/.build-id/ and when DEBUG_P is False, return a
++    # filename within: /usr/lib/.build-id/.
++    #
++    # The SUFFIX string is appended to the generated filename.
++    def build_id_to_usr_lib_filename(build_id, debug_p, suffix = ""):
++        key = build_id[:2]
++        rst = build_id[2:]
++
++        filename = '/usr/lib'
++        if debug_p:
++            filename += '/debug'
++        filename += '/.build-id/' + key + '/' + rst + suffix
++
++        return filename
++
++    # A regexp object used to match against the output of `dnf`.  This
++    # is initialised the first time it is needed.
++    find_objfile_suggestions_re = None
++
++    # Given BUILD_ID, a string containing a build-id, run a `dnf`
++    # command to figure out if any RPMs can provide a file with that
++    # build-id.
++    #
++    # If any suitable RPMs are found then `add_rpm_suggestion` is called
++    # to register the suggestion.
++    #
++    # This function is pretty slow, which is a shame, as the results
++    # returned are much nicer than just telling the user to try the
++    # lookup command for themselves.
++    def find_objfile_suggestions_in_thread(build_id):
++        global find_objfile_suggestions_re
++
++        if find_objfile_suggestions_re is None:
++            find_objfile_suggestions_re = re.compile("^(.*)-debuginfo-(.*) : Debug information for package (.*)$")
++
++        result = subprocess.run(['dnf', "--enablerepo=*debug*", '--nogpgcheck', '-C', 'provides',
++                                 build_id_to_usr_lib_filename(build_id, True)],
++                                capture_output=True, timeout=30)
++
++        lines = result.stdout.decode('utf-8').splitlines()
++        ts = rpm.TransactionSet()
++
++        for l in lines:
++            m = find_objfile_suggestions_re.match(l)
++            if not m:
++                continue
++            if m.group(1) != m.group(3):
++                return
++
++            main_rpm = m.group(1) + '-' + m.group(2)
++            dbg_rpm = m.group(1) + '-debuginfo-' + m.group(2)
++
++            if not is_rpm_installed(ts, main_rpm):
++                add_rpm_suggestion(main_rpm)
++
++            if not is_rpm_installed(ts, dbg_rpm):
++                add_rpm_suggestion(dbg_rpm)
++
++        return
++
++    # Call `find_objfile_suggestions_in_thread` is a separate thread,
++    # then wait for the thread to complete.  Don't touch any shared
++    # state while waiting for the thread to complete.  There's no
++    # locking on any of our caches, and the worker thread will add RPM
++    # suggestions as it wants.
++    #
++    # If thre thread takes too long to complete then print a message
++    # to the user telling them what's going on.
++    def find_objfile_suggestions_slow_core(build_id):
++        global __searching_message_printed
++
++        thread = Thread(target = find_objfile_suggestions_in_thread, args = (build_id, ))
++        thread.start()
++        start = time.time_ns()
++
++        while thread.is_alive ():
++            time.sleep(0.05)
++            now = time.time_ns ()
++            if not __searching_message_printed and (now - start > 1000000000):
++                print("Searching for packages to install that could improve debugging...")
++                __searching_message_printed = True
++
++        thread.join()
++
++
++    # Given BUILD_ID, a string containing a build-id, lookup suitable
++    # RPMs that could be installed to provide a file with the required
++    # build-id.
++    #
++    # Any suitable RPMs are recorded by calling `add_rpm_suggestion`, and
++    # will be printed before the next prompt.
++    def find_objfile_suggestions_slow(build_id):
++        global __build_id_lookup_cache
++        global __suggest_rpms
++
++        # The code to lookup an RPM given only a build-id is pretty
++        # slow.  Cache the results to try and reduce the UI delays.
++        if build_id in __build_id_lookup_cache:
++            rpms = __build_id_lookup_cache[build_id]
++            if rpms is not None:
++                for r in rpms:
++                    add_rpm_suggestion(r)
++            return
++
++        # Make sure the cache entry exists before we do the lookup.
++        # If, for any reason, the lookup raises an exception, then
++        # having a cache entry will prevent us retrying this lookup in
++        # the future.
++        __build_id_lookup_cache[build_id] = None
++
++        # Now do the lookup.  This is the slow part.
++        find_objfile_suggestions_slow_core(build_id)
++
++        # Fill in the cache, for a given build-id which RPMs were
++        # suggested.
++        rpms = []
++        for r in __suggest_rpms:
++            rpms.append(r)
++        __build_id_lookup_cache[build_id] = rpms
++
++
++    # Given BUILD_ID, a string containing a build-id, just record that we
++    # should advise the user to try installing RPMs based on this build-id.
++    def find_objfile_suggestions_fast(build_id):
++        add_build_id_suggestion(build_id)
++
++    # Given BUILD_ID, a string containing a build-id, which GDB has failed
++    # to find, possibly record some information so that we can, at the next
++    # prompt, give some RPM installation advice to the user.
++    #
++    # We have two different strategies for RPM lookup based on a build-id,
++    # one approach is that we actually lookup the RPMs and only suggest
++    # something if there is a suitable RPM.  However, this is pretty slow,
++    # and users will probably find this annoying.
++    #
++    # So we also have a fast way.  With this approach we just record the
++    # build-id that was missing and tell the user to try installing based on
++    # the build-id.  The downside with this is that if there is no RPM for
++    # that build-id, then the user will try the command, but nothing will
++    # install.
++    def find_objfile_suggestions(build_id):
++        if rpm_suggestion_is_disabled():
++            return
++
++        if param_rpm_suggestion_build_id_mode.fast_mode():
++            find_objfile_suggestions_fast(build_id)
++        else:
++            find_objfile_suggestions_slow(build_id)
++
++    # A missing debug handler class.  Just forwards the name of the
++    # objfile for which we are missing debug information to
++    # find_debug_suggestions.
++    class RPM_MissingDebugHandler(gdb.missing_debug.MissingDebugHandler):
++        def __init__(self):
++            super().__init__("rpm-suggestions")
++
++        def __call__(self, objfile):
++            find_debug_suggestions(objfile.filename)
++            return False
++
++    # A missing objfile handler class.  Just forwards the build-id of
++    # the objfile that is missing to find_objfile_suggestions.
++    class RPM_MissingObjfileHandler(gdb.missing_objfile.MissingObjfileHandler):
++        def __init__(self):
++            super().__init__("rpm-suggestions")
++
++        def __call__(self, pspace, build_id, filename):
++            find_objfile_suggestions(build_id)
++            return False
++
++    # Take a non-empty list of RPM names and print a command line a
++    # user could run to install these RPMs.
++    def print_rpm_suggestions(rpm_name_list):
++        print("Missing rpms, try: dnf --enablerepo='*debug*' install " + ' '.join(rpm_name_list))
++
++    # Take a non-empty list of build-id strings and print a series of
++    # lines that a user could run to instll the RPMs that provide
++    # files with this build-id.
++    #
++    # The printed commands will also install the corresponding debug
++    # packages for the executable with the given build-id.
++    def print_build_id_suggestions(build_id_list):
++        for build_id in build_id_list:
++            print("Missing file(s), try: dnf --enablerepo='*debug*' install "
++                  + build_id_to_usr_lib_filename(build_id, False)
++                  + ' '
++                  + build_id_to_usr_lib_filename(build_id, True, ".debug"))
++
++    # Called before GDB displays its prompt.  If the global __SUGGEST_RPMS
++    # dictionary is not empty, then this hook prints the keys of this
++    # dictionary as strings which are the names of RPMs.  This hook formats
++    # each RPM name into a suggested 'dnf install' command and suggests this
++    # to the user.
++    #
++    # Additionally, if the global __SUGGEST_BUILD_IDS dictionary is not
++    # empty, then this hook uses the keys of this dictionary as build-ids
++    # that were found to be missing, and formats these into some file based
++    # 'dnf install' suggestions to the user.
++    def before_prompt():
++        global __suggest_rpms
++        global __suggest_build_ids
++        global __searching_message_printed
++
++        # We allow the searching message to be printed just once
++        # between prompts.
++        __searching_message_printed = False
++
++        if len(__suggest_rpms) > 0:
++            print_rpm_suggestions(__suggest_rpms.keys())
++            __suggest_rpms = {}
++
++        if len(__suggest_build_ids) > 0:
++            print_build_id_suggestions(__suggest_build_ids.keys())
++            __suggest_build_ids = {}
++
++    # 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
++        global __suggest_build_ids
++        global __missing_build_ids
++
++        if not event.reload:
++            __missing_rpms = {}
++            __suggest_rpms = {}
++            __missing_build_ids = {}
++            __suggest_build_ids = {}
++
++
++    # 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 and missing objfile handlers with GDB.
++    gdb.missing_debug.register_handler(None, RPM_MissingDebugHandler())
++    gdb.missing_objfile.register_handler(None, RPM_MissingObjfileHandler())
++
++    # Implement the core of 'info rpm-suggestions'.  Reprint all rpm
++    # suggestions.
++    def info_rpm_suggestions():
++        global __missing_rpms
++        global __missing_build_ids
++
++        if len(__missing_rpms) == 0 and len(__missing_build_ids) == 0:
++            print("No RPM suggestions have been made so far.")
++            return
++
++        if len(__missing_rpms) > 0:
++            print_rpm_suggestions(__missing_rpms.keys())
++        if len(__missing_build_ids) > 0:
++            print_build_id_suggestions(__missing_build_ids.keys())
++
++####################################################################
++# The following code is outside the 'else' block of the attempt to #
++# load the 'rpm' module.  Nothing after this point depends on the  #
++# 'rpm' module.                                                    #
++####################################################################
++
++# The 'set rpm-suggestion' prefix command.
++class rpm_suggestion_set_prefix(gdb.Command):
++    """Prefix command for 'set' rpm-suggestion related commands."""
++
++    def __init__(self):
++        super().__init__("set rpm-suggestion", gdb.COMMAND_NONE,
++                         gdb.COMPLETE_NONE, True)
++
++# The 'show rpm-suggestion' prefix command.
++class rpm_suggestion_show_prefix(gdb.Command):
++    """Prefix command for 'show' rpm-suggestion related commands."""
++
++    def __init__(self):
++        super().__init__("show rpm-suggestion", gdb.COMMAND_NONE,
++                         gdb.COMPLETE_NONE, True)
++
++# The 'set/show rpm-suggestion enabled' command.
++class rpm_suggestion_enabled(gdb.Parameter):
++    """
++    When 'on' GDB will search for RPMS that might provide additional
++    debug information, or provide missing executables or shared
++    libraries (when opening a core file), and will make suggestions
++    about what should be installed.
++
++    When 'off' GDB will not make these suggestions.
++    """
++
++    set_doc = "Set whether to perform rpm-suggestion."
++    show_doc = "Show whether rpm-suggestion is enabled."
++
++    def __init__(self):
++        super().__init__("rpm-suggestion enabled", gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)
++        self.value = True
++
++# The 'set/show rpm-suggestion enabled' command.
++class rpm_suggestion_build_id_mode(gdb.Parameter):
++    """
++    When set to 'fast' (the default), GDB doesn't try to map a build-id to
++    an actual RPM, instead, GDB just suggests a command based on the
++    build-id which might install some RPMs, if there are any RPMs that
++    supply that build-id.  However, it is equally possible that there are no
++    suitable RPMs, and nothing will install.  This approach has almost zero
++    overhead.
++
++    When set to 'slow', GDB first does the build-id to RPM check itself, and
++    only if something is found are RPMs installation commands suggested.
++    The suggested command will include the name of the RPM to install.  This
++    approach is considerably slower as querying the RPM database for the RPM
++    that supplies a specific file is slow.
++    """
++
++    set_doc = "Set how build-id based rpm suggestions should be performed."
++    show_doc = "Show how build-id based rpm suggestions shoud be performed."
++
++    def __init__(self):
++        super().__init__("rpm-suggestion build-id-mode",
++                         gdb.COMMAND_NONE, gdb.PARAM_ENUM, ["fast", "slow"])
++        self.value = "fast"
++
++    def fast_mode(self):
++        return self.value == "fast"
++
++# The 'info rpm-suggestions' command.
++class rpm_suggestion_info(gdb.Command):
++    """Relist RPM suggestions.
++
++    Relist any RPM installation suggestions that have been made
++    since the executable was last changed."""
++    def __init__(self):
++        super().__init__("info rpm-suggestions", gdb.COMMAND_NONE, gdb.COMPLETE_NONE)
++
++    def invoke(self, args, from_tty):
++        if args != "":
++            raise gdb.GdbError("unexpected arguments: %s" % args)
++
++        info_rpm_suggestions ()
++
++
++# Create the 'set/show rpm-suggestion' commands.
++rpm_suggestion_set_prefix()
++rpm_suggestion_show_prefix()
++param_rpm_suggestion_enabled = rpm_suggestion_enabled()
++param_rpm_suggestion_build_id_mode = rpm_suggestion_build_id_mode()
++
++# Create the 'info rpm-suggestions' commands.
++rpm_suggestion_info()
+diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-lib.c
+@@ -0,0 +1,21 @@
++/* Copyright 2010 Free Software Foundation, Inc.
++
++   This file is part of GDB.
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++void
++lib (void)
++{
++}
+diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib-main.c
+@@ -0,0 +1,25 @@
++/* Copyright 2010 Free Software Foundation, Inc.
++
++   This file is part of GDB.
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++extern void lib (void);
++
++int
++main (void)
++{
++  lib ();
++  return 0;
++}
+diff --git a/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/gcore-buildid-exec-but-not-solib.exp
+@@ -0,0 +1,104 @@
++# Copyright 2016 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/>.
++
++require allow_shlib_tests
++
++set testfile "gcore-buildid-exec-but-not-solib"
++set srcmainfile ${testfile}-main.c
++set srclibfile ${testfile}-lib.c
++set libfile [standard_output_file ${testfile}-lib.so]
++set objfile [standard_output_file ${testfile}-main.o]
++set executable ${testfile}-main
++set binfile [standard_output_file ${executable}]
++set gcorefile [standard_output_file ${executable}.gcore]
++set outdir [file dirname $binfile]
++
++if { [gdb_compile_shlib ${srcdir}/${subdir}/${srclibfile} ${libfile} "debug additional_flags=-Wl,--build-id"] != ""
++     || [gdb_compile ${srcdir}/${subdir}/${srcmainfile} ${objfile} object {debug}] != "" } {
++     unsupported "-Wl,--build-id compilation failed"
++     return -1
++}
++set opts [list debug shlib=${libfile} "additional_flags=-Wl,--build-id"]
++if { [gdb_compile ${objfile} ${binfile} executable $opts] != "" } {
++     unsupported "-Wl,--build-id compilation failed"
++     return -1
++}
++
++clean_restart $executable
++gdb_load_shlib $libfile
++
++# Does this gdb support gcore?
++set test "help gcore"
++gdb_test_multiple $test $test {
++    -re "Undefined command: .gcore.*\r\n$gdb_prompt $" {
++	# gcore command not supported -- nothing to test here.
++	unsupported "gdb does not support gcore on this target"
++	return -1;
++    }
++    -re "Save a core file .*\r\n$gdb_prompt $" {
++	pass $test
++    }
++}
++
++if { ![runto lib] } then {
++    return -1
++}
++
++set escapedfilename [string_to_regexp ${gcorefile}]
++
++set test "save a corefile"
++gdb_test_multiple "gcore ${gcorefile}" $test {
++    -re "Saved corefile ${escapedfilename}\r\n$gdb_prompt $" {
++	pass $test
++    }
++    -re "Can't create a corefile\r\n$gdb_prompt $" {
++	unsupported $test
++	return -1
++    }
++}
++
++# Now restart gdb and load the corefile.
++
++clean_restart $executable
++gdb_load_shlib $libfile
++
++set buildid [build_id_debug_filename_get $libfile]
++
++regsub {\.debug$} $buildid {} buildid
++
++set debugdir [standard_output_file ${testfile}-debugdir]
++file delete -force -- $debugdir
++
++file mkdir $debugdir/[file dirname $libfile]
++file copy $libfile $debugdir/${libfile}
++
++file mkdir $debugdir/[file dirname $buildid]
++file copy $libfile $debugdir/${buildid}
++
++remote_exec build "ln -s /lib       ${debugdir}/"
++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_no_output "set solib-absolute-prefix $debugdir" \
++    "set solib-absolute-prefix"
++
++gdb_test_no_output "set debug-file-directory $debugdir" "set debug-file-directory"
++
++gdb_test "core ${gcorefile}" "Core was generated by .*" "re-load generated corefile"
++
++gdb_test "frame" "#0 \[^\r\n\]* lib .*" "library got loaded"
++
++gdb_test "bt"
++gdb_test "info shared"
+diff --git a/gdb/testsuite/gdb.base/gdbinit-history.exp b/gdb/testsuite/gdb.base/gdbinit-history.exp
+--- a/gdb/testsuite/gdb.base/gdbinit-history.exp
++++ b/gdb/testsuite/gdb.base/gdbinit-history.exp
+@@ -179,7 +179,8 @@ proc test_empty_history_filename { } {
+     global env
+     global gdb_prompt
+ 
+-    set common_history [list "set height 0" "set width 0"]
++    set common_history [list "set height 0" "set width 0" \
++			    "set rpm-suggestion enabled off"]
+ 
+     set test_dir [standard_output_file history_test]
+     remote_exec host "mkdir -p $test_dir"
+diff --git a/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp b/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/rhbz981154-misleading-yum-install-warning.exp
+@@ -0,0 +1,60 @@
++# Copyright (C) 2014  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/>.
++
++# Create a core file, then hide the executable.  Restart GDB and load
++# the core file.  Check GDB gives a message suggesting a 'dnf' command
++# to try and install the executable based on its build-id.
++
++standard_testfile "normal.c"
++
++if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
++    return -1
++}
++
++# Get the build-id of the file.
++set build_id_debug_file [build_id_debug_filename_get $binfile]
++regsub -all ".debug$" $build_id_debug_file "" build_id_without_debug
++
++# Run to main.
++if { ![runto_main] } {
++    return -1
++}
++
++# We first need to generate a corefile.
++set corefilename "[standard_output_file gcore.test]"
++if { ![gdb_gcore_cmd "$corefilename" "save corefile"] } {
++    untested "could not generate a corefile"
++    return -1
++}
++
++# Move the binfile to a temporary name.
++remote_exec build "mv $binfile ${binfile}.old"
++
++# Reinitialize GDB and see if we get a dnf suggestion.
++clean_restart
++
++gdb_test "set rpm-suggestion enabled on" "" \
++    "turn on rpm-suggestion feature"
++
++# GDB only makes build-id based RPM suggestions if /usr/lib is in
++# the debug-file-directory list, the reason being that system RPMs
++# will always install under this location.  If GDB is not looking
++# here then there's no point making suggestions.
++gdb_test "set debug-file-directory /usr/lib/" "" \
++    "set debug-file-directory"
++
++gdb_test "core-file [standard_output_file gcore.test]" \
++    "Missing file\\(s\\), try: dnf --enablerepo='\\*debug\\*' install [string_to_regexp /usr/lib/$build_id_without_debug] [string_to_regexp /usr/lib/debug/$build_id_debug_file]" \
++    "test first yum/dnf warning"
+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
+@@ -19,6 +19,13 @@ from enum import Enum
+ import gdb
+ from gdb.missing_debug import MissingDebugHandler
+ 
++# 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 = []
+@@ -118,4 +125,7 @@ def register(name, locus=None):
+ rhandler = exception_handler()
+ handler_obj = handler()
+ 
++# Discard the rpm-suggestion handler.
++gdb.missing_file_handlers = []
++
+ print("Success")
+diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.python/py-missing-objfile.py
+--- a/gdb/testsuite/gdb.python/py-missing-objfile.py
++++ b/gdb/testsuite/gdb.python/py-missing-objfile.py
+@@ -164,4 +164,7 @@ def register(name, locus=None):
+ rhandler = exception_handler()
+ handler_obj = handler()
+ 
++# Discard the rpm-suggestion handler.
++gdb.missing_file_handlers = []
++
+ print("Success")
+diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
+--- a/gdb/testsuite/lib/gdb.exp
++++ b/gdb/testsuite/lib/gdb.exp
+@@ -255,7 +255,8 @@ if ![info exists INTERNAL_GDBFLAGS] {
+ 		   "-nx" \
+ 		   "-q" \
+ 		   {-iex "set height 0"} \
+-		   {-iex "set width 0"}]]
++		   {-iex "set width 0"} \
++		   {-iex "set rpm-suggestion enabled off"}]]
+ 
+     # If DEBUGINFOD_URLS is set, gdb will try to download sources and
+     # debug info for f.i. system libraries.  Prevent this.
+@@ -2610,6 +2611,18 @@ proc default_gdb_start { } {
+ 	}
+     }
+ 
++    # Turn off the missing debug info messages as the testsuite does
++    # not expect them.
++    send_gdb "set rpm-suggestion enabled off\n"
++    gdb_expect 10 {
++	-re "$gdb_prompt $" {
++	    verbose "Disabled the missing debug info messages." 2
++	}
++	timeout {
++	    warning "Could not disable the missing debug info messages."
++	}
++    }
++
+     gdb_debug_init
+     return 0
+ }
+diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
+--- a/gdb/testsuite/lib/mi-support.exp
++++ b/gdb/testsuite/lib/mi-support.exp
+@@ -321,6 +321,17 @@ proc default_mi_gdb_start { { flags {} } } {
+ 	    warning "Couldn't set the width to 0."
+ 	}
+     }
++    # Turn off the missing debug info messages as the testsuite does
++    # not expect them.
++    send_gdb "190-gdb-set rpm-suggestion enabled off\n"
++    gdb_expect 10 {
++	-re ".*190-gdb-set rpm-suggestion enabled off\r\n190\\\^done\r\n$mi_gdb_prompt$" {
++	    verbose "Disabled the missing debug info messages." 2
++	}
++	timeout {
++	    warning "Could not disable the missing debug info messages."
++	}
++    }
+ 
+     if { $separate_inferior_pty } {
+ 	mi_create_inferior_pty

diff --git a/gdb-test-show-version.patch b/gdb-test-show-version.patch
new file mode 100644
index 0000000..feee38e
--- /dev/null
+++ b/gdb-test-show-version.patch
@@ -0,0 +1,34 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Fri, 27 Oct 2017 21:07:50 +0200
+Subject: gdb-test-show-version.patch
+
+;; Check distro name is included in the version output.
+
+diff --git a/gdb/testsuite/gdb.base/fedora-version.exp b/gdb/testsuite/gdb.base/fedora-version.exp
+new file mode 100644
+--- /dev/null
++++ b/gdb/testsuite/gdb.base/fedora-version.exp
+@@ -0,0 +1,22 @@
++# 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/>.
++
++# Start with a fresh gdb
++clean_restart
++
++# Check the version string contains either the Fedora or RHEL distro
++# name, and that the version number looks roughly correct in format.
++gdb_test "show version" \
++    "GNU gdb \\((Fedora Linux|Red Hat Enterprise Linux)\\) \[0-9\]+\\.\[0-9\]+-\[0-9\]+.*"

diff --git a/gdb.spec b/gdb.spec
index 93bfd38..e84e6ee 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -937,6 +937,13 @@ fi
 
 %changelog
 * Tue Jun 03 2025 Andrew Burgess <aburgess@redhat.com>
+- Rename 'gdb-add-rpm-suggestion-script.patch' to
+  'gdb-rpm-suggestion-script.patch' and
+  'gdb-6.3-rh-testversion-20041202.patch' to
+  'gdb-test-show-version.patch'.  The new names better reflect the
+  patch contents.
+
+* Tue Jun 03 2025 Andrew Burgess <aburgess@redhat.com>
 - Remove gdb-archer-next-over-throw-cxx-exec.patch, we now have
   upstream commit d462550c91c.
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-28  0:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-28  0:02 [rpms/gdb] gdb-17.2-rebase-f44: rename two of the patch files Andrew Burgess

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox