public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/gdb] gdb-17.2-rebase-f44: Rebase to FSF GDB 16.1.
@ 2026-06-28  0:02 
  0 siblings, 0 replies; only message in thread
From:  @ 2026-06-28  0:02 UTC (permalink / raw)
  To: git-commits

          A new commit has been pushed.

          Repo   : rpms/gdb
          Branch : gdb-17.2-rebase-f44
          Commit : 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 &region : 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 &region : 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 &region : 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, &reg, sizeof (reg), &regsize) == EOK)
--    nto_supply_gregset (regcache, (char *) &reg.greg);
--  if (devctl (ctl_fd, DCMD_PROC_GETFPREG, &reg, sizeof (reg), &regsize)
--      == EOK)
--    nto_supply_fpregset (regcache, (char *) &reg.fpreg);
--  if (devctl (ctl_fd, DCMD_PROC_GETALTREG, &reg, sizeof (reg), &regsize)
--      == EOK)
--    nto_supply_altregset (regcache, (char *) &reg.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 *) &reg,
--				sizeof (reg), &regsize);
--	  if (dev_set == -1)
--	    continue;
--
--	  if (nto_regset_fill (regcache, regset, (char *) &reg) == -1)
--	    continue;
--
--	  err = devctl (ctl_fd, dev_set, &reg, 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 *) &reg, sizeof (reg), &regsize);
--      if (dev_set == -1)
--	return;
--
--      len = nto_register_area (regcache->arch (),
--			       regno, regset, &off);
--
--      if (len < 1)
--	return;
--
--      regcache->raw_collect (regno, (char *) &reg + off);
--
--      err = devctl (ctl_fd, dev_set, &reg, 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

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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-28  0:02 [rpms/gdb] gdb-17.2-rebase-f44: Rebase to FSF GDB 16.1 

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