public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
To: git-commits@fedoraproject.org
Subject: [rpms/gdb] gdb-17.2-rebase-f44: Rebase to FSF GDB 16.1.
Date: Sun, 28 Jun 2026 00:02:02 GMT [thread overview]
Message-ID: <178260492228.1.4659770524731920611.rpms-gdb-5fc2d96b3010@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/gdb
Branch : gdb-17.2-rebase-f44
Commit : 5fc2d96b30102d32189266b67ff9c2087d1e70d9
Author : Alexandra Hájková <ahajkova@redhat.com>
Date : 2025-02-06T20:18:40+01:00
Stats : +18/-10305 in 11 file(s)
URL : https://src.fedoraproject.org/rpms/gdb/c/5fc2d96b30102d32189266b67ff9c2087d1e70d9?branch=gdb-17.2-rebase-f44
Log:
Rebase to FSF GDB 16.1.
Dropped:
gdb-backport-buildid-related-changes.patch
gdb-catchpoint-re-set.patch
gdb-remove-qnx-neutrino-support.patch
---
diff --git a/.gitignore b/.gitignore
index b15a13c..0ae6b1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
/new-fedora-release
/gdb-libstdc++-v3-python-8.1.1-20180626.tar.xz
/v2.0.5.tar.gz
-/gdb-15.1.tar.xz
-/gdb-15.2.tar.xz
+/gdb-16.1.tar.xz
+/gdb-16.0.tar.gz
diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include
index 31538e6..f6e9160 100644
--- a/_gdb.spec.Patch.include
+++ b/_gdb.spec.Patch.include
@@ -53,39 +53,7 @@ Patch010: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
#=fedora
Patch011: gdb-add-index.patch
-# Backport of upstream commit 36fb20fa93484b104d. This is not really
-# relevant for our branch, but later commits that are important, and
-# which we want to backport, conflict unless the cleanup in this
-# patch is in place.
-#
-# This commit will be part of GDB 16, so this back-port should drop
-# out when we rebase onto GDB 16.
-#
-# gdb: remove QNX Neutrino support
-#
-# Remove the support for the QNX Neutrino OS (tdep and native bits). This
-# has been unmaintained for years, and we don't have a way to see if it
-# works (or even builds, for the native parts). Without somebody actively
-# maintaining it, this is just a burden for developers, especially that
-# this port does a few weird unique things that require reasoning about
-# when doing big change.
-#
-# Support for GDBserver was removed in 2020, commit 613f149a90d6
-# ("gdbserver: remove support for Neutrino").
-#
-# Change-Id: I4e25ec26ab06636629adebd02ceb161ee31c232d
-# Approved-by: Kevin Buettner <kevinb@redhat.com>
-Patch012: gdb-remove-qnx-neutrino-support.patch
-
-# Backport patches related to build-id usage when opening a core
-# file, and also improving general build-id based lookup. These will
-# all drop out when rebasing to GDB 16.
-Patch013: gdb-backport-buildid-related-changes.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.
-Patch014: gdb-add-rpm-suggestion-script.patch
-
-
-Patch015: gdb-catchpoint-re-set.patch
+Patch012: gdb-add-rpm-suggestion-script.patch
diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include
index f630fc2..dad4d0a 100644
--- a/_gdb.spec.patch.include
+++ b/_gdb.spec.patch.include
@@ -10,6 +10,3 @@
%patch -p1 -P010
%patch -p1 -P011
%patch -p1 -P012
-%patch -p1 -P013
-%patch -p1 -P014
-%patch -p1 -P015
diff --git a/_git_upstream_commit b/_git_upstream_commit
index 0e087a9..1949935 100644
--- a/_git_upstream_commit
+++ b/_git_upstream_commit
@@ -1 +1 @@
-23c84db5b3cb4e8a0d555c76e1a0ab56dc8355f3
+f2a0e51cda4da686e35ca3bc08a4b5dad7130473
diff --git a/_patch_order b/_patch_order
index 5ae7707..047f472 100644
--- a/_patch_order
+++ b/_patch_order
@@ -9,7 +9,4 @@ gdb-rhbz-818343-set-solib-absolute-prefix-testcase.patch
gdb-rhbz1149205-catch-syscall-after-fork-test.patch
gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch
gdb-add-index.patch
-gdb-remove-qnx-neutrino-support.patch
-gdb-backport-buildid-related-changes.patch
gdb-add-rpm-suggestion-script.patch
-gdb-catchpoint-re-set.patch
diff --git a/gdb-add-rpm-suggestion-script.patch b/gdb-add-rpm-suggestion-script.patch
index 51357f4..98bda71 100644
--- a/gdb-add-rpm-suggestion-script.patch
+++ b/gdb-add-rpm-suggestion-script.patch
@@ -14,7 +14,7 @@ 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
-@@ -91,6 +91,7 @@ PYTHON_FILE_LIST = \
+@@ -92,6 +92,7 @@ PYTHON_FILE_LIST = \
gdb/command/missing_files.py \
gdb/command/pretty_printers.py \
gdb/command/prompt.py \
@@ -33,7 +33,7 @@ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
* Man Pages:: Manual pages
* Copying:: GNU General Public License says
how you can copy and share @value{GDBN}
-@@ -50341,6 +50342,111 @@ Show the current verbosity setting.
+@@ -50576,6 +50577,111 @@ Show the current verbosity setting.
@end table
@@ -957,7 +957,7 @@ diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.
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
-@@ -238,7 +238,8 @@ if ![info exists INTERNAL_GDBFLAGS] {
+@@ -255,7 +255,8 @@ if ![info exists INTERNAL_GDBFLAGS] {
"-nx" \
"-q" \
{-iex "set height 0"} \
@@ -967,7 +967,7 @@ diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
# If DEBUGINFOD_URLS is set, gdb will try to download sources and
# debug info for f.i. system libraries. Prevent this.
-@@ -2493,6 +2494,18 @@ proc default_gdb_start { } {
+@@ -2610,6 +2611,18 @@ proc default_gdb_start { } {
}
}
diff --git a/gdb-backport-buildid-related-changes.patch b/gdb-backport-buildid-related-changes.patch
deleted file mode 100644
index 7ace8c5..0000000
--- a/gdb-backport-buildid-related-changes.patch
+++ /dev/null
@@ -1,6753 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Andrew Burgess <aburgess@redhat.com>
-Date: Wed, 31 Jul 2024 15:58:20 +0100
-Subject: gdb-backport-buildid-related-changes.patch
-
-;; Backport patches related to build-id usage when opening a core
-;; file, and also improving general build-id based lookup. These will
-;; all drop out when rebasing to GDB 16.
-
-backport the following patches related to build-id usage
-
-This one patch backports the following upstream commits:
-
- * 195795b0fd4 gdb: fix a target: prefix issue in find_separate_debug_file
- * ea4c968ce54 gdb: avoid '//' in filenames when searching for debuginfo
- * 22836ca8859 gdb: check for multiple matching build-id files
- * 6d45af96ea5 gdbserver: add gdbserver support for vFile::stat packet
- * 3055e3d2f13 gdb: add GDB side target_ops::fileio_stat implementation
- * 08a115cc1c4 gdb: add target_fileio_stat, but no implementations yet
- * c7e38ee47c9 gdb: avoid duplicate search in build_id_to_bfd_suffix
- * 10ac7e80c01 gdb: remove find_and_open_solib so_list method
- * 3e35b4deae2 gdb/testsuite: tests for debug lookup within the sysroot
- * 6dfd07222c0 gdb: convert separate-debug-file to new(ish) debug scheme
- * 5cabc8098e6 gdb/python: implement Python find_exec_by_build_id hook
- * ef1a41f20b7 gdb: add extension hook ext_lang_find_objfile_from_buildid
- * 629bcc68d79 gdb: rename ext_lang_missing_debuginfo_result
- * 73d7312ff61 gdb: use mapped file information to improve debuginfod text
- * 5ddd0d7eefb gdb/python: avoid depending on the curses library
- * 8358d39b4f0 gdb: unify build-id to objfile lookup code
- * fa826a4bbe9 gdb: improve shared library build-id check for core-files
- * a47a679c769 gdb/corefile: improve file backed mapping handling
- * 522875f679b gdb/corefile: don't pretend unavailable sections are readable
- * 97832471899 gdb/build-id: protect against weirdly short build-ids
- * 9543c37620c gdb/testsuite: make gdb_gnu_strip_debug consistent
- * fc240bb143c gdb/fileio: fix errno for packets where an attachment is expected
- * df0445b370f gdb/testsuite: fix typo 'unsupport' to 'unsupported'
-
-I've merged these into a single (large) patch as these all merged
-without any changes (i.e. these represent exactly the upstream code),
-and all of these will be included in GDB 16, and so should all drop
-out together when we rebase to GDB 16 (the next rebase).
-
-All of these patches relate to either build-id usage when opening a
-core file, or improving GDB's build-id based debug lookup.
-
-diff --git a/gdb/NEWS b/gdb/NEWS
---- a/gdb/NEWS
-+++ b/gdb/NEWS
-@@ -1,6 +1,36 @@
- What has changed in GDB?
- (Organized release by release)
-
-+*** Change since GDB 15
-+
-+* Python API
-+
-+ ** New module gdb.missing_objfile that facilitates dealing with
-+ missing objfiles when opening a core-file.
-+
-+ ** New function gdb.missing_objfile.register_handler that can
-+ register an instance of a sub-class of
-+ gdb.missing_debug.MissingObjfileHandler as a handler for missing
-+ objfiles.
-+
-+ ** New class gdb.missing_objfile.MissingObjfileHandler which can be
-+ sub-classed to create handlers for missing objfiles.
-+
-+* New commands
-+
-+info missing-objfile-handlers
-+ List all the registered missing-objfile handlers.
-+
-+enable missing-objfile-handler LOCUS HANDLER
-+disable missing-objfile-handler LOCUS HANDLER
-+ Enable or disable a missing-objfile handler with a name matching the
-+ regular expression HANDLER, in LOCUS.
-+
-+ LOCUS can be 'global' to operate on global missing-objfile handler,
-+ 'progspace' to operate on handlers within the current program space,
-+ or can be a regular expression which is matched against the filename
-+ of the primary executable in each program space.
-+
- *** Changes in GDB 15
-
- * The MPX commands "show/set mpx bound" have been deprecated, as Intel
-@@ -212,6 +242,11 @@ qIsAddressTagged
- file is about, this new packet provides a more generic way to perform such
- a check.
-
-+vFile:stat
-+ Return information about files on the remote system. Like
-+ vFile:fstat but takes a filename rather than an open file
-+ descriptor.
-+
- *** Changes in GDB 14
-
- * GDB now supports the AArch64 Scalable Matrix Extension 2 (SME2), which
-diff --git a/gdb/build-id.c b/gdb/build-id.c
---- a/gdb/build-id.c
-+++ b/gdb/build-id.c
-@@ -26,6 +26,9 @@
- #include "filenames.h"
- #include "gdbcore.h"
- #include "cli/cli-style.h"
-+#include "gdbsupport/scoped_fd.h"
-+#include "debuginfod-support.h"
-+#include "extension.h"
-
- /* See build-id.h. */
-
-@@ -73,73 +76,177 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
- return retval;
- }
-
--/* Helper for build_id_to_debug_bfd. LINK is a path to a potential
-- build-id-based separate debug file, potentially a symlink to the real file.
-- If the file exists and matches BUILD_ID, return a BFD reference to it. */
-+/* Helper for build_id_to_debug_bfd. ORIGINAL_LINK with SUFFIX appended is
-+ a path to a potential build-id-based separate debug file, potentially a
-+ symlink to the real file. If the file exists and matches BUILD_ID,
-+ return a BFD reference to it. */
-
- static gdb_bfd_ref_ptr
--build_id_to_debug_bfd_1 (const std::string &link, size_t build_id_len,
-- const bfd_byte *build_id)
-+build_id_to_debug_bfd_1 (const std::string &original_link,
-+ size_t build_id_len, const bfd_byte *build_id,
-+ const char *suffix)
- {
-- if (separate_debug_file_debug)
-+ tribool supports_target_stat = TRIBOOL_UNKNOWN;
-+
-+ /* Drop the 'target:' prefix if the target filesystem is local. */
-+ std::string_view original_link_view (original_link);
-+ if (is_target_filename (original_link) && target_filesystem_is_local ())
-+ original_link_view
-+ = original_link_view.substr (strlen (TARGET_SYSROOT_PREFIX));
-+
-+ /* The upper bound of '10' here is completely arbitrary. The loop should
-+ terminate via 'break' when either (a) a readable symlink is found, or
-+ (b) a non-existing entry is found.
-+
-+ However, for remote targets, we rely on the remote returning sane
-+ error codes. If a remote sends back the wrong error code then it
-+ might trick GDB into thinking that the symlink exists, but points to a
-+ missing file, in which case GDB will try the next seqno. We don't
-+ want a broken remote to cause GDB to spin here forever, hence a fixed
-+ upper bound. */
-+
-+ for (unsigned seqno = 0; seqno < 10; seqno++)
- {
-- gdb_printf (gdb_stdlog, _(" Trying %s..."), link.c_str ());
-- gdb_flush (gdb_stdlog);
-- }
-+ std::string link (original_link_view);
-
-- /* lrealpath() is expensive even for the usually non-existent files. */
-- gdb::unique_xmalloc_ptr<char> filename_holder;
-- const char *filename = nullptr;
-- if (is_target_filename (link))
-- filename = link.c_str ();
-- else if (access (link.c_str (), F_OK) == 0)
-- {
-- filename_holder.reset (lrealpath (link.c_str ()));
-- filename = filename_holder.get ();
-- }
-+ if (seqno > 0)
-+ string_appendf (link, ".%u", seqno);
-
-- if (filename == NULL)
-- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog,
-- _(" no, unable to compute real path\n"));
-+ link += suffix;
-
-- return {};
-- }
-+ separate_debug_file_debug_printf ("Trying %s...", link.c_str ());
-
-- /* We expect to be silent on the non-existing files. */
-- gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget);
-+ gdb::unique_xmalloc_ptr<char> filename_holder;
-+ const char *filename = nullptr;
-+ if (is_target_filename (link))
-+ {
-+ gdb_assert (link.length () >= strlen (TARGET_SYSROOT_PREFIX));
-+ const char *link_on_target
-+ = link.c_str () + strlen (TARGET_SYSROOT_PREFIX);
-+
-+ fileio_error target_errno;
-+ if (supports_target_stat != TRIBOOL_FALSE)
-+ {
-+ struct stat sb;
-+ int res = target_fileio_stat (nullptr, link_on_target, &sb,
-+ &target_errno);
-+
-+ if (res != 0 && target_errno != FILEIO_ENOSYS)
-+ {
-+ separate_debug_file_debug_printf ("path doesn't exist");
-+ break;
-+ }
-+ else if (res != 0 && target_errno == FILEIO_ENOSYS)
-+ supports_target_stat = TRIBOOL_FALSE;
-+ else
-+ {
-+ supports_target_stat = TRIBOOL_TRUE;
-+ filename = link.c_str ();
-+ }
-+ }
-+
-+ if (supports_target_stat == TRIBOOL_FALSE)
-+ {
-+ gdb_assert (filename == nullptr);
-+
-+ /* Connecting to a target that doesn't support 'stat'. Try
-+ 'readlink' as an alternative. This isn't ideal, but is
-+ maybe better than nothing. Returns EINVAL if the path
-+ isn't a symbolic link, which hints that the path is
-+ available -- there are other errors e.g. ENOENT for when
-+ the path doesn't exist, but we just assume that anything
-+ other than EINVAL indicates the path doesn't exist. */
-+ std::optional<std::string> link_target
-+ = target_fileio_readlink (nullptr, link_on_target,
-+ &target_errno);
-+ if (link_target.has_value ()
-+ || target_errno == FILEIO_EINVAL)
-+ filename = link.c_str ();
-+ else
-+ {
-+ separate_debug_file_debug_printf ("path doesn't exist");
-+ break;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ struct stat buf;
-+
-+ /* The `access' call below automatically dereferences LINK, but
-+ we want to stop incrementing SEQNO once we find a symlink
-+ that doesn't exist. */
-+ if (lstat (link.c_str (), &buf) != 0)
-+ {
-+ separate_debug_file_debug_printf ("path doesn't exist");
-+ break;
-+ }
-+
-+ /* Can LINK be accessed, or if LINK is a symlink, can the file
-+ pointed too be accessed? Do this as lrealpath() is
-+ expensive, even for the usually non-existent files. */
-+ if (access (link.c_str (), F_OK) == 0)
-+ {
-+ filename_holder.reset (lrealpath (link.c_str ()));
-+ filename = filename_holder.get ();
-+ }
-+ }
-
-- if (debug_bfd == NULL)
-- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" no, unable to open.\n"));
-+ if (filename == nullptr)
-+ {
-+ separate_debug_file_debug_printf ("unable to compute real path");
-+ continue;
-+ }
-
-- return {};
-- }
-+ /* We expect to be silent on the non-existing files. */
-+ gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget);
-
-- if (!build_id_verify (debug_bfd.get(), build_id_len, build_id))
-- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" no, build-id does not match.\n"));
-+ if (debug_bfd == NULL)
-+ {
-+ separate_debug_file_debug_printf ("unable to open `%s`", filename);
-+ continue;
-+ }
-
-- return {};
-- }
-+ if (!build_id_verify (debug_bfd.get(), build_id_len, build_id))
-+ {
-+ separate_debug_file_debug_printf ("build-id does not match");
-+ continue;
-+ }
-
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" yes!\n"));
-+ separate_debug_file_debug_printf ("found a match");
-+ return debug_bfd;
-+ }
-
-- return debug_bfd;
-+ separate_debug_file_debug_printf ("no suitable file found");
-+ return {};
- }
-
- /* Common code for finding BFDs of a given build-id. This function
- works with both debuginfo files (SUFFIX == ".debug") and executable
-- files (SUFFIX == ""). */
-+ files (SUFFIX == "").
-+
-+ The build-id will be split into a single byte sub-directory, followed by
-+ the remaining build-id bytes as the filename, i.e. we use the lookup
-+ format: `.build-id/xx/yy....zz`. As a consequence, if BUILD_ID_LEN is
-+ less than 2 (bytes), no results will be found as there are not enough
-+ bytes to form the `yy....zz` part of the lookup filename. */
-
- static gdb_bfd_ref_ptr
- build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
- const char *suffix)
- {
-+ SEPARATE_DEBUG_FILE_SCOPED_DEBUG_ENTER_EXIT;
-+
-+ if (build_id_len < 2)
-+ {
-+ /* Zero length build-ids are ignored by bfd. */
-+ gdb_assert (build_id_len > 0);
-+ separate_debug_file_debug_printf
-+ ("Ignoring short build-id `%s' for build-id based lookup",
-+ bin2hex (build_id, build_id_len).c_str ());
-+ return {};
-+ }
-+
- /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
- cause "/.build-id/..." lookups. */
-
-@@ -158,30 +265,33 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
- std::string link = debugdir.get ();
- link += "/.build-id/";
-
-- if (size > 0)
-- {
-- size--;
-- string_appendf (link, "%02x/", (unsigned) *data++);
-- }
-+ gdb_assert (size > 1);
-+ size--;
-+ string_appendf (link, "%02x/", (unsigned) *data++);
-
- while (size-- > 0)
- string_appendf (link, "%02x", (unsigned) *data++);
-
-- link += suffix;
--
- gdb_bfd_ref_ptr debug_bfd
-- = build_id_to_debug_bfd_1 (link, build_id_len, build_id);
-+ = build_id_to_debug_bfd_1 (link, build_id_len, build_id, suffix);
- if (debug_bfd != NULL)
- return debug_bfd;
-
- /* Try to look under the sysroot as well. If the sysroot is
- "/the/sysroot", it will give
-- "/the/sysroot/usr/lib/debug/.build-id/ab/cdef.debug". */
-+ "/the/sysroot/usr/lib/debug/.build-id/ab/cdef.debug".
-+
-+ If the sysroot is 'target:' and the target filesystem is local to
-+ GDB then 'target:/path/to/check' becomes '/path/to/check' which
-+ we just checked above. */
-
-- if (!gdb_sysroot.empty ())
-+ if (!gdb_sysroot.empty ()
-+ && (gdb_sysroot != TARGET_SYSROOT_PREFIX
-+ || !target_filesystem_is_local ()))
- {
- link = gdb_sysroot + link;
-- debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id);
-+ debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id,
-+ suffix);
- if (debug_bfd != NULL)
- return debug_bfd;
- }
-@@ -198,9 +308,11 @@ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
- return build_id_to_bfd_suffix (build_id_len, build_id, ".debug");
- }
-
--/* See build-id.h. */
-+/* Find and open a BFD for an executable file given a build-id. If no BFD
-+ can be found, return NULL. The returned reference to the BFD must be
-+ released by the caller. */
-
--gdb_bfd_ref_ptr
-+static gdb_bfd_ref_ptr
- build_id_to_exec_bfd (size_t build_id_len, const bfd_byte *build_id)
- {
- return build_id_to_bfd_suffix (build_id_len, build_id, "");
-@@ -217,10 +329,9 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
- build_id = build_id_bfd_get (objfile->obfd.get ());
- if (build_id != NULL)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog,
-- _("\nLooking for separate debug info (build-id) for "
-- "%s\n"), objfile_name (objfile));
-+ SEPARATE_DEBUG_FILE_SCOPED_DEBUG_START_END
-+ ("looking for separate debug info (build-id) for %s",
-+ objfile_name (objfile));
-
- gdb_bfd_ref_ptr abfd (build_id_to_debug_bfd (build_id->size,
- build_id->data));
-@@ -229,9 +340,9 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
- && filename_cmp (bfd_get_filename (abfd.get ()),
- objfile_name (objfile)) == 0)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, "\"%s\": separate debug info file has no "
-- "debug info", bfd_get_filename (abfd.get ()));
-+ separate_debug_file_debug_printf
-+ ("\"%s\": separate debug info file has no debug info",
-+ bfd_get_filename (abfd.get ()));
- warnings->warn (_("\"%ps\": separate debug info file has no "
- "debug info"),
- styled_string (file_name_style.style (),
-@@ -243,3 +354,78 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
-
- return std::string ();
- }
-+
-+/* See build-id.h. */
-+
-+gdb_bfd_ref_ptr
-+find_objfile_by_build_id (program_space *pspace,
-+ const bfd_build_id *build_id,
-+ const char *expected_filename)
-+{
-+ gdb_bfd_ref_ptr abfd;
-+
-+ for (unsigned attempt = 0, max_attempts = 1;
-+ attempt < max_attempts && abfd == nullptr;
-+ ++attempt)
-+ {
-+ /* Try to find the executable (or shared object) by looking for a
-+ (sym)link on disk from the build-id to the object file. */
-+ abfd = build_id_to_exec_bfd (build_id->size, build_id->data);
-+
-+ if (abfd != nullptr || attempt > 0)
-+ break;
-+
-+ /* Attempt to query debuginfod for the executable. This will only
-+ get run during the first attempt, if an extension language hook
-+ (see below) asked for a second attempt then we will have already
-+ broken out of the loop above. */
-+ gdb::unique_xmalloc_ptr<char> path;
-+ scoped_fd fd = debuginfod_exec_query (build_id->data, build_id->size,
-+ expected_filename, &path);
-+ if (fd.get () >= 0)
-+ {
-+ abfd = gdb_bfd_open (path.get (), gnutarget);
-+
-+ if (abfd == nullptr)
-+ warning (_("\"%ps\" from debuginfod cannot be opened as bfd: %s"),
-+ styled_string (file_name_style.style (), path.get ()),
-+ gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
-+ else if (!build_id_verify (abfd.get (), build_id->size,
-+ build_id->data))
-+ abfd = nullptr;
-+ }
-+
-+ if (abfd != nullptr)
-+ break;
-+
-+ ext_lang_missing_file_result ext_result
-+ = ext_lang_find_objfile_from_buildid (pspace, build_id,
-+ expected_filename);
-+ if (!ext_result.filename ().empty ())
-+ {
-+ /* The extension identified the file for us. */
-+ abfd = gdb_bfd_open (ext_result.filename ().c_str (), gnutarget);
-+ if (abfd == nullptr)
-+ {
-+ warning (_("\"%ps\" from extension cannot be opened as bfd: %s"),
-+ styled_string (file_name_style.style (),
-+ ext_result.filename ().c_str ()),
-+ gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
-+ break;
-+ }
-+
-+ /* If the extension gave us a path to a file then we always
-+ assume that it is the correct file, we do no additional check
-+ of its build-id. */
-+ }
-+ else if (ext_result.try_again ())
-+ {
-+ /* The extension might have installed the file in the expected
-+ location, we should try again. */
-+ max_attempts = 2;
-+ continue;
-+ }
-+ }
-+
-+ return abfd;
-+}
-diff --git a/gdb/build-id.h b/gdb/build-id.h
---- a/gdb/build-id.h
-+++ b/gdb/build-id.h
-@@ -40,13 +40,6 @@ extern int build_id_verify (bfd *abfd,
- extern gdb_bfd_ref_ptr build_id_to_debug_bfd (size_t build_id_len,
- const bfd_byte *build_id);
-
--/* Find and open a BFD for an executable file given a build-id. If no BFD
-- can be found, return NULL. The returned reference to the BFD must be
-- released by the caller. */
--
--extern gdb_bfd_ref_ptr build_id_to_exec_bfd (size_t build_id_len,
-- const bfd_byte *build_id);
--
- /* Find the separate debug file for OBJFILE, by using the build-id
- associated with OBJFILE's BFD. If successful, returns the file name for the
- separate debug file, otherwise, return an empty string.
-@@ -60,6 +53,22 @@ extern gdb_bfd_ref_ptr build_id_to_exec_bfd (size_t build_id_len,
- extern std::string find_separate_debug_file_by_buildid
- (struct objfile *objfile, deferred_warnings *warnings);
-
-+/* Find an objfile (executable or shared library) that matches BUILD_ID.
-+ This is done by first checking in the debug-file-directory for a
-+ suitable .build-id/ sub-directory, and looking for a file with the
-+ required build-id (usually a symbolic link or hard link to the actual
-+ file).
-+
-+ If that doesn't find us a file then we call to debuginfod to see if it
-+ can provide the required file.
-+
-+ EXPECTED_FILENAME is used in output messages from debuginfod, this
-+ should be the file we were looking for but couldn't find. */
-+
-+extern gdb_bfd_ref_ptr find_objfile_by_build_id
-+ (struct program_space *pspace, const bfd_build_id *build_id,
-+ const char *expected_filename);
-+
- /* Return an hex-string representation of BUILD_ID. */
-
- static inline std::string
-diff --git a/gdb/corelow.c b/gdb/corelow.c
---- a/gdb/corelow.c
-+++ b/gdb/corelow.c
-@@ -47,17 +47,130 @@
- #include "gdbsupport/pathstuff.h"
- #include "gdbsupport/scoped_fd.h"
- #include "gdbsupport/x86-xstate.h"
--#include "debuginfod-support.h"
- #include <unordered_map>
- #include <unordered_set>
- #include "cli/cli-cmds.h"
- #include "xml-tdesc.h"
- #include "memtag.h"
-+#include "cli/cli-style.h"
-
- #ifndef O_LARGEFILE
- #define O_LARGEFILE 0
- #endif
-
-+/* A mem_range and the build-id associated with the file mapped into the
-+ given range. */
-+
-+struct mem_range_and_build_id
-+{
-+ mem_range_and_build_id (mem_range &&r, const bfd_build_id *id)
-+ : range (r),
-+ build_id (id)
-+ { /* Nothing. */ }
-+
-+ /* A range of memory addresses. */
-+ mem_range range;
-+
-+ /* The build-id of the file mapped into RANGE. */
-+ const bfd_build_id *build_id;
-+};
-+
-+/* An instance of this class is created within the core_target and is used
-+ to hold all the information that relating to mapped files, their address
-+ ranges, and their corresponding build-ids. */
-+
-+struct mapped_file_info
-+{
-+ /* See comment on function definition. */
-+
-+ void add (const char *soname, const char *expected_filename,
-+ const char *actual_filename, std::vector<mem_range> &&ranges,
-+ const bfd_build_id *build_id);
-+
-+ /* See comment on function definition. */
-+
-+ std::optional <core_target_mapped_file_info>
-+ lookup (const char *filename, const std::optional<CORE_ADDR> &addr);
-+
-+private:
-+
-+ /* Helper for ::lookup. BUILD_ID is a build-id that was found in
-+ one of the data structures within this class. Lookup the
-+ corresponding filename in m_build_id_to_filename_map and return a pair
-+ containing the build-id and filename.
-+
-+ If no corresponding filename is found in m_build_id_to_filename_map
-+ then the returned pair contains BUILD_ID and an empty string.
-+
-+ If BUILD_ID is nullptr then the returned pair contains nullptr and an
-+ empty string. */
-+
-+ struct core_target_mapped_file_info
-+ make_result (const bfd_build_id *build_id)
-+ {
-+ if (build_id != nullptr)
-+ {
-+ auto it = m_build_id_to_filename_map.find (build_id);
-+ if (it != m_build_id_to_filename_map.end ())
-+ return { build_id, it->second };
-+ }
-+
-+ return { build_id, {} };
-+ }
-+
-+ /* A type that maps a string to a build-id. */
-+ using string_to_build_id_map
-+ = std::unordered_map<std::string, const bfd_build_id *>;
-+
-+ /* A type that maps a build-id to a string. */
-+ using build_id_to_string_map
-+ = std::unordered_map<const bfd_build_id *, std::string>;
-+
-+ /* When loading a core file, the build-ids are extracted based on the
-+ file backed mappings. This map associates the name of a file that was
-+ mapped into the core file with the corresponding build-id. The
-+ build-id pointers in this map will never be nullptr as we only record
-+ files if they have a build-id. */
-+
-+ string_to_build_id_map m_filename_to_build_id_map;
-+
-+ /* Map a build-id pointer back to the name of the file that was mapped
-+ into the inferior's address space. If we lookup a matching build-id
-+ using either a soname or an address then this map allows us to also
-+ provide a full path to a file with a matching build-id. */
-+
-+ build_id_to_string_map m_build_id_to_filename_map;
-+
-+ /* If the file that was mapped into the core file was a shared library
-+ then it might have a DT_SONAME tag in its .dynamic section, this tag
-+ contains the name of a shared object. When opening a shared library,
-+ if it's basename appears in this map then we can use the corresponding
-+ build-id.
-+
-+ In the rare case that two different files have the same DT_SONAME
-+ value then the build-id pointer in this map will be nullptr, this
-+ indicates that it's not possible to find a build-id based on the given
-+ DT_SONAME value. */
-+
-+ string_to_build_id_map m_soname_to_build_id_map;
-+
-+ /* This vector maps memory ranges onto an associated build-id. The
-+ ranges are those of the files mapped into the core file.
-+
-+ Entries in this vector must not overlap, and are sorted be increasing
-+ memory address. Within each entry the build-id pointer will not be
-+ nullptr.
-+
-+ While building this vector the entries are not sorted, they are
-+ sorted once after the table has finished being built. */
-+
-+ std::vector<mem_range_and_build_id> m_address_to_build_id_list;
-+
-+ /* False if address_to_build_id_list is unsorted, otherwise true. */
-+
-+ bool m_address_to_build_id_list_sorted = false;
-+};
-+
- /* The core file target. */
-
- static const target_info core_target_info = {
-@@ -134,6 +247,34 @@ class core_target final : public process_stratum_target
- /* See definition. */
- void info_proc_mappings (struct gdbarch *gdbarch);
-
-+ std::optional <core_target_mapped_file_info>
-+ lookup_mapped_file_info (const char *filename,
-+ const std::optional<CORE_ADDR> &addr)
-+ {
-+ return m_mapped_file_info.lookup (filename, addr);
-+ }
-+
-+ /* Return a string containing the expected executable filename obtained
-+ from the mapped file information within the core file. The filename
-+ returned will be for the mapped file whose ELF headers are mapped at
-+ the lowest address (i.e. which GDB encounters first).
-+
-+ If no suitable filename can be found then the returned string will be
-+ empty.
-+
-+ If there are no build-ids embedded into the core file then the
-+ returned string will be empty.
-+
-+ If a non-empty string is returned then there is no guarantee that the
-+ named file exists on disk, or if it does exist on disk, then the
-+ on-disk file might have a different build-id to the desired
-+ build-id. */
-+ const std::string &
-+ expected_exec_filename () const
-+ {
-+ return m_expected_exec_filename;
-+ }
-+
- private: /* per-core data */
-
- /* Get rid of the core inferior. */
-@@ -156,19 +297,23 @@ class core_target final : public process_stratum_target
- still be useful. */
- std::vector<mem_range> m_core_unavailable_mappings;
-
-- /* Build m_core_file_mappings. Called from the constructor. */
-- void build_file_mappings ();
-+ /* Data structure that holds information mapping filenames and address
-+ ranges to the corresponding build-ids as well as the reverse build-id
-+ to filename mapping. */
-+ mapped_file_info m_mapped_file_info;
-
-- /* Helper method for xfer_partial. */
-- enum target_xfer_status xfer_memory_via_mappings (gdb_byte *readbuf,
-- const gdb_byte *writebuf,
-- ULONGEST offset,
-- ULONGEST len,
-- ULONGEST *xfered_len);
-+ /* Build m_core_file_mappings and m_mapped_file_info. Called from the
-+ constructor. */
-+ void build_file_mappings ();
-
- /* FIXME: kettenis/20031023: Eventually this field should
- disappear. */
- struct gdbarch *m_core_gdbarch = NULL;
-+
-+ /* If not empty then this contains the name of the executable discovered
-+ when processing the memory-mapped file information. This will only
-+ be set if we find a mapped with a suitable build-id. */
-+ std::string m_expected_exec_filename;
- };
-
- core_target::core_target ()
-@@ -216,9 +361,51 @@ core_target::core_target ()
- void
- core_target::build_file_mappings ()
- {
-+ /* Type holding information about a single file mapped into the inferior
-+ at the point when the core file was created. Associates a build-id
-+ with the list of regions the file is mapped into. */
-+ struct mapped_file
-+ {
-+ /* Type for a region of a file that was mapped into the inferior when
-+ the core file was generated. */
-+ struct region
-+ {
-+ /* Constructor. See member variables for argument descriptions. */
-+ region (CORE_ADDR start_, CORE_ADDR end_, CORE_ADDR file_ofs_)
-+ : start (start_),
-+ end (end_),
-+ file_ofs (file_ofs_)
-+ { /* Nothing. */ }
-+
-+ /* The inferior address for the start of the mapped region. */
-+ CORE_ADDR start;
-+
-+ /* The inferior address immediately after the mapped region. */
-+ CORE_ADDR end;
-+
-+ /* The offset within the mapped file for this content. */
-+ CORE_ADDR file_ofs;
-+ };
-+
-+ /* If not nullptr, then this is the build-id associated with this
-+ file. */
-+ const bfd_build_id *build_id = nullptr;
-+
-+ /* If true then we have seen multiple different build-ids associated
-+ with the same filename. The build_id field will have been set back
-+ to nullptr, and we should not set build_id in future. */
-+ bool ignore_build_id_p = false;
-+
-+ /* All the mapped regions of this file. */
-+ std::vector<region> regions;
-+ };
-+
- std::unordered_map<std::string, struct bfd *> bfd_map;
- std::unordered_set<std::string> unavailable_paths;
-
-+ /* All files mapped into the core file. The key is the filename. */
-+ std::unordered_map<std::string, mapped_file> mapped_files;
-+
- /* See linux_read_core_file_mappings() in linux-tdep.c for an example
- read_core_file_mappings method. */
- gdbarch_read_core_file_mappings (m_core_gdbarch,
-@@ -239,87 +426,206 @@ core_target::build_file_mappings ()
- weed out non-file-backed mappings. */
- gdb_assert (filename != nullptr);
-
-- if (unavailable_paths.find (filename) != unavailable_paths.end ())
-- {
-- /* We have already seen some mapping for FILENAME but failed to
-- find/open the file. There is no point in trying the same
-- thing again so just record that the range [start, end) is
-- unavailable. */
-- m_core_unavailable_mappings.emplace_back (start, end - start);
-- return;
-- }
--
-- struct bfd *bfd = bfd_map[filename];
-- if (bfd == nullptr)
-+ /* Add this mapped region to the data for FILENAME. */
-+ mapped_file &file_data = mapped_files[filename];
-+ file_data.regions.emplace_back (start, end, file_ofs);
-+ if (build_id != nullptr && !file_data.ignore_build_id_p)
- {
-- /* Use exec_file_find() to do sysroot expansion. It'll
-- also strip the potential sysroot "target:" prefix. If
-- there is no sysroot, an equivalent (possibly more
-- canonical) pathname will be provided. */
-- gdb::unique_xmalloc_ptr<char> expanded_fname
-- = exec_file_find (filename, NULL);
--
-- if (expanded_fname == nullptr && build_id != nullptr)
-- debuginfod_exec_query (build_id->data, build_id->size,
-- filename, &expanded_fname);
--
-- if (expanded_fname == nullptr)
-+ if (file_data.build_id == nullptr)
-+ file_data.build_id = build_id;
-+ else if (!build_id_equal (build_id, file_data.build_id))
- {
-- m_core_unavailable_mappings.emplace_back (start, end - start);
-- unavailable_paths.insert (filename);
-- warning (_("Can't open file %s during file-backed mapping "
-- "note processing"),
-- filename);
-- return;
-+ warning (_("Multiple build-ids found for %ps"),
-+ styled_string (file_name_style.style (), filename));
-+ file_data.build_id = nullptr;
-+ file_data.ignore_build_id_p = true;
- }
-+ }
-+ });
-
-- bfd = bfd_openr (expanded_fname.get (), "binary");
-+ /* Get the build-id of the core file. */
-+ const bfd_build_id *core_build_id
-+ = build_id_bfd_get (current_program_space->core_bfd ());
-
-- if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
-- {
-- m_core_unavailable_mappings.emplace_back (start, end - start);
-- unavailable_paths.insert (filename);
-- warning (_("Can't open file %s which was expanded to %s "
-+ for (const auto &iter : mapped_files)
-+ {
-+ const std::string &filename = iter.first;
-+ const mapped_file &file_data = iter.second;
-+
-+ /* If this mapped file has the same build-id as was discovered for
-+ the core-file itself, then we assume this is the main
-+ executable. Record the filename as we can use this later. */
-+ if (file_data.build_id != nullptr
-+ && m_expected_exec_filename.empty ()
-+ && build_id_equal (file_data.build_id, core_build_id))
-+ m_expected_exec_filename = filename;
-+
-+ /* Use exec_file_find() to do sysroot expansion. It'll
-+ also strip the potential sysroot "target:" prefix. If
-+ there is no sysroot, an equivalent (possibly more
-+ canonical) pathname will be provided. */
-+ gdb::unique_xmalloc_ptr<char> expanded_fname
-+ = exec_file_find (filename.c_str (), nullptr);
-+
-+ bool build_id_mismatch = false;
-+ if (expanded_fname != nullptr && file_data.build_id != nullptr)
-+ {
-+ /* We temporarily open the bfd as a structured target, this
-+ allows us to read the build-id from the bfd if there is one.
-+ For this task it's OK if we reuse an already open bfd object,
-+ so we make this call through GDB's bfd cache. Once we've
-+ checked the build-id (if there is one) we'll drop this
-+ reference and re-open the bfd using the "binary" target. */
-+ gdb_bfd_ref_ptr tmp_bfd
-+ = gdb_bfd_open (expanded_fname.get (), gnutarget);
-+
-+ if (tmp_bfd != nullptr
-+ && bfd_check_format (tmp_bfd.get (), bfd_object)
-+ && build_id_bfd_get (tmp_bfd.get ()) != nullptr)
-+ {
-+ /* The newly opened TMP_BFD has a build-id, and this mapped
-+ file has a build-id extracted from the core-file. Check
-+ the build-id's match, and if not, reject TMP_BFD. */
-+ const struct bfd_build_id *found
-+ = build_id_bfd_get (tmp_bfd.get ());
-+ if (!build_id_equal (found, file_data.build_id))
-+ build_id_mismatch = true;
-+ }
-+ }
-+
-+ gdb_bfd_ref_ptr abfd;
-+ if (expanded_fname != nullptr && !build_id_mismatch)
-+ {
-+ struct bfd *b = bfd_openr (expanded_fname.get (), "binary");
-+ abfd = gdb_bfd_ref_ptr::new_reference (b);
-+ }
-+
-+ if ((expanded_fname == nullptr
-+ || abfd == nullptr
-+ || !bfd_check_format (abfd.get (), bfd_object))
-+ && file_data.build_id != nullptr)
-+ {
-+ abfd = find_objfile_by_build_id (current_program_space,
-+ file_data.build_id,
-+ filename.c_str ());
-+
-+ if (abfd != nullptr)
-+ {
-+ /* The find_objfile_by_build_id will have opened ABFD using
-+ the GNUTARGET global bfd type, however, we need the bfd
-+ opened as the binary type (see the function's header
-+ comment), so now we reopen ABFD with the desired binary
-+ type. */
-+ expanded_fname
-+ = make_unique_xstrdup (bfd_get_filename (abfd.get ()));
-+ struct bfd *b = bfd_openr (expanded_fname.get (), "binary");
-+ gdb_assert (b != nullptr);
-+ abfd = gdb_bfd_ref_ptr::new_reference (b);
-+ }
-+ }
-+
-+ std::vector<mem_range> ranges;
-+ for (const mapped_file::region ®ion : file_data.regions)
-+ ranges.emplace_back (region.start, region.end - region.start);
-+
-+ if (expanded_fname == nullptr
-+ || abfd == nullptr
-+ || !bfd_check_format (abfd.get (), bfd_object))
-+ {
-+ /* If ABFD was opened, but the wrong format, close it now. */
-+ abfd = nullptr;
-+
-+ /* Record all regions for this file as unavailable. */
-+ for (const mapped_file::region ®ion : file_data.regions)
-+ m_core_unavailable_mappings.emplace_back (region.start,
-+ region.end
-+ - region.start);
-+
-+ /* And give the user an appropriate warning. */
-+ if (build_id_mismatch)
-+ {
-+ if (expanded_fname == nullptr
-+ || filename == expanded_fname.get ())
-+ warning (_("File %ps doesn't match build-id from core-file "
-+ "during file-backed mapping processing"),
-+ styled_string (file_name_style.style (),
-+ filename.c_str ()));
-+ else
-+ warning (_("File %ps which was expanded to %ps, doesn't match "
-+ "build-id from core-file during file-backed "
-+ "mapping processing"),
-+ styled_string (file_name_style.style (),
-+ filename.c_str ()),
-+ styled_string (file_name_style.style (),
-+ expanded_fname.get ()));
-+ }
-+ else
-+ {
-+ if (expanded_fname == nullptr
-+ || filename == expanded_fname.get ())
-+ warning (_("Can't open file %ps during file-backed mapping "
-+ "note processing"),
-+ styled_string (file_name_style.style (),
-+ filename.c_str ()));
-+ else
-+ warning (_("Can't open file %ps which was expanded to %ps "
- "during file-backed mapping note processing"),
-- filename, expanded_fname.get ());
-+ styled_string (file_name_style.style (),
-+ filename.c_str ()),
-+ styled_string (file_name_style.style (),
-+ expanded_fname.get ()));
-+ }
-+ }
-+ else
-+ {
-+ /* Ensure that the bfd will be closed when core_bfd is closed.
-+ This can be checked before/after a core file detach via "maint
-+ info bfds". */
-+ gdb_bfd_record_inclusion (current_program_space->core_bfd (),
-+ abfd.get ());
-+
-+ /* Create sections for each mapped region. */
-+ for (const mapped_file::region ®ion : file_data.regions)
-+ {
-+ /* Make new BFD section. All sections have the same name,
-+ which is permitted by bfd_make_section_anyway(). */
-+ asection *sec = bfd_make_section_anyway (abfd.get (), "load");
-+ if (sec == nullptr)
-+ error (_("Can't make section"));
-+ sec->filepos = region.file_ofs;
-+ bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
-+ bfd_set_section_size (sec, region.end - region.start);
-+ bfd_set_section_vma (sec, region.start);
-+ bfd_set_section_lma (sec, region.start);
-+ bfd_set_section_alignment (sec, 2);
-+
-+ /* Set target_section fields. */
-+ m_core_file_mappings.emplace_back (region.start, region.end, sec);
-+ }
-+ }
-
-- if (bfd != nullptr)
-- bfd_close (bfd);
-- return;
-- }
-- /* Ensure that the bfd will be closed when core_bfd is closed.
-- This can be checked before/after a core file detach via
-- "maint info bfds". */
-- gdb_bfd_record_inclusion (current_program_space->core_bfd (), bfd);
-- bfd_map[filename] = bfd;
-- }
-+ /* If this is a bfd with a build-id then record the filename,
-+ optional soname (DT_SONAME .dynamic attribute), and the range of
-+ addresses at which this bfd is mapped. This information can be
-+ used to perform build-id checking when loading the shared
-+ libraries. */
-+ if (file_data.build_id != nullptr)
-+ {
-+ normalize_mem_ranges (&ranges);
-
-- /* Make new BFD section. All sections have the same name,
-- which is permitted by bfd_make_section_anyway(). */
-- asection *sec = bfd_make_section_anyway (bfd, "load");
-- if (sec == nullptr)
-- error (_("Can't make section"));
-- sec->filepos = file_ofs;
-- bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
-- bfd_set_section_size (sec, end - start);
-- bfd_set_section_vma (sec, start);
-- bfd_set_section_lma (sec, start);
-- bfd_set_section_alignment (sec, 2);
--
-- /* Set target_section fields. */
-- m_core_file_mappings.emplace_back (start, end, sec);
--
-- /* If this is a bfd of a shared library, record its soname
-- and build id. */
-- if (build_id != nullptr)
-- {
-- gdb::unique_xmalloc_ptr<char> soname
-- = gdb_bfd_read_elf_soname (bfd->filename);
-- if (soname != nullptr)
-- set_cbfd_soname_build_id (current_program_space->cbfd,
-- soname.get (), build_id);
-- }
-- });
-+ const char *actual_filename = nullptr;
-+ gdb::unique_xmalloc_ptr<char> soname;
-+ if (abfd != nullptr)
-+ {
-+ actual_filename = bfd_get_filename (abfd.get ());
-+ soname = gdb_bfd_read_elf_soname (actual_filename);
-+ }
-+
-+ m_mapped_file_info.add (soname.get (), filename.c_str (),
-+ actual_filename, std::move (ranges),
-+ file_data.build_id);
-+ }
-+ }
-
- normalize_mem_ranges (&m_core_unavailable_mappings);
- }
-@@ -564,36 +870,31 @@ rename_vmcore_idle_reg_sections (bfd *abfd, inferior *inf)
- BFD ABFD. */
-
- static void
--locate_exec_from_corefile_build_id (bfd *abfd, int from_tty)
-+locate_exec_from_corefile_build_id (bfd *abfd, core_target *target,
-+ int from_tty)
- {
- const bfd_build_id *build_id = build_id_bfd_get (abfd);
- if (build_id == nullptr)
- return;
-
-- gdb_bfd_ref_ptr execbfd
-- = build_id_to_exec_bfd (build_id->size, build_id->data);
-+ /* The filename used for the find_objfile_by_build_id call. */
-+ std::string filename;
-
-- if (execbfd == nullptr)
-+ if (!target->expected_exec_filename ().empty ())
-+ filename = target->expected_exec_filename ();
-+ else
- {
-- /* Attempt to query debuginfod for the executable. */
-- gdb::unique_xmalloc_ptr<char> execpath;
-- scoped_fd fd = debuginfod_exec_query (build_id->data, build_id->size,
-- abfd->filename, &execpath);
--
-- if (fd.get () >= 0)
-- {
-- execbfd = gdb_bfd_open (execpath.get (), gnutarget);
--
-- if (execbfd == nullptr)
-- warning (_("\"%s\" from debuginfod cannot be opened as bfd: %s"),
-- execpath.get (),
-- gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
-- else if (!build_id_verify (execbfd.get (), build_id->size,
-- build_id->data))
-- execbfd.reset (nullptr);
-- }
-+ /* We didn't find an executable name from the mapped file
-+ information, so as a stand-in build a string based on the
-+ build-id. */
-+ std::string build_id_hex_str = bin2hex (build_id->data, build_id->size);
-+ filename = string_printf ("with build-id %s", build_id_hex_str.c_str ());
- }
-
-+ gdb_bfd_ref_ptr execbfd
-+ = find_objfile_by_build_id (current_program_space, build_id,
-+ filename.c_str ());
-+
- if (execbfd != nullptr)
- {
- exec_file_attach (bfd_get_filename (execbfd.get ()), from_tty);
-@@ -724,7 +1025,7 @@ core_target_open (const char *arg, int from_tty)
-
- if (current_program_space->exec_bfd () == nullptr)
- locate_exec_from_corefile_build_id (current_program_space->core_bfd (),
-- from_tty);
-+ target, from_tty);
-
- post_create_inferior (from_tty);
-
-@@ -963,55 +1264,6 @@ core_target::files_info ()
- print_section_info (&m_core_section_table, current_program_space->core_bfd ());
- }
- \f
--/* Helper method for core_target::xfer_partial. */
--
--enum target_xfer_status
--core_target::xfer_memory_via_mappings (gdb_byte *readbuf,
-- const gdb_byte *writebuf,
-- ULONGEST offset, ULONGEST len,
-- ULONGEST *xfered_len)
--{
-- enum target_xfer_status xfer_status;
--
-- xfer_status = (section_table_xfer_memory_partial
-- (readbuf, writebuf,
-- offset, len, xfered_len,
-- m_core_file_mappings));
--
-- if (xfer_status == TARGET_XFER_OK || m_core_unavailable_mappings.empty ())
-- return xfer_status;
--
-- /* There are instances - e.g. when debugging within a docker
-- container using the AUFS storage driver - where the pathnames
-- obtained from the note section are incorrect. Despite the path
-- being wrong, just knowing the start and end addresses of the
-- mappings is still useful; we can attempt an access of the file
-- stratum constrained to the address ranges corresponding to the
-- unavailable mappings. */
--
-- ULONGEST memaddr = offset;
-- ULONGEST memend = offset + len;
--
-- for (const auto &mr : m_core_unavailable_mappings)
-- {
-- if (mr.contains (memaddr))
-- {
-- if (!mr.contains (memend))
-- len = mr.start + mr.length - memaddr;
--
-- xfer_status = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY,
-- NULL,
-- readbuf,
-- writebuf,
-- offset,
-- len,
-- xfered_len);
-- break;
-- }
-- }
--
-- return xfer_status;
--}
-
- enum target_xfer_status
- core_target::xfer_partial (enum target_object object, const char *annex,
-@@ -1039,26 +1291,72 @@ core_target::xfer_partial (enum target_object object, const char *annex,
- if (xfer_status == TARGET_XFER_OK)
- return TARGET_XFER_OK;
-
-- /* Check file backed mappings. If they're available, use
-- core file provided mappings (e.g. from .note.linuxcore.file
-- or the like) as this should provide a more accurate
-- result. If not, check the stratum beneath us, which should
-- be the file stratum.
-+ /* Check file backed mappings. If they're available, use core file
-+ provided mappings (e.g. from .note.linuxcore.file or the like)
-+ as this should provide a more accurate result. */
-+ if (!m_core_file_mappings.empty ())
-+ {
-+ xfer_status = section_table_xfer_memory_partial
-+ (readbuf, writebuf, offset, len, xfered_len,
-+ m_core_file_mappings);
-+ if (xfer_status == TARGET_XFER_OK)
-+ return xfer_status;
-+ }
-
-- We also check unavailable mappings due to Docker/AUFS driver
-- issues. */
-- if (!m_core_file_mappings.empty ()
-- || !m_core_unavailable_mappings.empty ())
-+ /* If the access is within an unavailable file mapping then we try
-+ to check in the stratum below (the executable stratum). The
-+ thinking here is that if the mapping was read/write then the
-+ contents would have been written into the core file and the
-+ access would have been satisfied by m_core_section_table.
-+
-+ But if the access has not yet been resolved then we can assume
-+ the access is read-only. If the executable was not found
-+ during the mapped file check then we'll have an unavailable
-+ mapping entry, however, if the user has provided the executable
-+ (maybe in a different location) then we might be able to
-+ resolve the access from there.
-+
-+ If that fails, but the access is within an unavailable region,
-+ then the access itself should fail. */
-+ for (const auto &mr : m_core_unavailable_mappings)
- {
-- xfer_status = xfer_memory_via_mappings (readbuf, writebuf, offset,
-+ if (mr.contains (offset))
-+ {
-+ if (!mr.contains (offset + len))
-+ len = mr.start + mr.length - offset;
-+
-+ xfer_status
-+ = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY,
-+ nullptr, readbuf,
-+ writebuf, offset,
- len, xfered_len);
-+ if (xfer_status == TARGET_XFER_OK)
-+ return TARGET_XFER_OK;
-+
-+ return TARGET_XFER_E_IO;
-+ }
-+ }
-+
-+ /* The following is acting as a fallback in case we encounter a
-+ situation where the core file is lacking and mapped file
-+ information. Here we query the exec file stratum to see if it
-+ can resolve the access. Doing this when we are missing mapped
-+ file information might be the best we can do, but there are
-+ certainly cases this will get wrong, e.g. if an inferior created
-+ a zero initialised mapping over the top of some data that exists
-+ within the executable then this will return the executable data
-+ rather than the zero data. Maybe we should just drop this
-+ block? */
-+ if (m_core_file_mappings.empty ()
-+ && m_core_unavailable_mappings.empty ())
-+ {
-+ xfer_status
-+ = this->beneath ()->xfer_partial (object, annex, readbuf,
-+ writebuf, offset, len,
-+ xfered_len);
-+ if (xfer_status == TARGET_XFER_OK)
-+ return TARGET_XFER_OK;
- }
-- else
-- xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
-- writebuf, offset, len,
-- xfered_len);
-- if (xfer_status == TARGET_XFER_OK)
-- return TARGET_XFER_OK;
-
- /* Finally, attempt to access data in core file sections with
- no contents. These will typically read as all zero. */
-@@ -1515,6 +1813,182 @@ maintenance_print_core_file_backed_mappings (const char *args, int from_tty)
- targ->info_proc_mappings (targ->core_gdbarch ());
- }
-
-+/* Add more details discovered while processing the core-file's mapped file
-+ information, we're building maps between filenames and the corresponding
-+ build-ids, between address ranges and the corresponding build-ids, and
-+ also a reverse map between build-id and the corresponding filename.
-+
-+ SONAME is the DT_SONAME attribute extracted from the .dynamic section of
-+ a shared library that was mapped into the core file. This can be
-+ nullptr if the mapped files was not a shared library, or didn't have a
-+ DT_SONAME attribute.
-+
-+ EXPECTED_FILENAME is the name of the file that was mapped into the
-+ inferior as extracted from the core file, this should never be nullptr.
-+
-+ ACTUAL_FILENAME is the name of the actual file GDB found to provide the
-+ mapped file information, this can be nullptr if GDB failed to find a
-+ suitable file. This might be different to EXPECTED_FILENAME, e.g. GDB
-+ might have downloaded the file from debuginfod and so ACTUAL_FILENAME
-+ will be a file in the debuginfod client cache.
-+
-+ RANGES is the list of memory ranges at which this file was mapped into
-+ the inferior.
-+
-+ BUILD_ID is the build-id for this mapped file, this will never be
-+ nullptr. Not every mapped file will have a build-id, but there's no
-+ point calling this function if we failed to find a build-id; this
-+ structure only exists so we can lookup files based on their build-id. */
-+
-+void
-+mapped_file_info::add (const char *soname,
-+ const char *expected_filename,
-+ const char *actual_filename,
-+ std::vector<mem_range> &&ranges,
-+ const bfd_build_id *build_id)
-+{
-+ gdb_assert (build_id != nullptr);
-+ gdb_assert (expected_filename != nullptr);
-+
-+ if (soname != nullptr)
-+ {
-+ /* If we already have an entry with this SONAME then this indicates
-+ that the inferior has two files mapped into memory with different
-+ file names (and most likely different build-ids), but with the
-+ same DT_SONAME attribute. In this case we can't use the
-+ DT_SONAME to figure out the expected build-id of a shared
-+ library, so poison the entry for this SONAME by setting the entry
-+ to nullptr. */
-+ auto it = m_soname_to_build_id_map.find (soname);
-+ if (it != m_soname_to_build_id_map.end ()
-+ && it->second != nullptr
-+ && !build_id_equal (it->second, build_id))
-+ m_soname_to_build_id_map[soname] = nullptr;
-+ else
-+ m_soname_to_build_id_map[soname] = build_id;
-+ }
-+
-+ /* When the core file is initially opened and the mapped files are
-+ parsed, we group the build-id information based on the file name. As
-+ a consequence, we should see each EXPECTED_FILENAME value exactly
-+ once. This means that each insertion should always succeed. */
-+ const auto [it, inserted]
-+ = m_filename_to_build_id_map.emplace (expected_filename, build_id);
-+ gdb_assert (inserted);
-+
-+ /* Setup the reverse build-id to file name map. */
-+ if (actual_filename != nullptr)
-+ m_build_id_to_filename_map.emplace (build_id, actual_filename);
-+
-+ /* Setup the list of memory range to build-id objects. */
-+ for (mem_range &r : ranges)
-+ m_address_to_build_id_list.emplace_back (std::move (r), build_id);
-+
-+ /* At this point the m_address_to_build_id_list is unsorted (we just
-+ added some entries to the end of the list). All entries should be
-+ added before any look-ups are performed, and the list is only sorted
-+ when the first look-up is performed. */
-+ gdb_assert (!m_address_to_build_id_list_sorted);
-+}
-+
-+/* FILENAME is the name of a file GDB is trying to load, and ADDR is
-+ (optionally) an address within the file in the inferior's address space.
-+
-+ Search through the information gathered from the core-file's mapped file
-+ information looking for a file named FILENAME, or for a file that covers
-+ ADDR. If a match is found then return the build-id for the file along
-+ with the location where GDB found the mapped file.
-+
-+ The location of the mapped file might be the empty string if GDB was
-+ unable to find the mapped file.
-+
-+ If no build-id can be found for FILENAME then GDB will return a pair
-+ containing nullptr (for the build-id) and an empty string for the file
-+ name. */
-+
-+std::optional <core_target_mapped_file_info>
-+mapped_file_info::lookup (const char *filename,
-+ const std::optional<CORE_ADDR> &addr)
-+{
-+ if (filename != nullptr)
-+ {
-+ /* If there's a matching entry in m_filename_to_build_id_map then the
-+ associated build-id will not be nullptr, and can be used to
-+ validate that FILENAME is correct. */
-+ auto it = m_filename_to_build_id_map.find (filename);
-+ if (it != m_filename_to_build_id_map.end ())
-+ return make_result (it->second);
-+ }
-+
-+ if (addr.has_value ())
-+ {
-+ /* On the first lookup, sort the address_to_build_id_list. */
-+ if (!m_address_to_build_id_list_sorted)
-+ {
-+ std::sort (m_address_to_build_id_list.begin (),
-+ m_address_to_build_id_list.end (),
-+ [] (const mem_range_and_build_id &a,
-+ const mem_range_and_build_id &b) {
-+ return a.range < b.range;
-+ });
-+ m_address_to_build_id_list_sorted = true;
-+ }
-+
-+ /* Look for the first entry whose range's start address is not less
-+ than, or equal too, the address ADDR. If we find such an entry,
-+ then the previous entry's range might contain ADDR. If it does
-+ then that previous entry's build-id can be used. */
-+ auto it = std::lower_bound
-+ (m_address_to_build_id_list.begin (),
-+ m_address_to_build_id_list.end (),
-+ *addr,
-+ [] (const mem_range_and_build_id &a,
-+ const CORE_ADDR &b) {
-+ return a.range.start <= b;
-+ });
-+
-+ if (it != m_address_to_build_id_list.begin ())
-+ {
-+ --it;
-+
-+ if (it->range.contains (*addr))
-+ return make_result (it->build_id);
-+ }
-+ }
-+
-+ if (filename != nullptr)
-+ {
-+ /* If the basename of FILENAME appears in m_soname_to_build_id_map
-+ then when the mapped files were processed, we saw a file with a
-+ DT_SONAME attribute corresponding to FILENAME, use that build-id
-+ to validate FILENAME.
-+
-+ However, the build-id in this map might be nullptr if we saw
-+ multiple mapped files with the same DT_SONAME attribute (though
-+ this should be pretty rare). */
-+ auto it
-+ = m_soname_to_build_id_map.find (lbasename (filename));
-+ if (it != m_soname_to_build_id_map.end ()
-+ && it->second != nullptr)
-+ return make_result (it->second);
-+ }
-+
-+ return {};
-+}
-+
-+/* See gdbcore.h. */
-+
-+std::optional <core_target_mapped_file_info>
-+core_target_find_mapped_file (const char *filename,
-+ std::optional<CORE_ADDR> addr)
-+{
-+ core_target *targ = get_current_core_target ();
-+ if (targ == nullptr || current_program_space->cbfd.get () == nullptr)
-+ return {};
-+
-+ return targ->lookup_mapped_file_info (filename, addr);
-+}
-+
- void _initialize_corelow ();
- void
- _initialize_corelow ()
-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
-@@ -77,6 +77,8 @@ PYTHON_FILE_LIST = \
- gdb/FrameIterator.py \
- gdb/frames.py \
- gdb/missing_debug.py \
-+ gdb/missing_objfile.py \
-+ gdb/missing_files.py \
- gdb/printing.py \
- gdb/prompt.py \
- gdb/styling.py \
-@@ -86,7 +88,7 @@ PYTHON_FILE_LIST = \
- gdb/command/__init__.py \
- gdb/command/explore.py \
- gdb/command/frame_filters.py \
-- gdb/command/missing_debug.py \
-+ gdb/command/missing_files.py \
- gdb/command/pretty_printers.py \
- gdb/command/prompt.py \
- gdb/command/type_printers.py \
-diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
---- a/gdb/debuginfod-support.c
-+++ b/gdb/debuginfod-support.c
-@@ -409,7 +409,7 @@ debuginfod_exec_query (const unsigned char *build_id,
- std::optional<target_terminal::scoped_restore_terminal_state> term_state;
-
- {
-- user_data data ("executable for", filename);
-+ user_data data ("file", filename);
-
- debuginfod_set_user_data (c, &data);
- if (target_supports_terminal_ours ())
-@@ -423,7 +423,7 @@ debuginfod_exec_query (const unsigned char *build_id,
- debuginfod_set_user_data (c, nullptr);
- }
-
-- print_outcome (fd.get (), "executable for", filename);
-+ print_outcome (fd.get (), "file", filename);
-
- if (fd.get () >= 0)
- destname->reset (dname);
-diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
---- a/gdb/doc/gdb.texinfo
-+++ b/gdb/doc/gdb.texinfo
-@@ -21786,6 +21786,7 @@ contained in @var{filename} by using the @samp{-readnever} option.
- @c (eg rooted in val of env var GDBSYMS) could exist for mappable symbol
- @c files.
-
-+@anchor{core-file command}
- @kindex core-file
- @item core-file @r{[}@var{filename}@r{]}
- @itemx core
-@@ -24534,6 +24535,10 @@ future connections is shown. The available settings are:
- @tab @code{vFile:fstat}
- @tab Host I/O
-
-+@item @code{hostio-stat-packet}
-+@tab @code{vFile:stat}
-+@tab Host I/O
-+
- @item @code{hostio-setfs-packet}
- @tab @code{vFile:setfs}
- @tab Host I/O
-@@ -46289,6 +46294,13 @@ and the return value is the size of this attachment in bytes.
- If an error occurs the return value is -1. The format of the
- returned binary attachment is as described in @ref{struct stat}.
-
-+@item vFile:stat: @var{filename}
-+Get information about the file @var{filename} on the target.
-+On success the information is returned as a binary attachment
-+and the return value is the size of this attachment in bytes.
-+If an error occurs the return value is -1. The format of the
-+returned binary attachment is as described in @ref{struct stat}.
-+
- @item vFile:unlink: @var{filename}
- Delete the file at @var{filename} on the target. Return 0,
- or -1 if an error occurs. The @var{filename} is a string.
-diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
---- a/gdb/doc/python.texi
-+++ b/gdb/doc/python.texi
-@@ -231,6 +231,7 @@ optional arguments while skipping others. Example:
- * TUI Windows In Python:: Implementing new TUI windows.
- * Disassembly In Python:: Instruction Disassembly In Python
- * Missing Debug Info In Python:: Handle missing debug info from Python.
-+* Missing Objfiles In Python:: Handle objfiles from Python.
- @end menu
-
- @node Basic Python
-@@ -5370,10 +5371,11 @@ The @code{frame_filters} attribute is a dictionary of frame filter
- objects. @xref{Frame Filter API}, for more information.
- @end defvar
-
--@defvar Progspace.missing_debug_handlers
--The @code{missing_debug_handlers} attribute is a list of the missing
--debug handler objects for this program space. @xref{Missing Debug
--Info In Python}, for more information.
-+@defvar Progspace.missing_file_handlers
-+The @code{missing_file_handlers} attribute is a list of tuples. Each
-+tuple holds a missing-file handler object for this program space. For
-+more information, @pxref{Missing Debug Info In Python}, and
-+@ref{Missing Objfiles In Python}.
- @end defvar
-
- A program space has the following methods:
-@@ -5549,6 +5551,7 @@ Separate debug info objfiles are added with the
- @code{gdb.Objfile.add_separate_debug_file} method, described below.
- @end defvar
-
-+@anchor{Objfile.build_id}
- @defvar Objfile.build_id
- The build ID of the objfile as a string.
- If the objfile does not have a build ID then the value is @code{None}.
-@@ -8137,6 +8140,189 @@ returns a value other than @code{None}, no further handlers are called
- for this objfile.
- @end defun
-
-+@node Missing Objfiles In Python
-+@subsubsection Missing Objfiles In Python
-+@cindex python, handle missing objfiles
-+
-+When @value{GDBN} opens a core file, for example with the
-+@kbd{core-file} command (@pxref{core-file command}), @value{GDBN} will
-+attempt to load the corresponding executable and shared libraries.
-+Often these files can be found on the local machine, but sometimes
-+these files cannot be found, in which case the debugging experience
-+will be restricted.
-+
-+If @value{GDBN} fails to locate a particular file then there is an
-+opportunity for a Python extension to step in. A Python extension can
-+potentially locate the missing file using some platform- or
-+project-specific steps, and inform @value{GDBN} of its location. Or a
-+Python extension might provide some platform- or project-specific
-+advice to the user about how to obtain the missing file.
-+
-+A missing-objfile Python extension consists of a handler object which
-+has the @code{name} and @code{enabled} attributes, and implements the
-+@code{__call__} method. When @value{GDBN} encounters a situation
-+where a file cannot be found, but the build-id (@pxref{build ID}) for
-+the missing file is known, then the @code{__call__} method is invoked
-+to try and find the file. Full details of how handlers are written
-+can be found below.
-+
-+@subheading The @code{gdb.missing_objfile} Module
-+
-+@value{GDBN} comes with a @code{gdb.missing_objfile} module which
-+contains the following class and global function:
-+
-+@deftp{class} gdb.missing_objfile.MissingObjfileHandler
-+
-+@code{MissingObjfileHandler} is a base class from which user-created
-+handlers can derive, though it is not required that handlers derive
-+from this class, so long as any user created handler has the
-+@code{name} and @code{enabled} attributes, and implements the
-+@code{__call__} method.
-+
-+@defun MissingObjfileHandler.__init__ (name)
-+The @var{name} is a string used to reference this missing-objfile
-+handler within some @value{GDBN} commands. Valid names consist of the
-+characters @samp{[-_a-zA-Z0-9]}, creating a handler with an invalid
-+name raises a @code{ValueError} exception.
-+@end defun
-+
-+@defun MissingObjfileHandler.__call__ (pspace, build_id, filename)
-+
-+Sub-classes must override the @code{__call__} method. The
-+@var{pspace} argument will be a @code{gdb.Progspace}
-+(@pxref{Progspaces In Python}), this is the program space in which
-+@value{GDBN} is looking for the missing file.
-+
-+The @var{build_id} argument is a string containing the build-id of the
-+file that is missing, this will be in the same format as returned by
-+@code{Objfile.build_id} (@pxref{Objfile.build_id}).
-+
-+The @var{filename} argument contains the name of the file that
-+@value{GDBN} is looking for. This information is provided to allow
-+handlers to generate informative messages for the user. A handler is
-+not required to place the missing file at this location. There might
-+already be a file present at this location, but it might not match the
-+required build-id, in which case @value{GDBN} will have ignored it.
-+In some limited cases @value{GDBN} might not be able to establish the
-+@var{filename} of the file it is searching for, in this case
-+@value{GDBN} will use a string @samp{with build-id @var{build_id}} as a
-+replacement.
-+
-+The return value from the @code{__call__} method indicates what
-+@value{GDBN} should do next. The possible return values are:
-+
-+@itemize @bullet
-+@item @code{None}
-+
-+This indicates that this handler could not locate the missing file and
-+@value{GDBN} should call any other registered handlers.
-+
-+@item @code{True}
-+
-+This indicates that this handler has installed the missing file into a
-+location where @value{GDBN} would normally expect to find it. The
-+only location in which @value{GDBN} will look is within the
-+@file{.build-id} sub-directory within the @var{debug-file-directory}
-+(@pxref{debug-file-directory}).
-+
-+@value{GDBN} will repeat the normal lookup process, which should now
-+find the previously missing file.
-+
-+If @value{GDBN} still doesn't find file after this second attempt,
-+then the Python missing-objfile handlers are not invoked a second
-+time, this prevents a badly behaved handler causing @value{GDBN} to
-+get stuck in a loop. @value{GDBN} will continue without the missing
-+file, though this will degrade the debugging experience.
-+
-+@item @code{False}
-+
-+This indicates that this handler has done everything that it intends
-+to do but the missing file could not be found. @value{GDBN} will not
-+call any other registered handlers to look for the missing file.
-+@value{GDBN} will continue without the missing file, though this will
-+degrade the debugging experience.
-+
-+@item A string
-+
-+The returned string should contain a filename. @value{GDBN} will not
-+call any further registered handlers, and will instead use the
-+returned filename as the missing file.
-+@end itemize
-+
-+Invoking the @code{__call__} method from this base class will raise a
-+@code{NotImplementedError} exception.
-+@end defun
-+
-+@defvar MissingObjfileHandler.name
-+A read-only attribute which is a string, the name of this handler
-+passed to the @code{__init__} method.
-+@end defvar
-+
-+@defvar MissingObjfileHandler.enabled
-+A modifiable attribute containing a boolean; when @code{True}, the
-+handler is enabled, and will be used by @value{GDBN}. When
-+@code{False}, the handler has been disabled, and will not be used.
-+@end defvar
-+@end deftp
-+
-+@defun gdb.missing_objfile.register_handler (locus, handler, replace=@code{False})
-+Register a new missing-objfile handler with @value{GDBN}.
-+
-+@var{handler} is an instance of a sub-class of
-+@code{MissingObjfileHandler}, or at least an instance of an object that
-+has the same attributes and methods as @code{MissingObjfileHandler}.
-+
-+@var{locus} specifies to which handler list to prepend @var{handler}.
-+It can be either a @code{gdb.Progspace} (@pxref{Progspaces In Python})
-+or @code{None}, in which case the handler is registered globally. The
-+newly registered @var{handler} will be called before any other handler
-+from the same locus. Two handlers in the same locus cannot have the
-+same name, an attempt to add a handler with an already existing name
-+raises an exception unless @var{replace} is @code{True}, in which case
-+the old handler is deleted and the new handler is prepended to the
-+selected handler list.
-+
-+@value{GDBN} first calls the handlers for the current program space,
-+and then the globally registered handlers. As soon as a handler
-+returns a value other than @code{None}, no further handlers are
-+called.
-+@end defun
-+
-+@subheading Managing Missing-Objfile Handlers
-+
-+@value{GDBN} defines the following commands to manage registered
-+missing-objfile handlers:
-+
-+@table @code
-+
-+@kindex info missing-objfile-handlers
-+@item info missing-objfile-handlers @r{[} @var{locus} @r{[} @var{name-regexp} @r{]} @r{]}
-+Lists all registered missing-objfile handlers. Arguments @var{locus}
-+and @var{name-regexp} are both optional and can be used to filter
-+which handlers are listed.
-+
-+The @var{locus} argument should be either @kbd{global},
-+@kbd{progspace}, or the name of an object file. Only handlers
-+registered for the specified locus will be listed.
-+
-+The @var{name-regexp} is a regular expression used to match against
-+handler names.
-+
-+@kindex disable missing-objfile-handler
-+@item disable missing-objfile-handler @r{[} @var{locus} @r{[} @var{name-regexp} @r{]} @r{]}
-+The @var{locus} and @var{name-regexp} are interpreted as in @kbd{info
-+missing-objfile-handlers} above, but instead of listing the matching
-+handlers, all of the matching handlers are disabled. The
-+@code{enabled} field of each matching handler is set to @code{False}.
-+
-+@kindex enable missing-objfile-handler
-+@item enable missing-objfile-handler @r{[} @var{locus} @r{[} @var{name-regexp} @r{]} @r{]}
-+The @var{locus} and @var{name-regexp} are interpreted as in @kbd{info
-+missing-objfile-handlers} above, but instead of listing the matching
-+handlers, all of the matching handlers are enabled. The
-+@code{enabled} field of each matching handler is set to @code{True}.
-+@end table
-+
- @node Python Auto-loading
- @subsection Python Auto-loading
- @cindex Python auto-loading
-diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
---- a/gdb/extension-priv.h
-+++ b/gdb/extension-priv.h
-@@ -287,9 +287,22 @@ struct extension_language_ops
- /* Give extension languages a chance to deal with missing debug
- information. OBJFILE is the file for which GDB was unable to find
- any debug information. */
-- ext_lang_missing_debuginfo_result
-+ ext_lang_missing_file_result
- (*handle_missing_debuginfo) (const struct extension_language_defn *,
- struct objfile *objfile);
-+
-+ /* Give extension languages a chance to deal with missing objfiles.
-+ PSPACE is the program space in which GDB is searching for a missing
-+ objfile, and will not be NULL. BUILD_ID is the build-id of the
-+ objfile we're looking for, and will not be NULL. FILENAME is the name
-+ of the file we're looking for, and will not be NULL. See
-+ ext_lang_find_objfile_from_buildid for some additional information
-+ about the meaning of FILENAME. */
-+ ext_lang_missing_file_result
-+ (*find_objfile_from_buildid) (const struct extension_language_defn *,
-+ program_space *pspace,
-+ const struct bfd_build_id *build_id,
-+ const char *filename);
- };
-
- /* State necessary to restore a signal handler to its previous value. */
-diff --git a/gdb/extension.c b/gdb/extension.c
---- a/gdb/extension.c
-+++ b/gdb/extension.c
-@@ -1040,7 +1040,7 @@ ext_lang_print_insn (struct gdbarch *gdbarch, CORE_ADDR address,
-
- /* See extension.h. */
-
--ext_lang_missing_debuginfo_result
-+ext_lang_missing_file_result
- ext_lang_handle_missing_debuginfo (struct objfile *objfile)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
-@@ -1048,7 +1048,7 @@ ext_lang_handle_missing_debuginfo (struct objfile *objfile)
- if (extlang->ops == nullptr
- || extlang->ops->handle_missing_debuginfo == nullptr)
- continue;
-- ext_lang_missing_debuginfo_result result
-+ ext_lang_missing_file_result result
- = extlang->ops->handle_missing_debuginfo (extlang, objfile);
- if (!result.filename ().empty () || result.try_again ())
- return result;
-@@ -1057,6 +1057,28 @@ ext_lang_handle_missing_debuginfo (struct objfile *objfile)
- return {};
- }
-
-+/* See extension.h. */
-+
-+ext_lang_missing_file_result
-+ext_lang_find_objfile_from_buildid (program_space *pspace,
-+ const struct bfd_build_id *build_id,
-+ const char *filename)
-+{
-+ for (const struct extension_language_defn *extlang : extension_languages)
-+ {
-+ if (extlang->ops == nullptr
-+ || extlang->ops->find_objfile_from_buildid == nullptr)
-+ continue;
-+ ext_lang_missing_file_result result
-+ = extlang->ops->find_objfile_from_buildid (extlang, pspace, build_id,
-+ filename);
-+ if (!result.filename ().empty () || result.try_again ())
-+ return result;
-+ }
-+
-+ return {};
-+}
-+
- /* Called via an observer before gdb prints its prompt.
- Iterate over the extension languages giving them a chance to
- change the prompt. The first one to change the prompt wins,
-diff --git a/gdb/extension.h b/gdb/extension.h
---- a/gdb/extension.h
-+++ b/gdb/extension.h
-@@ -36,6 +36,7 @@ struct ui_file;
- struct ui_out;
- struct value;
- struct value_print_options;
-+struct program_space;
-
- /* A function to load and process a script file.
- The file has been opened and is ready to be read from the beginning.
-@@ -358,23 +359,23 @@ extern std::optional<int> ext_lang_print_insn
- it. And the third option is for the extension to just return a null
- result, indication there is nothing the extension can do to provide the
- missing debug information. */
--struct ext_lang_missing_debuginfo_result
-+struct ext_lang_missing_file_result
- {
- /* Default result. The extension was unable to provide the missing debug
- info. */
-- ext_lang_missing_debuginfo_result ()
-+ ext_lang_missing_file_result ()
- { /* Nothing. */ }
-
- /* When TRY_AGAIN is true GDB should try searching again, the extension
- may have installed the missing debug info into a suitable location.
- When TRY_AGAIN is false this is equivalent to the default, no
- argument, constructor. */
-- ext_lang_missing_debuginfo_result (bool try_again)
-+ ext_lang_missing_file_result (bool try_again)
- : m_try_again (try_again)
- { /* Nothing. */ }
-
- /* Look in FILENAME for the missing debug info. */
-- ext_lang_missing_debuginfo_result (std::string &&filename)
-+ ext_lang_missing_file_result (std::string &&filename)
- : m_filename (std::move (filename))
- { /* Nothing. */ }
-
-@@ -404,9 +405,28 @@ struct ext_lang_missing_debuginfo_result
-
- /* Called when GDB failed to find any debug information for OBJFILE. */
-
--extern ext_lang_missing_debuginfo_result ext_lang_handle_missing_debuginfo
-+extern ext_lang_missing_file_result ext_lang_handle_missing_debuginfo
- (struct objfile *objfile);
-
-+/* Called when GDB opens a core-file to find any object files for which a
-+ build-id could be extracted from the core-file, but the matching file
-+ could not otherwise be found by GDB.
-+
-+ PSPACE is the program space in which GDB is opening the core-file and
-+ is looking for a missing object file. BUILD_ID is the build-id of the
-+ file being looked for, and will not be NULL. FILENAME is the name of
-+ the file GDB is looking for, this will not be NULL. The FILENAME is
-+ provided only for creating helpful messages for the user. FILENAME
-+ might already exist on disk but have the wrong build-id, of FILENAME
-+ might not exist on disk. If the missing objfile can be found then it
-+ does not have to be placed at the location FILENAME.
-+
-+ The returned object indicates if the file could be found or not. */
-+
-+extern ext_lang_missing_file_result ext_lang_find_objfile_from_buildid
-+ (program_space *pspace, const struct bfd_build_id *build_id,
-+ const char *filename);
-+
- #if GDB_SELF_TEST
- namespace selftests {
- extern void (*hook_set_active_ext_lang) ();
-diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
---- a/gdb/gdbcore.h
-+++ b/gdb/gdbcore.h
-@@ -196,4 +196,70 @@ class thread_section_name
- std::string m_storage;
- };
-
-+/* Type returned from core_target_find_mapped_file. Holds information
-+ about a mapped file that was processed when a core file was initially
-+ loaded. */
-+struct core_target_mapped_file_info
-+{
-+ /* Constructor. BUILD_ID is not nullptr, and is the build-id for the
-+ mapped file. FILENAME is the location of the file that GDB loaded to
-+ provide the mapped file. This might be different from the name of the
-+ mapped file mentioned in the core file, e.g. if GDB downloads a file
-+ from debuginfod then FILENAME would point into the debuginfod client
-+ cache. The FILENAME can be the empty string if GDB was unable to find
-+ a file to provide the mapped file. */
-+
-+ core_target_mapped_file_info (const bfd_build_id *build_id,
-+ const std::string filename)
-+ : m_build_id (build_id),
-+ m_filename (filename)
-+ {
-+ gdb_assert (m_build_id != nullptr);
-+ }
-+
-+ /* The build-id for this mapped file. */
-+
-+ const bfd_build_id *
-+ build_id () const
-+ {
-+ return m_build_id;
-+ }
-+
-+ /* The file GDB used to provide this mapped file. */
-+
-+ const std::string &
-+ filename () const
-+ {
-+ return m_filename;
-+ }
-+
-+private:
-+ const bfd_build_id *m_build_id = nullptr;
-+ const std::string m_filename;
-+};
-+
-+/* If the current inferior has a core_target for its process target, then
-+ lookup information about a mapped file that was discovered when the
-+ core file was loaded.
-+
-+ The FILENAME is the file we're looking for. The ADDR, if provided, is a
-+ mapped address within the inferior which is known to be part of the file
-+ we are looking for.
-+
-+ As an example, when loading shared libraries this function can be
-+ called, in that case FILENAME will be the name of the shared library
-+ that GDB is trying to load and ADDR will be an inferior address which is
-+ part of the shared library we are looking for.
-+
-+ This function looks for a mapped file which matches FILENAME and/or
-+ which covers ADDR and returns information about that file.
-+
-+ The returned information includes the name of the mapped file if known
-+ and the build-id for the mapped file if known.
-+
-+ */
-+std::optional<core_target_mapped_file_info>
-+core_target_find_mapped_file (const char *filename,
-+ std::optional<CORE_ADDR> addr);
-+
- #endif /* !defined (GDBCORE_H) */
-diff --git a/gdb/inf-child.c b/gdb/inf-child.c
---- a/gdb/inf-child.c
-+++ b/gdb/inf-child.c
-@@ -320,6 +320,21 @@ inf_child_target::fileio_fstat (int fd, struct stat *sb, fileio_error *target_er
- return ret;
- }
-
-+/* Implementation of to_fileio_stat. */
-+
-+int
-+inf_child_target::fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno)
-+{
-+ int ret;
-+
-+ ret = lstat (filename, sb);
-+ if (ret == -1)
-+ *target_errno = host_to_fileio_error (errno);
-+
-+ return ret;
-+}
-+
- /* Implementation of to_fileio_close. */
-
- int
-diff --git a/gdb/inf-child.h b/gdb/inf-child.h
---- a/gdb/inf-child.h
-+++ b/gdb/inf-child.h
-@@ -81,6 +81,8 @@ class inf_child_target
- int fileio_pread (int fd, gdb_byte *read_buf, int len,
- ULONGEST offset, fileio_error *target_errno) override;
- int fileio_fstat (int fd, struct stat *sb, fileio_error *target_errno) override;
-+ int fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno) override;
- int fileio_close (int fd, fileio_error *target_errno) override;
- int fileio_unlink (struct inferior *inf,
- const char *filename,
-diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
---- a/gdb/python/lib/gdb/__init__.py
-+++ b/gdb/python/lib/gdb/__init__.py
-@@ -87,8 +87,9 @@ xmethods = []
- frame_filters = {}
- # Initial frame unwinders.
- frame_unwinders = []
--# Initial missing debug handlers.
--missing_debug_handlers = []
-+# The missing file handlers. Each item is a tuple with the form
-+# (TYPE, HANDLER) where TYPE is a string either 'debug' or 'objfile'.
-+missing_file_handlers = []
-
-
- def _execute_unwinders(pending_frame):
-@@ -271,6 +272,61 @@ class Thread(threading.Thread):
- super().start()
-
-
-+def _filter_missing_file_handlers(handlers, handler_type):
-+ """Each list of missing file handlers is a list of tuples, the first
-+ item in the tuple is a string either 'debug' or 'objfile' to
-+ indicate what type of handler it is. The second item in the tuple
-+ is the actual handler object.
-+
-+ This function takes HANDLER_TYPE which is a string, either 'debug'
-+ or 'objfile' and HANDLERS, a list of tuples. The function returns
-+ an iterable over all of the handler objects (extracted from the
-+ tuples) which match HANDLER_TYPE.
-+ """
-+
-+ return map(lambda t: t[1], filter(lambda t: t[0] == handler_type, handlers))
-+
-+
-+def _handle_missing_files(pspace, handler_type, cb):
-+ """Helper for _handle_missing_debuginfo and _handle_missing_objfile.
-+
-+ Arguments:
-+ pspace: The gdb.Progspace in which we're operating. Used to
-+ lookup program space specific handlers.
-+ handler_type: A string, either 'debug' or 'objfile', this is the
-+ type of handler we're looking for.
-+ cb: A callback which takes a handler and returns the result of
-+ calling the handler.
-+
-+ Returns:
-+ None: No suitable file could be found.
-+ False: A handler has decided that the requested file cannot be
-+ found, and no further searching should be done.
-+ True: The file has been found and installed in a location
-+ where GDB would normally look for it. GDB should
-+ repeat its lookup process, the file should now be in
-+ place.
-+ A string: This is the filename of where the missing file can
-+ be found.
-+ """
-+
-+ for handler in _filter_missing_file_handlers(
-+ pspace.missing_file_handlers, handler_type
-+ ):
-+ if handler.enabled:
-+ result = cb(handler)
-+ if result is not None:
-+ return result
-+
-+ for handler in _filter_missing_file_handlers(missing_file_handlers, handler_type):
-+ if handler.enabled:
-+ result = cb(handler)
-+ if result is not None:
-+ return result
-+
-+ return None
-+
-+
- def _handle_missing_debuginfo(objfile):
- """Internal function called from GDB to execute missing debug
- handlers.
-@@ -293,18 +349,46 @@ def _handle_missing_debuginfo(objfile):
- A string: This is the filename of a file containing the
- required debug information.
- """
-+
- pspace = objfile.progspace
-
-- for handler in pspace.missing_debug_handlers:
-- if handler.enabled:
-- result = handler(objfile)
-- if result is not None:
-- return result
-+ return _handle_missing_files(pspace, "debug", lambda h: h(objfile))
-
-- for handler in missing_debug_handlers:
-- if handler.enabled:
-- result = handler(objfile)
-- if result is not None:
-- return result
-
-- return None
-+def _handle_missing_objfile(pspace, buildid, filename):
-+ """Internal function called from GDB to execute missing objfile
-+ handlers.
-+
-+ Run each of the currently registered, and enabled missing objfile
-+ handler objects for the gdb.Progspace passed in as an argument,
-+ and then from the global list. Stop after the first handler that
-+ returns a result other than None.
-+
-+ Arguments:
-+ pspace: A gdb.Progspace for which the missing objfile handlers
-+ should be run. This is the program space in which an
-+ objfile was found to be missing.
-+ buildid: A string containing the build-id we're looking for.
-+ filename: The filename of the file GDB tried to find but
-+ couldn't. This is not where the file should be
-+ placed if found, in fact, this file might already
-+ exist on disk but have the wrong build-id. This is
-+ mostly provided in order to be used in messages to
-+ the user.
-+
-+ Returns:
-+ None: No objfile could be found for this build-id.
-+ False: A handler has done all it can with for this build-id,
-+ but no objfile could be found.
-+ True: An objfile might have been installed by a handler, GDB
-+ should check again. The only place GDB checks is within
-+ the .build-id sub-directory within the
-+ debug-file-directory. If the required file was not
-+ installed there then GDB will not find it.
-+ A string: This is the filename of a file containing the
-+ missing objfile.
-+ """
-+
-+ return _handle_missing_files(
-+ pspace, "objfile", lambda h: h(pspace, buildid, filename)
-+ )
-diff --git a/gdb/python/lib/gdb/command/missing_debug.py b/gdb/python/lib/gdb/command/missing_files.py
-similarity index 54%
-rename from gdb/python/lib/gdb/command/missing_debug.py
-rename to gdb/python/lib/gdb/command/missing_files.py
---- a/gdb/python/lib/gdb/command/missing_debug.py
-+++ b/gdb/python/lib/gdb/command/missing_files.py
-@@ -1,4 +1,4 @@
--# Missing debug related commands.
-+# Missing debug and objfile related commands.
- #
- # Copyright 2023-2024 Free Software Foundation, Inc.
- #
-@@ -21,7 +21,7 @@ import gdb
-
-
- def validate_regexp(exp, idstring):
-- """Compile exp into a compiler regular expression object.
-+ """Compile exp into a compiled regular expression object.
-
- Arguments:
- exp: The string to compile into a re.Pattern object.
-@@ -33,14 +33,15 @@ def validate_regexp(exp, idstring):
- Raises:
- SyntaxError: If exp is an invalid regexp.
- """
-+
- try:
- return re.compile(exp)
- except SyntaxError:
- raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp))
-
-
--def parse_missing_debug_command_args(arg):
-- """Internal utility to parse missing debug handler command argv.
-+def parse_missing_file_command_args(arg):
-+ """Internal utility to parse missing file handler command argv.
-
- Arguments:
- arg: The arguments to the command. The format is:
-@@ -52,6 +53,7 @@ def parse_missing_debug_command_args(arg):
- Raises:
- SyntaxError: an error processing ARG
- """
-+
- argv = gdb.string_to_argv(arg)
- argc = len(argv)
- if argc > 2:
-@@ -68,10 +70,10 @@ def parse_missing_debug_command_args(arg):
- )
-
-
--class InfoMissingDebugHanders(gdb.Command):
-- """GDB command to list missing debug handlers.
-+class InfoMissingFileHandlers(gdb.Command):
-+ """GDB command to list missing HTYPE handlers.
-
-- Usage: info missing-debug-handlers [LOCUS-REGEXP [NAME-REGEXP]]
-+ Usage: info missing-HTYPE-handlers [LOCUS-REGEXP [NAME-REGEXP]]
-
- LOCUS-REGEXP is a regular expression matching the location of the
- handler. If it is omitted, all registered handlers from all
-@@ -79,38 +81,47 @@ class InfoMissingDebugHanders(gdb.Command):
- the handlers from the current progspace, or a regular expression
- matching filenames of progspaces.
-
-- NAME-REGEXP is a regular expression to filter missing debug
-+ NAME-REGEXP is a regular expression to filter missing HTYPE
- handler names. If this omitted for a specified locus, then all
- registered handlers in the locus are listed.
- """
-
-- def __init__(self):
-- super().__init__("info missing-debug-handlers", gdb.COMMAND_FILES)
-+ def __init__(self, handler_type):
-+ # Update the doc string before calling the parent constructor,
-+ # replacing the string 'HTYPE' with the value of HANDLER_TYPE.
-+ # The parent constructor will grab a copy of this string to
-+ # use as the commands help text.
-+ self.__doc__ = self.__doc__.replace("HTYPE", handler_type)
-+ super().__init__(
-+ "info missing-" + handler_type + "-handlers", gdb.COMMAND_FILES
-+ )
-+ self.handler_type = handler_type
-
- def list_handlers(self, title, handlers, name_re):
-- """Lists the missing debug handlers whose name matches regexp.
-+ """Lists the missing file handlers whose name matches regexp.
-
- Arguments:
- title: The line to print before the list.
-- handlers: The list of the missing debug handlers.
-+ handlers: The list of the missing file handlers.
- name_re: handler name filter.
- """
-+
- if not handlers:
- return
- print(title)
-- for handler in handlers:
-+ for handler in gdb._filter_missing_file_handlers(handlers, self.handler_type):
- if name_re.match(handler.name):
- print(
- " %s%s" % (handler.name, "" if handler.enabled else " [disabled]")
- )
-
- def invoke(self, arg, from_tty):
-- locus_re, name_re = parse_missing_debug_command_args(arg)
-+ locus_re, name_re = parse_missing_file_command_args(arg)
-
- if locus_re.match("progspace") and locus_re.pattern != "":
- cp = gdb.current_progspace()
- self.list_handlers(
-- "Progspace %s:" % cp.filename, cp.missing_debug_handlers, name_re
-+ "Progspace %s:" % cp.filename, cp.missing_file_handlers, name_re
- )
-
- for progspace in gdb.progspaces():
-@@ -125,58 +136,71 @@ class InfoMissingDebugHanders(gdb.Command):
- msg = "Progspace %s:" % filename
- self.list_handlers(
- msg,
-- progspace.missing_debug_handlers,
-+ progspace.missing_file_handlers,
- name_re,
- )
-
- # Print global handlers last, as these are invoked last.
- if locus_re.match("global"):
-- self.list_handlers("Global:", gdb.missing_debug_handlers, name_re)
-+ self.list_handlers("Global:", gdb.missing_file_handlers, name_re)
-
-
--def do_enable_handler1(handlers, name_re, flag):
-- """Enable/disable missing debug handlers whose names match given regex.
-+def do_enable_handler1(handlers, name_re, flag, handler_type):
-+ """Enable/disable missing file handlers whose names match given regex.
-
- Arguments:
-- handlers: The list of missing debug handlers.
-+ handlers: The list of missing file handlers.
- name_re: Handler name filter.
- flag: A boolean indicating if we should enable or disable.
-+ handler_type: A string, either 'debug' or 'objfile', use to control
-+ which handlers are modified.
-
- Returns:
- The number of handlers affected.
- """
-+
- total = 0
-- for handler in handlers:
-+ for handler in gdb._filter_missing_file_handlers(handlers, handler_type):
- if name_re.match(handler.name) and handler.enabled != flag:
- handler.enabled = flag
- total += 1
- return total
-
-
--def do_enable_handler(arg, flag):
-- """Enable or disable missing debug handlers."""
-- (locus_re, name_re) = parse_missing_debug_command_args(arg)
-+def do_enable_handler(arg, flag, handler_type):
-+ """Enable or disable missing file handlers."""
-+
-+ (locus_re, name_re) = parse_missing_file_command_args(arg)
- total = 0
- if locus_re.match("global"):
-- total += do_enable_handler1(gdb.missing_debug_handlers, name_re, flag)
-+ total += do_enable_handler1(
-+ gdb.missing_file_handlers, name_re, flag, handler_type
-+ )
- if locus_re.match("progspace") and locus_re.pattern != "":
- total += do_enable_handler1(
-- gdb.current_progspace().missing_debug_handlers, name_re, flag
-+ gdb.current_progspace().missing_file_handlers, name_re, flag, handler_type
- )
- for progspace in gdb.progspaces():
- filename = progspace.filename or ""
- if locus_re.match(filename):
-- total += do_enable_handler1(progspace.missing_debug_handlers, name_re, flag)
-+ total += do_enable_handler1(
-+ progspace.missing_file_handlers, name_re, flag, handler_type
-+ )
- print(
-- "%d missing debug handler%s %s"
-- % (total, "" if total == 1 else "s", "enabled" if flag else "disabled")
-+ "%d missing %s handler%s %s"
-+ % (
-+ total,
-+ handler_type,
-+ "" if total == 1 else "s",
-+ "enabled" if flag else "disabled",
-+ )
- )
-
-
--class EnableMissingDebugHandler(gdb.Command):
-- """GDB command to enable missing debug handlers.
-+class EnableMissingFileHandler(gdb.Command):
-+ """GDB command to enable missing HTYPE handlers.
-
-- Usage: enable missing-debug-handler [LOCUS-REGEXP [NAME-REGEXP]]
-+ Usage: enable missing-HTYPE-handler [LOCUS-REGEXP [NAME-REGEXP]]
-
- LOCUS-REGEXP is a regular expression specifying the handlers to
- enable. It can be 'global', 'progspace' for the current
-@@ -187,18 +211,26 @@ class EnableMissingDebugHandler(gdb.Command):
- in the locus are affected.
- """
-
-- def __init__(self):
-- super().__init__("enable missing-debug-handler", gdb.COMMAND_FILES)
-+ def __init__(self, handler_type):
-+ # Update the doc string before calling the parent constructor,
-+ # replacing the string 'HTYPE' with the value of HANDLER_TYPE.
-+ # The parent constructor will grab a copy of this string to
-+ # use as the commands help text.
-+ self.__doc__ = self.__doc__.replace("HTYPE", handler_type)
-+ super().__init__(
-+ "enable missing-" + handler_type + "-handler", gdb.COMMAND_FILES
-+ )
-+ self.handler_type = handler_type
-
- def invoke(self, arg, from_tty):
- """GDB calls this to perform the command."""
-- do_enable_handler(arg, True)
-+ do_enable_handler(arg, True, self.handler_type)
-
-
--class DisableMissingDebugHandler(gdb.Command):
-- """GDB command to disable missing debug handlers.
-+class DisableMissingFileHandler(gdb.Command):
-+ """GDB command to disable missing HTYPE handlers.
-
-- Usage: disable missing-debug-handler [LOCUS-REGEXP [NAME-REGEXP]]
-+ Usage: disable missing-HTYPE-handler [LOCUS-REGEXP [NAME-REGEXP]]
-
- LOCUS-REGEXP is a regular expression specifying the handlers to
- enable. It can be 'global', 'progspace' for the current
-@@ -209,19 +241,28 @@ class DisableMissingDebugHandler(gdb.Command):
- in the locus are affected.
- """
-
-- def __init__(self):
-- super().__init__("disable missing-debug-handler", gdb.COMMAND_FILES)
-+ def __init__(self, handler_type):
-+ # Update the doc string before calling the parent constructor,
-+ # replacing the string 'HTYPE' with the value of HANDLER_TYPE.
-+ # The parent constructor will grab a copy of this string to
-+ # use as the commands help text.
-+ self.__doc__ = self.__doc__.replace("HTYPE", handler_type)
-+ super().__init__(
-+ "disable missing-" + handler_type + "-handler", gdb.COMMAND_FILES
-+ )
-+ self.handler_type = handler_type
-
- def invoke(self, arg, from_tty):
- """GDB calls this to perform the command."""
-- do_enable_handler(arg, False)
-+ do_enable_handler(arg, False, self.handler_type)
-
-
--def register_missing_debug_handler_commands():
-- """Installs the missing debug handler commands."""
-- InfoMissingDebugHanders()
-- EnableMissingDebugHandler()
-- DisableMissingDebugHandler()
-+def register_missing_file_handler_commands():
-+ """Installs the missing file handler commands."""
-+ for handler_type in ["debug", "objfile"]:
-+ InfoMissingFileHandlers(handler_type)
-+ EnableMissingFileHandler(handler_type)
-+ DisableMissingFileHandler(handler_type)
-
-
--register_missing_debug_handler_commands()
-+register_missing_file_handler_commands()
-diff --git a/gdb/python/lib/gdb/missing_debug.py b/gdb/python/lib/gdb/missing_debug.py
---- a/gdb/python/lib/gdb/missing_debug.py
-+++ b/gdb/python/lib/gdb/missing_debug.py
-@@ -17,48 +17,11 @@
- MissingDebugHandler base class, and register_handler function.
- """
-
--import sys
--
- import gdb
-+from gdb.missing_files import MissingFileHandler
-
--if sys.version_info >= (3, 7):
-- # Functions str.isascii() and str.isalnum are available starting Python
-- # 3.7.
-- def isascii(ch):
-- return ch.isascii()
--
-- def isalnum(ch):
-- return ch.isalnum()
--
--else:
-- # Fall back to curses.ascii.isascii() and curses.ascii.isalnum() for
-- # earlier versions.
-- from curses.ascii import isalnum, isascii
--
--
--def _validate_name(name):
-- """Validate a missing debug handler name string.
--
-- If name is valid as a missing debug handler name, then this
-- function does nothing. If name is not valid then an exception is
-- raised.
--
-- Arguments:
-- name: A string, the name of a missing debug handler.
--
-- Returns:
-- Nothing.
-
-- Raises:
-- ValueError: If name is invalid as a missing debug handler
-- name.
-- """
-- for ch in name:
-- if not isascii(ch) or not (isalnum(ch) or ch in "_-"):
-- raise ValueError("invalid character '%s' in handler name: %s" % (ch, name))
--
--
--class MissingDebugHandler(object):
-+class MissingDebugHandler(MissingFileHandler):
- """Base class for missing debug handlers written in Python.
-
- A missing debug handler has a single method __call__ along with
-@@ -69,41 +32,8 @@ class MissingDebugHandler(object):
- enabled: When true this handler is enabled.
- """
-
-- def __init__(self, name):
-- """Constructor.
--
-- Args:
-- name: An identifying name for this handler.
--
-- Raises:
-- TypeError: name is not a string.
-- ValueError: name contains invalid characters.
-- """
--
-- if not isinstance(name, str):
-- raise TypeError("incorrect type for name: %s" % type(name))
--
-- _validate_name(name)
--
-- self._name = name
-- self._enabled = True
--
-- @property
-- def name(self):
-- return self._name
--
-- @property
-- def enabled(self):
-- return self._enabled
--
-- @enabled.setter
-- def enabled(self, value):
-- if not isinstance(value, bool):
-- raise TypeError("incorrect type for enabled attribute: %s" % type(value))
-- self._enabled = value
--
- def __call__(self, objfile):
-- """GDB handle missing debug information for an objfile.
-+ """Handle missing debug information for an objfile.
-
- Arguments:
- objfile: A gdb.Objfile for which GDB could not find any
-@@ -124,62 +54,5 @@ class MissingDebugHandler(object):
-
-
- def register_handler(locus, handler, replace=False):
-- """Register handler in given locus.
--
-- The handler is prepended to the locus's missing debug handlers
-- list. The name of handler should be unique (or replace must be
-- True).
--
-- Arguments:
-- locus: Either a progspace, or None (in which case the unwinder
-- is registered globally).
-- handler: An object of a gdb.MissingDebugHandler subclass.
--
-- replace: If True, replaces existing handler with the same name
-- within locus. Otherwise, raises RuntimeException if
-- unwinder with the same name already exists.
--
-- Returns:
-- Nothing.
--
-- Raises:
-- RuntimeError: The name of handler is not unique.
-- TypeError: Bad locus type.
-- AttributeError: Required attributes of handler are missing.
-- """
--
-- if locus is None:
-- if gdb.parameter("verbose"):
-- gdb.write("Registering global %s handler ...\n" % handler.name)
-- locus = gdb
-- elif isinstance(locus, gdb.Progspace):
-- if gdb.parameter("verbose"):
-- gdb.write(
-- "Registering %s handler for %s ...\n" % (handler.name, locus.filename)
-- )
-- else:
-- raise TypeError("locus should be gdb.Progspace or None")
--
-- # Some sanity checks on HANDLER. Calling getattr will raise an
-- # exception if the attribute doesn't exist, which is what we want.
-- # These checks are not exhaustive; we don't check the attributes
-- # have the correct types, or the method has the correct signature,
-- # but this should catch some basic mistakes.
-- getattr(handler, "name")
-- getattr(handler, "enabled")
-- call_method = getattr(handler, "__call__")
-- if not callable(call_method):
-- raise AttributeError(
-- "'%s' object's '__call__' attribute is not callable"
-- % type(handler).__name__
-- )
--
-- i = 0
-- for needle in locus.missing_debug_handlers:
-- if needle.name == handler.name:
-- if replace:
-- del locus.missing_debug_handlers[i]
-- else:
-- raise RuntimeError("Handler %s already exists." % handler.name)
-- i += 1
-- locus.missing_debug_handlers.insert(0, handler)
-+ """See gdb.missing_files.register_handler."""
-+ gdb.missing_files.register_handler("debug", locus, handler, replace)
-diff --git a/gdb/python/lib/gdb/missing_files.py b/gdb/python/lib/gdb/missing_files.py
-new file mode 100644
---- /dev/null
-+++ b/gdb/python/lib/gdb/missing_files.py
-@@ -0,0 +1,204 @@
-+# Copyright (C) 2023-2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+"""
-+MissingFileHandler base class, and support functions used by the
-+missing_debug.py and missing_objfile.py modules.
-+"""
-+
-+import sys
-+
-+import gdb
-+
-+if sys.version_info >= (3, 7):
-+ # Functions str.isascii() and str.isalnum are available starting Python
-+ # 3.7.
-+ def isascii(ch):
-+ return ch.isascii()
-+
-+ def isalnum(ch):
-+ return ch.isalnum()
-+
-+else:
-+ # Older version of Python doesn't have str.isascii() and
-+ # str.isalnum() so provide our own.
-+ #
-+ # We could import isalnum() and isascii() from the curses library,
-+ # but that adds an extra dependency. Given these functions are
-+ # both small and trivial lets implement them here.
-+ #
-+ # These definitions are based on those in the curses library, but
-+ # simplified as we know C will always be a single character 'str'.
-+
-+ def isdigit(c):
-+ return 48 <= ord(c) <= 57
-+
-+ def islower(c):
-+ return 97 <= ord(c) <= 122
-+
-+ def isupper(c):
-+ return 65 <= ord(c) <= 90
-+
-+ def isalpha(c):
-+ return isupper(c) or islower(c)
-+
-+ def isalnum(c):
-+ return isalpha(c) or isdigit(c)
-+
-+ def isascii(c):
-+ return 0 <= ord(c) <= 127
-+
-+
-+def _validate_name(name):
-+ """Validate a missing file handler name string.
-+
-+ If name is valid as a missing file handler name, then this
-+ function does nothing. If name is not valid then an exception is
-+ raised.
-+
-+ Arguments:
-+ name: A string, the name of a missing file handler.
-+
-+ Returns:
-+ Nothing.
-+
-+ Raises:
-+ ValueError: If name is invalid as a missing file handler
-+ name.
-+ """
-+
-+ for ch in name:
-+ if not isascii(ch) or not (isalnum(ch) or ch in "_-"):
-+ raise ValueError("invalid character '%s' in handler name: %s" % (ch, name))
-+
-+
-+class MissingFileHandler(object):
-+ """Base class for missing file handlers written in Python.
-+
-+ A missing file handler has a single method __call__ along with the
-+ read/write attribute enabled, and a read-only attribute name. The
-+ attributes are provided by this class while the __call__ method is
-+ provided by a sub-class. Each sub-classes __call__ method will
-+ have a different signature.
-+
-+ Attributes:
-+ name: Read-only attribute, the name of this handler.
-+ enabled: When true this handler is enabled.
-+ """
-+
-+ def __init__(self, name):
-+ """Constructor.
-+
-+ Args:
-+ name: An identifying name for this handler.
-+
-+ Raises:
-+ TypeError: name is not a string.
-+ ValueError: name contains invalid characters.
-+ """
-+
-+ if not isinstance(name, str):
-+ raise TypeError("incorrect type for name: %s" % type(name))
-+
-+ _validate_name(name)
-+
-+ self._name = name
-+ self._enabled = True
-+
-+ @property
-+ def name(self):
-+ return self._name
-+
-+ @property
-+ def enabled(self):
-+ return self._enabled
-+
-+ @enabled.setter
-+ def enabled(self, value):
-+ if not isinstance(value, bool):
-+ raise TypeError("incorrect type for enabled attribute: %s" % type(value))
-+ self._enabled = value
-+
-+
-+def register_handler(handler_type, locus, handler, replace=False):
-+ """Register handler in given locus.
-+
-+ The handler is prepended to the locus's missing file handlers
-+ list. The name of handler should be unique (or replace must be
-+ True), and the name must pass the _validate_name check.
-+
-+ Arguments:
-+ handler_type: A string, either 'debug' or 'objfile' indicating the
-+ type of handler to be registered.
-+ locus: Either a progspace, or None (in which case the unwinder
-+ is registered globally).
-+ handler: An object used as a missing file handler. Usually a
-+ sub-class of MissingFileHandler.
-+ replace: If True, replaces existing handler with the same name
-+ within locus. Otherwise, raises RuntimeException if
-+ unwinder with the same name already exists.
-+
-+ Returns:
-+ Nothing.
-+
-+ Raises:
-+ RuntimeError: The name of handler is not unique.
-+ TypeError: Bad locus type.
-+ AttributeError: Required attributes of handler are missing.
-+ ValueError: If the name of the handler is invalid, or if
-+ handler_type is neither 'debug' or 'objfile'.
-+ """
-+
-+ if handler_type != "debug" and handler_type != "objfile":
-+ raise ValueError("handler_type must be 'debug' or 'objfile'")
-+
-+ if locus is None:
-+ if gdb.parameter("verbose"):
-+ gdb.write("Registering global %s handler ...\n" % handler.name)
-+ locus = gdb
-+ elif isinstance(locus, gdb.Progspace):
-+ if gdb.parameter("verbose"):
-+ gdb.write(
-+ "Registering %s handler for %s ...\n" % (handler.name, locus.filename)
-+ )
-+ else:
-+ raise TypeError("locus should be gdb.Progspace or None")
-+
-+ # Some sanity checks on HANDLER. Calling getattr will raise an
-+ # exception if the attribute doesn't exist, which is what we want.
-+ # These checks are not exhaustive; we don't check the attributes
-+ # have the correct types, or the method has the correct signature,
-+ # but this should catch some basic mistakes.
-+ name = getattr(handler, "name")
-+ _validate_name(name)
-+
-+ getattr(handler, "enabled")
-+
-+ call_method = getattr(handler, "__call__")
-+ if not callable(call_method):
-+ raise AttributeError(
-+ "'%s' object's '__call__' attribute is not callable"
-+ % type(handler).__name__
-+ )
-+
-+ i = 0
-+ for needle in locus.missing_file_handlers:
-+ if needle[0] == handler_type and needle[1].name == handler.name:
-+ if replace:
-+ del locus.missing_file_handlers[i]
-+ else:
-+ raise RuntimeError("Handler %s already exists." % handler.name)
-+ i += 1
-+ locus.missing_file_handlers.insert(0, (handler_type, handler))
-diff --git a/gdb/python/lib/gdb/missing_objfile.py b/gdb/python/lib/gdb/missing_objfile.py
-new file mode 100644
---- /dev/null
-+++ b/gdb/python/lib/gdb/missing_objfile.py
-@@ -0,0 +1,67 @@
-+# Copyright (C) 2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+"""
-+MissingObjfileHandler base class, and register_handler function.
-+"""
-+
-+import gdb
-+from gdb.missing_files import MissingFileHandler
-+
-+
-+class MissingObjfileHandler(MissingFileHandler):
-+ """Base class for missing objfile handlers written in Python.
-+
-+ A missing objfile handler has a single method __call__ along with
-+ the read/write attribute enabled, and a read-only attribute name.
-+
-+ Attributes:
-+ name: Read-only attribute, the name of this handler.
-+ enabled: When true this handler is enabled.
-+ """
-+
-+ def __call__(self, buildid, filename):
-+ """Handle a missing objfile when GDB can knows the build-id.
-+
-+ Arguments:
-+
-+ buildid: A string containing the build-id for the objfile
-+ GDB is searching for.
-+ filename: A string containing the name of the file GDB is
-+ searching for. This is provided only for the purpose
-+ of creating diagnostic messages. If the file is found
-+ it does not have to be placed here, and this file
-+ might already exist but GDB has determined it is not
-+ suitable for use, e.g. if the build-id doesn't match.
-+
-+ Returns:
-+
-+ True: GDB should try again to locate the missing objfile,
-+ the handler may have installed the missing file.
-+ False: GDB should move on without the objfile. The
-+ handler has determined that this objfile is not
-+ available.
-+ A string: GDB should load the file at the given path; it
-+ contains the requested objfile.
-+ None: This handler can't help with this objfile. GDB
-+ should try any other registered handlers.
-+
-+ """
-+ raise NotImplementedError("MissingObjfileHandler.__call__()")
-+
-+
-+def register_handler(locus, handler, replace=False):
-+ """See gdb.missing_files.register_handler."""
-+ gdb.missing_files.register_handler("objfile", locus, handler, replace)
-diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
---- a/gdb/python/py-progspace.c
-+++ b/gdb/python/py-progspace.c
-@@ -55,8 +55,8 @@ struct pspace_object
- /* The debug method list. */
- PyObject *xmethods;
-
-- /* The missing debug handler list. */
-- PyObject *missing_debug_handlers;
-+ /* The missing file handler list. */
-+ PyObject *missing_file_handlers;
- };
-
- extern PyTypeObject pspace_object_type
-@@ -166,7 +166,7 @@ pspy_dealloc (PyObject *self)
- Py_XDECREF (ps_self->frame_unwinders);
- Py_XDECREF (ps_self->type_printers);
- Py_XDECREF (ps_self->xmethods);
-- Py_XDECREF (ps_self->missing_debug_handlers);
-+ Py_XDECREF (ps_self->missing_file_handlers);
- Py_TYPE (self)->tp_free (self);
- }
-
-@@ -202,8 +202,8 @@ pspy_initialize (pspace_object *self)
- if (self->xmethods == NULL)
- return 0;
-
-- self->missing_debug_handlers = PyList_New (0);
-- if (self->missing_debug_handlers == nullptr)
-+ self->missing_file_handlers = PyList_New (0);
-+ if (self->missing_file_handlers == nullptr)
- return 0;
-
- return 1;
-@@ -349,18 +349,18 @@ pspy_get_xmethods (PyObject *o, void *ignore)
- /* Return the list of missing debug handlers for this program space. */
-
- static PyObject *
--pspy_get_missing_debug_handlers (PyObject *o, void *ignore)
-+pspy_get_missing_file_handlers (PyObject *o, void *ignore)
- {
- pspace_object *self = (pspace_object *) o;
-
-- Py_INCREF (self->missing_debug_handlers);
-- return self->missing_debug_handlers;
-+ Py_INCREF (self->missing_file_handlers);
-+ return self->missing_file_handlers;
- }
-
- /* Set this program space's list of missing debug handlers to HANDLERS. */
-
- static int
--pspy_set_missing_debug_handlers (PyObject *o, PyObject *handlers,
-+pspy_set_missing_file_handlers (PyObject *o, PyObject *handlers,
- void *ignore)
- {
- pspace_object *self = (pspace_object *) o;
-@@ -380,9 +380,9 @@ pspy_set_missing_debug_handlers (PyObject *o, PyObject *handlers,
- }
-
- /* Take care in case the LHS and RHS are related somehow. */
-- gdbpy_ref<> tmp (self->missing_debug_handlers);
-+ gdbpy_ref<> tmp (self->missing_file_handlers);
- Py_INCREF (handlers);
-- self->missing_debug_handlers = handlers;
-+ self->missing_file_handlers = handlers;
-
- return 0;
- }
-@@ -779,8 +779,8 @@ static gdb_PyGetSetDef pspace_getset[] =
- "Type printers.", NULL },
- { "xmethods", pspy_get_xmethods, NULL,
- "Debug methods.", NULL },
-- { "missing_debug_handlers", pspy_get_missing_debug_handlers,
-- pspy_set_missing_debug_handlers, "Missing debug handlers.", NULL },
-+ { "missing_file_handlers", pspy_get_missing_file_handlers,
-+ pspy_set_missing_file_handlers, "Missing file handlers.", NULL },
- { NULL }
- };
-
-diff --git a/gdb/python/python.c b/gdb/python/python.c
---- a/gdb/python/python.c
-+++ b/gdb/python/python.c
-@@ -35,6 +35,7 @@
- #include "location.h"
- #include "run-on-main-thread.h"
- #include "observable.h"
-+#include "build-id.h"
-
- #if GDB_SELF_TEST
- #include "gdbsupport/selftest.h"
-@@ -128,8 +129,11 @@ static std::optional<std::string> gdbpy_colorize
- (const std::string &filename, const std::string &contents);
- static std::optional<std::string> gdbpy_colorize_disasm
- (const std::string &content, gdbarch *gdbarch);
--static ext_lang_missing_debuginfo_result gdbpy_handle_missing_debuginfo
-+static ext_lang_missing_file_result gdbpy_handle_missing_debuginfo
- (const struct extension_language_defn *extlang, struct objfile *objfile);
-+static ext_lang_missing_file_result gdbpy_find_objfile_from_buildid
-+ (const struct extension_language_defn *extlang, program_space *pspace,
-+ const struct bfd_build_id *build_id, const char *missing_filename);
-
- /* The interface between gdb proper and loading of python scripts. */
-
-@@ -177,7 +181,8 @@ static const struct extension_language_ops python_extension_ops =
-
- gdbpy_print_insn,
-
-- gdbpy_handle_missing_debuginfo
-+ gdbpy_handle_missing_debuginfo,
-+ gdbpy_find_objfile_from_buildid
- };
-
- #endif /* HAVE_PYTHON */
-@@ -1761,10 +1766,10 @@ gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2)
- /* Implement the 'handle_missing_debuginfo' hook for Python. GDB has
- failed to find any debug information for OBJFILE. The extension has a
- chance to record this, or even install the required debug information.
-- See the description of ext_lang_missing_debuginfo_result in
-- extension-priv.h for details of the return value. */
-+ See the description of ext_lang_missing_file_result in extension-priv.h
-+ for details of the return value. */
-
--static ext_lang_missing_debuginfo_result
-+static ext_lang_missing_file_result
- gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
- struct objfile *objfile)
- {
-@@ -1812,7 +1817,7 @@ gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
- if (PyBool_Check (pyo_execute_ret.get ()))
- {
- bool try_again = PyObject_IsTrue (pyo_execute_ret.get ());
-- return ext_lang_missing_debuginfo_result (try_again);
-+ return ext_lang_missing_file_result (try_again);
- }
-
- if (!gdbpy_is_string (pyo_execute_ret.get ()))
-@@ -1832,7 +1837,108 @@ gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
- return {};
- }
-
-- return ext_lang_missing_debuginfo_result (std::string (filename.get ()));
-+ return ext_lang_missing_file_result (std::string (filename.get ()));
-+}
-+
-+/* Implement the find_objfile_from_buildid hook for Python. PSPACE is the
-+ program space in which GDB is trying to find an objfile, BUILD_ID is the
-+ build-id for the missing objfile, and EXPECTED_FILENAME is a non-NULL
-+ string which can be used (if needed) in messages to the user, and
-+ represents the file GDB is looking for. */
-+
-+static ext_lang_missing_file_result
-+gdbpy_find_objfile_from_buildid (const struct extension_language_defn *extlang,
-+ program_space *pspace,
-+ const struct bfd_build_id *build_id,
-+ const char *missing_filename)
-+{
-+ gdb_assert (pspace != nullptr);
-+ gdb_assert (build_id != nullptr);
-+ gdb_assert (missing_filename != nullptr);
-+
-+ /* Early exit if Python is not initialised. */
-+ if (!gdb_python_initialized || gdb_python_module == nullptr)
-+ return {};
-+
-+ gdbpy_enter enter_py;
-+
-+ /* Convert BUILD_ID into a Python object. */
-+ std::string hex_form = bin2hex (build_id->data, build_id->size);
-+ gdbpy_ref<> pyo_buildid = host_string_to_python_string (hex_form.c_str ());
-+ if (pyo_buildid == nullptr)
-+ {
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ /* Convert MISSING_FILENAME to a Python object. */
-+ gdbpy_ref<> pyo_filename = host_string_to_python_string (missing_filename);
-+ if (pyo_filename == nullptr)
-+ {
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ /* Convert PSPACE to a Python object. */
-+ gdbpy_ref<> pyo_pspace = pspace_to_pspace_object (pspace);
-+ if (pyo_pspace == nullptr)
-+ {
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ /* Lookup the helper function within the GDB module. */
-+ gdbpy_ref<> pyo_handler
-+ (PyObject_GetAttrString (gdb_python_module, "_handle_missing_objfile"));
-+ if (pyo_handler == nullptr)
-+ {
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ /* Call the function, passing in the Python objfile object. */
-+ gdbpy_ref<> pyo_execute_ret
-+ (PyObject_CallFunctionObjArgs (pyo_handler.get (), pyo_pspace.get (),
-+ pyo_buildid.get (), pyo_filename.get (),
-+ nullptr));
-+ if (pyo_execute_ret == nullptr)
-+ {
-+ /* If the handler is cancelled due to a Ctrl-C, then propagate
-+ the Ctrl-C as a GDB exception instead of swallowing it. */
-+ gdbpy_print_stack_or_quit ();
-+ return {};
-+ }
-+
-+ /* Parse the result, and convert it back to the C++ object. */
-+ if (pyo_execute_ret == Py_None)
-+ return {};
-+
-+ if (PyBool_Check (pyo_execute_ret.get ()))
-+ {
-+ /* We know the value is a bool, so it must be either Py_True or
-+ Py_False. Anything else would not get past the above check. */
-+ bool try_again = pyo_execute_ret.get () == Py_True;
-+ return ext_lang_missing_file_result (try_again);
-+ }
-+
-+ if (!gdbpy_is_string (pyo_execute_ret.get ()))
-+ {
-+ PyErr_SetString (PyExc_ValueError,
-+ "return value from _find_objfile_by_buildid should "
-+ "be None, a bool, or a str");
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ gdb::unique_xmalloc_ptr<char> filename
-+ = python_string_to_host_string (pyo_execute_ret.get ());
-+ if (filename == nullptr)
-+ {
-+ gdbpy_print_stack ();
-+ return {};
-+ }
-+
-+ return ext_lang_missing_file_result (std::string (filename.get ()));
- }
-
- /* Compute the list of active python type printers and store them in
-diff --git a/gdb/remote.c b/gdb/remote.c
---- a/gdb/remote.c
-+++ b/gdb/remote.c
-@@ -246,6 +246,7 @@ enum {
- PACKET_vFile_unlink,
- PACKET_vFile_readlink,
- PACKET_vFile_fstat,
-+ PACKET_vFile_stat,
- PACKET_qXfer_auxv,
- PACKET_qXfer_features,
- PACKET_qXfer_exec_file,
-@@ -996,6 +997,9 @@ class remote_target : public process_stratum_target
-
- int fileio_fstat (int fd, struct stat *sb, fileio_error *target_errno) override;
-
-+ int fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno) override;
-+
- int fileio_close (int fd, fileio_error *target_errno) override;
-
- int fileio_unlink (struct inferior *inf,
-@@ -12661,6 +12665,9 @@ remote_target::remote_hostio_send_command (int command_bytes, int which_packet,
- return -1;
- }
-
-+ if (*remote_errno != FILEIO_SUCCESS)
-+ return -1;
-+
- /* Make sure we saw an attachment if and only if we expected one. */
- if ((attachment_tmp == NULL && attachment != NULL)
- || (attachment_tmp != NULL && attachment == NULL))
-@@ -13027,6 +13034,41 @@ remote_target::fileio_readlink (struct inferior *inf, const char *filename,
- return ret;
- }
-
-+/* Helper function to handle ::fileio_fstat and ::fileio_stat result
-+ processing. When this function is called the remote syscall has been
-+ performed and we know we didn't get an error back.
-+
-+ ATTACHMENT and ATTACHMENT_LEN are the attachment data extracted from the
-+ remote syscall reply. EXPECTED_LEN is the length returned from the
-+ fstat or stat call, this the length of the returned data (in ATTACHMENT)
-+ once it has been decoded. The fstat/stat result (from the ATTACHMENT
-+ data) is to be placed in ST. */
-+
-+static int
-+fileio_process_fstat_and_stat_reply (const char *attachment,
-+ int attachment_len,
-+ int expected_len,
-+ struct stat *st)
-+{
-+ struct fio_stat fst;
-+
-+ int read_len
-+ = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
-+ (gdb_byte *) &fst, sizeof (fst));
-+
-+ if (read_len != expected_len)
-+ error (_("vFile:fstat returned %d, but %d bytes."),
-+ expected_len, read_len);
-+
-+ if (read_len != sizeof (fst))
-+ error (_("vFile:fstat returned %d bytes, but expecting %d."),
-+ read_len, (int) sizeof (fst));
-+
-+ remote_fileio_to_host_stat (&fst, st);
-+
-+ return 0;
-+}
-+
- /* Implementation of to_fileio_fstat. */
-
- int
-@@ -13037,8 +13079,6 @@ remote_target::fileio_fstat (int fd, struct stat *st, fileio_error *remote_errno
- int left = get_remote_packet_size ();
- int attachment_len, ret;
- const char *attachment;
-- struct fio_stat fst;
-- int read_len;
-
- remote_buffer_add_string (&p, &left, "vFile:fstat:");
-
-@@ -13070,19 +13110,41 @@ remote_target::fileio_fstat (int fd, struct stat *st, fileio_error *remote_errno
- return 0;
- }
-
-- read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
-- (gdb_byte *) &fst, sizeof (fst));
-+ return fileio_process_fstat_and_stat_reply (attachment, attachment_len,
-+ ret, st);
-+}
-
-- if (read_len != ret)
-- error (_("vFile:fstat returned %d, but %d bytes."), ret, read_len);
-+/* Implementation of to_fileio_stat. */
-
-- if (read_len != sizeof (fst))
-- error (_("vFile:fstat returned %d bytes, but expecting %d."),
-- read_len, (int) sizeof (fst));
-+int
-+remote_target::fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *st, fileio_error *remote_errno)
-+{
-+ struct remote_state *rs = get_remote_state ();
-+ char *p = rs->buf.data ();
-+ int left = get_remote_packet_size () - 1;
-
-- remote_fileio_to_host_stat (&fst, st);
-+ if (remote_hostio_set_filesystem (inf, remote_errno) != 0)
-+ return {};
-
-- return 0;
-+ remote_buffer_add_string (&p, &left, "vFile:stat:");
-+
-+ remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
-+ strlen (filename));
-+
-+ int attachment_len;
-+ const char *attachment;
-+ int ret = remote_hostio_send_command (p - rs->buf.data (), PACKET_vFile_stat,
-+ remote_errno, &attachment,
-+ &attachment_len);
-+
-+ /* Unlike ::fileio_fstat, the stat fileio call was added later on, and
-+ has none of the legacy bfd issues, so we can just return the error. */
-+ if (ret < 0)
-+ return ret;
-+
-+ return fileio_process_fstat_and_stat_reply (attachment, attachment_len,
-+ ret, st);
- }
-
- /* Implementation of to_filesystem_is_local. */
-@@ -16157,6 +16219,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
-
- add_packet_config_cmd (PACKET_vFile_fstat, "vFile:fstat", "hostio-fstat", 0);
-
-+ add_packet_config_cmd (PACKET_vFile_stat, "vFile:stat", "hostio-stat", 0);
-+
- add_packet_config_cmd (PACKET_vAttach, "vAttach", "attach", 0);
-
- add_packet_config_cmd (PACKET_vRun, "vRun", "run", 0);
-diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
---- a/gdb/solib-aix.c
-+++ b/gdb/solib-aix.c
-@@ -689,6 +689,11 @@ const solib_ops solib_aix_so_ops =
- solib_aix_open_symbol_file_object,
- solib_aix_in_dynsym_resolve_code,
- solib_aix_bfd_open,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ default_find_solib_addr,
- };
-
- void _initialize_solib_aix ();
-diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
---- a/gdb/solib-darwin.c
-+++ b/gdb/solib-darwin.c
-@@ -665,4 +665,9 @@ const solib_ops darwin_so_ops =
- open_symbol_file_object,
- darwin_in_dynsym_resolve_code,
- darwin_bfd_open,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ default_find_solib_addr,
- };
-diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
---- a/gdb/solib-dsbt.c
-+++ b/gdb/solib-dsbt.c
-@@ -914,6 +914,11 @@ const solib_ops dsbt_so_ops =
- open_symbol_file_object,
- dsbt_in_dynsym_resolve_code,
- solib_bfd_open,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ default_find_solib_addr,
- };
-
- void _initialize_dsbt_solib ();
-diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c
---- a/gdb/solib-frv.c
-+++ b/gdb/solib-frv.c
-@@ -1086,4 +1086,9 @@ const solib_ops frv_so_ops =
- open_symbol_file_object,
- frv_in_dynsym_resolve_code,
- solib_bfd_open,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ default_find_solib_addr,
- };
-diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
---- a/gdb/solib-svr4.c
-+++ b/gdb/solib-svr4.c
-@@ -3353,6 +3353,15 @@ svr4_iterate_over_objfiles_in_search_order
- }
- }
-
-+/* See solib_ops::find_solib_addr in solist.h. */
-+
-+static std::optional<CORE_ADDR>
-+svr4_find_solib_addr (solib &so)
-+{
-+ auto *li = gdb::checked_static_cast<lm_info_svr4 *> (so.lm_info.get ());
-+ return li->l_addr_inferior;
-+}
-+
- const struct solib_ops svr4_so_ops =
- {
- svr4_relocate_section_addresses,
-@@ -3363,11 +3372,11 @@ const struct solib_ops svr4_so_ops =
- open_symbol_file_object,
- svr4_in_dynsym_resolve_code,
- solib_bfd_open,
-- nullptr,
- svr4_same,
- svr4_keep_data_in_core,
- svr4_update_solib_event_breakpoints,
- svr4_handle_solib_event,
-+ svr4_find_solib_addr,
- };
-
- void _initialize_svr4_solib ();
-diff --git a/gdb/solib-target.c b/gdb/solib-target.c
---- a/gdb/solib-target.c
-+++ b/gdb/solib-target.c
-@@ -412,4 +412,9 @@ const solib_ops solib_target_so_ops =
- solib_target_open_symbol_file_object,
- solib_target_in_dynsym_resolve_code,
- solib_bfd_open,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ nullptr,
-+ default_find_solib_addr,
- };
-diff --git a/gdb/solib.c b/gdb/solib.c
---- a/gdb/solib.c
-+++ b/gdb/solib.c
-@@ -45,7 +45,6 @@
- #include "gdb_bfd.h"
- #include "gdbsupport/filestuff.h"
- #include "gdbsupport/scoped_fd.h"
--#include "debuginfod-support.h"
- #include "source.h"
- #include "cli/cli-style.h"
-
-@@ -113,7 +112,6 @@ show_solib_search_path (struct ui_file *file, int from_tty,
- static gdb::unique_xmalloc_ptr<char>
- solib_find_1 (const char *in_pathname, int *fd, bool is_solib)
- {
-- const solib_ops *ops = gdbarch_so_ops (current_inferior ()->arch ());
- int found_file = -1;
- gdb::unique_xmalloc_ptr<char> temp_pathname;
- const char *fskind = effective_target_file_system_kind ();
-@@ -296,12 +294,6 @@ solib_find_1 (const char *in_pathname, int *fd, bool is_solib)
- target_lbasename (fskind, in_pathname),
- O_RDONLY | O_BINARY, &temp_pathname);
-
-- /* If not found, and we're looking for a solib, try to use target
-- supplied solib search method. */
-- if (is_solib && found_file < 0 && ops->find_and_open_solib)
-- found_file = ops->find_and_open_solib (in_pathname, O_RDONLY | O_BINARY,
-- &temp_pathname);
--
- /* If not found, next search the inferior's $PATH environment variable. */
- if (found_file < 0 && sysroot == NULL)
- found_file = openp (current_inferior ()->environment.get ("PATH"),
-@@ -475,58 +467,6 @@ solib_bfd_open (const char *pathname)
- return abfd;
- }
-
--/* Mapping of a core file's shared library sonames to their respective
-- build-ids. Added to the registries of core file bfds. */
--
--typedef std::unordered_map<std::string, std::string> soname_build_id_map;
--
--/* Key used to associate a soname_build_id_map to a core file bfd. */
--
--static const struct registry<bfd>::key<soname_build_id_map>
-- cbfd_soname_build_id_data_key;
--
--/* See solib.h. */
--
--void
--set_cbfd_soname_build_id (gdb_bfd_ref_ptr abfd, const char *soname,
-- const bfd_build_id *build_id)
--{
-- gdb_assert (abfd.get () != nullptr);
-- gdb_assert (soname != nullptr);
-- gdb_assert (build_id != nullptr);
--
-- soname_build_id_map *mapptr
-- = cbfd_soname_build_id_data_key.get (abfd.get ());
--
-- if (mapptr == nullptr)
-- mapptr = cbfd_soname_build_id_data_key.emplace (abfd.get ());
--
-- (*mapptr)[soname] = build_id_to_string (build_id);
--}
--
--/* If SONAME had a build-id associated with it in ABFD's registry by a
-- previous call to set_cbfd_soname_build_id then return the build-id
-- as a NULL-terminated hex string. */
--
--static gdb::unique_xmalloc_ptr<char>
--get_cbfd_soname_build_id (gdb_bfd_ref_ptr abfd, const char *soname)
--{
-- if (abfd.get () == nullptr || soname == nullptr)
-- return {};
--
-- soname_build_id_map *mapptr
-- = cbfd_soname_build_id_data_key.get (abfd.get ());
--
-- if (mapptr == nullptr)
-- return {};
--
-- auto it = mapptr->find (lbasename (soname));
-- if (it == mapptr->end ())
-- return {};
--
-- return make_unique_xstrdup (it->second.c_str ());
--}
--
- /* Given a pointer to one of the shared objects in our list of mapped
- objects, use the recorded name to open a bfd descriptor for the
- object, build a section table, relocate all the section addresses
-@@ -546,36 +486,55 @@ solib_map_sections (solib &so)
-
- gdb::unique_xmalloc_ptr<char> filename (tilde_expand (so.so_name.c_str ()));
- gdb_bfd_ref_ptr abfd (ops->bfd_open (filename.get ()));
-- gdb::unique_xmalloc_ptr<char> build_id_hexstr
-- = get_cbfd_soname_build_id (current_program_space->cbfd,
-- so.so_name.c_str ());
-+
-+ /* If we have a core target then the core target might have some helpful
-+ information (i.e. build-ids) about the shared libraries we are trying
-+ to load. Grab those hints now and use the below to validate or find
-+ the shared libraries.
-+
-+ If we don't have a core target then this will return an empty struct
-+ with no hint information, we then lookup the shared library based on
-+ its filename. */
-+ std::optional<CORE_ADDR> solib_addr = ops->find_solib_addr (so);
-+ std::optional <const core_target_mapped_file_info> mapped_file_info
-+ = core_target_find_mapped_file (so.so_name.c_str (), solib_addr);
-
- /* If we already know the build-id of this solib from a core file, verify
- it matches ABFD's build-id. If there is a mismatch or the solib wasn't
- found, attempt to query debuginfod for the correct solib. */
-- if (build_id_hexstr.get () != nullptr)
-+ if (mapped_file_info.has_value ())
- {
-- bool mismatch = false;
-+ bool mismatch = (abfd != nullptr
-+ && build_id_bfd_get (abfd.get ()) != nullptr
-+ && !build_id_equal (mapped_file_info->build_id (),
-+ build_id_bfd_get (abfd.get ())));
-
-- if (abfd != nullptr && abfd->build_id != nullptr)
-- {
-- std::string build_id = build_id_to_string (abfd->build_id);
--
-- if (build_id != build_id_hexstr.get ())
-- mismatch = true;
-- }
- if (abfd == nullptr || mismatch)
- {
-- scoped_fd fd = debuginfod_exec_query (
-- (const unsigned char *) build_id_hexstr.get (), 0,
-- so.so_name.c_str (), &filename);
--
-- if (fd.get () >= 0)
-- abfd = ops->bfd_open (filename.get ());
-- else if (mismatch)
-- warning (_ ("Build-id of %ps does not match core file."),
-- styled_string (file_name_style.style (),
-- filename.get ()));
-+ /* If GDB found a suitable file during the file mapping
-+ processing stage then lets use that. We don't check the
-+ build-id after opening this file, either this file was found
-+ by build-id, in which case it's going to match, or this file
-+ doesn't have a build-id, so checking tells us nothing.
-+ However, if it was good enough during the mapped file
-+ processing, we assume it's good enough now. */
-+ if (!mapped_file_info->filename ().empty ())
-+ abfd = ops->bfd_open (mapped_file_info->filename ().c_str ());
-+ else
-+ abfd = nullptr;
-+
-+ if (abfd == nullptr)
-+ abfd = find_objfile_by_build_id (current_program_space,
-+ mapped_file_info->build_id (),
-+ so.so_name.c_str ());
-+
-+ if (abfd == nullptr && mismatch)
-+ {
-+ warning (_ ("Build-id of %ps does not match core file."),
-+ styled_string (file_name_style.style (),
-+ filename.get ()));
-+ abfd = nullptr;
-+ }
- }
- }
-
-@@ -1705,6 +1664,14 @@ remove_user_added_objfile (struct objfile *objfile)
- }
- }
-
-+/* See solist.h. */
-+
-+std::optional<CORE_ADDR>
-+default_find_solib_addr (solib &so)
-+{
-+ return {};
-+}
-+
- void _initialize_solib ();
-
- void
-diff --git a/gdb/solib.h b/gdb/solib.h
---- a/gdb/solib.h
-+++ b/gdb/solib.h
-@@ -136,11 +136,4 @@ extern void update_solib_breakpoints (void);
-
- extern void handle_solib_event (void);
-
--/* Associate SONAME with BUILD_ID in ABFD's registry so that it can be
-- retrieved with get_cbfd_soname_build_id. */
--
--extern void set_cbfd_soname_build_id (gdb_bfd_ref_ptr abfd,
-- const char *soname,
-- const bfd_build_id *build_id);
--
- #endif /* SOLIB_H */
-diff --git a/gdb/solist.h b/gdb/solist.h
---- a/gdb/solist.h
-+++ b/gdb/solist.h
-@@ -132,14 +132,6 @@ struct solib_ops
- /* Find and open shared library binary file. */
- gdb_bfd_ref_ptr (*bfd_open) (const char *pathname);
-
-- /* Optional extra hook for finding and opening a solib.
-- If TEMP_PATHNAME is non-NULL: If the file is successfully opened a
-- pointer to a malloc'd and realpath'd copy of SONAME is stored there,
-- otherwise NULL is stored there. */
-- int (*find_and_open_solib) (const char *soname,
-- unsigned o_flags,
-- gdb::unique_xmalloc_ptr<char> *temp_pathname);
--
- /* Given two so_list objects, one from the GDB thread list
- and another from the list returned by current_sos, return 1
- if they represent the same library.
-@@ -167,6 +159,23 @@ struct solib_ops
- NULL, in which case no specific preprocessing is necessary
- for this target. */
- void (*handle_event) (void);
-+
-+ /* Return an address within the inferior's address space which is known
-+ to be part of SO. If there is no such address, or GDB doesn't know
-+ how to figure out such an address then an empty optional is
-+ returned.
-+
-+ The returned address can be used when loading the shared libraries
-+ for a core file. GDB knows the build-ids for (some) files mapped
-+ into the inferior's address space, and knows the address ranges which
-+ those mapped files cover. If GDB can figure out a representative
-+ address for the library then this can be used to match a library to a
-+ mapped file, and thus to a build-id. GDB can then use this
-+ information to help locate the shared library objfile, if the objfile
-+ is not in the expected place (as defined by the shared libraries file
-+ name). */
-+
-+ std::optional<CORE_ADDR> (*find_solib_addr) (solib &so);
- };
-
- /* A unique pointer to a so_list. */
-@@ -186,4 +195,9 @@ extern gdb_bfd_ref_ptr solib_bfd_fopen (const char *pathname, int fd);
- /* Find solib binary file and open it. */
- extern gdb_bfd_ref_ptr solib_bfd_open (const char *in_pathname);
-
-+/* A default implementation of the solib_ops::find_solib_addr callback.
-+ This just returns an empty std::optional<CORE_ADDR> indicating GDB is
-+ unable to find an address within the library SO. */
-+extern std::optional<CORE_ADDR> default_find_solib_addr (solib &so);
-+
- #endif
-diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
---- a/gdb/symfile-debug.c
-+++ b/gdb/symfile-debug.c
-@@ -637,7 +637,7 @@ objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
- the user a system specific message that guides them to finding
- the missing debug info. */
-
-- ext_lang_missing_debuginfo_result ext_result
-+ ext_lang_missing_file_result ext_result
- = ext_lang_handle_missing_debuginfo (this);
- if (!ext_result.filename ().empty ())
- {
-diff --git a/gdb/symfile.c b/gdb/symfile.c
---- a/gdb/symfile.c
-+++ b/gdb/symfile.c
-@@ -1237,6 +1237,8 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
- struct objfile *parent_objfile,
- deferred_warnings *warnings)
- {
-+ SEPARATE_DEBUG_FILE_SCOPED_DEBUG_ENTER_EXIT;
-+
- unsigned long file_crc;
- int file_crc_p;
- struct stat parent_stat, abfd_stat;
-@@ -1251,19 +1253,13 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
- if (filename_cmp (name.c_str (), objfile_name (parent_objfile)) == 0)
- return 0;
-
-- if (separate_debug_file_debug)
-- {
-- gdb_printf (gdb_stdlog, _(" Trying %s..."), name.c_str ());
-- gdb_flush (gdb_stdlog);
-- }
-+ separate_debug_file_debug_printf ("Trying %s...", name.c_str ());
-
- gdb_bfd_ref_ptr abfd (gdb_bfd_open (name.c_str (), gnutarget));
-
- if (abfd == NULL)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" no, unable to open.\n"));
--
-+ separate_debug_file_debug_printf ("unable to open file");
- return 0;
- }
-
-@@ -1285,10 +1281,7 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
- if (abfd_stat.st_dev == parent_stat.st_dev
- && abfd_stat.st_ino == parent_stat.st_ino)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog,
-- _(" no, same file as the objfile.\n"));
--
-+ separate_debug_file_debug_printf ("same file as the objfile");
- return 0;
- }
- verified_as_different = 1;
-@@ -1300,9 +1293,7 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
-
- if (!file_crc_p)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" no, error computing CRC.\n"));
--
-+ separate_debug_file_debug_printf ("error computing CRC");
- return 0;
- }
-
-@@ -1318,20 +1309,18 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
- {
- if (!gdb_bfd_crc (parent_objfile->obfd.get (), &parent_crc))
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog,
-- _(" no, error computing CRC.\n"));
--
-+ separate_debug_file_debug_printf ("error computing CRC");
- return 0;
- }
- }
-
- if (verified_as_different || parent_crc != file_crc)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, "the debug information found in \"%s\""
-- " does not match \"%s\" (CRC mismatch).\n",
-- name.c_str (), objfile_name (parent_objfile));
-+ separate_debug_file_debug_printf
-+ ("the debug information found in \"%s\" does not match "
-+ "\"%s\" (CRC mismatch).", name.c_str (),
-+ objfile_name (parent_objfile));
-+
- warnings->warn (_("the debug information found in \"%ps\""
- " does not match \"%ps\" (CRC mismatch)."),
- styled_string (file_name_style.style (),
-@@ -1343,8 +1332,7 @@ separate_debug_file_exists (const std::string &name, unsigned long crc,
- return 0;
- }
-
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog, _(" yes!\n"));
-+ separate_debug_file_debug_printf ("found a match");
-
- return 1;
- }
-@@ -1385,23 +1373,18 @@ find_separate_debug_file (const char *dir,
- unsigned long crc32, struct objfile *objfile,
- deferred_warnings *warnings)
- {
-- if (separate_debug_file_debug)
-- gdb_printf (gdb_stdlog,
-- _("\nLooking for separate debug info (debug link) for "
-- "%s\n"), objfile_name (objfile));
-+ SEPARATE_DEBUG_FILE_SCOPED_DEBUG_START_END
-+ ("looking for separate debug info (debug link) for %s",
-+ objfile_name (objfile));
-
- /* First try in the same directory as the original file. */
-- std::string debugfile = dir;
-- debugfile += debuglink;
-+ std::string debugfile = path_join (dir, debuglink);
-
- if (separate_debug_file_exists (debugfile, crc32, objfile, warnings))
- return debugfile;
-
- /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */
-- debugfile = dir;
-- debugfile += DEBUG_SUBDIRECTORY;
-- debugfile += "/";
-- debugfile += debuglink;
-+ debugfile = path_join (dir, DEBUG_SUBDIRECTORY, debuglink);
-
- if (separate_debug_file_exists (debugfile, crc32, objfile, warnings))
- return debugfile;
-@@ -1414,10 +1397,13 @@ find_separate_debug_file (const char *dir,
- bool target_prefix = is_target_filename (dir);
- const char *dir_notarget
- = target_prefix ? dir + strlen (TARGET_SYSROOT_PREFIX) : dir;
-+ const char *target_prefix_str = target_prefix ? TARGET_SYSROOT_PREFIX : "";
- std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
- = dirnames_to_char_ptr_vec (debug_file_directory.c_str ());
-- gdb::unique_xmalloc_ptr<char> canon_sysroot
-- = gdb_realpath (gdb_sysroot.c_str ());
-+ const char *sysroot_str = gdb_sysroot.c_str ();
-+ if (is_target_filename (sysroot_str) && target_filesystem_is_local ())
-+ sysroot_str += strlen (TARGET_SYSROOT_PREFIX);
-+ gdb::unique_xmalloc_ptr<char> canon_sysroot = gdb_realpath (sysroot_str);
-
- /* MS-Windows/MS-DOS don't allow colons in file names; we must
- convert the drive letter into a one-letter directory, so that the
-@@ -1442,12 +1428,8 @@ find_separate_debug_file (const char *dir,
-
- for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
- {
-- debugfile = target_prefix ? TARGET_SYSROOT_PREFIX : "";
-- debugfile += debugdir;
-- debugfile += "/";
-- debugfile += drive;
-- debugfile += dir_notarget;
-- debugfile += debuglink;
-+ debugfile = path_join (target_prefix_str, debugdir.get (),
-+ drive.c_str (), dir_notarget, debuglink);
-
- if (separate_debug_file_exists (debugfile, crc32, objfile, warnings))
- return debugfile;
-@@ -1464,39 +1446,18 @@ find_separate_debug_file (const char *dir,
- {
- /* If the file is in the sysroot, try using its base path in
- the global debugfile directory. */
-- debugfile = target_prefix ? TARGET_SYSROOT_PREFIX : "";
-- debugfile += debugdir;
-- debugfile += "/";
-- debugfile += base_path;
-- debugfile += "/";
-- debugfile += debuglink;
-+ debugfile = path_join (target_prefix_str, debugdir.get (),
-+ base_path, debuglink);
-
- if (separate_debug_file_exists (debugfile, crc32, objfile, warnings))
- return debugfile;
-
- /* If the file is in the sysroot, try using its base path in
-- the sysroot's global debugfile directory. GDB_SYSROOT
-- might refer to a target: path; we strip the "target:"
-- prefix -- but if that would yield the empty string, we
-- don't bother at all, because that would just give the
-- same result as above. */
-+ the sysroot's global debugfile directory. */
- if (gdb_sysroot != TARGET_SYSROOT_PREFIX)
- {
-- debugfile = target_prefix ? TARGET_SYSROOT_PREFIX : "";
-- if (is_target_filename (gdb_sysroot))
-- {
-- std::string root
-- = gdb_sysroot.substr (strlen (TARGET_SYSROOT_PREFIX));
-- gdb_assert (!root.empty ());
-- debugfile += root;
-- }
-- else
-- debugfile += gdb_sysroot;
-- debugfile += debugdir;
-- debugfile += "/";
-- debugfile += base_path;
-- debugfile += "/";
-- debugfile += debuglink;
-+ debugfile = path_join (gdb_sysroot.c_str (), debugdir.get (),
-+ base_path, debuglink);
-
- if (separate_debug_file_exists (debugfile, crc32, objfile,
- warnings))
-diff --git a/gdb/symfile.h b/gdb/symfile.h
---- a/gdb/symfile.h
-+++ b/gdb/symfile.h
-@@ -371,6 +371,25 @@ extern gdb_bfd_ref_ptr find_separate_debug_file_in_section (struct objfile *);
-
- extern bool separate_debug_file_debug;
-
-+/* Print a "separate-debug-file" debug statement. */
-+
-+#define separate_debug_file_debug_printf(fmt, ...) \
-+ debug_prefixed_printf_cond (separate_debug_file_debug, \
-+ "separate-debug-file", \
-+ fmt, ##__VA_ARGS__)
-+
-+/* Print "separate-debug-file" enter/exit debug statements. */
-+
-+#define SEPARATE_DEBUG_FILE_SCOPED_DEBUG_ENTER_EXIT \
-+ scoped_debug_enter_exit (separate_debug_file_debug, \
-+ "separate-debug-file")
-+
-+/* Print "separate-debug-file" start/end debug statements. */
-+
-+#define SEPARATE_DEBUG_FILE_SCOPED_DEBUG_START_END(fmt, ...) \
-+ scoped_debug_start_end (separate_debug_file_debug, \
-+ "separate-debug-file", fmt, ##__VA_ARGS__)
-+
- /* Read full symbols immediately. */
-
- extern int readnow_symbol_files;
-diff --git a/gdb/target.c b/gdb/target.c
---- a/gdb/target.c
-+++ b/gdb/target.c
-@@ -3196,6 +3196,14 @@ target_ops::fileio_fstat (int fd, struct stat *sb, fileio_error *target_errno)
- return -1;
- }
-
-+int
-+target_ops::fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno)
-+{
-+ *target_errno = FILEIO_ENOSYS;
-+ return -1;
-+}
-+
- int
- target_ops::fileio_close (int fd, fileio_error *target_errno)
- {
-@@ -3315,6 +3323,29 @@ target_fileio_fstat (int fd, struct stat *sb, fileio_error *target_errno)
-
- /* See target.h. */
-
-+int
-+target_fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno)
-+{
-+ for (target_ops *t = default_fileio_target (); t != NULL; t = t->beneath ())
-+ {
-+ int ret = t->fileio_stat (inf, filename, sb, target_errno);
-+
-+ if (ret == -1 && *target_errno == FILEIO_ENOSYS)
-+ continue;
-+
-+ target_debug_printf_nofunc ("target_fileio_stat (%s) = %d (%d)",
-+ filename, ret,
-+ ret != -1 ? 0 : *target_errno);
-+ return ret;
-+ }
-+
-+ *target_errno = FILEIO_ENOSYS;
-+ return -1;
-+}
-+
-+/* See target.h. */
-+
- int
- target_fileio_close (int fd, fileio_error *target_errno)
- {
-diff --git a/gdb/target.h b/gdb/target.h
---- a/gdb/target.h
-+++ b/gdb/target.h
-@@ -1011,6 +1011,14 @@ struct target_ops
- *TARGET_ERRNO). */
- virtual int fileio_fstat (int fd, struct stat *sb, fileio_error *target_errno);
-
-+ /* Get information about the file FILENAME and put it in SB. Look for
-+ FILENAME in the filesystem as seen by INF. If INF is NULL, use the
-+ filesystem seen by the debugger (GDB or, for remote targets, the
-+ remote stub). Return 0 on success, or -1 if an error occurs (and
-+ set *TARGET_ERRNO). */
-+ virtual int fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno);
-+
- /* Close FD on the target. Return 0, or -1 if an error occurs
- (and set *TARGET_ERRNO). */
- virtual int fileio_close (int fd, fileio_error *target_errno);
-@@ -2220,6 +2228,14 @@ extern int target_fileio_pread (int fd, gdb_byte *read_buf, int len,
- extern int target_fileio_fstat (int fd, struct stat *sb,
- fileio_error *target_errno);
-
-+/* Get information about the file at FILENAME on the target and put it in
-+ SB. Look in the filesystem as seen by INF. If INF is NULL, use the
-+ filesystem seen by the debugger (GDB or, for remote targets, the remote
-+ stub). Return 0 on success, or -1 if an error occurs (and set
-+ *TARGET_ERRNO). */
-+extern int target_fileio_stat (struct inferior *inf, const char *filename,
-+ struct stat *sb, fileio_error *target_errno);
-+
- /* Close FD on the target. Return 0, or -1 if an error occurs
- (and set *TARGET_ERRNO). */
- extern int target_fileio_close (int fd, fileio_error *target_errno);
-diff --git a/gdb/testsuite/gdb.base/build-id-seqno.c b/gdb/testsuite/gdb.base/build-id-seqno.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/build-id-seqno.c
-@@ -0,0 +1,22 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+int
-+main (void)
-+{
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/build-id-seqno.exp b/gdb/testsuite/gdb.base/build-id-seqno.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/build-id-seqno.exp
-@@ -0,0 +1,133 @@
-+# This testcase is part of GDB, the GNU debugger.
-+#
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+# Setup a .build-id/ based debug directory containing multiple entries
-+# for the same build-id, with each entry given a different sequence
-+# number.
-+#
-+# Ensure that GDB will scan over broken symlinks for the same build-id
-+# (but different sequence number) to find later working symlinks.
-+#
-+# This test only places debug information on the host, so it is always
-+# local to GDB.
-+
-+require {!is_remote host}
-+
-+standard_testfile
-+
-+if {[build_executable "failed to prepare" $testfile $srcfile] == -1} {
-+ return -1
-+}
-+
-+# Split out BINFILE.debug. Remove debug from BINFILE.
-+if {[gdb_gnu_strip_debug $binfile] != 0} {
-+ return -1
-+}
-+
-+# Get the '.build-id/xx/xxx...xxx' part of the filename.
-+set build_id_filename [build_id_debug_filename_get $binfile]
-+
-+# Hide (rename) BINFILE.debug, this should ensure GDB can't find it
-+# directly but needs to look for the build-id based file in the debug
-+# directory.
-+set hidden_debuginfo [standard_output_file "hidden_$testfile.debug"]
-+remote_exec build "mv ${binfile}.debug $hidden_debuginfo"
-+
-+# A filename that doesn't exist. Some symlinks will point at this
-+# file.
-+set missing_debuginfo [host_standard_output_file "missing_debuginfo"]
-+
-+# Create the debug directory, and the .build-id directory structure
-+# within it.
-+set debugdir [host_standard_output_file "debug"]
-+remote_exec host "mkdir -p $debugdir/[file dirname $build_id_filename]"
-+
-+set host_hidden_debuginfo [gdb_remote_download host $hidden_debuginfo]
-+remote_exec host "ln -fs $host_hidden_debuginfo $debugdir/$build_id_filename"
-+
-+# Start GDB and load global BINFILE. If FIND_DEBUGINFO is true then
-+# we expect GDB to find the debug information matching BINFILE,
-+# otherwise, we expect GDB not to find the debug information.
-+proc load_binfile_check_debug_is_found { find_debuginfo testname } {
-+ with_test_prefix "$testname" {
-+ clean_restart
-+
-+ gdb_test_no_output "set debug-file-directory $::debugdir" \
-+ "set debug-file-directory"
-+
-+ gdb_file_cmd $::binfile
-+
-+ if { $find_debuginfo } {
-+ gdb_assert { [regexp [string_to_regexp \
-+ "Reading symbols from $::hidden_debuginfo..."] \
-+ $::gdb_file_cmd_msg] } \
-+ "debuginfo was read via build-id"
-+ } else {
-+ gdb_assert { [regexp "\\(No debugging symbols found in \[^\r\n\]+/$::testfile\\)" \
-+ $::gdb_file_cmd_msg] } \
-+ }
-+ }
-+}
-+
-+# Return a copy of FILENAME, which should end '.debug', with NUMBER
-+# added, e.g. add_seqno 1 "foo.debug" --> "foo.1.debug".
-+proc add_seqno { number filename } {
-+ return [regsub "\.debug\$" $filename ".${number}.debug"]
-+}
-+
-+load_binfile_check_debug_is_found true \
-+ "find debuginfo with a single build-id file"
-+
-+remote_exec host "ln -fs $host_hidden_debuginfo \
-+ $debugdir/[add_seqno 1 $build_id_filename]"
-+remote_exec host "ln -fs $host_hidden_debuginfo \
-+ $debugdir/[add_seqno 2 $build_id_filename]"
-+remote_exec host "ln -fs $host_hidden_debuginfo \
-+ $debugdir/[add_seqno 3 $build_id_filename]"
-+
-+load_binfile_check_debug_is_found true \
-+ "find debuginfo with 4 build-id files"
-+
-+remote_exec host "ln -fs $missing_debuginfo $debugdir/$build_id_filename"
-+
-+load_binfile_check_debug_is_found true \
-+ "find debuginfo, first build-id file is bad"
-+
-+remote_exec host "ln -fs $missing_debuginfo \
-+ $debugdir/[add_seqno 1 $build_id_filename]"
-+remote_exec host "ln -fs $missing_debuginfo \
-+ $debugdir/[add_seqno 3 $build_id_filename]"
-+
-+load_binfile_check_debug_is_found true \
-+ "find debuginfo, first 2 build-id files are bad"
-+
-+remote_exec host "ln -fs $missing_debuginfo \
-+ $debugdir/[add_seqno 2 $build_id_filename]"
-+
-+load_binfile_check_debug_is_found false \
-+ "cannot find debuginfo, all build-id files are bad"
-+
-+remote_exec host "ln -fs $host_hidden_debuginfo \
-+ $debugdir/[add_seqno 3 $build_id_filename]"
-+
-+load_binfile_check_debug_is_found true \
-+ "find debuginfo, last build-id file is good"
-+
-+remote_exec host "rm -f $debugdir/[add_seqno 1 $build_id_filename]"
-+
-+load_binfile_check_debug_is_found false \
-+ "cannot find debuginfo, file with seqno 1 is missing"
-diff --git a/gdb/testsuite/gdb.base/corefile-buildid.exp b/gdb/testsuite/gdb.base/corefile-buildid.exp
---- a/gdb/testsuite/gdb.base/corefile-buildid.exp
-+++ b/gdb/testsuite/gdb.base/corefile-buildid.exp
-@@ -172,11 +172,9 @@ proc locate_exec_from_core_build_id {corefile buildid suffix \
- "mkdir -p [file join $debugdir [file dirname $buildid]]"
-
- set files_list {}
-+ lappend files_list $binfile $buildid
- if {$sepdebug} {
-- lappend files_list "$binfile.stripped" $buildid
- lappend files_list "$binfile.debug" "$buildid.debug"
-- } else {
-- lappend files_list $binfile $buildid
- }
- if {$shared} {
- global sharedir
-@@ -200,12 +198,7 @@ proc locate_exec_from_core_build_id {corefile buildid suffix \
- gdb_test "core-file $corefile" "Program terminated with .*" \
- "load core file"
- if {$symlink} {
-- if {$sepdebug} {
-- set expected_file [file join $builddir \
-- [file tail "$binfile.stripped"]]
-- } else {
-- set expected_file [file join $builddir [file tail $binfile]]
-- }
-+ set expected_file [file join $builddir [file tail $binfile]]
- } else {
- set expected_file $buildid
- }
-@@ -245,15 +238,12 @@ proc do_corefile_buildid_tests {args} {
-
- if {$sepdebug} {
- # Strip debuginfo into its own file.
-- if {[gdb_gnu_strip_debug [standard_output_file $program_to_run]] \
-- != 0} {
-+ if {[gdb_gnu_strip_debug [standard_output_file $program_to_run] \
-+ no-debuglink] != 0} {
- untested "could not strip executable for [join $suffix \ ]"
- return
- }
-
-- # Run the stripped program instead of the original.
-- set program_to_run [file join $builddir \
-- [file tail "$binfile.stripped"]]
- lappend suffix "sepdebug"
- }
-
-diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
---- a/gdb/testsuite/gdb.base/corefile.exp
-+++ b/gdb/testsuite/gdb.base/corefile.exp
-@@ -199,6 +199,45 @@ gdb_test "up" "#\[0-9\]* *(\[0-9xa-fH'\]* in)? .* \\(.*\\).*" "up (reinit)"
-
- gdb_test "core" "No core file now."
-
-+# Temporarily move coremmap.data out of the way and reload the core
-+# file. We should still be able to read buf2 as the contents of this
-+# are written into the core file. In contrast buf2ro should no longer
-+# be readable as the contents of this region are not within the core
-+# file, GDB relies on reading this from the coremmap.data file, which
-+# can no longer be found.
-+set coremmap_data_filename \
-+ [standard_output_file coredir.[getpid]/coremmap.data]
-+set coremmap_data_backup_filename \
-+ [standard_output_file coredir.[getpid]/coremmap.data.backup]
-+remote_exec host "mv ${coremmap_data_filename} \
-+ ${coremmap_data_backup_filename}"
-+
-+clean_restart $binfile
-+
-+# Load the core file and check we get a warning about the
-+# coremmap.data file being missing.
-+gdb_test_multiple "core-file $corefile" "warn about coremmap.data missing" {
-+ -re -wrap "warning: Can't open file \[^\r\n\]+/coremmap.data during file-backed mapping note processing\r\n.*" {
-+ pass $gdb_test_name
-+ }
-+}
-+
-+# This xfail was just copied from earlier in the script where we also
-+# read from buf2.
-+setup_xfail "*-*-sunos*" "*-*-aix*"
-+gdb_test "x/8bd buf2" \
-+ ".*:.*0.*1.*2.*3.*4.*5.*6.*7.*" \
-+ "accessing mmapped data in core file with coremmap.data removed"
-+
-+gdb_test "x/8bd buf2ro" \
-+ "$hex\[^:\]*:\\s+Cannot access memory at address $hex" \
-+ "accessing read-only mmapped data in core file with coremmap.data removed"
-+
-+# Restore the coremmap.data file so later tests don't give warnings
-+# when the core file is reloaded.
-+remote_exec host "mv ${coremmap_data_backup_filename} \
-+ ${coremmap_data_filename}"
-+
- # Test that we can unload the core with the "detach" command.
-
- proc_with_prefix corefile_detach {} {
-diff --git a/gdb/testsuite/gdb.base/solib-search.exp b/gdb/testsuite/gdb.base/solib-search.exp
---- a/gdb/testsuite/gdb.base/solib-search.exp
-+++ b/gdb/testsuite/gdb.base/solib-search.exp
-@@ -43,7 +43,11 @@ set right_binfile2_lib \
- set binfile1_lib [standard_output_file ${libname1}.so]
- set binfile2_lib [standard_output_file ${libname2}.so]
-
--set lib_flags [list debug ldflags=-Wl,-Bsymbolic]
-+# When this test was written, GDB's ability to track down shared
-+# libraries for a core file based on the build-id much poorer. As GDB
-+# has improved we now need to disable build-ids in order for this test
-+# to function as expected.
-+set lib_flags [list debug no-build-id ldflags=-Wl,-Bsymbolic]
- set wrong_lib_flags "$lib_flags additional_flags=-DARRAY_SIZE=1"
- set right_lib_flags "$lib_flags additional_flags=-DARRAY_SIZE=8192 additional_flags=-DRIGHT"
-
-diff --git a/gdb/testsuite/gdb.base/sysroot-debug-lookup.exp b/gdb/testsuite/gdb.base/sysroot-debug-lookup.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/sysroot-debug-lookup.exp
-@@ -0,0 +1,184 @@
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+# Test GDB's ability to find debug information by looking within the
-+# sysroot.
-+#
-+# We compile a static binary (to reduce what we need to copy into the
-+# sysroot), split the debug information from the binary, and setup a
-+# sysroot.
-+#
-+# The debug-file-directory is set to just '/debug', but we're
-+# expecting GDB to actually look in '$SYSROOT/debug'.
-+#
-+# There's a test for using .build-id based lookup, and a test for
-+# gnu_debuglink based lookup.
-+
-+require {!is_remote host}
-+
-+standard_testfile main.c
-+
-+# Create a copy of BINFILE, split out the debug information, and then
-+# setup a sysroot. Hide (by moving) the actual debug information file
-+# and create a symlink to the hidden debug information from within the
-+# sysroot.
-+#
-+# Start GDB, set the sysroot, and then load the executable, ensure GDB
-+# finds the debug information, which must have happened by lookin in
-+# the sysroot.
-+proc_with_prefix lookup_via_build_id {} {
-+ set filename ${::binfile}_1
-+ if { [build_executable "build exec" ${filename} $::srcfile \
-+ {additional_flags=-static debug build-id}] } {
-+ return
-+ }
-+
-+ # Split debug information into a .debug file, remove debug
-+ # information from FILENAME. Don't add a .gnu_debuglink to
-+ # FILENAME, we rely on the build-id.
-+ if {[gdb_gnu_strip_debug $filename { no-debuglink }] != 0} {
-+ unsupported "cannot split debug information from executable"
-+ return
-+ }
-+
-+ set sysroot [standard_output_file "sysroot1"]
-+ set debug_dir "/debug"
-+
-+ set debug_symlink \
-+ ${sysroot}${debug_dir}/[build_id_debug_filename_get $filename]
-+
-+ set build_id_dir [file dirname $debug_symlink]
-+
-+ set debug_filename ${filename}_hidden_debug
-+
-+ remote_exec build "mkdir -p $build_id_dir"
-+ remote_exec build "mv $filename.debug $debug_filename"
-+ remote_exec build "ln -sf $debug_filename $debug_symlink"
-+
-+ foreach_with_prefix sysroot_prefix { "" "target:" } {
-+ clean_restart
-+
-+ gdb_test_no_output "set sysroot ${sysroot_prefix}$sysroot" "set sysroot"
-+ gdb_test_no_output "set debug-file-directory $debug_dir"
-+
-+ gdb_file_cmd $filename
-+
-+ gdb_assert { $::gdb_file_cmd_debug_info eq "debug" } \
-+ "ensure debug information was found"
-+
-+ if { $sysroot_prefix eq "target:"
-+ && [target_info gdb_protocol] == "extended-remote"} {
-+ # Only when using the extended-remote board will we have
-+ # started a remote target by this point. In this case GDB
-+ # will see the 'target:' prefix as remote, and so the
-+ # reported filename will include the 'target:' prefix.
-+ #
-+ # In all other cases we will still be using the default,
-+ # initial target, in which case GDB considers the
-+ # 'target:' prefix to indicate the local filesystem.
-+ set lookup_filename $sysroot_prefix$debug_symlink
-+ } else {
-+ set lookup_filename $debug_filename
-+ }
-+ set re [string_to_regexp "Reading symbols from $lookup_filename..."]
-+ gdb_assert {[regexp $re $::gdb_file_cmd_msg]} \
-+ "debug symbols read from correct file"
-+ }
-+}
-+
-+# Create a copy of BINFILE, split out the debug information, and then
-+# setup a sysroot. Hide (by moving) the actual debug information file
-+# and create a symlink to the hidden debug information from within the
-+# sysroot.
-+#
-+# Copy the executable into the sysroot and then start GDB, set the
-+# sysroot, and load the executable. Check that GDB finds the debug
-+# information, which must have happened by lookin in the sysroot.
-+proc_with_prefix lookup_via_debuglink {} {
-+ set filename ${::binfile}_2
-+ if { [build_executable "build exec" ${filename} $::srcfile \
-+ {additional_flags=-static debug no-build-id}] } {
-+ return
-+ }
-+
-+ # Split debug information into a .debug file, remove debug
-+ # information from FILENAME.
-+ if {[gdb_gnu_strip_debug $filename] != 0} {
-+ unsupported "cannot split debug information from executable"
-+ return
-+ }
-+
-+ # We're going to setup the sysroot like this:
-+ #
-+ # sysroot2/
-+ # bin/
-+ # $FILENAME
-+ # debug/
-+ # bin/
-+ # $FILENAME.debug
-+ #
-+ # When looking up debug information via the debuglink, GDB will
-+ # only search in the sysroot if the original objfile was in the
-+ # sysroot. And GDB will resolve symlinks, so if the objfile is
-+ # symlinked to outside the sysroot, GDB will not search in the
-+ # sysroot for the debug information.
-+ #
-+ # So we have to copy the executable into the sysroot.
-+ #
-+ # We are OK to symlink the debug information to a file outside the
-+ # sysroot though.
-+
-+ set sysroot [standard_output_file "sysroot2"]
-+
-+ foreach path { bin debug/bin } {
-+ remote_exec build "mkdir -p $sysroot/$path"
-+ }
-+
-+ # Copy the executable into the sysroot.
-+ set file_basename [file tail $filename]
-+ set exec_in_sysroot ${sysroot}/bin/${file_basename}
-+ remote_exec build "cp $filename $exec_in_sysroot"
-+
-+ # Rename the debug file outside of the sysroot, this should stop
-+ # GDB finding this file "by accident".
-+ set debug_filename ${filename}_hidden_debug
-+ remote_exec build "mv $filename.debug $debug_filename"
-+
-+ # Symlink the debug information into the sysroot.
-+ set debug_symlink \
-+ ${sysroot}/debug/bin/${file_basename}.debug
-+ remote_exec build "ln -sf $debug_filename $debug_symlink"
-+
-+ foreach_with_prefix sysroot_prefix { "" "target:" } {
-+ # Restart GDB and setup the sysroot and debug directory.
-+ clean_restart
-+ gdb_test_no_output "set sysroot ${sysroot_prefix}$sysroot" "set sysroot"
-+ gdb_test_no_output "set debug-file-directory /debug"
-+
-+ # Load the executable, we expect GDB to find the debug information
-+ # in the sysroot.
-+ gdb_file_cmd ${sysroot_prefix}$exec_in_sysroot
-+
-+ gdb_assert { $::gdb_file_cmd_debug_info eq "debug" } \
-+ "ensure debug information was found"
-+
-+ set re [string_to_regexp "Reading symbols from ${sysroot_prefix}$debug_symlink..."]
-+ gdb_assert {[regexp $re $::gdb_file_cmd_msg]} \
-+ "debug symbols read from correct file"
-+ }
-+}
-+
-+lookup_via_build_id
-+lookup_via_debuglink
-diff --git a/gdb/testsuite/gdb.debuginfod/build-id-no-debug-warning.exp b/gdb/testsuite/gdb.debuginfod/build-id-no-debug-warning.exp
---- a/gdb/testsuite/gdb.debuginfod/build-id-no-debug-warning.exp
-+++ b/gdb/testsuite/gdb.debuginfod/build-id-no-debug-warning.exp
-@@ -30,14 +30,11 @@ if {[build_executable "build executable" ${testfile} ${srcfile} \
- return -1
- }
-
--# Split BINFILE into BINFILE.stripped and BINFILE.debug, the first is
--# the executable with the debug information removed, and the second is
--# the debug information.
-+# Split debug information from BINFILE into BINFILE.debug.
- #
--# However, by passing the "no-debuglink" flag we prevent this proc
--# from adding a .gnu_debuglink section to the executable. Any lookup
--# of the debug information by GDB will need to be done based on the
--# build-id.
-+# By passing the "no-debuglink" flag we prevent this proc from adding
-+# a .gnu_debuglink section to BINFILE. Any lookup of the debug
-+# information by GDB will need to be done based on the build-id.
- if {[gdb_gnu_strip_debug $binfile no-debuglink]} {
- unsupported "cannot produce separate debug info files"
- return -1
-@@ -59,12 +56,6 @@ set debuginfod_debugdir [standard_output_file "debug"]
- remote_exec build "mkdir $debuginfod_debugdir"
- remote_exec build "mv $debugfile $debuginfod_debugdir"
-
--# This is BINFILE with the debug information removed. We are going to
--# place this in the BUILD_ID_DEBUG_FILE location, this would usually
--# represent a mistake by the user, and will trigger a warning from
--# GDB, this is the warning we are checking for.
--set stripped_binfile [standard_output_file "${binfile}.stripped"]
--
- # Create the .build-id/PREFIX directory name from
- # .build-id/PREFIX/SUFFIX.debug filename.
- set debugdir [file dirname ${build_id_debug_file}]
-@@ -76,7 +67,7 @@ remote_exec build "mkdir -p $debugdir"
- # information, which will point back at this file, which also doesn't
- # have debug information, which could cause a loop. But GDB will spot
- # this and give a warning.
--remote_exec build "mv ${stripped_binfile} ${build_id_debug_file}"
-+remote_exec build "mv ${binfile} ${build_id_debug_file}"
-
- # Now start GDB.
- clean_restart
-diff --git a/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-1.c b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-1.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-1.c
-@@ -0,0 +1,24 @@
-+/* Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+/* This is in the shared library. */
-+extern int foo (void);
-+
-+int
-+main (void)
-+{
-+ int res = foo ();
-+ return res;
-+}
-diff --git a/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-2.c b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-2.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-2.c
-@@ -0,0 +1,22 @@
-+/* Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+volatile int *library_ptr = (int *) POINTER_VALUE;
-+
-+int
-+foo (void)
-+{
-+ return *library_ptr;
-+}
-diff --git a/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-3.c b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-3.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file-3.c
-@@ -0,0 +1,45 @@
-+/* Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <unistd.h>
-+#include <sys/mman.h>
-+
-+volatile void* library_base_address = 0;
-+volatile int *ptr = 0;
-+
-+int
-+main ()
-+{
-+ struct stat buf;
-+ int res;
-+
-+ int fd = open (SHLIB_FILENAME, O_RDONLY);
-+ assert (fd != -1);
-+
-+ res = fstat (fd, &buf);
-+ assert (res == 0);
-+
-+ library_base_address
-+ = mmap (NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-+
-+ res = *ptr; /* Undefined behaviour here. */
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.debuginfod/corefile-mapped-file.exp b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/corefile-mapped-file.exp
-@@ -0,0 +1,380 @@
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+# This test checks GDB's ability to use build-ids when setting up file backed
-+# mappings as part of reading a core-file.
-+#
-+# A core-file contains a list of the files that were mapped into the process
-+# at the time of the core-file creation. If the file was mapped read-only
-+# then the file contents will not be present in the core-file, but instead GDB
-+# is expected to open the mapped file and read the contents from there if
-+# needed. And this is what GDB does.
-+#
-+# GDB (via the BFD library) will also spot if a mapped looks like a valid ELF
-+# and contains a build-id, this build-id is passed back to GDB so that GDB can
-+# validate the on-disk file it finds matches the file that was mapped when the
-+# core-file was created.
-+#
-+# In addition, if the on-disk file is found to have a non-matching build-id
-+# then GDB can use debuginfod to (try) and download a suitable file.
-+#
-+# This test is about checking that this file backed mapping mechanism works
-+# correctly; that GDB will spot when the build-ids fail to match and will
-+# refuse to load an incorrect file. Additionally we check that the correct
-+# file can be downloaded from debuginfod.
-+#
-+# The test is rather contrived though. Instead of relying on having a shared
-+# library mapped at the time of crash we mmap a shared library into the
-+# process and then check this mapping within the test.
-+#
-+# The problem with using a normal shared library load for this test is that
-+# the shared library list is processed as part of a separate step when opening
-+# the core file. Right now this separate step doesn't check the build-ids
-+# correctly, so GDB will potentially open the wrong shared library file. The
-+# sections of this incorrect shared library are then added to GDB's list of
-+# target sections, and are used to satisfy memory reads, which can give the
-+# wrong results.
-+#
-+# This obviously needs fixing, but is a separate problem from the one being
-+# tested here, so this test deliberately checks the mapping using a file that
-+# is mmaped rather than loaded as a shared library, as such the file is in the
-+# core-files list of mapped files, but is not in the shared library list.
-+#
-+# Despite this test living in the gdb.debuginfod/ directory, only the last
-+# part of this test actually uses debuginfod, everything up to that point is
-+# pretty generic.
-+
-+require {!is_remote host}
-+require {!is_remote target}
-+
-+load_lib debuginfod-support.exp
-+
-+require allow_shlib_tests
-+
-+standard_testfile -1.c -2.c -3.c
-+
-+# Compile an executable that loads the shared library as an actual
-+# shared library, then use GDB to figure out the offset of the
-+# variable 'library_ptr' within the library.
-+set library_filename [standard_output_file "libfoo.so"]
-+set binfile2 [standard_output_file "library_loader"]
-+
-+if {[prepare_for_testing_full "build exec which loads the shared library" \
-+ [list $library_filename \
-+ { debug shlib build-id \
-+ additional_flags=-DPOINTER_VALUE=0x12345678 } \
-+ $srcfile2 {}] \
-+ [list $binfile2 [list debug shlib=$library_filename ] \
-+ $srcfile { debug }]] != 0} {
-+ return
-+}
-+
-+if {![runto_main]} {
-+ return
-+}
-+
-+if { [is_address_zero_readable] } {
-+ return
-+}
-+
-+set ptr_address [get_hexadecimal_valueof "&library_ptr" "unknown"]
-+
-+set ptr_offset "unknown"
-+gdb_test_multiple "info proc mappings" "" {
-+ -re "^\\s+($hex)\\s+($hex)\\s+$hex\\s+($hex)\[^\r\n\]+$library_filename\r\n" {
-+ set low_addr $expect_out(1,string)
-+ set high_addr $expect_out(2,string)
-+ set file_offset $expect_out(3,string)
-+
-+ if {[expr $ptr_address >= $low_addr] && [expr $ptr_address < $high_addr]} {
-+ set mapping_offset [expr $ptr_address - $low_addr]
-+ set ptr_offset [format 0x%x [expr $file_offset + $mapping_offset]]
-+ }
-+
-+ exp_continue
-+ }
-+
-+ -re "^$gdb_prompt $" {
-+ }
-+
-+ -re "(^\[^\r\n\]*)\r\n" {
-+ set tmp $expect_out(1,string)
-+ exp_continue
-+ }
-+}
-+
-+gdb_assert { $ptr_offset ne "unknown" } \
-+ "found pointer offset"
-+
-+set ptr_size [get_integer_valueof "sizeof (library_ptr)" "unknown"]
-+set ptr_format_char ""
-+if { $ptr_size == 2 } {
-+ set ptr_format_char "b"
-+} elseif { $ptr_size == 4 } {
-+ set ptr_format_char "w"
-+} elseif { $ptr_size == 8 } {
-+ set ptr_format_char "g"
-+}
-+if { $ptr_format_char eq "" } {
-+ untested "could not figure out size of library_ptr variable"
-+ return
-+}
-+
-+# Helper proc to read a value from inferior memory. Reads at address held in
-+# global PTR_ADDRESS, and use PTR_FORMAT_CHAR for the size of the read.
-+proc read_ptr_value { } {
-+ set value ""
-+ gdb_test_multiple "x/1${::ptr_format_char}x ${::ptr_address}" "" {
-+ -re -wrap "^${::hex}(?:\\s+<\[^>\]+>)?:\\s+($::hex)" {
-+ set value $expect_out(1,string)
-+ }
-+ -re -wrap "^${::hex}(?:\\s+<\[^>\]+>)?:\\s+Cannot access memory at address ${::hex}" {
-+ set value "unavailable"
-+ }
-+ }
-+ return $value
-+}
-+
-+set ptr_expected_value [read_ptr_value]
-+if { $ptr_expected_value eq "" } {
-+ untested "could not find expected value for library_ptr"
-+ return
-+}
-+
-+# Now compile a second executable. This one doesn't load the shared
-+# library as an actual shared library, but instead mmaps the library
-+# into the executable.
-+#
-+# Load this executable within GDB and confirm that we can use the
-+# offset we calculated previously to view the value of 'library_ptr'.
-+set opts [list debug additional_flags=-DSHLIB_FILENAME=\"$library_filename\"]
-+if {[prepare_for_testing "prepare second executable" $binfile \
-+ $srcfile3 $opts] != 0} {
-+ return
-+}
-+
-+if {![runto_main]} {
-+ return
-+}
-+
-+gdb_breakpoint [gdb_get_line_number "Undefined behaviour here" $srcfile3]
-+gdb_continue_to_breakpoint "run to breakpoint"
-+
-+set library_base_address \
-+ [get_hexadecimal_valueof "library_base_address" "unknown"]
-+set ptr_address [format 0x%x [expr $library_base_address + $ptr_offset]]
-+
-+set ptr_value [read_ptr_value]
-+gdb_assert { $ptr_value == $ptr_expected_value } \
-+ "check value of pointer variable"
-+
-+# Now rerun the second executable outside of GDB. The executable should crash
-+# and generate a corefile.
-+set corefile [core_find $binfile]
-+if {$corefile eq ""} {
-+ untested "could not generate core file"
-+ return
-+}
-+
-+# Load a core file from the global COREFILE. Use TESTNAME as the name
-+# of the test.
-+#
-+# If LINE_RE is not the empty string then this is a regexp for a line
-+# that we expect to see in the output when loading the core file, if
-+# the line is not present then this test will fail.
-+#
-+# Any lines beginning with 'warning: ' will cause this test to fail.
-+#
-+# A couple of other standard lines that are produced when loading a
-+# core file are also checked for, just to make sure the core file
-+# loading has progressed as expected.
-+proc load_core_file { testname { line_re "" } } {
-+ set code {}
-+
-+ if { $line_re ne "" } {
-+ append code {
-+ -re "^$line_re\r\n" {
-+ set saw_expected_line true
-+ exp_continue
-+ }
-+ }
-+ set saw_expected_line false
-+ } else {
-+ set saw_expected_line true
-+ }
-+
-+ set saw_unknown_warning false
-+ set saw_generated_by_line false
-+ set saw_prog_terminated_line false
-+
-+ append code {
-+ -re "^warning: \[^\r\n\]+\r\n" {
-+ set saw_unknown_warning true
-+ exp_continue
-+ }
-+
-+ -re "^Core was generated by \[^\r\n\]+\r\n" {
-+ set saw_generated_by_line true
-+ exp_continue
-+ }
-+
-+ -re "^Program terminated with signal SIGSEGV, Segmentation fault\\.\r\n" {
-+ set saw_prog_terminated_line true
-+ exp_continue
-+ }
-+
-+ -re "^$::gdb_prompt $" {
-+ gdb_assert {$saw_generated_by_line \
-+ && $saw_prog_terminated_line \
-+ && $saw_expected_line \
-+ && !$saw_unknown_warning} \
-+ $gdb_test_name
-+ }
-+
-+ -re "^\[^\r\n\]*\r\n" {
-+ exp_continue
-+ }
-+ }
-+
-+ set res [catch { return [gdb_test_multiple "core-file $::corefile" \
-+ "$testname" $code] } string]
-+
-+ if {$res == 1} {
-+ global errorInfo errorCode
-+ return -code error -errorinfo $errorInfo -errorcode $errorCode $string
-+ } elseif {$res == 2} {
-+ return $string
-+ } else {
-+ # We expect RES to be 2 (TCL_RETURN) or 1 (TCL_ERROR). If we get
-+ # here then somehow the 'catch' above finished without hitting
-+ # either of those cases, which is .... weird.
-+ perror "unexepcted return value, code = $res, value = $string"
-+ return -1
-+ }
-+}
-+
-+# And now restart GDB, load the core-file and check that the library shows as
-+# being mapped in, and that we can still read the library_ptr value from
-+# memory.
-+clean_restart $binfile
-+
-+load_core_file "load core file"
-+
-+set library_base_address [get_hexadecimal_valueof "library_base_address" \
-+ "unknown" "get library_base_address in core-file"]
-+set ptr_address [format 0x%x [expr $library_base_address + $ptr_offset]]
-+
-+set ptr_value [read_ptr_value]
-+gdb_assert { $ptr_value == $ptr_expected_value } \
-+ "check value of pointer variable from core-file"
-+
-+# Now move the shared library file away and restart GDB. This time when we
-+# load the core-file we should see a warning that GDB has failed to map in the
-+# library file. An attempt to read the variable from the library file should
-+# fail / give a warning.
-+set library_backup_filename [standard_output_file "libfoo.so.backup"]
-+remote_exec build "mv \"$library_filename\" \"$library_backup_filename\""
-+
-+clean_restart $binfile
-+
-+load_core_file "load corefile with library file missing" \
-+ "warning: Can't open file [string_to_regexp $library_filename] during file-backed mapping note processing"
-+
-+set ptr_value [read_ptr_value]
-+gdb_assert { $ptr_value eq "unavailable" } \
-+ "check value of pointer is unavailable with library file missing"
-+
-+# Now symlink the .build-id/xx/xxx...xxx filename within the debug
-+# directory to library we just moved aside. Restart GDB and setup the
-+# debug-file-directory before loading the core file.
-+#
-+# GDB should lookup the file to map via the build-id link in the
-+# .build-id/ directory.
-+set debugdir [standard_output_file "debugdir"]
-+set build_id_filename \
-+ $debugdir/[build_id_debug_filename_get $library_backup_filename ""]
-+
-+remote_exec build "mkdir -p [file dirname $build_id_filename]"
-+remote_exec build "ln -sf $library_backup_filename $build_id_filename"
-+
-+clean_restart $binfile
-+
-+gdb_test_no_output "set debug-file-directory $debugdir" \
-+ "set debug-file-directory"
-+
-+load_core_file "load corefile, lookup in debug-file-directory"
-+
-+set ptr_value [read_ptr_value]
-+gdb_assert { $ptr_value == $ptr_expected_value } \
-+ "check value of pointer variable from core-file, lookup in debug-file-directory"
-+
-+# Build a new version of the shared library, keep the library the same size,
-+# but change the contents so the build-id changes. Then restart GDB and load
-+# the core-file again. GDB should spot that the build-id for the shared
-+# library is not as expected, and should refuse to map in the shared library.
-+if {[build_executable "build second version of shared library" \
-+ $library_filename $srcfile2 \
-+ { debug shlib build-id \
-+ additional_flags=-DPOINTER_VALUE=0x11223344 }] != 0} {
-+ return
-+}
-+
-+clean_restart $binfile
-+
-+load_core_file "load corefile with wrong library in place" \
-+ "warning: File [string_to_regexp $library_filename] doesn't match build-id from core-file during file-backed mapping processing"
-+
-+set ptr_value [read_ptr_value]
-+gdb_assert { $ptr_value eq "unavailable" } \
-+ "check value of pointer is unavailable with wrong library in place"
-+
-+# Setup a debuginfod server which can serve the original shared library file.
-+# Then restart GDB and load the core-file. GDB should download the original
-+# shared library from debuginfod and use that to provide the file backed
-+# mapping.
-+if {![allow_debuginfod_tests]} {
-+ untested "skippig debuginfod parts of this test"
-+ return
-+}
-+
-+set server_dir [standard_output_file "debuginfod.server"]
-+file mkdir $server_dir
-+file rename -force $library_backup_filename $server_dir
-+
-+prepare_for_debuginfod cache db
-+
-+set url [start_debuginfod $db $server_dir]
-+if { $url eq "" } {
-+ unresolved "failed to start debuginfod server"
-+ return
-+}
-+
-+with_debuginfod_env $cache {
-+ setenv DEBUGINFOD_URLS $url
-+
-+ clean_restart
-+ gdb_test_no_output "set debuginfod enabled on" \
-+ "enabled debuginfod for initial test"
-+ gdb_load $binfile
-+
-+ load_core_file "load corefile, download library from debuginfod" \
-+ "Downloading\[^\r\n\]* file [string_to_regexp $library_filename]\\.\\.\\."
-+
-+ set ptr_value [read_ptr_value]
-+ gdb_assert { $ptr_value == $ptr_expected_value } \
-+ "check value of pointer variable after downloading library file"
-+}
-+
-+stop_debuginfod
-diff --git a/gdb/testsuite/gdb.debuginfod/solib-with-soname-1.c b/gdb/testsuite/gdb.debuginfod/solib-with-soname-1.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/solib-with-soname-1.c
-@@ -0,0 +1,39 @@
-+/* Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <stdlib.h>
-+
-+/* It is important that these two variables have names of the same length
-+ so that the debug information in the two library versions is laid out
-+ the same. If they differ then the .dynamic section might move, which
-+ will trigger a different check within GDB than the one we actually want
-+ to check. */
-+
-+#if LIB_VERSION == 1
-+volatile int *library_1_var = (volatile int *) 0x12345678;
-+#elif LIB_VERSION == 2
-+volatile int *library_2_var = (volatile int *) 0x11223344;
-+#else
-+# error Unknown library version
-+#endif
-+
-+int
-+foo (void)
-+{
-+ /* This should trigger a core dump. */
-+ abort ();
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.debuginfod/solib-with-soname-2.c b/gdb/testsuite/gdb.debuginfod/solib-with-soname-2.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/solib-with-soname-2.c
-@@ -0,0 +1,41 @@
-+/* Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <dlfcn.h>
-+#include <stddef.h>
-+
-+/* This is in the shared library. */
-+extern int foo (void);
-+
-+/* This is updated by the .exp file. */
-+char *libname = "libfoo_2.so";
-+
-+int
-+main (void)
-+{
-+ void *handle;
-+ int res, tmp;
-+
-+ handle = dlopen (libname, RTLD_LAZY);
-+ assert (handle != NULL);
-+
-+ res = foo ();
-+
-+ tmp = dlclose (handle);
-+ assert (tmp == 0);
-+
-+ return res;
-+}
-diff --git a/gdb/testsuite/gdb.debuginfod/solib-with-soname.exp b/gdb/testsuite/gdb.debuginfod/solib-with-soname.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.debuginfod/solib-with-soname.exp
-@@ -0,0 +1,290 @@
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+# This test exercises GDB's ability to validate build-ids when loading
-+# shared libraries for a core file.
-+#
-+# The test creates two "versions" of a shared library, sets up a
-+# symlink to point to one version of the library, and creates a core file.
-+#
-+# We then try re-loading the core file and executable and check that
-+# GDB is able to correctly load the shared library. To confuse things
-+# we retarget the library symlink at the other version of the library.
-+#
-+# After that we repeat the test, but this time deleting the symlink
-+# completely.
-+#
-+# Then we remove the version of the library completely, at this point
-+# we do expect GDB to give a warning about being unable to load the library.
-+#
-+# And finally, we setup debuginfod and have it serve the missing
-+# library file, GDB should correctly download the library file.
-+#
-+# Despite this test living in the gdb.debuginfod/ directory, only the last
-+# part of this test actually uses debuginfod, everything up to that point is
-+# pretty generic.
-+
-+load_lib debuginfod-support.exp
-+
-+require allow_shlib_tests
-+require {istarget "*-linux*"}
-+require {!is_remote host}
-+require {!using_fission}
-+
-+standard_testfile -1.c -2.c
-+
-+# Build two similar, but slightly different versions of the shared
-+# library. Both libraries have DT_SONAME set to the generic
-+# libfoo.so, we'll create a symlink with that name later.
-+set library_1_filename [standard_output_file "libfoo_1.so"]
-+set library_2_filename [standard_output_file "libfoo_2.so"]
-+
-+# The generic name for the library.
-+set library_filename [standard_output_file "libfoo.so"]
-+
-+# When compiling a shared library the -Wl,-soname,NAME option is
-+# automatically added based on the final name of the library. We want
-+# to compile libfoo_1.so, but set the soname to libfoo.so. To achieve
-+# this we first compile into libfoo.so, and then rename the library to
-+# libfoo_1.so.
-+if {[build_executable "build libfoo_1.so" $library_filename \
-+ $srcfile \
-+ { debug shlib build-id \
-+ additional_flags=-DLIB_VERSION=1 }] == -1} {
-+ return
-+}
-+remote_exec build "mv ${library_filename} ${library_1_filename}"
-+
-+# See the comment above, but this time we rename to libfoo_2.so.
-+if {[build_executable "build libfoo_2.so" $library_filename \
-+ $srcfile \
-+ { debug shlib build-id \
-+ additional_flags=-DLIB_VERSION=2 }] == -1} {
-+ return
-+}
-+remote_exec build "mv ${library_filename} ${library_2_filename}"
-+
-+# Create libfoo.so symlink to the libfoo_1.so library. If this
-+# symlink creation fails then we assume we can't create symlinks on
-+# this host. If this succeeds then later symlink creation is required
-+# to succeed, and will trigger an FAIL if it doesn't.
-+set status \
-+ [remote_exec build \
-+ "ln -sf ${library_1_filename} ${library_filename}"]
-+if {[lindex $status 0] != 0} {
-+ unsupported "host does not support symbolic links"
-+ return
-+}
-+
-+# Build the executable. This links against libfoo.so, which is
-+# poining at libfoo_1.so. Just to confuse things even more, this
-+# executable uses dlopen to load libfoo_2.so. Weird!
-+if { [build_executable "build executable" ${binfile} ${srcfile2} \
-+ [list debug shlib=${library_filename} shlib_load]] == -1 } {
-+ return
-+}
-+
-+# If the board file is automatically splitting the debug information
-+# into a separate file (e.g. the cc-with-gnu-debuglink.exp board) then
-+# this test isn't going to work.
-+clean_restart
-+gdb_file_cmd $binfile
-+if {$gdb_file_cmd_debug_info ne "debug"} {
-+ unsupported "failed to find debug information"
-+ return
-+}
-+if {[regexp "${testfile}.debug" $gdb_file_cmd_msg]} {
-+ unsupported "debug information has been split to a separate file"
-+ return
-+}
-+
-+# Run BINFILE which will generate a corefile.
-+set corefile [core_find $binfile]
-+if {$corefile eq ""} {
-+ untested "could not generate core file"
-+ return
-+}
-+
-+# Helper proc to load global BINFILE and then load global COREFILE.
-+#
-+# If EXPECT_WARNING is true then we require a warning about being
-+# unable to load the shared library symbols, otherwise, EXPECT_WARNING
-+# is false and we require no warning.
-+#
-+# If EXPECT_DOWNLOAD is true then we require a line indicating that
-+# the shared library is being downloaded from debuginfod, otherwise
-+# the shared library should not be downloaded.
-+#
-+# If DEBUGDIR is not the empty string then 'debug-file-directory' is
-+# set to the value of DEBUGDIR.
-+proc load_exec_and_core_file { expect_warning expect_download testname \
-+ {debugdir ""} } {
-+ with_test_prefix $testname {
-+ clean_restart $::binfile
-+
-+ if { $debugdir ne "" } {
-+ gdb_test_no_output "set debug-file-directory $debugdir" \
-+ "set debug directory"
-+ }
-+
-+ set saw_warning false
-+ set saw_download false
-+ set saw_generated false
-+ set saw_terminated false
-+
-+ gdb_test_multiple "core-file $::corefile" "load core file" {
-+ -re "^Core was generated by \[^\r\n\]+\r\n" {
-+ set saw_generated true
-+ exp_continue
-+ }
-+ -re "^Program terminated with signal \[^\r\n\]+\r\n" {
-+ set saw_terminated true
-+ exp_continue
-+ }
-+ -re "^warning: Can't open file \[^\r\n\]+ during file-backed mapping note processing\r\n" {
-+ # Ignore warnings from the file backed mapping phase.
-+ exp_continue
-+ }
-+ -re "^warning: Could not load shared library symbols for \[^\r\n\]+/libfoo\\.so\\.\r\n" {
-+ set saw_warning true
-+ exp_continue
-+ }
-+ -re "^Downloading file \[^\r\n\]+/libfoo_1\\.so\\.\\.\\.\r\n" {
-+ set saw_download true
-+ exp_continue
-+ }
-+ -re "^$::gdb_prompt $" {
-+ gdb_assert { $saw_generated && $saw_terminated \
-+ && $saw_warning == $expect_warning \
-+ && $saw_download == $expect_download } \
-+ $gdb_test_name
-+ }
-+ -re "^\[^\r\n\]*\r\n" {
-+ exp_continue
-+ }
-+ }
-+
-+ # If we don't expect a warning then debug symbols from the
-+ # shared library should be available. Confirm we can read a
-+ # variable from the shared library. If we do expect a warning
-+ # then the shared library debug symbols have not loaded, and
-+ # the library variable should not be available.
-+ if { !$expect_warning } {
-+ gdb_test "print/x library_1_var" " = 0x12345678" \
-+ "check library_1_var can be read"
-+ } else {
-+ gdb_test "print/x library_1_var" \
-+ "^No symbol \"library_1_var\" in current context\\." \
-+ "check library_1_var cannot be read"
-+ }
-+ }
-+}
-+
-+# Initial test, just load the executable and core file. At this point
-+# everything should load fine as everything is where we expect to find
-+# it.
-+load_exec_and_core_file false false \
-+ "load core file, all libraries as expected"
-+
-+# Update libfoo.so symlink to point at the second library then reload
-+# the core file. GDB should spot that the symlink points to the wrong
-+# file, but should be able to figure out the correct file to load as
-+# the right file will be in the mapped file list.
-+set status [remote_exec build \
-+ "ln -sf ${library_2_filename} ${library_filename}"]
-+gdb_assert { [lindex $status 0] == 0 } \
-+ "update library symlink to point to the wrong file"
-+
-+load_exec_and_core_file false false \
-+ "load core file, symlink points to wrong file"
-+
-+# Remove libfoo.so symlink and reload the core file. As in the
-+# previous test GDB should be able to figure out the correct file to
-+# load as the correct file will still appear in the mapped file list.
-+set status [remote_exec build "rm -f ${library_filename}"]
-+gdb_assert { [lindex $status 0] == 0 } "remove library symlink"
-+
-+load_exec_and_core_file false false \
-+ "load core file, symlink removed"
-+
-+# Remove LIBRARY_1_FILENAME. We'll now see a warning that the mapped
-+# file can't be loaded (we ignore that warning), and we'll see a
-+# warning that the shared library can't be loaded.
-+set library_1_backup_filename ${library_1_filename}.backup
-+set status \
-+ [remote_exec build \
-+ "mv ${library_1_filename} ${library_1_backup_filename}"]
-+gdb_assert { [lindex $status 0] == 0 } \
-+ "remove libfoo_1.so"
-+
-+load_exec_and_core_file true false \
-+ "load core file, libfoo_1.so removed"
-+
-+# Symlink the .build-id/xx/xxx...xxx filename within the debug
-+# directory to LIBRARY_1_BACKUP_FILENAME, now when we restart GDB it
-+# should find the missing library within the debug directory.
-+set debugdir [standard_output_file "debugdir"]
-+set build_id_filename \
-+ $debugdir/[build_id_debug_filename_get $library_1_backup_filename ""]
-+set status \
-+ [remote_exec build \
-+ "mkdir -p [file dirname $build_id_filename]"]
-+gdb_assert { [lindex $status 0] == 0 } \
-+ "create sub-directory within the debug directory"
-+set status \
-+ [remote_exec build \
-+ "ln -sf $library_1_backup_filename $build_id_filename"]
-+gdb_assert { [lindex $status 0] == 0 } \
-+ "create symlink within the debug directory "
-+
-+load_exec_and_core_file false false \
-+ "load core file, find libfoo_1.so through debug-file-directory" \
-+ $debugdir
-+
-+# Setup a debuginfod server which can serve the original shared
-+# library file.
-+if {![allow_debuginfod_tests]} {
-+ untested "skippig debuginfod parts of this test"
-+ return
-+}
-+
-+set server_dir [standard_output_file "debuginfod.server"]
-+file mkdir $server_dir
-+file rename -force $library_1_backup_filename $server_dir
-+
-+prepare_for_debuginfod cache db
-+
-+set url [start_debuginfod $db $server_dir]
-+if { $url eq "" } {
-+ unresolved "failed to start debuginfod server"
-+ return
-+}
-+
-+with_debuginfod_env $cache {
-+ setenv DEBUGINFOD_URLS $url
-+
-+ save_vars { GDBFLAGS } {
-+ append GDBFLAGS " -ex \"set debuginfod enabled on\""
-+
-+ # Reload the executable and core file. GDB should download
-+ # the file libfoo_1.so using debuginfod during the mapped file
-+ # phase, but should then reuse that download during the shared
-+ # library phase.
-+ load_exec_and_core_file false true \
-+ "load core file, use debuginfod"
-+ }
-+}
-+
-+stop_debuginfod
-diff --git a/gdb/testsuite/gdb.dwarf2/short-build-id.exp b/gdb/testsuite/gdb.dwarf2/short-build-id.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.dwarf2/short-build-id.exp
-@@ -0,0 +1,119 @@
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+# Create a file with an artificially short (1-byte) build-id, and
-+# check that GDB doesn't try to load debug information. If we do try
-+# then we end up loading from: `debug-directory/.build-id/xx/.debug`
-+# which isn't right.
-+
-+load_lib dwarf.exp
-+
-+# This test can only be run on targets which support DWARF-2 and use gas.
-+require dwarf2_support
-+
-+# No remote host testing either.
-+require {!is_remote host}
-+
-+standard_testfile main.c
-+
-+# Create an assembler file which encodes BUILDID as the build-id. Compile
-+# this along with the global SRCFILE to create a test executable.
-+#
-+# Split the debug information out from the newly created executable and place
-+# it into the debug file directory.
-+#
-+# Load the executable into GDB and check to see if the debug information was
-+# loaded or not. For this test we are expecting that the debug information
-+# was not loaded. The reason is that, with short values for BUILDID, GDB ends
-+# up looking for the debug information in weird locations.
-+proc run_test { buildid } {
-+ set len [string length $buildid]
-+
-+ set asm_file [standard_output_file "$::testfile.$len.S"]
-+ Dwarf::assemble $asm_file {
-+ declare_labels int_label int_label2
-+
-+ upvar buildid buildid
-+
-+ build_id $buildid
-+
-+ cu { label cu_start } {
-+ compile_unit {{language @DW_LANG_C}} {
-+ int_label2: base_type {
-+ {name int}
-+ {byte_size 4 sdata}
-+ {encoding @DW_ATE_signed}
-+ }
-+
-+ constant {
-+ {name the_int}
-+ {type :$int_label2}
-+ {const_value 99 data1}
-+ }
-+ }
-+ }
-+
-+ aranges {} cu_start {
-+ arange {} 0 0
-+ }
-+ }
-+
-+ set execfile [standard_output_file $::testfile.$len]
-+
-+ if { [build_executable_from_specs "failed to build" \
-+ $execfile {debug no-build-id} \
-+ $::srcfile debug \
-+ $asm_file {}] } {
-+ return
-+ }
-+
-+ # Create the debug directory.
-+ set debugdir [standard_output_file "debugdir.$len"]
-+ set build_id_dir $debugdir/.build-id/$buildid
-+ remote_exec host "mkdir -p $build_id_dir"
-+
-+ # Split out the debug information.
-+ if {[gdb_gnu_strip_debug $execfile no-debuglink]} {
-+ unresolved "failed to split out debug information"
-+ return
-+ }
-+
-+ # Move the debug information into the debug directory. We place the debug
-+ # information into a file called just '.debug'. GDB should not check this
-+ # file, but at one point GDB would check this file, even though this
-+ # doesn't make much sense.
-+ set execfile_debug ${execfile}.debug
-+ remote_exec host "mv $execfile_debug $build_id_dir/.debug"
-+
-+ # Start GDB, set the debug-file-directory, and try loading the file.
-+ clean_restart
-+
-+ gdb_test_no_output "set debug-file-directory $debugdir" \
-+ "set debug-file-directory"
-+
-+ gdb_file_cmd $execfile
-+
-+ gdb_assert { $::gdb_file_cmd_debug_info eq "nodebug" } \
-+ "no debug should be loaded"
-+
-+ # For sanity, read something that was encoded in the debug
-+ # information, this should fail.
-+ gdb_test "print the_int" \
-+ "(?:No symbol table is loaded|No symbol \"the_int\" in current context).*"
-+}
-+
-+foreach_with_prefix buildid { a4 "" } {
-+ run_test $buildid
-+}
-diff --git a/gdb/testsuite/gdb.python/py-missing-objfile-lib.c b/gdb/testsuite/gdb.python/py-missing-objfile-lib.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.python/py-missing-objfile-lib.c
-@@ -0,0 +1,35 @@
-+/* This test program is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+struct lib_type
-+{
-+ int a;
-+ int b;
-+};
-+
-+volatile struct lib_type global_lib_var = { 0, 0 };
-+
-+int
-+foo (void)
-+{
-+ int res = 0;
-+
-+ res += global_lib_var.a;
-+ res += global_lib_var.b;
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.c b/gdb/testsuite/gdb.python/py-missing-objfile.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.python/py-missing-objfile.c
-@@ -0,0 +1,49 @@
-+/* This test program is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <stdlib.h>
-+
-+struct exec_type
-+{
-+ int a;
-+ int b;
-+ int c;
-+};
-+
-+volatile struct exec_type global_exec_var = { 0, 0, 0 };
-+
-+extern int foo (void);
-+
-+void
-+dump_core (void)
-+{
-+ abort ();
-+}
-+
-+int
-+main (void)
-+{
-+ int res = foo ();
-+
-+ res += global_exec_var.a;
-+ res += global_exec_var.b;
-+ res += global_exec_var.c;
-+
-+ dump_core ();
-+
-+ return res;
-+}
-diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.exp b/gdb/testsuite/gdb.python/py-missing-objfile.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.python/py-missing-objfile.exp
-@@ -0,0 +1,565 @@
-+# Copyright (C) 2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+load_lib gdb-python.exp
-+
-+require allow_python_tests
-+require {!is_remote host}
-+
-+standard_testfile .c -lib.c
-+
-+# Build the library.
-+set libname ${testfile}-lib
-+set libfile [standard_output_file $libname]
-+if { [build_executable "build shlib" $libfile $srcfile2 \
-+ {debug shlib build-id}] == -1} {
-+ return
-+}
-+
-+# Build the executable.
-+set opts [list debug build-id shlib=${libfile}]
-+if { [build_executable "build exec" $binfile $srcfile $opts] == -1} {
-+ return
-+}
-+
-+# The cc-with-gnu-debuglink board will split the debug out into the
-+# .debug directory. This test script relies on having GDB lookup the
-+# objfile and debug via the build-id, which this test sets up. Trying
-+# to do that, while also supporting the cc-with-gnu-debuglink board is
-+# just too complicated.
-+if {[file isdirectory [standard_output_file ".debug"]]} {
-+ unsupported "split debug testing not supported"
-+ return
-+}
-+
-+set remote_python_file \
-+ [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
-+
-+# Generate a core file.
-+set corefile [core_find $binfile {}]
-+if {$corefile == ""} {
-+ unsupported "core file not generated"
-+ return 0
-+}
-+
-+# Create a directory named DIRNAME for use as the
-+# debug-file-directory. Populate the directory with links (based on
-+# the build-ids) to each file in the list FILES.
-+#
-+# Return the full filename of DIRNAME on the host.
-+proc setup_debugdir { dirname files } {
-+ set debugdir [host_standard_output_file $dirname]
-+
-+ # Create basic empty directory structure (in case FILES is empty).
-+ remote_exec host "mkdir -p $debugdir/.build-id/"
-+
-+ foreach file $files {
-+ set build_id_filename [build_id_debug_filename_get $file ""]
-+
-+ remote_exec host "mkdir -p $debugdir/[file dirname $build_id_filename]"
-+ remote_exec host "ln -s $file $debugdir/$build_id_filename"
-+ }
-+
-+ return $debugdir
-+}
-+
-+# Query some symbols in the inferior to see if GDB managed to find the
-+# executable (when EXEC_LOADED is true) and/or the library (when LIB_LOADED
-+# is true).
-+proc check_loaded_debug { exec_loaded lib_loaded } {
-+ if { $exec_loaded } {
-+ gdb_test "whatis global_exec_var" "^type = volatile struct exec_type"
-+
-+ if { $lib_loaded } {
-+ gdb_test "whatis global_lib_var" "^type = volatile struct lib_type"
-+ } else {
-+ gdb_test "whatis global_lib_var" \
-+ "^No symbol \"global_lib_var\" in current context\\."
-+ }
-+ } else {
-+ gdb_test "whatis global_exec_var" \
-+ "^No symbol table is loaded\\. Use the \"file\" command\\."
-+ gdb_test "whatis global_lib_var" \
-+ "^No symbol table is loaded\\. Use the \"file\" command\\."
-+ }
-+}
-+
-+# Load the global corefile. The EXTRA_RE is checked for prior to GDB
-+# announcing that the core-file has been loaded.
-+proc load_core_file { {extra_re ".*"} } {
-+ gdb_test "core-file $::corefile" \
-+ [multi_line \
-+ "$extra_re" \
-+ "Core was generated by \[^\r\n\]+" \
-+ "Program terminated with signal SIGABRT, Aborted\\." \
-+ "\[^\r\n\]+(?:\r\n\[^\r\n\]+)?"] \
-+ "loaded the core file"
-+}
-+
-+# Set the debug-file-directory to DIRNAME.
-+proc set_debug_file_dir { dirname } {
-+ gdb_test_no_output "set debug-file-directory $dirname" \
-+ "set debug-file-directory"
-+}
-+
-+# Restart GDB and load the support Python script.
-+proc clean_restart_load_python {} {
-+ clean_restart
-+ gdb_test "source $::remote_python_file" "^Success" \
-+ "load python script"
-+}
-+
-+# For sanity, lets check that we can load the specify the executable
-+# and then load the core-file the easy way.
-+with_test_prefix "initial sanity check" {
-+ clean_restart $binfile
-+ load_core_file
-+ check_loaded_debug true true
-+}
-+
-+# Move the executable and library into a location that the core-file
-+# can't possibly know about. After this the only way GDB can track
-+# down these files will be by looking in the debug-file-directory.
-+set hidden_dir [host_standard_output_file "hidden"]
-+set hidden_binfile "$hidden_dir/$testfile"
-+set hidden_libfile "$hidden_dir/$libname"
-+remote_exec host "mkdir -p $hidden_dir"
-+remote_exec host "mv $libfile $hidden_libfile"
-+remote_exec host "mv $binfile $hidden_binfile"
-+
-+# If using the fission-dwp board then we'll have .dwp files that also
-+# need to be moved.
-+if {[remote_file host exists ${libfile}.dwp]} {
-+ remote_exec host "mv ${libfile}.dwp ${hidden_libfile}.dwp"
-+}
-+
-+if {[remote_file host exists ${binfile}.dwp]} {
-+ remote_exec host "mv ${binfile}.dwp ${hidden_binfile}.dwp"
-+}
-+
-+with_test_prefix "no objfiles, no debug-file-directory" {
-+ clean_restart
-+ load_core_file
-+ check_loaded_debug false false
-+}
-+
-+# Setup some debug-file-directories.
-+set debugdir_no_lib \
-+ [setup_debugdir "debugdir.no-lib" [list "$hidden_binfile"]]
-+set debugdir_empty \
-+ [setup_debugdir "debugdir.empty" {}]
-+set debugdir_all \
-+ [setup_debugdir "debugdir.all" [list "$hidden_libfile" \
-+ "$hidden_binfile"]]
-+
-+with_test_prefix "no objfiles available" {
-+ # Another sanity check that GDB can find the files via the
-+ # debug-file-directory.
-+ clean_restart
-+ set_debug_file_dir $debugdir_empty
-+ load_core_file
-+ check_loaded_debug false false
-+}
-+
-+with_test_prefix "all objfiles available" {
-+ # Another sanity check that GDB can find the files via the
-+ # debug-file-directory.
-+ set_debug_file_dir $debugdir_all
-+ load_core_file
-+ check_loaded_debug true true
-+}
-+
-+with_test_prefix "lib objfile missing" {
-+ # Another sanity check that GDB can find the files via the
-+ # debug-file-directory.
-+ set_debug_file_dir $debugdir_no_lib
-+ load_core_file
-+ check_loaded_debug true false
-+}
-+
-+with_test_prefix "all objfiles missing, handler returns None" {
-+ clean_restart_load_python
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(None, handler_obj)" \
-+ "register initial handler"
-+ load_core_file
-+
-+ check_loaded_debug false false
-+
-+ # The handler should be called three times, once for the
-+ # mapped-file, once for the core-file's exec, and once for the
-+ # shared library.
-+ gdb_test "python print(handler_obj.call_count)" "^3" \
-+ "check handler was called three times"
-+}
-+
-+with_test_prefix "lib objfile missing, handler returns None" {
-+ # Reset handler_obj.
-+ gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_NONE)"
-+
-+ set_debug_file_dir $debugdir_no_lib
-+ load_core_file
-+ check_loaded_debug true false
-+
-+ # The handler will be called twice, once when GDB tries to
-+ # load the shared library during the memory-mapped file phase,
-+ # then again for the shared library loading.
-+ gdb_test "python print(handler_obj.call_count)" "^2" \
-+ "check handler was called three times"
-+}
-+
-+with_test_prefix "handler installs lib objfile" {
-+ set build_id_filename [build_id_debug_filename_get \
-+ $hidden_libfile ""]
-+ remote_exec host \
-+ "mkdir -p $debugdir_no_lib/[file dirname $build_id_filename]"
-+ gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \
-+ \"$hidden_libfile\", \"$debugdir_no_lib/$build_id_filename\")" \
-+ "configure handler"
-+
-+ load_core_file
-+ check_loaded_debug true true
-+
-+ # Cleanup so the test can be reproduced again later if needed.
-+ remote_exec host "rm $debugdir_no_lib/$build_id_filename"
-+}
-+
-+with_test_prefix "handler points to lib objfile" {
-+ set build_id_filename [build_id_debug_filename_get \
-+ $hidden_libfile ""]
-+ remote_exec host \
-+ "mkdir -p $debugdir_no_lib/[file dirname $build_id_filename]"
-+ gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \
-+ \"$hidden_libfile\")" \
-+ "configure handler"
-+
-+ load_core_file
-+ check_loaded_debug true true
-+
-+ # Cleanup so the test can be reproduced again later if needed.
-+ remote_exec host "rm $debugdir_no_lib/$build_id_filename"
-+
-+ # The handler will only have been called once when loading the
-+ # memory-mapped file. GDB is smart enough to reuse the previously
-+ # discovered BFD object as the shared library.
-+ gdb_test "python print(handler_obj.call_count)" "^1" \
-+ "check good handler hasn't been called again"
-+
-+ # Validate the filename and build-id arguments passed to the handler.
-+ set expected_buildid [get_build_id $hidden_libfile]
-+ gdb_test "python print(handler_last_buildid)" "^$expected_buildid"
-+ gdb_test "python print(handler_last_filename)" \
-+ "^[string_to_regexp $libfile]"
-+}
-+
-+# Register another global handler, this one raises an exception. Reload the
-+# core-file, the bad handler should be invoked first, which raises an
-+# excetption, at which point GDB should skip further Python handlers.
-+with_test_prefix "handler raises an exception" {
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(None, rhandler)"
-+
-+ foreach_with_prefix exception_type {gdb.GdbError TypeError} {
-+ gdb_test_no_output \
-+ "python rhandler.exception_type = $exception_type"
-+
-+ # Load the core file. We expect the exception message to appear at
-+ # least once in the output.
-+ set re [string_to_regexp \
-+ "Python Exception <class '$exception_type'>: message"]
-+ load_core_file "${re}.*"
-+
-+ # Our original handler is still registered, but should not have been
-+ # called again (as the exception occurs first).
-+ gdb_test "python print(handler_obj.call_count)" "^1" \
-+ "check good handler hasn't been called again"
-+ }
-+}
-+
-+# Re-start GDB.
-+clean_restart_load_python
-+
-+# Attempt to register a missing-debug-handler with NAME. The expectation is
-+# that this should fail as NAME contains some invalid characters.
-+proc check_bad_name {name} {
-+ set name_re [string_to_regexp $name]
-+ set re \
-+ [multi_line \
-+ "ValueError.*: invalid character '.' in handler name: $name_re" \
-+ "Error occurred in Python.*"]
-+
-+ gdb_test "python register(\"$name\")" $re \
-+ "check that '$name' is not accepted"
-+}
-+
-+# We don't attempt to be exhaustive here, just check a few random examples
-+# of invalid names.
-+check_bad_name "!! Bad Name"
-+check_bad_name "Bad Name"
-+check_bad_name "(Bad Name)"
-+check_bad_name "Bad \[Name\]"
-+check_bad_name "Bad,Name"
-+check_bad_name "Bad;Name"
-+
-+# Check that there are no handlers registered.
-+gdb_test_no_output "info missing-objfile-handlers" \
-+ "check no handlers are registered"
-+
-+# Grab the current program space object, used for registering handler later.
-+gdb_test_no_output "python pspace = gdb.selected_inferior().progspace"
-+
-+# Now register some handlers.
-+foreach hspec {{\"Foo\" None}
-+ {\"-bar\" None}
-+ {\"baz-\" pspace}
-+ {\"abc-def\" pspace}} {
-+ lassign $hspec name locus
-+ gdb_test "python register($name, $locus)"
-+}
-+
-+with_test_prefix "all handlers enabled" {
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Current Progspace:" \
-+ " abc-def" \
-+ " baz-" \
-+ "Global:" \
-+ " -bar" \
-+ " Foo"]
-+
-+ set_debug_file_dir $debugdir_no_lib
-+ load_core_file
-+
-+ # As we perform two look ups, first for the mapped-file then for the
-+ # shared library, each handler will be called twice.
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', 'baz-', '-bar', 'Foo', 'abc-def', 'baz-', '-bar', 'Foo']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "disable 'baz-'" {
-+ gdb_test "disable missing-objfile-handler progspace baz-" \
-+ "^1 missing objfile handler disabled"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def" \
-+ " baz- \\\[disabled\\\]" \
-+ "Global:" \
-+ " -bar" \
-+ " Foo"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', '-bar', 'Foo', 'abc-def', '-bar', 'Foo']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "disable 'Foo'" {
-+ gdb_test "disable missing-objfile-handler .* Foo" \
-+ "^1 missing objfile handler disabled"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def" \
-+ " baz- \\\[disabled\\\]" \
-+ "Global:" \
-+ " -bar" \
-+ " Foo \\\[disabled\\\]"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', '-bar', 'abc-def', '-bar']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "disable everything" {
-+ gdb_test "disable missing-objfile-handler .* .*" \
-+ "^2 missing objfile handlers disabled"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def \\\[disabled\\\]" \
-+ " baz- \\\[disabled\\\]" \
-+ "Global:" \
-+ " -bar \\\[disabled\\\]" \
-+ " Foo \\\[disabled\\\]"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {[]}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "enable 'abc-def'" {
-+ set re [string_to_regexp $hidden_binfile]
-+
-+ gdb_test "enable missing-objfile-handler \"$re\" abc-def" \
-+ "^1 missing objfile handler enabled" \
-+ "enable missing-objfile-handler"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def" \
-+ " baz- \\\[disabled\\\]" \
-+ "Global:" \
-+ " -bar \\\[disabled\\\]" \
-+ " Foo \\\[disabled\\\]"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', 'abc-def']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "enable global handlers" {
-+ gdb_test "enable missing-objfile-handler global" \
-+ "^2 missing objfile handlers enabled"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def" \
-+ " baz- \\\[disabled\\\]" \
-+ "Global:" \
-+ " -bar" \
-+ " Foo"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', '-bar', 'Foo', 'abc-def', '-bar', 'Foo']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+# Add handler_obj to the global handler list, and configure it to
-+# return False. We should call all of the program space specific
-+# handlers (which return None), and then call handler_obj from the
-+# global list, which returns False, at which point we shouldn't call
-+# anyone else.
-+with_test_prefix "return False handler in global list" {
-+ gdb_test "enable missing-objfile-handler progspace" \
-+ "^1 missing objfile handler enabled"
-+
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(None, handler_obj)" \
-+ "register handler_obj in global list"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " abc-def" \
-+ " baz-" \
-+ "Global:" \
-+ " handler" \
-+ " -bar" \
-+ " Foo"]
-+
-+ gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \
-+ "confirgure handler"
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['abc-def', 'baz-', 'handler', 'abc-def', 'baz-', 'handler']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+# Now add handler_obj to the current program space's handler list. We
-+# use the same handler object here, that's fine. We should only see a
-+# call to the first handler object in the call log.
-+with_test_prefix "return False handler in progspace list" {
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(pspace, handler_obj)" \
-+ "register handler_obj in progspace list"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " handler" \
-+ " abc-def" \
-+ " baz-" \
-+ "Global:" \
-+ " handler" \
-+ " -bar" \
-+ " Foo"]
-+
-+ load_core_file
-+ gdb_test "python print(handler_call_log)" \
-+ [string_to_regexp {['handler', 'handler']}]
-+ gdb_test_no_output "python handler_call_log = \[\]" \
-+ "reset call log"
-+}
-+
-+with_test_prefix "check handler replacement" {
-+ # First, check we can have the same name appear in both program
-+ # space and global lists without giving an error.
-+ gdb_test_no_output "python register(\"Foo\", pspace)"
-+
-+ gdb_test "info missing-objfile-handlers" \
-+ [multi_line \
-+ "Progspace \[^\r\n\]+:" \
-+ " Foo" \
-+ " handler" \
-+ " abc-def" \
-+ " baz-" \
-+ "Global:" \
-+ " handler" \
-+ " -bar" \
-+ " Foo"]
-+
-+ # Now check that we get an error if we try to add a handler with
-+ # the same name.
-+ gdb_test "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"))" \
-+ [multi_line \
-+ "RuntimeError.*: Handler Foo already exists\\." \
-+ "Error occurred in Python.*"]
-+
-+ gdb_test "python gdb.missing_objfile.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \
-+ [multi_line \
-+ "RuntimeError.*: Handler Foo already exists\\." \
-+ "Error occurred in Python.*"]
-+
-+ # And now try again, but this time with 'replace=True', we
-+ # shouldn't get an error in this case.
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"), replace=True)"
-+
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)"
-+
-+ # Now disable a handler and check we still need to use 'replace=True'.
-+ gdb_test "disable missing-objfile-handler progspace Foo" \
-+ "^1 missing objfile handler disabled"
-+
-+ gdb_test "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"))" \
-+ [multi_line \
-+ "RuntimeError.*: Handler Foo already exists\\." \
-+ "Error occurred in Python.*"] \
-+ "still get an error when handler is disabled"
-+
-+ gdb_test_no_output \
-+ "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \
-+ "can replace a disabled handler"
-+}
-diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.python/py-missing-objfile.py
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.python/py-missing-objfile.py
-@@ -0,0 +1,167 @@
-+# Copyright (C) 2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+import shutil
-+import os
-+from enum import Enum
-+
-+import gdb
-+from gdb.missing_objfile import MissingObjfileHandler
-+
-+# A global log that is filled in by instances of the LOG_HANDLER class
-+# when they are called.
-+handler_call_log = []
-+
-+# A global holding a string, the build-id of the last missing objfile
-+# which triggered the 'handler' class below. This is set in the
-+# __call__ method of the 'handler' class and then checked from the
-+# expect script.
-+handler_last_buildid = None
-+
-+
-+# A global holding a string, the filename of the last missing objfile
-+# which triggered the 'handler' class below. This is set in the
-+# __call__ method of the 'handler' class and then checked from the
-+# expect script.
-+handler_last_filename = None
-+
-+
-+# A helper function that makes some assertions about the arguments
-+# passed to a MissingObjfileHandler.__call__() method.
-+def check_args(pspace, buildid, filename):
-+ assert type(filename) == str
-+ assert filename != ""
-+ assert type(pspace) == gdb.Progspace
-+ assert type(buildid) == str
-+ assert buildid != ""
-+
-+
-+# Enum used to configure the 'handler' class from the test script.
-+class Mode(Enum):
-+ RETURN_NONE = 0
-+ RETURN_TRUE = 1
-+ RETURN_FALSE = 2
-+ RETURN_STRING = 3
-+
-+
-+# A missing objfile handler which can be configured to return each of
-+# the different possible return types.
-+class handler(MissingObjfileHandler):
-+ def __init__(self):
-+ super().__init__("handler")
-+ self._call_count = 0
-+ self._mode = Mode.RETURN_NONE
-+
-+ def __call__(self, pspace, buildid, filename):
-+ global handler_call_log, handler_last_buildid, handler_last_filename
-+ check_args(pspace, buildid, filename)
-+ handler_call_log.append(self.name)
-+ handler_last_buildid = buildid
-+ handler_last_filename = filename
-+ self._call_count += 1
-+ if self._mode == Mode.RETURN_NONE:
-+ return None
-+
-+ if self._mode == Mode.RETURN_TRUE:
-+ shutil.copy(self._src, self._dest)
-+
-+ # If we're using the fission-dwp board then there will
-+ # also be a .dwp file that needs to be copied.
-+ dwp_src = self._src + ".dwp"
-+ if os.path.exists(dwp_src):
-+ dwp_dest = self._dest + ".dwp"
-+ shutil.copy(dwp_src, dwp_dest)
-+
-+ return True
-+
-+ if self._mode == Mode.RETURN_FALSE:
-+ return False
-+
-+ if self._mode == Mode.RETURN_STRING:
-+ return self._dest
-+
-+ assert False
-+
-+ @property
-+ def call_count(self):
-+ """Return a count, the number of calls to __call__ since the last
-+ call to set_mode.
-+ """
-+ return self._call_count
-+
-+ def set_mode(self, mode, *args):
-+ self._call_count = 0
-+ self._mode = mode
-+
-+ if mode == Mode.RETURN_NONE:
-+ assert len(args) == 0
-+ return
-+
-+ if mode == Mode.RETURN_TRUE:
-+ assert len(args) == 2
-+ self._src = args[0]
-+ self._dest = args[1]
-+ return
-+
-+ if mode == Mode.RETURN_FALSE:
-+ assert len(args) == 0
-+ return
-+
-+ if mode == Mode.RETURN_STRING:
-+ assert len(args) == 1
-+ self._dest = args[0]
-+ return
-+
-+ assert False
-+
-+
-+# A missing objfile handler which raises an exception. The type of
-+# exception to be raised is configured from the test script.
-+class exception_handler(MissingObjfileHandler):
-+ def __init__(self):
-+ super().__init__("exception_handler")
-+ self.exception_type = None
-+
-+ def __call__(self, pspace, buildid, filename):
-+ global handler_call_log
-+ check_args(pspace, buildid, filename)
-+ handler_call_log.append(self.name)
-+ assert self.exception_type is not None
-+ raise self.exception_type("message")
-+
-+
-+# A very simple logging missing objfile handler. Always returns None
-+# so that GDB will try any other registered handlers, but first logs
-+# the name of this handler into the global HANDLER_CALL_LOG, which can
-+# then be checked from the test script.
-+class log_handler(MissingObjfileHandler):
-+ def __call__(self, pspace, buildid, filename):
-+ global handler_call_log
-+ check_args(pspace, buildid, filename)
-+ handler_call_log.append(self.name)
-+ return None
-+
-+
-+# A basic helper function, this keeps lines shorter in the TCL script.
-+def register(name, locus=None):
-+ gdb.missing_objfile.register_handler(locus, log_handler(name))
-+
-+
-+# Create instances of the handlers, but don't install any. We install
-+# these as needed from the TCL script.
-+rhandler = exception_handler()
-+handler_obj = handler()
-+
-+print("Success")
-diff --git a/gdb/testsuite/gdb.server/build-id-seqno.c b/gdb/testsuite/gdb.server/build-id-seqno.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.server/build-id-seqno.c
-@@ -0,0 +1,22 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+int
-+main (void)
-+{
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.server/build-id-seqno.exp b/gdb/testsuite/gdb.server/build-id-seqno.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.server/build-id-seqno.exp
-@@ -0,0 +1,198 @@
-+# This testcase is part of GDB, the GNU debugger.
-+#
-+# Copyright 2024 Free Software Foundation, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+# Setup a .build-id/ based debug directory containing multiple entries
-+# for the same build-id, with each entry given a different sequence
-+# number.
-+#
-+# Ensure that GDB will scan over broken symlinks for the same build-id
-+# (but different sequence number) to find later working symlinks.
-+#
-+# This test places the build-id files within a directory next to where
-+# gdbserver is started, and places a relative address in the
-+# debug-file-directory, in this way we require GDB to find the debug
-+# information via gdbserver.
-+
-+require {!is_remote host}
-+
-+load_lib gdbserver-support.exp
-+
-+standard_testfile
-+
-+if {[build_executable "failed to prepare" $testfile $srcfile] == -1} {
-+ return -1
-+}
-+
-+# Split out BINFILE.debug. Remove debug from BINFILE.
-+if {[gdb_gnu_strip_debug $binfile] != 0} {
-+ return -1
-+}
-+
-+# Get the '.build-id/xx/xxx...xxx' part of the filename.
-+set build_id_filename [build_id_debug_filename_get $binfile]
-+
-+# Hide (rename) BINFILE.debug, this should ensure GDB can't find it
-+# directly but needs to look for the build-id based file in the debug
-+# directory.
-+set hidden_debuginfo [standard_output_file "hidden_$testfile.debug"]
-+remote_exec build "mv ${binfile}.debug $hidden_debuginfo"
-+
-+# A filename that doesn't exist. Some symlinks will point at this
-+# file.
-+set missing_debuginfo "missing_debuginfo"
-+
-+# Helper called from gdb_finish when the 'target' is remote. Ensure the
-+# debug directory we create is deleted.
-+proc cleanup_remote_target {} {
-+ remote_exec target "rm -fr debug/"
-+}
-+
-+if { ![is_remote target] } {
-+ set gdbserver_dir [standard_output_file "gdbserver-dir"]/
-+} else {
-+ lappend gdb_finish_hooks cleanup_remote_target
-+ set gdbserver_dir ""
-+}
-+
-+# Copy files to the target (if needed).
-+set target_binfile [gdb_remote_download target $binfile]
-+set target_debuginfo [gdb_remote_download target $hidden_debuginfo]
-+
-+# Setup the debug information on the target.
-+set debugdir "${gdbserver_dir}debug"
-+remote_exec target \
-+ "mkdir -p $debugdir/[file dirname $build_id_filename]"
-+remote_exec target \
-+ "ln -sf $target_debuginfo $debugdir/$build_id_filename"
-+
-+# Start GDB and load global BINFILE. If DEBUGINFO_FILE is not the
-+# empty string then this contains the '.build-id/xx/xxx....xxxx' part
-+# of the filename which we expect GDB to read from the remote target.
-+# If DEBUGINFO_FILE is the empty string then we don't expect GDB to
-+# find any debug information.
-+proc load_binfile_check_debug_is_found { debuginfo_file testname } {
-+ with_test_prefix "$testname" {
-+ with_timeout_factor 5 {
-+ # Probing for .build-id based debug files on remote
-+ # targets uses the vFile:stat packet by default, though
-+ # there is a work around that avoids this which can be
-+ # used if GDB is connected to an older gdbserver without
-+ # 'stat' support.
-+ #
-+ # Check the work around works by disabling use of the
-+ # vFile:stat packet.
-+ foreach_with_prefix stat_pkt {auto off} {
-+ clean_restart
-+
-+ gdb_test_no_output "set debug-file-directory debug" \
-+ "set debug-file-directory"
-+
-+ gdb_test_no_output "set sysroot target:"
-+
-+ gdb_test "set remote hostio-stat-packet $stat_pkt"
-+
-+ # Make sure we're disconnected, in case we're testing with an
-+ # extended-remote board, therefore already connected.
-+ gdb_test "disconnect" ".*"
-+
-+ # Start gdbserver. This needs to be done after starting GDB. When
-+ # gdbserver is running local to GDB, start gdbserver in a sub-directory,
-+ # this prevents GDB from finding the debug information itself.
-+ if { ![is_remote target] } {
-+ with_cwd $::gdbserver_dir {
-+ set res [gdbserver_start "" $::target_binfile]
-+ }
-+ } else {
-+ set res [gdbserver_start "" $::target_binfile]
-+ }
-+ set gdbserver_protocol [lindex $res 0]
-+ set gdbserver_gdbport [lindex $res 1]
-+
-+ # Connect to gdbserver. The output will be placed into the global
-+ # GDB_TARGET_REMOTE_CMD_MSG, and we'll match against this below.
-+ gdb_assert {[gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0} \
-+ "connect to gdbserver"
-+
-+ if { $debuginfo_file ne "" } {
-+ gdb_assert { [regexp "Reading symbols from target:debug/[string_to_regexp $debuginfo_file]\\.\\.\\." \
-+ $::gdb_target_remote_cmd_msg] } \
-+ "debuginfo was read via build-id"
-+ gdb_assert { [regexp "Reading debug/[string_to_regexp $debuginfo_file] from remote target\\.\\.\\." \
-+ $::gdb_target_remote_cmd_msg] } \
-+ "debuginfo was read from remote target"
-+ } else {
-+ gdb_assert { [regexp "\\(No debugging symbols found in \[^\r\n\]+/$::testfile\\)" \
-+ $::gdb_target_remote_cmd_msg] }
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+# Return a copy of FILENAME, which should end '.debug', with NUMBER
-+# added, e.g. add_seqno 1 "foo.debug" --> "foo.1.debug".
-+proc add_seqno { number filename } {
-+ return [regsub "\.debug\$" $filename ".${number}.debug"]
-+}
-+
-+# Precompute sequence numbered build-id filenames.
-+set build_id_1_filename [add_seqno 1 $build_id_filename]
-+set build_id_2_filename [add_seqno 2 $build_id_filename]
-+set build_id_3_filename [add_seqno 3 $build_id_filename]
-+
-+load_binfile_check_debug_is_found $build_id_filename \
-+ "find debuginfo with a single build-id file"
-+
-+remote_exec target "ln -fs $target_debuginfo \
-+ $debugdir/$build_id_1_filename"
-+remote_exec target "ln -fs $target_debuginfo \
-+ $debugdir/$build_id_2_filename"
-+remote_exec target "ln -fs $target_debuginfo \
-+ $debugdir/$build_id_3_filename"
-+
-+load_binfile_check_debug_is_found $build_id_filename \
-+ "find debuginfo with 4 build-id files"
-+
-+remote_exec target "ln -fs $missing_debuginfo $debugdir/$build_id_filename"
-+
-+load_binfile_check_debug_is_found $build_id_1_filename \
-+ "find debuginfo, first build-id file is bad"
-+
-+remote_exec target "ln -fs $missing_debuginfo \
-+ $debugdir/$build_id_1_filename"
-+remote_exec target "ln -fs $missing_debuginfo \
-+ $debugdir/$build_id_3_filename"
-+
-+load_binfile_check_debug_is_found $build_id_2_filename \
-+ "find debuginfo, first 2 build-id files are bad"
-+
-+remote_exec target "ln -fs $missing_debuginfo \
-+ $debugdir/$build_id_2_filename"
-+
-+load_binfile_check_debug_is_found "" \
-+ "cannot find debuginfo, all build-id files are bad"
-+
-+remote_exec target "ln -fs $target_debuginfo \
-+ $debugdir/$build_id_3_filename"
-+
-+load_binfile_check_debug_is_found $build_id_3_filename \
-+ "find debuginfo, last build-id file is good"
-+
-+remote_exec target "rm -f $debugdir/$build_id_1_filename"
-+
-+load_binfile_check_debug_is_found "" \
-+ "cannot find debuginfo, file with seqno 1 is missing"
-diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
---- a/gdb/testsuite/lib/dwarf.exp
-+++ b/gdb/testsuite/lib/dwarf.exp
-@@ -2993,25 +2993,32 @@ namespace eval Dwarf {
-
- proc _note {type name hexdata} {
- set namelen [expr [string length $name] + 1]
-+ set datalen [expr [string length $hexdata] / 2]
-
- # Name size.
- _op .4byte $namelen
- # Data size.
-- _op .4byte [expr [string length $hexdata] / 2]
-+ _op .4byte $datalen
- # Type.
- _op .4byte $type
- # The name.
- _op .ascii [_quote $name]
-- # Alignment.
-+ # Alignment (to 4-byte boundary).
- set align 2
- set total [expr {($namelen + (1 << $align) - 1) & -(1 << $align)}]
- for {set i $namelen} {$i < $total} {incr i} {
-- _op .byte 0
-+ _op .byte 0 padding
- }
- # The data.
- foreach {a b} [split $hexdata {}] {
- _op .byte 0x$a$b
- }
-+ # Alignment (to 4-byte boundary).
-+ set align 2
-+ set total [expr {($datalen + (1 << $align) - 1) & -(1 << $align)}]
-+ for {set i $datalen} {$i < $total} {incr i} {
-+ _op .byte 0 padding
-+ }
- }
-
- # Emit a note section holding the given build-id.
-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
-@@ -5337,6 +5337,7 @@ proc quote_for_host { args } {
- # debug information
- # - text_segment=addr: Tell the linker to place the text segment at ADDR.
- # - build-id: Ensure the final binary includes a build-id.
-+# - no-build-id: Ensure the final binary does not include a build-id.
- # - column-info/no-column-info: Enable/Disable generation of column table
- # information.
- #
-@@ -5448,6 +5449,18 @@ proc gdb_compile {source dest type options} {
- lappend new_options "additional_flags=-Wl,--build-id"
- }
-
-+ # If the 'no-build-id' option is used then disable the build-id.
-+ if {[lsearch -exact $options no-build-id] > 0} {
-+ lappend new_options "additional_flags=-Wl,--build-id=none"
-+ }
-+
-+ # Sanity check. If both 'build-id' and 'no-build-id' are used
-+ # then what is expected from us!
-+ if {[lsearch -exact $options build-id] > 0
-+ && [lsearch -exact $options no-build-id] > 0} {
-+ error "cannot use build-id and no-build-id options"
-+ }
-+
- # Treating .c input files as C++ is deprecated in Clang, so
- # explicitly force C++ language.
- if { !$getting_compiler_info
-@@ -8144,21 +8157,25 @@ proc get_build_id { filename } {
-
- # Return the build-id hex string (usually 160 bits as 40 hex characters)
- # converted to the form: .build-id/ab/cdef1234...89.debug
-+#
-+# The '.debug' suffix can be changed by passing the SUFFIX argument.
-+#
- # Return "" if no build-id found.
--proc build_id_debug_filename_get { filename } {
-+proc build_id_debug_filename_get { filename {suffix ".debug"} } {
- set data [get_build_id $filename]
- if { $data == "" } {
- return ""
- }
- regsub {^..} $data {\0/} data
-- return ".build-id/${data}.debug"
-+ return ".build-id/${data}${suffix}"
- }
-
- # DEST should be a file compiled with debug information. This proc
--# creates two new files DEST.debug which contains the debug
--# information extracted from DEST, and DEST.stripped, which is a copy
--# of DEST with the debug information removed. A '.gnu_debuglink'
--# section will be added to DEST.stripped that points to DEST.debug.
-+# creates DEST.debug which contains the debug information extracted
-+# from DEST, and DEST is updated with the debug information removed.
-+#
-+# By default a '.gnu_debuglink' section will be added to DEST that
-+# points to DEST.debug.
- #
- # If ARGS is passed, it is a list of optional flags. The currently
- # supported flags are:
-@@ -8166,7 +8183,7 @@ proc build_id_debug_filename_get { filename } {
- # - no-main : remove the symbol entry for main from the separate
- # debug file DEST.debug,
- # - no-debuglink : don't add the '.gnu_debuglink' section to
--# DEST.stripped.
-+# DEST.
- #
- # Function returns zero on success. Function will return non-zero failure code
- # on some targets not supporting separate debug info (such as i386-msdos).
-@@ -8225,20 +8242,26 @@ proc gdb_gnu_strip_debug { dest args } {
- # Unless the "no-debuglink" flag is passed, then link the two
- # previous output files together, adding the .gnu_debuglink
- # section to the stripped_file, containing a pointer to the
-- # debug_file, save the new file in dest.
-+ # debug_file.
- if {[lsearch -exact $args "no-debuglink"] == -1} {
-- set result [catch "exec $objcopy_program --add-gnu-debuglink=${debug_file} ${stripped_file} ${dest}" output]
-+ set result [catch "exec $objcopy_program --add-gnu-debuglink=${debug_file} ${stripped_file} ${stripped_file}-tmp" output]
- verbose "result is $result"
- verbose "output is $output"
- if {$result == 1} {
- return 1
- }
-+ file delete "${stripped_file}"
-+ file rename "${stripped_file}-tmp" "${stripped_file}"
- }
-
- # Workaround PR binutils/10802:
- # Preserve the 'x' bit also for PIEs (Position Independent Executables).
-- set perm [file attributes ${stripped_file} -permissions]
-- file attributes ${dest} -permissions $perm
-+ set perm [file attributes ${dest} -permissions]
-+ file attributes ${stripped_file} -permissions $perm
-+
-+ # Move the stripped_file back into dest.
-+ file delete ${dest}
-+ file rename ${stripped_file} ${dest}
-
- return 0
- }
-diff --git a/gdbserver/hostio.cc b/gdbserver/hostio.cc
---- a/gdbserver/hostio.cc
-+++ b/gdbserver/hostio.cc
-@@ -486,6 +486,42 @@ handle_fstat (char *own_buf, int *new_packet_len)
- write_enn (own_buf);
- }
-
-+static void
-+handle_stat (char *own_buf, int *new_packet_len)
-+{
-+ int bytes_sent;
-+ char *p;
-+ struct stat st;
-+ struct fio_stat fst;
-+ char filename[HOSTIO_PATH_MAX];
-+
-+ p = own_buf + strlen ("vFile:stat:");
-+
-+ if (require_filename (&p, filename)
-+ || require_end (p))
-+ {
-+ hostio_packet_error (own_buf);
-+ return;
-+ }
-+
-+ if (lstat (filename, &st) == -1)
-+ {
-+ hostio_error (own_buf);
-+ return;
-+ }
-+
-+ host_to_fileio_stat (&st, &fst);
-+
-+ bytes_sent = hostio_reply_with_data (own_buf,
-+ (char *) &fst, sizeof (fst),
-+ new_packet_len);
-+
-+ /* If the response does not fit into a single packet, do not attempt
-+ to return a partial response, but simply fail. */
-+ if (bytes_sent < sizeof (fst))
-+ write_enn (own_buf);
-+}
-+
- static void
- handle_close (char *own_buf)
- {
-@@ -603,6 +639,8 @@ handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
- handle_pwrite (own_buf, packet_len);
- else if (startswith (own_buf, "vFile:fstat:"))
- handle_fstat (own_buf, new_packet_len);
-+ else if (startswith (own_buf, "vFile:stat:"))
-+ handle_stat (own_buf, new_packet_len);
- else if (startswith (own_buf, "vFile:close:"))
- handle_close (own_buf);
- else if (startswith (own_buf, "vFile:unlink:"))
-diff --git a/gdbsupport/pathstuff.cc b/gdbsupport/pathstuff.cc
---- a/gdbsupport/pathstuff.cc
-+++ b/gdbsupport/pathstuff.cc
-@@ -198,11 +198,17 @@ path_join (gdb::array_view<const char *> paths)
- {
- const char *path = paths[i];
-
-- if (i > 0)
-- gdb_assert (strlen (path) == 0 || !IS_ABSOLUTE_PATH (path));
--
-- if (!ret.empty () && !IS_DIR_SEPARATOR (ret.back ()))
-- ret += '/';
-+ if (!ret.empty ())
-+ {
-+ /* If RET doesn't already end with a separator then add one. */
-+ if (!IS_DIR_SEPARATOR (ret.back ()))
-+ ret += '/';
-+
-+ /* Now that RET ends with a separator, ignore any at the start of
-+ PATH. */
-+ while (IS_DIR_SEPARATOR (path[0]))
-+ ++path;
-+ }
-
- ret.append (path);
- }
-diff --git a/gdbsupport/pathstuff.h b/gdbsupport/pathstuff.h
---- a/gdbsupport/pathstuff.h
-+++ b/gdbsupport/pathstuff.h
-@@ -64,8 +64,10 @@ extern const char *child_path (const char *parent, const char *child);
-
- /* Join elements in PATHS into a single path.
-
-- The first element can be absolute or relative. All the others must be
-- relative. */
-+ The first element can be absolute or relative. Only a single directory
-+ separator will be placed between elements of PATHS, if one element ends
-+ with a directory separator, or an element starts with a directory
-+ separator, then these will be collapsed into a single separator. */
-
- extern std::string path_join (gdb::array_view<const char *> paths);
-
diff --git a/gdb-catchpoint-re-set.patch b/gdb-catchpoint-re-set.patch
deleted file mode 100644
index 4989700..0000000
--- a/gdb-catchpoint-re-set.patch
+++ /dev/null
@@ -1,575 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Andrew Burgess <aburgess@redhat.com>
-Date: Wed, 14 Aug 2024 15:16:46 +0100
-Subject: gdb-catchpoint-re-set.patch
-
- ;; Backport upstream commit a92e943014f to fix rhbz2304296.
-
-gdb: implement ::re_set method for catchpoint class
-
-It is possible to attach a condition to a catchpoint. This can't be
-done when the catchpoint is created, but can be done with the
-'condition' command, this is documented in the GDB manual:
-
- You can also use the 'if' keyword with the 'watch' command. The
- 'catch' command does not recognize the 'if' keyword; 'condition' is the
- only way to impose a further condition on a catchpoint.
-
-A GDB crash was reported against Fedora GDB where a user had attached
-a condition to a catchpoint and then restarted the inferior. When the
-catchpoint was hit GDB would immediately segfault. I was able to
-reproduce the failure on upstream GDB:
-
- (gdb) file ./some/binary
- (gdb) catch syscall write
- (gdb) run
- ...
- Catchpoint 1 (returned from syscall write), 0x00007ffff7b594a7 in write () from /lib64/libc.so.6
- (gdb) condition 1 $_streq((char *) $rsi, "foobar") == 0
- (gdb) run
- ...
- Fatal signal: Segmentation fault
- ...
-
-What happened here is that on the system in question we had debug
-information available for both the main application and also for
-libc.
-
-When the condition was attached GDB was stopped inside libc and as the
-debug information was available GDB found a reference to the 'char'
-type (for the cast) inside libc's debug information.
-
-When the inferior is restarted GDB discards all of the objfiles
-associated with shared libraries, and this includes libc. As such the
-'char' type, which is objfile owned, is discarded and the reference to
-it from the catchpoint's condition expression becomes invalid.
-
-Now, if it were a breakpoint instead of a catchpoint, what would
-happen is that after the shared library objfiles had been discarded
-we'd call the virtual breakpoint::re_set method on the breakpoint, and
-this would update the breakpoint's condition expression. This is
-because user breakpoints are actually instances of the code_breakpoint
-class and the code_breakpoint::re_set method contains the code to
-recompute the breakpoint's condition expression.
-
-However, catchpoints are instances of the catchpoint class which
-inherits from the base breakpoint class. The catchpoint class does
-not override breakpoint::re_set, and breakpoint::re_set is empty!
-
-The consequence of this is that catchpoint condition expressions are
-never recomputed, and the dangling pointer to the now deleted, objfile
-owned type 'char' is left around, and, when the catchpoint is hit, the
-invalid pointer is used when GDB tries to evaluate the condition
-expression.
-
-In this commit I have implemented catchpoint::re_set. This is pretty
-simple and just recomputes the condition expression as you'd expect.
-If the condition doesn't evaluate then the catchpoint is marked as
-disabled_by_cond.
-
-I have also made breakpoint::re_set pure virtual. With the addition
-of catchpoint::re_set every sub-class of breakpoint now implements the
-::re_set method, and if new sub-classes are added in the future I
-think that they _must_ implement ::re_set in order to avoid this
-problem. As such falling back to an empty breakpoint::re_set doesn't
-seem helpful.
-
-For testing I have not relied on stopping in libc and having libc
-debug information available, this doesn't seem like a good idea for
-the GDB testsuite. Instead I create a (rather pointless) condition
-check that uses a type defined only within a shared library. When the
-inferior is restarted the catchpoint will temporarily be marked as
-disabled_by_cond (due to the type not being available), but once the
-shared library is loaded again the catchpoint will be re-enabled.
-Without the fixes above then the same crashing behaviour can be
-observed.
-
-One point of note: the dangling pointer of course exposes undefined
-behaviour, with no guarantee of a crash. Though a crash is what I
-usually see I have see GDB throw random errors from the expression
-evaluation code, and once, I saw no problem at all! If you recompile
-GDB with the address sanitizer, or run under valgrind, then the bug
-will be exposed every time.
-
-After fixing this bug I checked bugzilla and found PR gdb/29960 which
-is the same bug. I was able to reproduce the bug before this commit,
-and after this commit GDB is no longer crashing.
-
-Before:
-
- (gdb) file /tmp/hello.x
- Reading symbols from /tmp/hello.x...
- (gdb) run
- Starting program: /tmp/hello.x
- Hello World
- [Inferior 1 (process 1101855) exited normally]
- (gdb) catch syscall 1
- Catchpoint 1 (syscall 'write' [1])
- (gdb) condition 1 write.fd == 1
- (gdb) run
- Starting program: /tmp/hello.x
-
- Fatal signal: Segmentation fault
- ...
-
-And after:
-
- (gdb) file /tmp/hello.x
- Reading symbols from /tmp/hello.x...
- (gdb) run
- Starting program: /tmp/hello.x
- Hello World
- Args: ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 )
- [Inferior 1 (process 1102373) exited normally]
- (gdb) catch syscall 1
- Catchpoint 1 (syscall 'write' [1])
- (gdb) condition 1 write.fd == 1
- (gdb) r
- Starting program: /tmp/hello.x
- Error in testing condition for breakpoint 1:
- Attempt to extract a component of a value that is not a structure.
-
- Catchpoint 1 (call to syscall write), 0x00007ffff7eb94a7 in write ()
- from /lib64/libc.so.6
- (gdb) ptype write
- type = <unknown return type> ()
- (gdb)
-
-Notice we get the error now when the condition fails to evaluate.
-This seems reasonable given that 'write' will be a function, and
-indeed the final 'ptype' shows that it's a function, not a struct.
-
-Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29960
-
-Reviewed-By: Tom de Vries <tdevries@suse.de>
-
-diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
---- a/gdb/breakpoint.c
-+++ b/gdb/breakpoint.c
-@@ -8146,6 +8146,60 @@ catchpoint::catchpoint (struct gdbarch *gdbarch, bool temp,
- pspace = current_program_space;
- }
-
-+/* See breakpoint.h. */
-+
-+void
-+catchpoint::re_set ()
-+{
-+ /* All catchpoints are associated with a specific program_space. */
-+ gdb_assert (pspace != nullptr);
-+
-+ /* Catchpoints have a single dummy location. */
-+ gdb_assert (locations ().size () == 1);
-+ bp_location &bl = m_locations.front ();
-+
-+ if (cond_string == nullptr)
-+ {
-+ /* It shouldn't be possible to have a parsed condition expression
-+ cached on this location if the catchpoint doesn't have a condition
-+ string set. */
-+ gdb_assert (bl.cond == nullptr);
-+
-+ /* Nothing to re-compute, and the catchpoint cannot change. */
-+ return;
-+ }
-+
-+ bool previous_disabled_by_cond = bl.disabled_by_cond;
-+
-+ /* Start by marking the location disabled and discarding the previously
-+ computed condition expression. Now if we get an exception, even if
-+ it's a quit exception, we'll leave the location disabled and there
-+ will be no (possibly invalid) expression cached. */
-+ bl.disabled_by_cond = true;
-+ bl.cond = nullptr;
-+
-+ const char *s = cond_string.get ();
-+ try
-+ {
-+ switch_to_program_space_and_thread (pspace);
-+
-+ bl.cond = parse_exp_1 (&s, bl.address, block_for_pc (bl.address),
-+ nullptr);
-+ bl.disabled_by_cond = false;
-+ }
-+ catch (const gdb_exception_error &e)
-+ {
-+ /* Any exception thrown must be from either the parse_exp_1 or
-+ earlier in the try block. As such the following two asserts
-+ should be true. */
-+ gdb_assert (bl.disabled_by_cond);
-+ gdb_assert (bl.cond == nullptr);
-+ }
-+
-+ if (previous_disabled_by_cond != bl.disabled_by_cond)
-+ notify_breakpoint_modified (this);
-+}
-+
- /* Notify interpreters and observers that breakpoint B was created. */
-
- static void
-diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
---- a/gdb/breakpoint.h
-+++ b/gdb/breakpoint.h
-@@ -702,11 +702,10 @@ struct breakpoint : public intrusive_list_node<breakpoint>
-
- /* Reevaluate a breakpoint. This is necessary after symbols change
- (e.g., an executable or DSO was loaded, or the inferior just
-- started). */
-- virtual void re_set ()
-- {
-- /* Nothing to re-set. */
-- }
-+ started). This is pure virtual as, at a minimum, each sub-class must
-+ recompute any cached condition expressions based off of the
-+ cond_string member variable. */
-+ virtual void re_set () = 0;
-
- /* Insert the breakpoint or watchpoint or activate the catchpoint.
- Return 0 for success, 1 if the breakpoint, watchpoint or
-@@ -1120,6 +1119,10 @@ struct catchpoint : public breakpoint
- catchpoint (struct gdbarch *gdbarch, bool temp, const char *cond_string);
-
- ~catchpoint () override = 0;
-+
-+ /* If the catchpoint has a condition set then recompute the cached
-+ expression within the single dummy location. */
-+ void re_set () override;
- };
-
- \f
-diff --git a/gdb/testsuite/gdb.base/reset-catchpoint-cond-lib.c b/gdb/testsuite/gdb.base/reset-catchpoint-cond-lib.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/reset-catchpoint-cond-lib.c
-@@ -0,0 +1,76 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <stdio.h>
-+#include <signal.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <unistd.h>
-+#include <assert.h>
-+#include <stdlib.h>
-+
-+/* This type is used by GDB. */
-+struct lib_type
-+{
-+ int a;
-+ int b;
-+ int c;
-+};
-+
-+/* Ensure the type above is used. */
-+volatile struct lib_type global_lib_object = { 1, 2, 3 };
-+
-+/* This pointer is checked by GDB. */
-+volatile void *opaque_ptr = 0;
-+
-+void
-+lib_func_test_syscall (void)
-+{
-+ puts ("Inside library\n");
-+ fflush (stdout);
-+}
-+
-+static void
-+sig_handler (int signo)
-+{
-+ /* Nothing. */
-+}
-+
-+void
-+lib_func_test_signal (void)
-+{
-+ signal (SIGUSR1, sig_handler);
-+
-+ kill (getpid (), SIGUSR1);
-+}
-+
-+void
-+lib_func_test_fork (void)
-+{
-+ pid_t pid = fork ();
-+ assert (pid != -1);
-+
-+ if (pid == 0)
-+ {
-+ /* Child: just exit. */
-+ exit (0);
-+ }
-+
-+ /* Parent. */
-+ waitpid (pid, NULL, 0);
-+}
-diff --git a/gdb/testsuite/gdb.base/reset-catchpoint-cond.c b/gdb/testsuite/gdb.base/reset-catchpoint-cond.c
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/reset-catchpoint-cond.c
-@@ -0,0 +1,50 @@
-+/* This testcase is part of GDB, the GNU debugger.
-+
-+ Copyright 2024 Free Software Foundation, Inc.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 3 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-+
-+extern void lib_func_test_syscall (void);
-+extern void lib_func_test_signal (void);
-+extern void lib_func_test_fork (void);
-+
-+/* We use this to perform some filler work. */
-+volatile int global_var = 0;
-+
-+/* Just somewhere for GDB to put a breakpoint. */
-+void
-+breakpt_before_exit (void)
-+{
-+ /* Nothing. */
-+}
-+
-+int
-+main (void)
-+{
-+#if defined TEST_SYSCALL
-+ lib_func_test_syscall ();
-+#elif defined TEST_SIGNAL
-+ lib_func_test_signal ();
-+#elif defined TEST_FORK
-+ lib_func_test_fork ();
-+#else
-+# error compile with suitable -DTEST_xxx macro defined
-+#endif
-+
-+ ++global_var;
-+
-+ breakpt_before_exit ();
-+
-+ return 0;
-+}
-diff --git a/gdb/testsuite/gdb.base/reset-catchpoint-cond.exp b/gdb/testsuite/gdb.base/reset-catchpoint-cond.exp
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/reset-catchpoint-cond.exp
-@@ -0,0 +1,169 @@
-+# Copyright 2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+# Test that the condition for a catchpoint is correctly reset after
-+# shared libraries are unloaded, as happens when an inferior is
-+# restarted.
-+#
-+# If this is not done then, when the catchpoint is hit on the second
-+# run, we'll evaluate the parsed expression from the first run, which
-+# might include references to types owned by the now deleted objfile
-+# (for the shared library loaded in the first run).
-+#
-+# This scripts tests a number of different catchpoint types. Inside
-+# GDB these are all sub-classes of the 'catchpoint' type, which is
-+# where the fix for the above issue resides, so all catchpoint types
-+# should work correctly.
-+
-+standard_testfile .c -lib.c
-+
-+set libfile $binfile-lib.so
-+
-+set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
-+
-+if {[build_executable "build shared library" $libfile $srcfile2 \
-+ {debug shlib}] == -1} {
-+ return
-+}
-+
-+# Depending on whether or not libc debug info is installed, when we
-+# hit a syscall catchpoint inside libc there might be a source line
-+# included in the output.
-+#
-+# This regexp will match an optional line and can be added to the
-+# expected catchpoint output to ignore the (possibly missing) source
-+# line.
-+set libc_src_line_re "(?:\r\n\[^\r\n\]+)?"
-+
-+# Check the Python bp_modified_list and then reset the list back to
-+# empty. TESTNAME is just a string. BP_NUM is a list of breakpoint
-+# numbers that are expected to appear (in the given order) in the
-+# bp_modified_list.
-+
-+proc check_modified_bp_list { testname bp_num } {
-+ if { [allow_python_tests] } {
-+ set expected [join $bp_num ", "]
-+
-+ gdb_test "python print(bp_modified_list)" "\\\[$expected\\\]" \
-+ $testname
-+ gdb_test_no_output -nopass "python bp_modified_list=\[\]" \
-+ "reset bp_modified_list after $testname"
-+ }
-+}
-+
-+# Build an executable and run tests on 'catch MODE'.
-+
-+proc run_test { mode } {
-+ set exec_name ${::binfile}-${mode}
-+
-+ set macro TEST_[string toupper $mode]
-+
-+ if {[build_executable "build test executable" $exec_name $::srcfile \
-+ [list debug shlib=$::libfile additional_flags=-D${macro}]] == -1} {
-+ return
-+ }
-+
-+ clean_restart $exec_name
-+ gdb_load_shlib $::libfile
-+
-+ if {![runto_main]} {
-+ return
-+ }
-+
-+ if { $mode eq "syscall" } {
-+ gdb_test "catch syscall write" \
-+ "Catchpoint $::decimal \\(syscall 'write' \[^)\]+\\)"
-+ set catch_re "call to syscall write"
-+ } elseif { $mode eq "signal" } {
-+ gdb_test "catch signal SIGUSR1" \
-+ "Catchpoint $::decimal \\(signal SIGUSR1\\)"
-+ set catch_re "signal SIGUSR1"
-+ } elseif { $mode eq "fork" } {
-+ gdb_test "catch fork" \
-+ "Catchpoint $::decimal \\(fork\\)"
-+ set catch_re "forked process $::decimal"
-+ } else {
-+ error "unknown mode $mode"
-+ }
-+ set cp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*"]
-+
-+ gdb_breakpoint "breakpt_before_exit"
-+
-+ gdb_test "continue" \
-+ "Catchpoint ${cp_num} \[^\r\n\]+$::libc_src_line_re"
-+
-+ if { [allow_python_tests] } {
-+ gdb_test_no_output "source $::pyfile" "import python scripts"
-+ check_modified_bp_list \
-+ "check b/p modified observer has not yet triggered" {}
-+ }
-+
-+ with_test_prefix "with false condition" {
-+ gdb_test_no_output "condition $cp_num ((struct lib_type *) opaque_ptr) != 0" \
-+ "set catchpoint condition"
-+
-+ check_modified_bp_list \
-+ "catchpoint modified once by setting condition" \
-+ [list $cp_num]
-+
-+ gdb_run_cmd
-+ gdb_test "" [multi_line \
-+ "Breakpoint $::decimal, main \\(\\) \[^\r\n\]+" \
-+ "$::decimal\\s+\[^\r\n\]+"]
-+
-+ check_modified_bp_list "catchpoint modified twice at startup" \
-+ [list $cp_num $cp_num "$::decimal"]
-+
-+ gdb_test "continue" \
-+ [multi_line \
-+ "Breakpoint $::decimal, breakpt_before_exit \\(\\) at \[^\r\n\]+" \
-+ "$::decimal\\s+\[^\r\n\]+"] \
-+ "continue to breakpt_before_exit"
-+ }
-+
-+ # Check the bp_modified_list against '.*'. We don't care at this
-+ # point what's in the list (nothing relevant has happened since we
-+ # last checked), but this has the side effect of clearing the list.
-+ check_modified_bp_list "clear bp modified list" { .* }
-+
-+ with_test_prefix "with true condition" {
-+ gdb_test_no_output "condition $cp_num ((struct lib_type *) opaque_ptr) == 0" \
-+ "set catchpoint condition"
-+
-+ check_modified_bp_list \
-+ "catchpoint modified once by setting condition" \
-+ [list $cp_num]
-+
-+ gdb_run_cmd
-+ gdb_test "" [multi_line \
-+ "Breakpoint $::decimal, main \\(\\) \[^\r\n\]+" \
-+ "$::decimal\\s+\[^\r\n\]+"]
-+
-+ check_modified_bp_list "catchpoint modified twice at startup" \
-+ [list $cp_num $cp_num "$::decimal"]
-+
-+ gdb_test "continue" \
-+ "Catchpoint $cp_num \\($catch_re\\), \[^\r\n\]+$::libc_src_line_re" \
-+ "continue until catchpoint hit"
-+
-+ check_modified_bp_list "catchpoint modified again when hit" \
-+ [list $cp_num]
-+ }
-+}
-+
-+# Run the tests.
-+foreach_with_prefix mode { syscall signal fork } {
-+ run_test $mode
-+}
-diff --git a/gdb/testsuite/gdb.base/reset-catchpoint-cond.py b/gdb/testsuite/gdb.base/reset-catchpoint-cond.py
-new file mode 100644
---- /dev/null
-+++ b/gdb/testsuite/gdb.base/reset-catchpoint-cond.py
-@@ -0,0 +1,21 @@
-+# Copyright (C) 2024 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+
-+bp_modified_list = []
-+
-+def bp_modified(bp):
-+ bp_modified_list.append (bp.number)
-+
-+gdb.events.breakpoint_modified.connect(bp_modified)
diff --git a/gdb-remove-qnx-neutrino-support.patch b/gdb-remove-qnx-neutrino-support.patch
deleted file mode 100644
index d13c9a1..0000000
--- a/gdb-remove-qnx-neutrino-support.patch
+++ /dev/null
@@ -1,2923 +0,0 @@
-From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
-From: Simon Marchi <simon.marchi@polymtl.ca>
-Date: Thu, 25 Jul 2024 13:41:35 -0400
-Subject: gdb-remove-qnx-neutrino-support.patch
-
-;; Backport of upstream commit 36fb20fa93484b104d. This is not really
-;; relevant for our branch, but later commits that are important, and
-;; which we want to backport, conflict unless the cleanup in this
-;; patch is in place.
-;;
-;; This commit will be part of GDB 16, so this back-port should drop
-;; out when we rebase onto GDB 16.
-;;
-;; gdb: remove QNX Neutrino support
-;;
-;; Remove the support for the QNX Neutrino OS (tdep and native bits). This
-;; has been unmaintained for years, and we don't have a way to see if it
-;; works (or even builds, for the native parts). Without somebody actively
-;; maintaining it, this is just a burden for developers, especially that
-;; this port does a few weird unique things that require reasoning about
-;; when doing big change.
-;;
-;; Support for GDBserver was removed in 2020, commit 613f149a90d6
-;; ("gdbserver: remove support for Neutrino").
-;;
-;; Change-Id: I4e25ec26ab06636629adebd02ceb161ee31c232d
-;; Approved-by: Kevin Buettner <kevinb@redhat.com>
-
-diff --git a/gdb/Makefile.in b/gdb/Makefile.in
---- a/gdb/Makefile.in
-+++ b/gdb/Makefile.in
-@@ -828,7 +828,6 @@ ALL_TARGET_OBS = \
- i386-go32-tdep.o \
- i386-linux-tdep.o \
- i386-netbsd-tdep.o \
-- i386-nto-tdep.o \
- i386-obsd-tdep.o \
- i386-sol2-tdep.o \
- i386-tdep.o \
-@@ -856,7 +855,6 @@ ALL_TARGET_OBS = \
- nds32-tdep.o \
- nios2-linux-tdep.o \
- nios2-tdep.o \
-- nto-tdep.o \
- obsd-tdep.o \
- or1k-linux-tdep.o \
- or1k-tdep.o \
-@@ -1441,7 +1439,6 @@ HFILES_NO_SRCDIR = \
- nds32-tdep.h \
- nios2-tdep.h \
- elf-none-tdep.h \
-- nto-tdep.h \
- objc-lang.h \
- objfiles.h \
- obsd-nat.h \
-@@ -1573,7 +1570,6 @@ HFILES_NO_SRCDIR = \
- compile/gcc-c-plugin.h \
- compile/gcc-cp-plugin.h \
- config/nm-linux.h \
-- config/nm-nto.h \
- config/djgpp/langinfo.h \
- config/djgpp/nl_types.h \
- config/i386/nm-i386gnu.h \
-diff --git a/gdb/config/nm-nto.h b/gdb/config/nm-nto.h
-deleted file mode 100644
---- a/gdb/config/nm-nto.h
-+++ /dev/null
-@@ -1,29 +0,0 @@
--/* Native support for QNX Neutrino version 6.
--
-- Copyright (C) 2003-2024 Free Software Foundation, Inc.
--
-- This code was donated by QNX Software Systems Ltd.
--
-- 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/>. */
--
--#ifndef CONFIG_NM_NTO_H
--#define CONFIG_NM_NTO_H
--
--/* Setup the valid realtime signal range. */
--#define REALTIME_LO 41
--#define REALTIME_HI 56
--
--#endif /* CONFIG_NM_NTO_H */
-diff --git a/gdb/configure.host b/gdb/configure.host
---- a/gdb/configure.host
-+++ b/gdb/configure.host
-@@ -110,7 +110,6 @@ i[34567]86-*-mingw32*) gdb_host=mingw
- i[34567]86-*-msdosdjgpp*) gdb_host=go32 ;;
- i[34567]86-*-linux*) gdb_host=linux ;;
- i[34567]86-*-gnu*) gdb_host=i386gnu ;;
--i[3456]86-*-nto*) gdb_host=nto ;;
- i[34567]86-*-openbsd*) gdb_host=obsd ;;
- i[34567]86-*-solaris2* | x86_64-*-solaris2*)
- gdb_host=sol2 ;;
-diff --git a/gdb/configure.nat b/gdb/configure.nat
---- a/gdb/configure.nat
-+++ b/gdb/configure.nat
-@@ -421,15 +421,6 @@ case ${gdb_host} in
-
- esac
- ;;
-- nto)
-- case ${gdb_host_cpu} in
-- i386)
-- # Host: Intel 386 running QNX.
-- NATDEPFILES='nto-procfs.o'
-- NAT_FILE='config/nm-nto.h'
-- ;;
-- esac
-- ;;
- obsd)
- case ${gdb_host_cpu} in
- i386)
-diff --git a/gdb/configure.tgt b/gdb/configure.tgt
---- a/gdb/configure.tgt
-+++ b/gdb/configure.tgt
-@@ -304,11 +304,6 @@ i[34567]86-*-openbsd*)
- # Target: OpenBSD/i386
- gdb_target_obs="i386-bsd-tdep.o i386-obsd-tdep.o bsd-uthread.o"
- ;;
--i[34567]86-*-nto*)
-- # Target: Intel 386 running qnx6.
-- gdb_target_obs="solib-svr4.o \
-- i386-nto-tdep.o nto-tdep.o"
-- ;;
- i[34567]86-*-solaris2* | x86_64-*-solaris2*)
- # Target: Solaris x86_64
- gdb_target_obs="${i386_tobjs} ${amd64_tobjs} \
-@@ -803,7 +798,6 @@ case "${targ}" in
- gdb_osabi=GDB_OSABI_FREEBSD ;;
- *-*-linux* | *-*-uclinux*)
- gdb_osabi=GDB_OSABI_LINUX ;;
--*-*-nto*) gdb_osabi=GDB_OSABI_QNXNTO ;;
- m68*-*-openbsd* | m88*-*-openbsd* | vax-*-openbsd*) ;;
- *-*-openbsd*) gdb_osabi=GDB_OSABI_OPENBSD ;;
- *-*-solaris*) gdb_osabi=GDB_OSABI_SOLARIS ;;
-diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
---- a/gdb/doc/gdb.texinfo
-+++ b/gdb/doc/gdb.texinfo
-@@ -2742,7 +2742,7 @@ environment:
- @end smallexample
-
- This command is available when debugging locally on most targets, excluding
--@sc{djgpp}, Cygwin, MS Windows, and QNX Neutrino.
-+@sc{djgpp}, Cygwin, and MS Windows.
-
- @kindex set startup-with-shell
- @anchor{set startup-with-shell}
-@@ -22011,7 +22011,7 @@ name and remembers it that way.
- @cindex shared libraries
- @anchor{Shared Libraries}
- @value{GDBN} supports @sc{gnu}/Linux, MS-Windows, SunOS,
--Darwin/Mach-O, SVr4, IBM RS/6000 AIX, QNX Neutrino, FDPIC (FR-V), and
-+Darwin/Mach-O, SVr4, IBM RS/6000 AIX, FDPIC (FR-V), and
- DSBT (TIC6X) shared libraries.
-
- On MS-Windows @value{GDBN} must be linked with the Expat library to support
-@@ -25203,16 +25203,6 @@ Show the file to which @code{procfs} API trace is written.
- These commands enable and disable tracing of entries into and exits
- from the @code{syscall} interface.
-
--@item info pidlist
--@kindex info pidlist
--@cindex process list, QNX Neutrino
--For QNX Neutrino only, this command displays the list of all the
--processes and all the threads within each process.
--
--@item info meminfo
--@kindex info meminfo
--@cindex mapinfo list, QNX Neutrino
--For QNX Neutrino only, this command displays the list of all mapinfos.
- @end table
-
- @node DJGPP Native
-diff --git a/gdb/i386-nto-tdep.c b/gdb/i386-nto-tdep.c
-deleted file mode 100644
---- a/gdb/i386-nto-tdep.c
-+++ /dev/null
-@@ -1,379 +0,0 @@
--/* Target-dependent code for QNX Neutrino x86.
--
-- Copyright (C) 2003-2024 Free Software Foundation, Inc.
--
-- Contributed by QNX Software Systems Ltd.
--
-- 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/>. */
--
--#include "extract-store-integer.h"
--#include "frame.h"
--#include "osabi.h"
--#include "regcache.h"
--#include "target.h"
--
--#include "i386-tdep.h"
--#include "i387-tdep.h"
--#include "nto-tdep.h"
--#include "solib.h"
--#include "solib-svr4.h"
--
--#ifndef X86_CPU_FXSR
--#define X86_CPU_FXSR (1L << 12)
--#endif
--
--/* Why 13? Look in our /usr/include/x86/context.h header at the
-- x86_cpu_registers structure and you'll see an 'exx' junk register
-- that is just filler. Don't ask me, ask the kernel guys. */
--#define NUM_GPREGS 13
--
--/* Mapping between the general-purpose registers in `struct xxx'
-- format and GDB's register cache layout. */
--
--/* From <x86/context.h>. */
--static int i386nto_gregset_reg_offset[] =
--{
-- 7 * 4, /* %eax */
-- 6 * 4, /* %ecx */
-- 5 * 4, /* %edx */
-- 4 * 4, /* %ebx */
-- 11 * 4, /* %esp */
-- 2 * 4, /* %epb */
-- 1 * 4, /* %esi */
-- 0 * 4, /* %edi */
-- 8 * 4, /* %eip */
-- 10 * 4, /* %eflags */
-- 9 * 4, /* %cs */
-- 12 * 4, /* %ss */
-- -1 /* filler */
--};
--
--/* Given a GDB register number REGNUM, return the offset into
-- Neutrino's register structure or -1 if the register is unknown. */
--
--static int
--nto_reg_offset (int regnum)
--{
-- if (regnum >= 0 && regnum < ARRAY_SIZE (i386nto_gregset_reg_offset))
-- return i386nto_gregset_reg_offset[regnum];
--
-- return -1;
--}
--
--static void
--i386nto_supply_gregset (struct regcache *regcache, char *gpregs)
--{
-- struct gdbarch *gdbarch = regcache->arch ();
-- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
--
-- gdb_assert (tdep->gregset_reg_offset == i386nto_gregset_reg_offset);
-- i386_gregset.supply_regset (&i386_gregset, regcache, -1,
-- gpregs, NUM_GPREGS * 4);
--}
--
--static void
--i386nto_supply_fpregset (struct regcache *regcache, char *fpregs)
--{
-- if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
-- i387_supply_fxsave (regcache, -1, fpregs);
-- else
-- i387_supply_fsave (regcache, -1, fpregs);
--}
--
--static void
--i386nto_supply_regset (struct regcache *regcache, int regset, char *data)
--{
-- switch (regset)
-- {
-- case NTO_REG_GENERAL:
-- i386nto_supply_gregset (regcache, data);
-- break;
-- case NTO_REG_FLOAT:
-- i386nto_supply_fpregset (regcache, data);
-- break;
-- }
--}
--
--static int
--i386nto_regset_id (int regno)
--{
-- if (regno == -1)
-- return NTO_REG_END;
-- else if (regno < I386_NUM_GREGS)
-- return NTO_REG_GENERAL;
-- else if (regno < I386_NUM_GREGS + I387_NUM_REGS)
-- return NTO_REG_FLOAT;
-- else if (regno < I386_SSE_NUM_REGS)
-- return NTO_REG_FLOAT; /* We store xmm registers in fxsave_area. */
--
-- return -1; /* Error. */
--}
--
--static int
--i386nto_register_area (struct gdbarch *gdbarch,
-- int regno, int regset, unsigned *off)
--{
-- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
--
-- *off = 0;
-- if (regset == NTO_REG_GENERAL)
-- {
-- if (regno == -1)
-- return NUM_GPREGS * 4;
--
-- *off = nto_reg_offset (regno);
-- if (*off == -1)
-- return 0;
-- return 4;
-- }
-- else if (regset == NTO_REG_FLOAT)
-- {
-- unsigned off_adjust, regsize, regset_size, regno_base;
-- /* The following are flags indicating number in our fxsave_area. */
-- int first_four = (regno >= I387_FCTRL_REGNUM (tdep)
-- && regno <= I387_FISEG_REGNUM (tdep));
-- int second_four = (regno > I387_FISEG_REGNUM (tdep)
-- && regno <= I387_FOP_REGNUM (tdep));
-- int st_reg = (regno >= I387_ST0_REGNUM (tdep)
-- && regno < I387_ST0_REGNUM (tdep) + 8);
-- int xmm_reg = (regno >= I387_XMM0_REGNUM (tdep)
-- && regno < I387_MXCSR_REGNUM (tdep));
--
-- if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
-- {
-- off_adjust = 32;
-- regsize = 16;
-- regset_size = 512;
-- /* fxsave_area structure. */
-- if (first_four)
-- {
-- /* fpu_control_word, fpu_status_word, fpu_tag_word, fpu_operand
-- registers. */
-- regsize = 2; /* Two bytes each. */
-- off_adjust = 0;
-- regno_base = I387_FCTRL_REGNUM (tdep);
-- }
-- else if (second_four)
-- {
-- /* fpu_ip, fpu_cs, fpu_op, fpu_ds registers. */
-- regsize = 4;
-- off_adjust = 8;
-- regno_base = I387_FISEG_REGNUM (tdep) + 1;
-- }
-- else if (st_reg)
-- {
-- /* ST registers. */
-- regsize = 16;
-- off_adjust = 32;
-- regno_base = I387_ST0_REGNUM (tdep);
-- }
-- else if (xmm_reg)
-- {
-- /* XMM registers. */
-- regsize = 16;
-- off_adjust = 160;
-- regno_base = I387_XMM0_REGNUM (tdep);
-- }
-- else if (regno == I387_MXCSR_REGNUM (tdep))
-- {
-- regsize = 4;
-- off_adjust = 24;
-- regno_base = I387_MXCSR_REGNUM (tdep);
-- }
-- else
-- {
-- /* Whole regset. */
-- gdb_assert (regno == -1);
-- off_adjust = 0;
-- regno_base = 0;
-- regsize = regset_size;
-- }
-- }
-- else
-- {
-- regset_size = 108;
-- /* fsave_area structure. */
-- if (first_four || second_four)
-- {
-- /* fpu_control_word, ... , fpu_ds registers. */
-- regsize = 4;
-- off_adjust = 0;
-- regno_base = I387_FCTRL_REGNUM (tdep);
-- }
-- else if (st_reg)
-- {
-- /* One of ST registers. */
-- regsize = 10;
-- off_adjust = 7 * 4;
-- regno_base = I387_ST0_REGNUM (tdep);
-- }
-- else
-- {
-- /* Whole regset. */
-- gdb_assert (regno == -1);
-- off_adjust = 0;
-- regno_base = 0;
-- regsize = regset_size;
-- }
-- }
--
-- if (regno != -1)
-- *off = off_adjust + (regno - regno_base) * regsize;
-- else
-- *off = 0;
-- return regsize;
-- }
-- return -1;
--}
--
--static int
--i386nto_regset_fill (const struct regcache *regcache, int regset, char *data)
--{
-- if (regset == NTO_REG_GENERAL)
-- {
-- int regno;
--
-- for (regno = 0; regno < NUM_GPREGS; regno++)
-- {
-- int offset = nto_reg_offset (regno);
-- if (offset != -1)
-- regcache->raw_collect (regno, data + offset);
-- }
-- }
-- else if (regset == NTO_REG_FLOAT)
-- {
-- if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
-- i387_collect_fxsave (regcache, -1, data);
-- else
-- i387_collect_fsave (regcache, -1, data);
-- }
-- else
-- return -1;
--
-- return 0;
--}
--
--/* Return whether THIS_FRAME corresponds to a QNX Neutrino sigtramp
-- routine. */
--
--static int
--i386nto_sigtramp_p (const frame_info_ptr &this_frame)
--{
-- CORE_ADDR pc = get_frame_pc (this_frame);
-- const char *name;
--
-- find_pc_partial_function (pc, &name, NULL, NULL);
-- return name && strcmp ("__signalstub", name) == 0;
--}
--
--/* Assuming THIS_FRAME is a QNX Neutrino sigtramp routine, return the
-- address of the associated sigcontext structure. */
--
--static CORE_ADDR
--i386nto_sigcontext_addr (const frame_info_ptr &this_frame)
--{
-- struct gdbarch *gdbarch = get_frame_arch (this_frame);
-- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-- gdb_byte buf[4];
-- CORE_ADDR ptrctx;
--
-- /* We store __ucontext_t addr in EDI register. */
-- get_frame_register (this_frame, I386_EDI_REGNUM, buf);
-- ptrctx = extract_unsigned_integer (buf, 4, byte_order);
-- ptrctx += 24 /* Context pointer is at this offset. */;
--
-- return ptrctx;
--}
--
--static void
--init_i386nto_ops (void)
--{
-- nto_regset_id = i386nto_regset_id;
-- nto_supply_gregset = i386nto_supply_gregset;
-- nto_supply_fpregset = i386nto_supply_fpregset;
-- nto_supply_altregset = nto_dummy_supply_regset;
-- nto_supply_regset = i386nto_supply_regset;
-- nto_register_area = i386nto_register_area;
-- nto_regset_fill = i386nto_regset_fill;
-- nto_fetch_link_map_offsets =
-- svr4_ilp32_fetch_link_map_offsets;
--}
--
--static void
--i386nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
--{
-- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-- static solib_ops nto_svr4_so_ops;
--
-- /* Deal with our strange signals. */
-- nto_initialize_signals ();
--
-- /* NTO uses ELF. */
-- i386_elf_init_abi (info, gdbarch);
--
-- /* Neutrino rewinds to look more normal. Need to override the i386
-- default which is [unfortunately] to decrement the PC. */
-- set_gdbarch_decr_pc_after_break (gdbarch, 0);
--
-- tdep->gregset_reg_offset = i386nto_gregset_reg_offset;
-- tdep->gregset_num_regs = ARRAY_SIZE (i386nto_gregset_reg_offset);
-- tdep->sizeof_gregset = NUM_GPREGS * 4;
--
-- tdep->sigtramp_p = i386nto_sigtramp_p;
-- tdep->sigcontext_addr = i386nto_sigcontext_addr;
-- tdep->sc_reg_offset = i386nto_gregset_reg_offset;
-- tdep->sc_num_regs = ARRAY_SIZE (i386nto_gregset_reg_offset);
--
-- /* Setjmp()'s return PC saved in EDX (5). */
-- tdep->jb_pc_offset = 20; /* 5x32 bit ints in. */
--
-- set_solib_svr4_fetch_link_map_offsets
-- (gdbarch, svr4_ilp32_fetch_link_map_offsets);
--
-- /* Initialize this lazily, to avoid an initialization order
-- dependency on solib-svr4.c's _initialize routine. */
-- if (nto_svr4_so_ops.in_dynsym_resolve_code == NULL)
-- {
-- nto_svr4_so_ops = svr4_so_ops;
--
-- /* Our loader handles solib relocations differently than svr4. */
-- nto_svr4_so_ops.relocate_section_addresses
-- = nto_relocate_section_addresses;
--
-- /* Supply a nice function to find our solibs. */
-- nto_svr4_so_ops.find_and_open_solib
-- = nto_find_and_open_solib;
--
-- /* Our linker code is in libc. */
-- nto_svr4_so_ops.in_dynsym_resolve_code
-- = nto_in_dynsym_resolve_code;
-- }
-- set_gdbarch_so_ops (gdbarch, &nto_svr4_so_ops);
--
-- set_gdbarch_wchar_bit (gdbarch, 32);
-- set_gdbarch_wchar_signed (gdbarch, 0);
--}
--
--void _initialize_i386nto_tdep ();
--void
--_initialize_i386nto_tdep ()
--{
-- init_i386nto_ops ();
-- gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_QNXNTO,
-- i386nto_init_abi);
-- gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
-- nto_elf_osabi_sniffer);
--}
-diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
-deleted file mode 100644
---- a/gdb/nto-procfs.c
-+++ /dev/null
-@@ -1,1588 +0,0 @@
--/* Machine independent support for QNX Neutrino /proc (process file system)
-- for GDB. Written by Colin Burgess at QNX Software Systems Limited.
--
-- Copyright (C) 2003-2024 Free Software Foundation, Inc.
--
-- Contributed by QNX Software Systems Ltd.
--
-- 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/>. */
--
--
--#include <fcntl.h>
--#include <spawn.h>
--#include <sys/debug.h>
--#include <sys/procfs.h>
--#include <sys/neutrino.h>
--#include <sys/syspage.h>
--#include <dirent.h>
--#include <sys/netmgr.h>
--#include <sys/auxv.h>
--
--#include "gdbcore.h"
--#include "inferior.h"
--#include "target.h"
--#include "objfiles.h"
--#include "gdbthread.h"
--#include "nto-tdep.h"
--#include "command.h"
--#include "regcache.h"
--#include "solib.h"
--#include "inf-child.h"
--#include "gdbsupport/filestuff.h"
--#include "gdbsupport/scoped_fd.h"
--
--#define NULL_PID 0
--#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
-- _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY)
--
--int ctl_fd;
--
--static sighandler_t ofunc;
--
--static procfs_run run;
--
--/* Create the "native" and "procfs" targets. */
--
--struct nto_procfs_target : public inf_child_target
--{
-- void open (const char *arg, int from_tty) override;
--
-- void attach (const char *, int) override = 0;
--
-- void post_attach (int);
--
-- void detach (inferior *, int) override;
--
-- void resume (ptid_t, int, enum gdb_signal) override;
--
-- ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
--
-- void fetch_registers (struct regcache *, int) override;
-- void store_registers (struct regcache *, int) override;
--
-- enum target_xfer_status xfer_partial (enum target_object object,
-- const char *annex,
-- gdb_byte *readbuf,
-- const gdb_byte *writebuf,
-- ULONGEST offset, ULONGEST len,
-- ULONGEST *xfered_len) override;
--
-- void files_info () override;
--
-- int insert_breakpoint (struct gdbarch *, struct bp_target_info *) override;
--
-- int remove_breakpoint (struct gdbarch *, struct bp_target_info *,
-- enum remove_bp_reason) override;
--
-- int can_use_hw_breakpoint (enum bptype, int, int) override;
--
-- int insert_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override;
--
-- int remove_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override;
--
-- int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
-- struct expression *) override;
--
-- int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
-- struct expression *) override;
--
-- bool stopped_by_watchpoint () override;
--
-- void kill () override;
--
-- void create_inferior (const char *, const std::string &,
-- char **, int) override;
--
-- void mourn_inferior () override;
--
-- void pass_signals (gdb::array_view<const unsigned char>) override;
--
-- bool thread_alive (ptid_t ptid) override;
--
-- void update_thread_list () override;
--
-- std::string pid_to_str (ptid_t) override;
--
-- void interrupt () override;
--
-- const char *extra_thread_info (struct thread_info *) override;
--
-- const char *pid_to_exec_file (int pid) override;
--};
--
--/* For "target native". */
--
--static const target_info nto_native_target_info = {
-- "native",
-- N_("QNX Neutrino local process"),
-- N_("QNX Neutrino local process (started by the \"run\" command).")
--};
--
--class nto_procfs_target_native final : public nto_procfs_target
--{
-- const target_info &info () const override
-- { return nto_native_target_info; }
--};
--
--/* For "target procfs <node>". */
--
--static const target_info nto_procfs_target_info = {
-- "procfs",
-- N_("QNX Neutrino local or remote process"),
-- N_("QNX Neutrino process. target procfs NODE")
--};
--
--struct nto_procfs_target_procfs final : public nto_procfs_target
--{
-- const target_info &info () const override
-- { return nto_procfs_target_info; }
--};
--
--static ptid_t do_attach (ptid_t ptid);
--
--/* These two globals are only ever set in procfs_open_1, but are
-- referenced elsewhere. 'nto_procfs_node' is a flag used to say
-- whether we are local, or we should get the current node descriptor
-- for the remote QNX node. */
--static char *nodestr;
--static unsigned nto_procfs_node = ND_LOCAL_NODE;
--
--/* Return the current QNX Node, or error out. This is a simple
-- wrapper for the netmgr_strtond() function. The reason this
-- is required is because QNX node descriptors are transient so
-- we have to re-acquire them every time. */
--static unsigned
--nto_node (void)
--{
-- unsigned node;
--
-- if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0
-- || nodestr == NULL)
-- return ND_LOCAL_NODE;
--
-- node = netmgr_strtond (nodestr, 0);
-- if (node == -1)
-- error (_("Lost the QNX node. Debug session probably over."));
--
-- return (node);
--}
--
--static enum gdb_osabi
--procfs_is_nto_target (bfd *abfd)
--{
-- return GDB_OSABI_QNXNTO;
--}
--
--/* This is called when we call 'target native' or 'target procfs
-- <arg>' from the (gdb) prompt. For QNX6 (nto), the only valid arg
-- will be a QNX node string, eg: "/net/some_node". If arg is not a
-- valid QNX node, we will default to local. */
--void
--nto_procfs_target::open (const char *arg, int from_tty)
--{
-- char *endstr;
-- char buffer[50];
-- int total_size;
-- procfs_sysinfo *sysinfo;
-- char nto_procfs_path[PATH_MAX];
--
-- /* Offer to kill previous inferiors before opening this target. */
-- target_preopen (from_tty);
--
-- nto_is_nto_target = procfs_is_nto_target;
--
-- /* Set the default node used for spawning to this one,
-- and only override it if there is a valid arg. */
--
-- xfree (nodestr);
-- nodestr = NULL;
--
-- nto_procfs_node = ND_LOCAL_NODE;
-- nodestr = (arg != NULL) ? xstrdup (arg) : NULL;
--
-- if (nodestr)
-- {
-- nto_procfs_node = netmgr_strtond (nodestr, &endstr);
-- if (nto_procfs_node == -1)
-- {
-- if (errno == ENOTSUP)
-- gdb_printf ("QNX Net Manager not found.\n");
-- gdb_printf ("Invalid QNX node %s: error %d (%s).\n", nodestr,
-- errno, safe_strerror (errno));
-- xfree (nodestr);
-- nodestr = NULL;
-- nto_procfs_node = ND_LOCAL_NODE;
-- }
-- else if (*endstr)
-- {
-- if (*(endstr - 1) == '/')
-- *(endstr - 1) = 0;
-- else
-- *endstr = 0;
-- }
-- }
-- snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s",
-- (nodestr != NULL) ? nodestr : "", "/proc");
--
-- scoped_fd fd (open (nto_procfs_path, O_RDONLY));
-- if (fd.get () == -1)
-- {
-- gdb_printf ("Error opening %s : %d (%s)\n", nto_procfs_path, errno,
-- safe_strerror (errno));
-- error (_("Invalid procfs arg"));
-- }
--
-- sysinfo = (void *) buffer;
-- if (devctl (fd.get (), DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK)
-- {
-- gdb_printf ("Error getting size: %d (%s)\n", errno,
-- safe_strerror (errno));
-- error (_("Devctl failed."));
-- }
-- else
-- {
-- total_size = sysinfo->total_size;
-- sysinfo = alloca (total_size);
-- if (sysinfo == NULL)
-- {
-- gdb_printf ("Memory error: %d (%s)\n", errno,
-- safe_strerror (errno));
-- error (_("alloca failed."));
-- }
-- else
-- {
-- if (devctl (fd.get (), DCMD_PROC_SYSINFO, sysinfo, total_size, 0)
-- != EOK)
-- {
-- gdb_printf ("Error getting sysinfo: %d (%s)\n", errno,
-- safe_strerror (errno));
-- error (_("Devctl failed."));
-- }
-- else
-- {
-- if (sysinfo->type !=
-- nto_map_arch_to_cputype
-- (gdbarch_bfd_arch_info
-- (current_inferior ()->arch ())->arch_name))
-- error (_("Invalid target CPU."));
-- }
-- }
-- }
--
-- inf_child_target::open (arg, from_tty);
-- gdb_printf ("Debugging using %s\n", nto_procfs_path);
--}
--
--static void
--procfs_set_thread (ptid_t ptid)
--{
-- pid_t tid;
--
-- tid = ptid.tid ();
-- devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0);
--}
--
--/* Return true if the thread TH is still alive. */
--
--bool
--nto_procfs_target::thread_alive (ptid_t ptid)
--{
-- pid_t tid;
-- pid_t pid;
-- procfs_status status;
-- int err;
--
-- tid = ptid.tid ();
-- pid = ptid.pid ();
--
-- if (kill (pid, 0) == -1)
-- return false;
--
-- status.tid = tid;
-- if ((err = devctl (ctl_fd, DCMD_PROC_TIDSTATUS,
-- &status, sizeof (status), 0)) != EOK)
-- return false;
--
-- /* Thread is alive or dead but not yet joined,
-- or dead and there is an alive (or dead unjoined) thread with
-- higher tid.
--
-- If the tid is not the same as requested, requested tid is dead. */
-- return (status.tid == tid) && (status.state != STATE_DEAD);
--}
--
--static void
--update_thread_private_data_name (struct thread_info *new_thread,
-- const char *newname)
--{
-- nto_thread_info *pti = get_nto_thread_info (new_thread);
--
-- gdb_assert (newname != NULL);
-- gdb_assert (new_thread != NULL);
--
-- if (pti)
-- {
-- pti = new nto_thread_info;
-- new_thread->priv.reset (pti);
-- }
--
-- pti->name = newname;
--}
--
--static void
--update_thread_private_data (struct thread_info *new_thread,
-- pthread_t tid, int state, int flags)
--{
-- procfs_info pidinfo;
-- struct _thread_name *tn;
-- procfs_threadctl tctl;
--
--#if _NTO_VERSION > 630
-- gdb_assert (new_thread != NULL);
--
-- if (devctl (ctl_fd, DCMD_PROC_INFO, &pidinfo,
-- sizeof(pidinfo), 0) != EOK)
-- return;
--
-- memset (&tctl, 0, sizeof (tctl));
-- tctl.cmd = _NTO_TCTL_NAME;
-- tn = (struct _thread_name *) (&tctl.data);
--
-- /* Fetch name for the given thread. */
-- tctl.tid = tid;
-- tn->name_buf_len = sizeof (tctl.data) - sizeof (*tn);
-- tn->new_name_len = -1; /* Getting, not setting. */
-- if (devctl (ctl_fd, DCMD_PROC_THREADCTL, &tctl, sizeof (tctl), NULL) != EOK)
-- tn->name_buf[0] = '\0';
--
-- tn->name_buf[_NTO_THREAD_NAME_MAX] = '\0';
--
-- update_thread_private_data_name (new_thread, tn->name_buf);
--
-- nto_thread_info *pti = get_nto_thread_info (new_thread);
-- pti->tid = tid;
-- pti->state = state;
-- pti->flags = flags;
--#endif /* _NTO_VERSION */
--}
--
--void
--nto_procfs_target::update_thread_list ()
--{
-- procfs_status status;
-- pid_t pid;
-- ptid_t ptid;
-- pthread_t tid;
-- struct thread_info *new_thread;
--
-- if (ctl_fd == -1)
-- return;
--
-- prune_threads ();
--
-- pid = current_inferior ()->pid;
--
-- status.tid = 1;
--
-- for (tid = 1;; ++tid)
-- {
-- if (status.tid == tid
-- && (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0)
-- != EOK))
-- break;
-- if (status.tid != tid)
-- /* The reason why this would not be equal is that devctl might have
-- returned different tid, meaning the requested tid no longer exists
-- (e.g. thread exited). */
-- continue;
-- ptid = ptid_t (pid, 0, tid);
-- new_thread = this->find_thread (ptid);
-- if (!new_thread)
-- new_thread = add_thread (ptid);
-- update_thread_private_data (new_thread, tid, status.state, 0);
-- status.tid++;
-- }
-- return;
--}
--
--static void
--procfs_pidlist (const char *args, int from_tty)
--{
-- struct dirent *dirp = NULL;
-- char buf[PATH_MAX];
-- procfs_info *pidinfo = NULL;
-- procfs_debuginfo *info = NULL;
-- procfs_status *status = NULL;
-- pid_t num_threads = 0;
-- pid_t pid;
-- char name[512];
-- char procfs_dir[PATH_MAX];
--
-- snprintf (procfs_dir, sizeof (procfs_dir), "%s%s",
-- (nodestr != NULL) ? nodestr : "", "/proc");
--
-- gdb_dir_up dp (opendir (procfs_dir));
-- if (dp == NULL)
-- {
-- gdb_printf (gdb_stderr, "failed to opendir \"%s\" - %d (%s)",
-- procfs_dir, errno, safe_strerror (errno));
-- return;
-- }
--
-- /* Start scan at first pid. */
-- rewinddir (dp.get ());
--
-- do
-- {
-- /* Get the right pid and procfs path for the pid. */
-- do
-- {
-- dirp = readdir (dp.get ());
-- if (dirp == NULL)
-- return;
-- snprintf (buf, sizeof (buf), "%s%s/%s/as",
-- (nodestr != NULL) ? nodestr : "",
-- "/proc", dirp->d_name);
-- pid = atoi (dirp->d_name);
-- }
-- while (pid == 0);
--
-- /* Open the procfs path. */
-- scoped_fd fd (open (buf, O_RDONLY));
-- if (fd.get () == -1)
-- {
-- gdb_printf (gdb_stderr, "failed to open %s - %d (%s)\n",
-- buf, errno, safe_strerror (errno));
-- continue;
-- }
--
-- pidinfo = (procfs_info *) buf;
-- if (devctl (fd.get (), DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK)
-- {
-- gdb_printf (gdb_stderr,
-- "devctl DCMD_PROC_INFO failed - %d (%s)\n",
-- errno, safe_strerror (errno));
-- break;
-- }
-- num_threads = pidinfo->num_threads;
--
-- info = (procfs_debuginfo *) buf;
-- if (devctl (fd.get (), DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0)
-- != EOK)
-- strcpy (name, "unavailable");
-- else
-- strcpy (name, info->path);
--
-- /* Collect state info on all the threads. */
-- status = (procfs_status *) buf;
-- for (status->tid = 1; status->tid <= num_threads; status->tid++)
-- {
-- const int err
-- = devctl (fd.get (), DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0);
-- gdb_printf ("%s - %d", name, pid);
-- if (err == EOK && status->tid != 0)
-- gdb_printf ("/%d\n", status->tid);
-- else
-- {
-- gdb_printf ("\n");
-- break;
-- }
-- }
-- }
-- while (dirp != NULL);
--}
--
--static void
--procfs_meminfo (const char *args, int from_tty)
--{
-- procfs_mapinfo *mapinfos = NULL;
-- static int num_mapinfos = 0;
-- procfs_mapinfo *mapinfo_p, *mapinfo_p2;
-- int flags = ~0, err, num, i, j;
--
-- struct
-- {
-- procfs_debuginfo info;
-- char buff[_POSIX_PATH_MAX];
-- } map;
--
-- struct info
-- {
-- unsigned addr;
-- unsigned size;
-- unsigned flags;
-- unsigned debug_vaddr;
-- unsigned long long offset;
-- };
--
-- struct printinfo
-- {
-- unsigned long long ino;
-- unsigned dev;
-- struct info text;
-- struct info data;
-- char name[256];
-- } printme;
--
-- /* Get the number of map entrys. */
-- err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num);
-- if (err != EOK)
-- {
-- printf ("failed devctl num mapinfos - %d (%s)\n", err,
-- safe_strerror (err));
-- return;
-- }
--
-- mapinfos = XNEWVEC (procfs_mapinfo, num);
--
-- num_mapinfos = num;
-- mapinfo_p = mapinfos;
--
-- /* Fill the map entrys. */
-- err = devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, num
-- * sizeof (procfs_mapinfo), &num);
-- if (err != EOK)
-- {
-- printf ("failed devctl mapinfos - %d (%s)\n", err, safe_strerror (err));
-- xfree (mapinfos);
-- return;
-- }
--
-- num = std::min (num, num_mapinfos);
--
-- /* Run through the list of mapinfos, and store the data and text info
-- so we can print it at the bottom of the loop. */
-- for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++)
-- {
-- if (!(mapinfo_p->flags & flags))
-- mapinfo_p->ino = 0;
--
-- if (mapinfo_p->ino == 0) /* Already visited. */
-- continue;
--
-- map.info.vaddr = mapinfo_p->vaddr;
--
-- err = devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
-- if (err != EOK)
-- continue;
--
-- memset (&printme, 0, sizeof printme);
-- printme.dev = mapinfo_p->dev;
-- printme.ino = mapinfo_p->ino;
-- printme.text.addr = mapinfo_p->vaddr;
-- printme.text.size = mapinfo_p->size;
-- printme.text.flags = mapinfo_p->flags;
-- printme.text.offset = mapinfo_p->offset;
-- printme.text.debug_vaddr = map.info.vaddr;
-- strcpy (printme.name, map.info.path);
--
-- /* Check for matching data. */
-- for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++)
-- {
-- if (mapinfo_p2->vaddr != mapinfo_p->vaddr
-- && mapinfo_p2->ino == mapinfo_p->ino
-- && mapinfo_p2->dev == mapinfo_p->dev)
-- {
-- map.info.vaddr = mapinfo_p2->vaddr;
-- err =
-- devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
-- if (err != EOK)
-- continue;
--
-- if (strcmp (map.info.path, printme.name))
-- continue;
--
-- /* Lower debug_vaddr is always text, if necessary, swap. */
-- if ((int) map.info.vaddr < (int) printme.text.debug_vaddr)
-- {
-- memcpy (&(printme.data), &(printme.text),
-- sizeof (printme.data));
-- printme.text.addr = mapinfo_p2->vaddr;
-- printme.text.size = mapinfo_p2->size;
-- printme.text.flags = mapinfo_p2->flags;
-- printme.text.offset = mapinfo_p2->offset;
-- printme.text.debug_vaddr = map.info.vaddr;
-- }
-- else
-- {
-- printme.data.addr = mapinfo_p2->vaddr;
-- printme.data.size = mapinfo_p2->size;
-- printme.data.flags = mapinfo_p2->flags;
-- printme.data.offset = mapinfo_p2->offset;
-- printme.data.debug_vaddr = map.info.vaddr;
-- }
-- mapinfo_p2->ino = 0;
-- }
-- }
-- mapinfo_p->ino = 0;
--
-- gdb_printf ("%s\n", printme.name);
-- gdb_printf ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size,
-- printme.text.addr);
-- gdb_printf ("\t\tflags=%08x\n", printme.text.flags);
-- gdb_printf ("\t\tdebug=%08x\n", printme.text.debug_vaddr);
-- gdb_printf ("\t\toffset=%s\n", phex (printme.text.offset, 8));
-- if (printme.data.size)
-- {
-- gdb_printf ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size,
-- printme.data.addr);
-- gdb_printf ("\t\tflags=%08x\n", printme.data.flags);
-- gdb_printf ("\t\tdebug=%08x\n", printme.data.debug_vaddr);
-- gdb_printf ("\t\toffset=%s\n", phex (printme.data.offset, 8));
-- }
-- gdb_printf ("\tdev=0x%x\n", printme.dev);
-- gdb_printf ("\tino=0x%x\n", (unsigned int) printme.ino);
-- }
-- xfree (mapinfos);
-- return;
--}
--
--/* Print status information about what we're accessing. */
--void
--nto_procfs_target::files_info ()
--{
-- struct inferior *inf = current_inferior ();
--
-- gdb_printf ("\tUsing the running image of %s %s via %s.\n",
-- inf->attach_flag ? "attached" : "child",
-- target_pid_to_str (ptid_t (inf->pid)).c_str (),
-- (nodestr != NULL) ? nodestr : "local node");
--}
--
--/* Target to_pid_to_exec_file implementation. */
--
--const char *
--nto_procfs_target::pid_to_exec_file (const int pid)
--{
-- int proc_fd;
-- static char proc_path[PATH_MAX];
-- ssize_t rd;
--
-- /* Read exe file name. */
-- snprintf (proc_path, sizeof (proc_path), "%s/proc/%d/exefile",
-- (nodestr != NULL) ? nodestr : "", pid);
-- proc_fd = open (proc_path, O_RDONLY);
-- if (proc_fd == -1)
-- return NULL;
--
-- rd = read (proc_fd, proc_path, sizeof (proc_path) - 1);
-- close (proc_fd);
-- if (rd <= 0)
-- {
-- proc_path[0] = '\0';
-- return NULL;
-- }
-- proc_path[rd] = '\0';
-- return proc_path;
--}
--
--/* Attach to process PID, then initialize for debugging it. */
--void
--nto_procfs_target::attach (const char *args, int from_tty)
--{
-- int pid;
-- struct inferior *inf;
--
-- pid = parse_pid_to_attach (args);
--
-- if (pid == getpid ())
-- error (_("Attaching GDB to itself is not a good idea..."));
--
-- target_announce_attach (from_tty, pid);
--
-- ptid_t ptid = do_attach (ptid_t (pid));
-- inf = current_inferior ();
-- inferior_appeared (inf, pid);
-- inf->attach_flag = true;
--
-- if (!inf->target_is_pushed (ops))
-- inf->push_target (ops);
--
-- update_thread_list ();
--
-- switch_to_thread (this->find_thread (ptid));
--}
--
--void
--nto_procfs_target::post_attach (pid_t pid)
--{
-- if (current_program_space->exec_bfd ())
-- solib_create_inferior_hook (0);
--}
--
--static ptid_t
--do_attach (ptid_t ptid)
--{
-- procfs_status status;
-- struct sigevent event;
-- char path[PATH_MAX];
--
-- snprintf (path, PATH_MAX - 1, "%s%s/%d/as",
-- (nodestr != NULL) ? nodestr : "", "/proc", ptid.pid ());
-- ctl_fd = open (path, O_RDWR);
-- if (ctl_fd == -1)
-- error (_("Couldn't open proc file %s, error %d (%s)"), path, errno,
-- safe_strerror (errno));
-- if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK)
-- error (_("Couldn't stop process"));
--
-- /* Define a sigevent for process stopped notification. */
-- event.sigev_notify = SIGEV_SIGNAL_THREAD;
-- event.sigev_signo = SIGUSR1;
-- event.sigev_code = 0;
-- event.sigev_value.sival_ptr = NULL;
-- event.sigev_priority = -1;
-- devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
--
-- if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK
-- && status.flags & _DEBUG_FLAG_STOPPED)
-- SignalKill (nto_node (), ptid.pid (), 0, SIGCONT, 0, 0);
-- nto_init_solib_absolute_prefix ();
-- return ptid_t (ptid.pid (), 0, status.tid);
--}
--
--/* Ask the user what to do when an interrupt is received. */
--static void
--interrupt_query (void)
--{
-- if (query (_("Interrupted while waiting for the program.\n\
--Give up (and stop debugging it)? ")))
-- {
-- target_mourn_inferior (inferior_ptid);
-- quit ();
-- }
--}
--
--/* The user typed ^C twice. */
--static void
--nto_handle_sigint_twice (int signo)
--{
-- signal (signo, ofunc);
-- interrupt_query ();
-- signal (signo, nto_handle_sigint_twice);
--}
--
--static void
--nto_handle_sigint (int signo)
--{
-- /* If this doesn't work, try more severe steps. */
-- signal (signo, nto_handle_sigint_twice);
--
-- target_interrupt ();
--}
--
--sptid_t
--nto_procfs_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
-- target_wait_flags options)
--{
-- sigset_t set;
-- siginfo_t info;
-- procfs_status status;
-- static int exit_signo = 0; /* To track signals that cause termination. */
--
-- ourstatus->set_spurious ();
--
-- if (inferior_ptid == null_ptid)
-- {
-- ourstatus->set_stopped (GDB_SIGNAL_0);
-- exit_signo = 0;
-- return null_ptid;
-- }
--
-- sigemptyset (&set);
-- sigaddset (&set, SIGUSR1);
--
-- devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
-- while (!(status.flags & _DEBUG_FLAG_ISTOP))
-- {
-- ofunc = signal (SIGINT, nto_handle_sigint);
-- sigwaitinfo (&set, &info);
-- signal (SIGINT, ofunc);
-- devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
-- }
--
-- nto_inferior_data (NULL)->stopped_flags = status.flags;
-- nto_inferior_data (NULL)->stopped_pc = status.ip;
--
-- if (status.flags & _DEBUG_FLAG_SSTEP)
-- ourstatus->set_stopped (GDB_SIGNAL_TRAP);
-- /* Was it a breakpoint? */
-- else if (status.flags & _DEBUG_FLAG_TRACE)
-- ourstatus->set_stopped (GDB_SIGNAL_TRAP);
-- else if (status.flags & _DEBUG_FLAG_ISTOP)
-- {
-- switch (status.why)
-- {
-- case _DEBUG_WHY_SIGNALLED:
-- ourstatus->set_stopped (gdb_signal_from_host (status.info.si_signo));
-- exit_signo = 0;
-- break;
-- case _DEBUG_WHY_FAULTED:
-- if (status.info.si_signo == SIGTRAP)
-- {
-- ourstatus->set_stopped (0);
-- exit_signo = 0;
-- }
-- else
-- {
-- ourstatus->set_stopped
-- (gdb_signal_from_host (status.info.si_signo));
-- exit_signo = ourstatus->sig ();
-- }
-- break;
--
-- case _DEBUG_WHY_TERMINATED:
-- {
-- int waitval = 0;
--
-- waitpid (inferior_ptid.pid (), &waitval, WNOHANG);
-- if (exit_signo)
-- {
-- /* Abnormal death. */
-- ourstatus->set_signalled (exit_signo);
-- }
-- else
-- {
-- /* Normal death. */
-- ourstatus->set_exited (WEXITSTATUS (waitval));
-- }
-- exit_signo = 0;
-- break;
-- }
--
-- case _DEBUG_WHY_REQUESTED:
-- /* We are assuming a requested stop is due to a SIGINT. */
-- ourstatus->set_stopped (GDB_SIGNAL_INT);
-- exit_signo = 0;
-- break;
-- }
-- }
--
-- return ptid_t (status.pid, 0, status.tid);
--}
--
--/* Read the current values of the inferior's registers, both the
-- general register set and floating point registers (if supported)
-- and update gdb's idea of their current values. */
--void
--nto_procfs_target::fetch_registers (struct regcache *regcache, int regno)
--{
-- union
-- {
-- procfs_greg greg;
-- procfs_fpreg fpreg;
-- procfs_altreg altreg;
-- }
-- reg;
-- int regsize;
--
-- procfs_set_thread (regcache->ptid ());
-- if (devctl (ctl_fd, DCMD_PROC_GETGREG, ®, sizeof (reg), ®size) == EOK)
-- nto_supply_gregset (regcache, (char *) ®.greg);
-- if (devctl (ctl_fd, DCMD_PROC_GETFPREG, ®, sizeof (reg), ®size)
-- == EOK)
-- nto_supply_fpregset (regcache, (char *) ®.fpreg);
-- if (devctl (ctl_fd, DCMD_PROC_GETALTREG, ®, sizeof (reg), ®size)
-- == EOK)
-- nto_supply_altregset (regcache, (char *) ®.altreg);
--}
--
--/* Helper for procfs_xfer_partial that handles memory transfers.
-- Arguments are like target_xfer_partial. */
--
--static enum target_xfer_status
--procfs_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
-- ULONGEST memaddr, ULONGEST len, ULONGEST *xfered_len)
--{
-- int nbytes;
--
-- if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) != (off_t) memaddr)
-- return TARGET_XFER_E_IO;
--
-- if (writebuf != NULL)
-- nbytes = write (ctl_fd, writebuf, len);
-- else
-- nbytes = read (ctl_fd, readbuf, len);
-- if (nbytes <= 0)
-- return TARGET_XFER_E_IO;
-- *xfered_len = nbytes;
-- return TARGET_XFER_OK;
--}
--
--/* Target to_xfer_partial implementation. */
--
--enum target_xfer_status
--nto_procfs_target::xfer_partial (enum target_object object,
-- const char *annex, gdb_byte *readbuf,
-- const gdb_byte *writebuf, ULONGEST offset,
-- ULONGEST len, ULONGEST *xfered_len)
--{
-- switch (object)
-- {
-- case TARGET_OBJECT_MEMORY:
-- return procfs_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
-- case TARGET_OBJECT_AUXV:
-- if (readbuf != NULL)
-- {
-- int err;
-- CORE_ADDR initial_stack;
-- debug_process_t procinfo;
-- /* For 32-bit architecture, size of auxv_t is 8 bytes. */
-- const unsigned int sizeof_auxv_t = sizeof (auxv_t);
-- const unsigned int sizeof_tempbuf = 20 * sizeof_auxv_t;
-- int tempread;
-- gdb_byte *const tempbuf = alloca (sizeof_tempbuf);
--
-- if (tempbuf == NULL)
-- return TARGET_XFER_E_IO;
--
-- err = devctl (ctl_fd, DCMD_PROC_INFO, &procinfo,
-- sizeof procinfo, 0);
-- if (err != EOK)
-- return TARGET_XFER_E_IO;
--
-- initial_stack = procinfo.initial_stack;
--
-- /* procfs is always 'self-hosted', no byte-order manipulation. */
-- tempread = nto_read_auxv_from_initial_stack (initial_stack, tempbuf,
-- sizeof_tempbuf,
-- sizeof (auxv_t));
-- tempread = std::min (tempread, len) - offset;
-- memcpy (readbuf, tempbuf + offset, tempread);
-- *xfered_len = tempread;
-- return tempread ? TARGET_XFER_OK : TARGET_XFER_EOF;
-- }
-- /* Fallthru */
-- default:
-- return this->beneath ()->xfer_partial (object, annex,
-- readbuf, writebuf, offset, len,
-- xfered_len);
-- }
--}
--
--/* Take a program previously attached to and detaches it.
-- The program resumes execution and will no longer stop
-- on signals, etc. We'd better not have left any breakpoints
-- in the program or it'll die when it hits one. */
--void
--nto_procfs_target::detach (inferior *inf, int from_tty)
--{
-- target_announce_detach ();
--
-- if (siggnal)
-- SignalKill (nto_node (), inf->pid, 0, 0, 0, 0);
--
-- close (ctl_fd);
-- ctl_fd = -1;
--
-- switch_to_no_thread ();
-- detach_inferior (inf->pid);
-- init_thread_list ();
-- inf_child_maybe_unpush_target (ops);
--}
--
--static int
--procfs_breakpoint (CORE_ADDR addr, int type, int size)
--{
-- procfs_break brk;
--
-- brk.type = type;
-- brk.addr = addr;
-- brk.size = size;
-- errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
-- if (errno != EOK)
-- return 1;
-- return 0;
--}
--
--int
--nto_procfs_target::insert_breakpoint (struct gdbarch *gdbarch,
-- struct bp_target_info *bp_tgt)
--{
-- bp_tgt->placed_address = bp_tgt->reqstd_address;
-- return procfs_breakpoint (bp_tgt->placed_address, _DEBUG_BREAK_EXEC, 0);
--}
--
--int
--nto_procfs_target::remove_breakpoint (struct gdbarch *gdbarch,
-- struct bp_target_info *bp_tgt,
-- enum remove_bp_reason reason)
--{
-- return procfs_breakpoint (bp_tgt->placed_address, _DEBUG_BREAK_EXEC, -1);
--}
--
--int
--nto_procfs_target::insert_hw_breakpoint (struct gdbarch *gdbarch,
-- struct bp_target_info *bp_tgt)
--{
-- bp_tgt->placed_address = bp_tgt->reqstd_address;
-- return procfs_breakpoint (bp_tgt->placed_address,
-- _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0);
--}
--
--int
--nto_procfs_target::remove_hw_breakpoint (struct gdbarch *gdbarch,
-- struct bp_target_info *bp_tgt)
--{
-- return procfs_breakpoint (bp_tgt->placed_address,
-- _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1);
--}
--
--void
--nto_procfs_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
--{
-- int signal_to_pass;
-- procfs_status status;
-- sigset_t *run_fault = (sigset_t *) (void *) &run.fault;
--
-- if (inferior_ptid == null_ptid)
-- return;
--
-- procfs_set_thread (ptid == minus_one_ptid ? inferior_ptid :
-- ptid);
--
-- run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
-- if (step)
-- run.flags |= _DEBUG_RUN_STEP;
--
-- sigemptyset (run_fault);
-- sigaddset (run_fault, FLTBPT);
-- sigaddset (run_fault, FLTTRACE);
-- sigaddset (run_fault, FLTILL);
-- sigaddset (run_fault, FLTPRIV);
-- sigaddset (run_fault, FLTBOUNDS);
-- sigaddset (run_fault, FLTIOVF);
-- sigaddset (run_fault, FLTIZDIV);
-- sigaddset (run_fault, FLTFPE);
-- /* Peter V will be changing this at some point. */
-- sigaddset (run_fault, FLTPAGE);
--
-- run.flags |= _DEBUG_RUN_ARM;
--
-- signal_to_pass = gdb_signal_to_host (signo);
--
-- if (signal_to_pass)
-- {
-- devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
-- signal_to_pass = gdb_signal_to_host (signo);
-- if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
-- {
-- if (signal_to_pass != status.info.si_signo)
-- {
-- SignalKill (nto_node (), inferior_ptid.pid (), 0,
-- signal_to_pass, 0, 0);
-- run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
-- }
-- else /* Let it kill the program without telling us. */
-- sigdelset (&run.trace, signal_to_pass);
-- }
-- }
-- else
-- run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
--
-- errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
-- if (errno != EOK)
-- {
-- perror (_("run error!\n"));
-- return;
-- }
--}
--
--void
--nto_procfs_target::mourn_inferior ()
--{
-- if (inferior_ptid != null_ptid)
-- {
-- SignalKill (nto_node (), inferior_ptid.pid (), 0, SIGKILL, 0, 0);
-- close (ctl_fd);
-- }
-- switch_to_no_thread ();
-- init_thread_list ();
-- inf_child_mourn_inferior (ops);
--}
--
--/* This function breaks up an argument string into an argument
-- vector suitable for passing to execvp().
-- E.g., on "run a b c d" this routine would get as input
-- the string "a b c d", and as output it would fill in argv with
-- the four arguments "a", "b", "c", "d". The only additional
-- functionality is simple quoting. The gdb command:
-- run a "b c d" f
-- will fill in argv with the three args "a", "b c d", "e". */
--static void
--breakup_args (char *scratch, char **argv)
--{
-- char *pp, *cp = scratch;
-- char quoting = 0;
--
-- for (;;)
-- {
-- /* Scan past leading separators. */
-- quoting = 0;
-- while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-- cp++;
--
-- /* Break if at end of string. */
-- if (*cp == '\0')
-- break;
--
-- /* Take an arg. */
-- if (*cp == '"')
-- {
-- cp++;
-- quoting = strchr (cp, '"') ? 1 : 0;
-- }
--
-- *argv++ = cp;
--
-- /* Scan for next arg separator. */
-- pp = cp;
-- if (quoting)
-- cp = strchr (pp, '"');
-- if ((cp == NULL) || (!quoting))
-- cp = strchr (pp, ' ');
-- if (cp == NULL)
-- cp = strchr (pp, '\t');
-- if (cp == NULL)
-- cp = strchr (pp, '\n');
--
-- /* No separators => end of string => break. */
-- if (cp == NULL)
-- {
-- pp = cp;
-- break;
-- }
--
-- /* Replace the separator with a terminator. */
-- *cp++ = '\0';
-- }
--
-- /* Execv requires a null-terminated arg vector. */
-- *argv = NULL;
--}
--
--void
--nto_procfs_target::create_inferior (const char *exec_file,
-- const std::string &allargs,
-- char **env, int from_tty)
--{
-- struct inheritance inherit;
-- pid_t pid;
-- int flags, errn;
-- char **argv, *args;
-- const char *in = "", *out = "", *err = "";
-- int fd, fds[3];
-- sigset_t set;
-- struct inferior *inf;
--
-- argv = xmalloc ((allargs.size () / (unsigned) 2 + 2) *
-- sizeof (*argv));
-- argv[0] = const_cast<char *> (get_exec_file (1));
-- if (!argv[0])
-- {
-- if (exec_file)
-- argv[0] = exec_file;
-- else
-- return;
-- }
--
-- args = xstrdup (allargs.c_str ());
-- breakup_args (args, (exec_file != NULL) ? &argv[1] : &argv[0]);
--
-- argv = nto_parse_redirection (argv, &in, &out, &err);
--
-- fds[0] = STDIN_FILENO;
-- fds[1] = STDOUT_FILENO;
-- fds[2] = STDERR_FILENO;
--
-- /* If the user specified I/O via gdb's --tty= arg, use it, but only
-- if the i/o is not also being specified via redirection. */
-- const char *inferior_tty = current_inferior ()->tty ();
-- if (inferior_tty != nullptr)
-- {
-- if (!in[0])
-- in = inferior_tty;
-- if (!out[0])
-- out = inferior_tty;
-- if (!err[0])
-- err = inferior_tty;
-- }
--
-- if (in[0])
-- {
-- fd = open (in, O_RDONLY);
-- if (fd == -1)
-- perror (in);
-- else
-- fds[0] = fd;
-- }
-- if (out[0])
-- {
-- fd = open (out, O_WRONLY);
-- if (fd == -1)
-- perror (out);
-- else
-- fds[1] = fd;
-- }
-- if (err[0])
-- {
-- fd = open (err, O_WRONLY);
-- if (fd == -1)
-- perror (err);
-- else
-- fds[2] = fd;
-- }
--
-- /* Clear any pending SIGUSR1's but keep the behavior the same. */
-- signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
--
-- sigemptyset (&set);
-- sigaddset (&set, SIGUSR1);
-- sigprocmask (SIG_UNBLOCK, &set, NULL);
--
-- memset (&inherit, 0, sizeof (inherit));
--
-- if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0)
-- {
-- inherit.nd = nto_node ();
-- inherit.flags |= SPAWN_SETND;
-- inherit.flags &= ~SPAWN_EXEC;
-- }
-- inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
-- inherit.pgroup = SPAWN_NEWPGROUP;
-- pid = spawnp (argv[0], 3, fds, &inherit, argv,
-- ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0);
-- xfree (args);
--
-- sigprocmask (SIG_BLOCK, &set, NULL);
--
-- if (pid == -1)
-- error (_("Error spawning %s: %d (%s)"), argv[0], errno,
-- safe_strerror (errno));
--
-- if (fds[0] != STDIN_FILENO)
-- close (fds[0]);
-- if (fds[1] != STDOUT_FILENO)
-- close (fds[1]);
-- if (fds[2] != STDERR_FILENO)
-- close (fds[2]);
--
-- ptid_t ptid = do_attach (ptid_t (pid));
-- update_thread_list ();
-- switch_to_thread (this->find_thread (ptid));
--
-- inf = current_inferior ();
-- inferior_appeared (inf, pid);
-- inf->attach_flag = false;
--
-- flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */
-- errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0);
-- if (errn != EOK)
-- {
-- /* FIXME: expected warning? */
-- /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n",
-- errn, safe_strerror(errn) ); */
-- }
-- if (!inf->target_is_pushed (ops))
-- inf->push_target (ops);
-- target_terminal::init ();
--
-- if (current_program_space->exec_bfd () != NULL
-- || (current_program_space->symfile_object_file != NULL
-- && current_program_space->symfile_object_file->obfd != NULL))
-- solib_create_inferior_hook (0);
--}
--
--void
--nto_procfs_target::interrupt ()
--{
-- devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
--}
--
--void
--nto_procfs_target::kill ()
--{
-- target_mourn_inferior (inferior_ptid);
--}
--
--/* Fill buf with regset and return devctl cmd to do the setting. Return
-- -1 if we fail to get the regset. Store size of regset in regsize. */
--static int
--get_regset (int regset, char *buf, int bufsize, int *regsize)
--{
-- int dev_get, dev_set;
-- switch (regset)
-- {
-- case NTO_REG_GENERAL:
-- dev_get = DCMD_PROC_GETGREG;
-- dev_set = DCMD_PROC_SETGREG;
-- break;
--
-- case NTO_REG_FLOAT:
-- dev_get = DCMD_PROC_GETFPREG;
-- dev_set = DCMD_PROC_SETFPREG;
-- break;
--
-- case NTO_REG_ALT:
-- dev_get = DCMD_PROC_GETALTREG;
-- dev_set = DCMD_PROC_SETALTREG;
-- break;
--
-- case NTO_REG_SYSTEM:
-- default:
-- return -1;
-- }
-- if (devctl (ctl_fd, dev_get, buf, bufsize, regsize) != EOK)
-- return -1;
--
-- return dev_set;
--}
--
--void
--nto_procfs_target::store_registers (struct regcache *regcache, int regno)
--{
-- union
-- {
-- procfs_greg greg;
-- procfs_fpreg fpreg;
-- procfs_altreg altreg;
-- }
-- reg;
-- unsigned off;
-- int len, regset, regsize, dev_set, err;
-- char *data;
-- ptid_t ptid = regcache->ptid ();
--
-- if (ptid == null_ptid)
-- return;
-- procfs_set_thread (ptid);
--
-- if (regno == -1)
-- {
-- for (regset = NTO_REG_GENERAL; regset < NTO_REG_END; regset++)
-- {
-- dev_set = get_regset (regset, (char *) ®,
-- sizeof (reg), ®size);
-- if (dev_set == -1)
-- continue;
--
-- if (nto_regset_fill (regcache, regset, (char *) ®) == -1)
-- continue;
--
-- err = devctl (ctl_fd, dev_set, ®, regsize, 0);
-- if (err != EOK)
-- gdb_printf (gdb_stderr,
-- "Warning unable to write regset %d: %s\n",
-- regno, safe_strerror (err));
-- }
-- }
-- else
-- {
-- regset = nto_regset_id (regno);
-- if (regset == -1)
-- return;
--
-- dev_set = get_regset (regset, (char *) ®, sizeof (reg), ®size);
-- if (dev_set == -1)
-- return;
--
-- len = nto_register_area (regcache->arch (),
-- regno, regset, &off);
--
-- if (len < 1)
-- return;
--
-- regcache->raw_collect (regno, (char *) ® + off);
--
-- err = devctl (ctl_fd, dev_set, ®, regsize, 0);
-- if (err != EOK)
-- gdb_printf (gdb_stderr,
-- "Warning unable to write regset %d: %s\n", regno,
-- safe_strerror (err));
-- }
--}
--
--/* Set list of signals to be handled in the target. */
--
--void
--nto_procfs_target::pass_signals
-- (gdb::array_view<const unsigned char> pass_signals)
--{
-- int signo;
--
-- sigfillset (&run.trace);
--
-- for (signo = 1; signo < NSIG; signo++)
-- {
-- int target_signo = gdb_signal_from_host (signo);
-- if (target_signo < pass_signals.size () && pass_signals[target_signo])
-- sigdelset (&run.trace, signo);
-- }
--}
--
--std::string
--nto_procfs_target::pid_to_str (ptid_t ptid)
--{
-- int pid, tid;
-- struct tidinfo *tip;
--
-- pid = ptid.pid ();
-- tid = ptid.tid ();
--
--#if 0 /* NYI */
-- tip = procfs_thread_info (pid, tid);
-- if (tip != NULL)
-- snprintf (&buf[n], 1023, " (state = 0x%02x)", tip->state);
--#endif
--
-- return string_printf ("process %d", pid);
--}
--
--/* to_can_run implementation for "target procfs". Note this really
-- means "can this target be the default run target", which there can
-- be only one, and we make it be "target native" like other ports.
-- "target procfs <node>" wouldn't make sense as default run target, as
-- it needs <node>. */
--
--int
--nto_procfs_target::can_run ()
--{
-- return 0;
--}
--
--/* "target procfs". */
--static nto_procfs_target_procfs nto_procfs_ops;
--
--/* "target native". */
--static nto_procfs_target_native nto_native_ops;
--
--/* Create the "native" and "procfs" targets. */
--
--static void
--init_procfs_targets (void)
--{
-- /* Register "target native". This is the default run target. */
-- add_target (nto_native_target_info, inf_child_open_target);
-- set_native_target (&nto_native_ops);
--
-- /* Register "target procfs <node>". */
-- add_target (nto_procfs_target_info, inf_child_open_target);
--}
--
--#define OSTYPE_NTO 1
--
--void _initialize_procfs ();
--void
--_initialize_procfs ()
--{
-- sigset_t set;
--
-- init_procfs_targets ();
--
-- /* We use SIGUSR1 to gain control after we block waiting for a process.
-- We use sigwaitevent to wait. */
-- sigemptyset (&set);
-- sigaddset (&set, SIGUSR1);
-- sigprocmask (SIG_BLOCK, &set, NULL);
--
-- /* Initially, make sure all signals are reported. */
-- sigfillset (&run.trace);
--
-- /* Stuff some information. */
-- nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags;
-- nto_cpuinfo_valid = 1;
--
-- add_info ("pidlist", procfs_pidlist, _("pidlist"));
-- add_info ("meminfo", procfs_meminfo, _("memory information"));
--
-- nto_is_nto_target = procfs_is_nto_target;
--}
--
--
--static int
--procfs_hw_watchpoint (int addr, int len, enum target_hw_bp_type type)
--{
-- procfs_break brk;
--
-- switch (type)
-- {
-- case hw_read:
-- brk.type = _DEBUG_BREAK_RD;
-- break;
-- case hw_access:
-- brk.type = _DEBUG_BREAK_RW;
-- break;
-- default: /* Modify. */
--/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason. */
-- brk.type = _DEBUG_BREAK_RW;
-- }
-- brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW. */
-- brk.addr = addr;
-- brk.size = len;
--
-- errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
-- if (errno != EOK)
-- {
-- perror (_("Failed to set hardware watchpoint"));
-- return -1;
-- }
-- return 0;
--}
--
--bool
--nto_procfs_target::can_use_hw_breakpoint (enum bptype type,
-- int cnt, int othertype)
--{
-- return 1;
--}
--
--int
--nto_procfs_target::remove_hw_watchpoint (CORE_ADDR addr, int len,
-- enum target_hw_bp_type type,
-- struct expression *cond)
--{
-- return procfs_hw_watchpoint (addr, -1, type);
--}
--
--int
--nto_procfs_target::insert_hw_watchpoint (CORE_ADDR addr, int len,
-- enum target_hw_bp_type type,
-- struct expression *cond)
--{
-- return procfs_hw_watchpoint (addr, len, type);
--}
--
--bool
--nto_procfs_target::stopped_by_watchpoint ()
--{
-- /* NOTE: nto_stopped_by_watchpoint will be called ONLY while we are
-- stopped due to a SIGTRAP. This assumes gdb works in 'all-stop' mode;
-- future gdb versions will likely run in 'non-stop' mode in which case
-- we will have to store/examine statuses per thread in question.
-- Until then, this will work fine. */
--
-- struct inferior *inf = current_inferior ();
-- struct nto_inferior_data *inf_data;
--
-- gdb_assert (inf != NULL);
--
-- inf_data = nto_inferior_data (inf);
--
-- return inf_data->stopped_flags
-- & (_DEBUG_FLAG_TRACE_RD
-- | _DEBUG_FLAG_TRACE_WR
-- | _DEBUG_FLAG_TRACE_MODIFY);
--}
-diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
-deleted file mode 100644
---- a/gdb/nto-tdep.c
-+++ /dev/null
-@@ -1,521 +0,0 @@
--/* nto-tdep.c - general QNX Neutrino target functionality.
--
-- Copyright (C) 2003-2024 Free Software Foundation, Inc.
--
-- Contributed by QNX Software Systems Ltd.
--
-- 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/>. */
--
--#include <sys/stat.h>
--#include "nto-tdep.h"
--#include "extract-store-integer.h"
--#include "top.h"
--#include "inferior.h"
--#include "infrun.h"
--#include "gdbarch.h"
--#include "bfd.h"
--#include "elf-bfd.h"
--#include "solib-svr4.h"
--#include "gdbcore.h"
--#include "objfiles.h"
--#include "source.h"
--#include "gdbsupport/pathstuff.h"
--
--#define QNX_NOTE_NAME "QNX"
--#define QNX_INFO_SECT_NAME "QNX_info"
--
--#ifdef __CYGWIN__
--#include <sys/cygwin.h>
--#endif
--
--#ifdef __CYGWIN__
--static char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6";
--#elif defined(__sun__) || defined(linux)
--static char default_nto_target[] = "/opt/QNXsdk/target/qnx6";
--#else
--static char default_nto_target[] = "";
--#endif
--
--struct nto_target_ops current_nto_target;
--
--static const registry<inferior>::key<struct nto_inferior_data>
-- nto_inferior_data_reg;
--
--static char *
--nto_target (void)
--{
-- char *p = getenv ("QNX_TARGET");
--
--#ifdef __CYGWIN__
-- static char buf[PATH_MAX];
-- if (p)
-- cygwin_conv_path (CCP_WIN_A_TO_POSIX, p, buf, PATH_MAX);
-- else
-- cygwin_conv_path (CCP_WIN_A_TO_POSIX, default_nto_target, buf, PATH_MAX);
-- return buf;
--#else
-- return p ? p : default_nto_target;
--#endif
--}
--
--/* Take a string such as i386, rs6000, etc. and map it onto CPUTYPE_X86,
-- CPUTYPE_PPC, etc. as defined in nto-share/dsmsgs.h. */
--int
--nto_map_arch_to_cputype (const char *arch)
--{
-- if (!strcmp (arch, "i386") || !strcmp (arch, "x86"))
-- return CPUTYPE_X86;
-- if (!strcmp (arch, "rs6000") || !strcmp (arch, "powerpc"))
-- return CPUTYPE_PPC;
-- if (!strcmp (arch, "mips"))
-- return CPUTYPE_MIPS;
-- if (!strcmp (arch, "arm"))
-- return CPUTYPE_ARM;
-- if (!strcmp (arch, "sh"))
-- return CPUTYPE_SH;
-- return CPUTYPE_UNKNOWN;
--}
--
--int
--nto_find_and_open_solib (const char *solib, unsigned o_flags,
-- gdb::unique_xmalloc_ptr<char> *temp_pathname)
--{
-- char *buf, *arch_path, *nto_root;
-- const char *endian;
-- const char *base;
-- const char *arch;
-- int arch_len, len, ret;
--#define PATH_FMT \
-- "%s/lib:%s/usr/lib:%s/usr/photon/lib:%s/usr/photon/dll:%s/lib/dll"
--
-- nto_root = nto_target ();
-- gdbarch *gdbarch = current_inferior ()->arch ();
-- if (strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name, "i386") == 0)
-- {
-- arch = "x86";
-- endian = "";
-- }
-- else if (strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name,
-- "rs6000") == 0
-- || strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name,
-- "powerpc") == 0)
-- {
-- arch = "ppc";
-- endian = "be";
-- }
-- else
-- {
-- arch = gdbarch_bfd_arch_info (gdbarch)->arch_name;
-- endian = gdbarch_byte_order (gdbarch)
-- == BFD_ENDIAN_BIG ? "be" : "le";
-- }
--
-- /* In case nto_root is short, add strlen(solib)
-- so we can reuse arch_path below. */
--
-- arch_len = (strlen (nto_root) + strlen (arch) + strlen (endian) + 2
-- + strlen (solib));
-- arch_path = (char *) alloca (arch_len);
-- xsnprintf (arch_path, arch_len, "%s/%s%s", nto_root, arch, endian);
--
-- len = strlen (PATH_FMT) + strlen (arch_path) * 5 + 1;
-- buf = (char *) alloca (len);
-- xsnprintf (buf, len, PATH_FMT, arch_path, arch_path, arch_path, arch_path,
-- arch_path);
--
-- base = lbasename (solib);
-- ret = openp (buf, OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH, base, o_flags,
-- temp_pathname);
-- if (ret < 0 && base != solib)
-- {
-- xsnprintf (arch_path, arch_len, "/%s", solib);
-- ret = open (arch_path, o_flags, 0);
-- if (temp_pathname)
-- {
-- if (ret >= 0)
-- *temp_pathname = gdb_realpath (arch_path);
-- else
-- temp_pathname->reset (NULL);
-- }
-- }
-- return ret;
--}
--
--void
--nto_init_solib_absolute_prefix (void)
--{
-- char buf[PATH_MAX * 2], arch_path[PATH_MAX];
-- char *nto_root;
-- const char *endian;
-- const char *arch;
--
-- nto_root = nto_target ();
-- gdbarch *gdbarch = current_inferior ()->arch ();
-- if (strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name, "i386") == 0)
-- {
-- arch = "x86";
-- endian = "";
-- }
-- else if (strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name,
-- "rs6000") == 0
-- || strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name,
-- "powerpc") == 0)
-- {
-- arch = "ppc";
-- endian = "be";
-- }
-- else
-- {
-- arch = gdbarch_bfd_arch_info (gdbarch)->arch_name;
-- endian = gdbarch_byte_order (gdbarch)
-- == BFD_ENDIAN_BIG ? "be" : "le";
-- }
--
-- xsnprintf (arch_path, sizeof (arch_path), "%s/%s%s", nto_root, arch, endian);
--
-- xsnprintf (buf, sizeof (buf), "set solib-absolute-prefix %s", arch_path);
-- execute_command (buf, 0);
--}
--
--char **
--nto_parse_redirection (char *pargv[], const char **pin, const char **pout,
-- const char **perr)
--{
-- char **argv;
-- const char *in, *out, *err, *p;
-- int argc, i, n;
--
-- for (n = 0; pargv[n]; n++);
-- if (n == 0)
-- return NULL;
-- in = "";
-- out = "";
-- err = "";
--
-- argv = XCNEWVEC (char *, n + 1);
-- argc = n;
-- for (i = 0, n = 0; n < argc; n++)
-- {
-- p = pargv[n];
-- if (*p == '>')
-- {
-- p++;
-- if (*p)
-- out = p;
-- else
-- out = pargv[++n];
-- }
-- else if (*p == '<')
-- {
-- p++;
-- if (*p)
-- in = p;
-- else
-- in = pargv[++n];
-- }
-- else if (*p++ == '2' && *p++ == '>')
-- {
-- if (*p == '&' && *(p + 1) == '1')
-- err = out;
-- else if (*p)
-- err = p;
-- else
-- err = pargv[++n];
-- }
-- else
-- argv[i++] = pargv[n];
-- }
-- *pin = in;
-- *pout = out;
-- *perr = err;
-- return argv;
--}
--
--static CORE_ADDR
--lm_addr (const solib &so)
--{
-- auto *li = gdb::checked_static_cast<const lm_info_svr4 *> (so.lm_info.get ());
--
-- return li->l_addr;
--}
--
--static CORE_ADDR
--nto_truncate_ptr (CORE_ADDR addr)
--{
-- gdbarch *gdbarch = current_inferior ()->arch ();
-- if (gdbarch_ptr_bit (gdbarch) == sizeof (CORE_ADDR) * 8)
-- /* We don't need to truncate anything, and the bit twiddling below
-- will fail due to overflow problems. */
-- return addr;
-- else
-- return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (gdbarch)) - 1);
--}
--
--static Elf_Internal_Phdr *
--find_load_phdr (bfd *abfd)
--{
-- Elf_Internal_Phdr *phdr;
-- unsigned int i;
--
-- if (!elf_tdata (abfd))
-- return NULL;
--
-- phdr = elf_tdata (abfd)->phdr;
-- for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
-- {
-- if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
-- return phdr;
-- }
-- return NULL;
--}
--
--void
--nto_relocate_section_addresses (solib &so, target_section *sec)
--{
-- /* Neutrino treats the l_addr base address field in link.h as different than
-- the base address in the System V ABI and so the offset needs to be
-- calculated and applied to relocations. */
-- Elf_Internal_Phdr *phdr = find_load_phdr (sec->the_bfd_section->owner);
-- unsigned vaddr = phdr ? phdr->p_vaddr : 0;
--
-- sec->addr = nto_truncate_ptr (sec->addr + lm_addr (so) - vaddr);
-- sec->endaddr = nto_truncate_ptr (sec->endaddr + lm_addr (so) - vaddr);
--}
--
--/* This is cheating a bit because our linker code is in libc.so. If we
-- ever implement lazy linking, this may need to be re-examined. */
--int
--nto_in_dynsym_resolve_code (CORE_ADDR pc)
--{
-- if (in_plt_section (pc))
-- return 1;
-- return 0;
--}
--
--void
--nto_dummy_supply_regset (struct regcache *regcache, char *regs)
--{
-- /* Do nothing. */
--}
--
--static void
--nto_sniff_abi_note_section (bfd *abfd, asection *sect, void *obj)
--{
-- const char *sectname;
-- unsigned int sectsize;
-- /* Buffer holding the section contents. */
-- char *note;
-- unsigned int namelen;
-- const char *name;
-- const unsigned sizeof_Elf_Nhdr = 12;
--
-- sectname = bfd_section_name (sect);
-- sectsize = bfd_section_size (sect);
--
-- if (sectsize > 128)
-- sectsize = 128;
--
-- if (sectname != NULL && strstr (sectname, QNX_INFO_SECT_NAME) != NULL)
-- *(enum gdb_osabi *) obj = GDB_OSABI_QNXNTO;
-- else if (sectname != NULL && strstr (sectname, "note") != NULL
-- && sectsize > sizeof_Elf_Nhdr)
-- {
-- note = XNEWVEC (char, sectsize);
-- bfd_get_section_contents (abfd, sect, note, 0, sectsize);
-- namelen = (unsigned int) bfd_h_get_32 (abfd, note);
-- name = note + sizeof_Elf_Nhdr;
-- if (sectsize >= namelen + sizeof_Elf_Nhdr
-- && namelen == sizeof (QNX_NOTE_NAME)
-- && 0 == strcmp (name, QNX_NOTE_NAME))
-- *(enum gdb_osabi *) obj = GDB_OSABI_QNXNTO;
--
-- XDELETEVEC (note);
-- }
--}
--
--enum gdb_osabi
--nto_elf_osabi_sniffer (bfd *abfd)
--{
-- enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
--
-- bfd_map_over_sections (abfd,
-- nto_sniff_abi_note_section,
-- &osabi);
--
-- return osabi;
--}
--
--static const char * const nto_thread_state_str[] =
--{
-- "DEAD", /* 0 0x00 */
-- "RUNNING", /* 1 0x01 */
-- "READY", /* 2 0x02 */
-- "STOPPED", /* 3 0x03 */
-- "SEND", /* 4 0x04 */
-- "RECEIVE", /* 5 0x05 */
-- "REPLY", /* 6 0x06 */
-- "STACK", /* 7 0x07 */
-- "WAITTHREAD", /* 8 0x08 */
-- "WAITPAGE", /* 9 0x09 */
-- "SIGSUSPEND", /* 10 0x0a */
-- "SIGWAITINFO", /* 11 0x0b */
-- "NANOSLEEP", /* 12 0x0c */
-- "MUTEX", /* 13 0x0d */
-- "CONDVAR", /* 14 0x0e */
-- "JOIN", /* 15 0x0f */
-- "INTR", /* 16 0x10 */
-- "SEM", /* 17 0x11 */
-- "WAITCTX", /* 18 0x12 */
-- "NET_SEND", /* 19 0x13 */
-- "NET_REPLY" /* 20 0x14 */
--};
--
--const char *
--nto_extra_thread_info (struct target_ops *self, struct thread_info *ti)
--{
-- if (ti != NULL && ti->priv != NULL)
-- {
-- nto_thread_info *priv = get_nto_thread_info (ti);
--
-- if (priv->state < ARRAY_SIZE (nto_thread_state_str))
-- return nto_thread_state_str [priv->state];
-- }
-- return "";
--}
--
--void
--nto_initialize_signals (void)
--{
-- /* We use SIG45 for pulses, or something, so nostop, noprint
-- and pass them. */
-- signal_stop_update (gdb_signal_from_name ("SIG45"), 0);
-- signal_print_update (gdb_signal_from_name ("SIG45"), 0);
-- signal_pass_update (gdb_signal_from_name ("SIG45"), 1);
--
-- /* By default we don't want to stop on these two, but we do want to pass. */
--#if defined(SIGSELECT)
-- signal_stop_update (SIGSELECT, 0);
-- signal_print_update (SIGSELECT, 0);
-- signal_pass_update (SIGSELECT, 1);
--#endif
--
--#if defined(SIGPHOTON)
-- signal_stop_update (SIGPHOTON, 0);
-- signal_print_update (SIGPHOTON, 0);
-- signal_pass_update (SIGPHOTON, 1);
--#endif
--}
--
--/* Read AUXV from initial_stack. */
--LONGEST
--nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, gdb_byte *readbuf,
-- LONGEST len, size_t sizeof_auxv_t)
--{
-- gdb_byte targ32[4]; /* For 32 bit target values. */
-- gdb_byte targ64[8]; /* For 64 bit target values. */
-- CORE_ADDR data_ofs = 0;
-- ULONGEST anint;
-- LONGEST len_read = 0;
-- gdb_byte *buff;
-- enum bfd_endian byte_order;
-- int ptr_size;
--
-- if (sizeof_auxv_t == 16)
-- ptr_size = 8;
-- else
-- ptr_size = 4;
--
-- /* Skip over argc, argv and envp... Comment from ldd.c:
--
-- The startup frame is set-up so that we have:
-- auxv
-- NULL
-- ...
-- envp2
-- envp1 <----- void *frame + (argc + 2) * sizeof(char *)
-- NULL
-- ...
-- argv2
-- argv1
-- argc <------ void * frame
--
-- On entry to ldd, frame gives the address of argc on the stack. */
-- /* Read argc. 4 bytes on both 64 and 32 bit arches and luckily little
-- * endian. So we just read first 4 bytes. */
-- if (target_read_memory (initial_stack + data_ofs, targ32, 4) != 0)
-- return 0;
--
-- byte_order = gdbarch_byte_order (current_inferior ()->arch ());
--
-- anint = extract_unsigned_integer (targ32, sizeof (targ32), byte_order);
--
-- /* Size of pointer is assumed to be 4 bytes (32 bit arch.) */
-- data_ofs += (anint + 2) * ptr_size; /* + 2 comes from argc itself and
-- NULL terminating pointer in
-- argv. */
--
-- /* Now loop over env table: */
-- anint = 0;
-- while (target_read_memory (initial_stack + data_ofs, targ64, ptr_size)
-- == 0)
-- {
-- if (extract_unsigned_integer (targ64, ptr_size, byte_order) == 0)
-- anint = 1; /* Keep looping until non-null entry is found. */
-- else if (anint)
-- break;
-- data_ofs += ptr_size;
-- }
-- initial_stack += data_ofs;
--
-- memset (readbuf, 0, len);
-- buff = readbuf;
-- while (len_read <= len-sizeof_auxv_t)
-- {
-- if (target_read_memory (initial_stack + len_read, buff, sizeof_auxv_t)
-- == 0)
-- {
-- /* Both 32 and 64 bit structures have int as the first field. */
-- const ULONGEST a_type
-- = extract_unsigned_integer (buff, sizeof (targ32), byte_order);
--
-- if (a_type == AT_NULL)
-- break;
-- buff += sizeof_auxv_t;
-- len_read += sizeof_auxv_t;
-- }
-- else
-- break;
-- }
-- return len_read;
--}
--
--/* Return nto_inferior_data for the given INFERIOR. If not yet created,
-- construct it. */
--
--struct nto_inferior_data *
--nto_inferior_data (struct inferior *const inferior)
--{
-- struct inferior *const inf = inferior ? inferior : current_inferior ();
-- struct nto_inferior_data *inf_data;
--
-- gdb_assert (inf != NULL);
--
-- inf_data = nto_inferior_data_reg.get (inf);
-- if (inf_data == NULL)
-- inf_data = nto_inferior_data_reg.emplace (inf);
--
-- return inf_data;
--}
-diff --git a/gdb/nto-tdep.h b/gdb/nto-tdep.h
-deleted file mode 100644
---- a/gdb/nto-tdep.h
-+++ /dev/null
-@@ -1,194 +0,0 @@
--/* nto-tdep.h - QNX Neutrino target header.
--
-- Copyright (C) 2003-2024 Free Software Foundation, Inc.
--
-- Contributed by QNX Software Systems Ltd.
--
-- 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/>. */
--
--#ifndef NTO_TDEP_H
--#define NTO_TDEP_H
--
--#include "solist.h"
--#include "osabi.h"
--#include "regset.h"
--#include "gdbthread.h"
--#include "gdbsupport/gdb-checked-static-cast.h"
--
--/* Target operations defined for Neutrino targets (<target>-nto-tdep.c). */
--
--struct nto_target_ops
--{
--/* The CPUINFO flags from the remote. Currently used by
-- i386 for fxsave but future proofing other hosts.
-- This is initialized in procfs_attach or nto_start_remote
-- depending on our host/target. It would only be invalid
-- if we were talking to an older pdebug which didn't support
-- the cpuinfo message. */
-- unsigned cpuinfo_flags;
--
--/* True if successfully retrieved cpuinfo from remote. */
-- int cpuinfo_valid;
--
--/* Given a register, return an id that represents the Neutrino
-- regset it came from. If reg == -1 update all regsets. */
-- int (*regset_id) (int);
--
-- void (*supply_gregset) (struct regcache *, char *);
--
-- void (*supply_fpregset) (struct regcache *, char *);
--
-- void (*supply_altregset) (struct regcache *, char *);
--
--/* Given a regset, tell gdb about registers stored in data. */
-- void (*supply_regset) (struct regcache *, int, char *);
--
--/* Given a register and regset, calculate the offset into the regset
-- and stuff it into the last argument. If regno is -1, calculate the
-- size of the entire regset. Returns length of data, -1 if unknown
-- regset, 0 if unknown register. */
-- int (*register_area) (struct gdbarch *, int, int, unsigned *);
--
--/* Build the Neutrino register set info into the data buffer.
-- Return -1 if unknown regset, 0 otherwise. */
-- int (*regset_fill) (const struct regcache *, int, char *);
--
--/* Gives the fetch_link_map_offsets function exposure outside of
-- solib-svr4.c so that we can override relocate_section_addresses(). */
-- struct link_map_offsets *(*fetch_link_map_offsets) (void);
--
--/* Used by nto_elf_osabi_sniffer to determine if we're connected to an
-- Neutrino target. */
-- enum gdb_osabi (*is_nto_target) (bfd *abfd);
--};
--
--extern struct nto_target_ops current_nto_target;
--
--#define nto_cpuinfo_flags (current_nto_target.cpuinfo_flags)
--
--#define nto_cpuinfo_valid (current_nto_target.cpuinfo_valid)
--
--#define nto_regset_id (current_nto_target.regset_id)
--
--#define nto_supply_gregset (current_nto_target.supply_gregset)
--
--#define nto_supply_fpregset (current_nto_target.supply_fpregset)
--
--#define nto_supply_altregset (current_nto_target.supply_altregset)
--
--#define nto_supply_regset (current_nto_target.supply_regset)
--
--#define nto_register_area (current_nto_target.register_area)
--
--#define nto_regset_fill (current_nto_target.regset_fill)
--
--#define nto_fetch_link_map_offsets \
--(current_nto_target.fetch_link_map_offsets)
--
--#define nto_is_nto_target (current_nto_target.is_nto_target)
--
--/* Keep this consistant with neutrino syspage.h. */
--enum
--{
-- CPUTYPE_X86,
-- CPUTYPE_PPC,
-- CPUTYPE_MIPS,
-- CPUTYPE_SPARE,
-- CPUTYPE_ARM,
-- CPUTYPE_SH,
-- CPUTYPE_UNKNOWN
--};
--
--enum
--{
-- OSTYPE_QNX4,
-- OSTYPE_NTO
--};
--
--/* These correspond to the DSMSG_* versions in dsmsgs.h. */
--enum
--{
-- NTO_REG_GENERAL,
-- NTO_REG_FLOAT,
-- NTO_REG_SYSTEM,
-- NTO_REG_ALT,
-- NTO_REG_END
--};
--
--typedef char qnx_reg64[8];
--
--typedef struct _debug_regs
--{
-- qnx_reg64 padding[1024];
--} nto_regset_t;
--
--struct nto_thread_info : public private_thread_info
--{
-- short tid = 0;
-- unsigned char state = 0;
-- unsigned char flags = 0;
-- std::string name;
--};
--
--static inline nto_thread_info *
--get_nto_thread_info (thread_info *thread)
--{
-- return gdb::checked_static_cast<nto_thread_info *> (thread->priv.get ());
--}
--
--/* Per-inferior data, common for both procfs and remote. */
--struct nto_inferior_data
--{
-- /* Last stopped flags result from wait function */
-- unsigned int stopped_flags = 0;
--
-- /* Last known stopped PC */
-- CORE_ADDR stopped_pc = 0;
--};
--
--/* Generic functions in nto-tdep.c. */
--
--void nto_init_solib_absolute_prefix (void);
--
--char **nto_parse_redirection (char *start_argv[], const char **in,
-- const char **out, const char **err);
--
--void nto_relocate_section_addresses (solib &, target_section *);
--
--int nto_map_arch_to_cputype (const char *);
--
--int nto_find_and_open_solib (const char *, unsigned,
-- gdb::unique_xmalloc_ptr<char> *);
--
--enum gdb_osabi nto_elf_osabi_sniffer (bfd *abfd);
--
--void nto_initialize_signals (void);
--
--/* Dummy function for initializing nto_target_ops on targets which do
-- not define a particular regset. */
--void nto_dummy_supply_regset (struct regcache *regcache, char *regs);
--
--int nto_in_dynsym_resolve_code (CORE_ADDR pc);
--
--const char *nto_extra_thread_info (struct target_ops *self, struct thread_info *);
--
--LONGEST nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
-- gdb_byte *readbuf,
-- LONGEST len, size_t sizeof_auxv_t);
--
--struct nto_inferior_data *nto_inferior_data (struct inferior *inf);
--
--#endif /* NTO_TDEP_H */
-diff --git a/gdb/osabi.c b/gdb/osabi.c
---- a/gdb/osabi.c
-+++ b/gdb/osabi.c
-@@ -70,7 +70,6 @@ static const struct osabi_names gdb_osabi_names[] =
- { "OpenBSD", NULL },
- { "WindowsCE", NULL },
- { "DJGPP", NULL },
-- { "QNX-Neutrino", NULL },
- { "Cygwin", NULL },
- { "Windows", NULL },
- { "AIX", NULL },
-diff --git a/gdb/osabi.h b/gdb/osabi.h
---- a/gdb/osabi.h
-+++ b/gdb/osabi.h
-@@ -35,7 +35,6 @@ enum gdb_osabi
- GDB_OSABI_OPENBSD,
- GDB_OSABI_WINCE,
- GDB_OSABI_GO32,
-- GDB_OSABI_QNXNTO,
- GDB_OSABI_CYGWIN,
- GDB_OSABI_WINDOWS,
- GDB_OSABI_AIX,
-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
-@@ -8079,7 +8079,6 @@ gdb_caching_proc gdb_has_argv0 {} {
- || [istarget *-wince-pe] || [istarget *-*-mingw32ce*]
- || [istarget *-*-osf*]
- || [istarget *-*-dicos*]
-- || [istarget *-*-nto*]
- || [istarget *-*-*vms*]
- || [istarget *-*-lynx*178]) } {
- fail "argv\[0\] should be available on this target"
diff --git a/gdb.spec b/gdb.spec
index cc5d580..db3bb7c 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -41,11 +41,11 @@ Name: %{?scl_prefix}gdb
# See timestamp of source gnulib installed into gnulib/ .
%global snapgnulib 20220501
%global tarname gdb-%{version}
-Version: 15.2
+Version: 16.1
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 7%{?dist}
+Release: 1%{?dist}
License: GPL-3.0-or-later AND BSD-3-Clause AND FSFAP AND LGPL-2.1-or-later AND GPL-2.0-or-later AND LGPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND GFDL-1.3-or-later AND LGPL-2.0-or-later WITH GCC-exception-2.0 AND GPL-3.0-or-later WITH GCC-exception-3.1 AND GPL-2.0-or-later WITH GNU-compiler-exception
# Do not provide URL for snapshots as the file lasts there only for 2 days.
@@ -135,10 +135,6 @@ BuildRequires: gcc-c++
#=push+jan
Source2: gdb-orphanripper.c
-# Man page for gstack(1).
-#=push+jan
-Source3: gdb-gstack.man
-
# /etc/gdbinit (from Debian but with Fedora compliant location).
#=fedora
Source4: gdbinit
@@ -802,7 +798,6 @@ rm -rf $RPM_BUILD_ROOT/%{_libdir}/lib{bfd*,opcodes*,iberty*,ctf*,sframe*}
# pstack obsoletion
-cp -p %{SOURCE3} $RPM_BUILD_ROOT%{_mandir}/man1/gstack.1
ln -s gstack.1 $RPM_BUILD_ROOT%{_mandir}/man1/pstack.1
ln -s gstack $RPM_BUILD_ROOT%{_bindir}/pstack
@@ -928,6 +923,13 @@ fi
# endif scl
%changelog
+* Thu Jan 23 2025 Alexandra Hájková <ahajkova@redhat.com> - 16.1-1
+- Rebase to FSF GDB 16.1.
+ Dropped:
+ gdb-backport-buildid-related-changes.patch
+ gdb-catchpoint-re-set.patch
+ gdb-remove-qnx-neutrino-support.patch
+
* Thu Jan 23 2025 Alexandra Hájková <ahajkova@redhat.com>
- Remove upstreamed gdb-6.3-gstack-20050411.patch.
diff --git a/sources b/sources
index 89046f0..511a189 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (gdb-15.2.tar.xz) = 624007deceb5b15ba89c0725883d1a699fa46714ef30887f3d0165e17c5d65d634671740a135aa69e437d916218abb08cfa2a38ed309ff19d48f51da56b2a8ba
+SHA512 (gdb-16.1.tar.xz) = 17b322fde0655a849506851c879aba9ad1f8bfee804b900efc718806091bec75511383bd4d632b8b32a32ef207233331581501157df18a8df528abe6ff667577
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=178260492228.1.4659770524731920611.rpms-gdb-5fc2d96b3010@fedoraproject.org \
--to=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