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: rename two of the patch files
Date: Sun, 28 Jun 2026 00:02:15 GMT [thread overview]
Message-ID: <178260493556.1.13192544990099379139.rpms-gdb-152468cce99e@fedoraproject.org> (raw)
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.
reply other threads:[~2026-06-28 0:02 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=178260493556.1.13192544990099379139.rpms-gdb-152468cce99e@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