sim: mips: merge mips64vr4300 with existing multi-run build
[binutils-gdb.git] / gdb / solib.c
index f3eea399e0efc78e1bcc66d32c20287c79587dcc..59fd866b652982b8332a7029e7da42dfdf2ada95 100644 (file)
@@ -1,6 +1,6 @@
 /* Handle shared libraries for GDB, the GNU Debugger.
 
-   Copyright (C) 1990-2018 Free Software Foundation, Inc.
+   Copyright (C) 1990-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include <fcntl.h>
 #include "symtab.h"
 #include "bfd.h"
+#include "build-id.h"
 #include "symfile.h"
 #include "objfiles.h"
 #include "gdbcore.h"
 #include "command.h"
 #include "target.h"
 #include "frame.h"
-#include "gdb_regex.h"
+#include "gdbsupport/gdb_regex.h"
 #include "inferior.h"
-#include "environ.h"
+#include "gdbsupport/environ.h"
 #include "language.h"
 #include "gdbcmd.h"
 #include "completer.h"
+#include "elf/external.h"
+#include "elf/common.h"
 #include "filenames.h"         /* for DOSish file names */
 #include "exec.h"
 #include "solist.h"
-#include "observer.h"
-#include "readline/readline.h"
+#include "observable.h"
+#include "readline/tilde.h"
 #include "remote.h"
 #include "solib.h"
 #include "interps.h"
 #include "filesystem.h"
 #include "gdb_bfd.h"
-#include "filestuff.h"
+#include "gdbsupport/filestuff.h"
+#include "gdbsupport/scoped_fd.h"
+#include "debuginfod-support.h"
 #include "source.h"
+#include "cli/cli-style.h"
+#include "solib-target.h"
 
-/* Architecture-specific operations.  */
-
-/* Per-architecture data key.  */
-static struct gdbarch_data *solib_data;
-
-static void *
-solib_init (struct obstack *obstack)
-{
-  struct target_so_ops **ops;
-
-  ops = OBSTACK_ZALLOC (obstack, struct target_so_ops *);
-  *ops = current_target_so_ops;
-  return ops;
-}
-
-static const struct target_so_ops *
-solib_ops (struct gdbarch *gdbarch)
-{
-  const struct target_so_ops **ops
-    = (const struct target_so_ops **) gdbarch_data (gdbarch, solib_data);
-
-  return *ops;
-}
-
-/* Set the solib operations for GDBARCH to NEW_OPS.  */
-
-void
-set_solib_ops (struct gdbarch *gdbarch, const struct target_so_ops *new_ops)
-{
-  const struct target_so_ops **ops
-    = (const struct target_so_ops **) gdbarch_data (gdbarch, solib_data);
-
-  *ops = new_ops;
-}
-\f
-
-/* external data declarations */
-
-/* FIXME: gdbarch needs to control this variable, or else every
-   configuration needs to call set_solib_ops.  */
-struct target_so_ops *current_target_so_ops;
+/* See solib.h.  */
 
-/* Local function prototypes */
+bool debug_solib;
 
 /* If non-empty, this is a search path for loading non-absolute shared library
    symbol files.  This takes precedence over the environment variables PATH
    and LD_LIBRARY_PATH.  */
-static char *solib_search_path = NULL;
+static std::string solib_search_path;
 static void
 show_solib_search_path (struct ui_file *file, int from_tty,
                        struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("The search path for loading non-absolute "
-                           "shared library symbol files is %s.\n"),
-                   value);
+  gdb_printf (file, _("The search path for loading non-absolute "
+                     "shared library symbol files is %s.\n"),
+             value);
 }
 
 /* Same as HAVE_DOS_BASED_FILE_SYSTEM, but useable as an rvalue.  */
@@ -143,18 +110,18 @@ show_solib_search_path (struct ui_file *file, int from_tty,
    *   If IS_SOLIB is non-zero:
    *     Look in inferior's $LD_LIBRARY_PATH.
    *
-   * The last check avoids doing this search when targetting remote
+   * The last check avoids doing this search when targeting remote
    * machines since a sysroot will almost always be set.
 */
 
 static gdb::unique_xmalloc_ptr<char>
-solib_find_1 (const char *in_pathname, int *fd, int is_solib)
+solib_find_1 (const char *in_pathname, int *fd, bool is_solib)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
   int found_file = -1;
   gdb::unique_xmalloc_ptr<char> temp_pathname;
   const char *fskind = effective_target_file_system_kind ();
-  const char *sysroot = gdb_sysroot;
+  const char *sysroot = gdb_sysroot.c_str ();
   int prefix_len, orig_prefix_len;
 
   /* If the absolute prefix starts with "target:" but the filesystem
@@ -217,23 +184,23 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
     temp_pathname.reset (xstrdup (in_pathname));
   else
     {
-      int need_dir_separator;
+      bool need_dir_separator;
 
       /* Concatenate the sysroot and the target reported filename.  We
         may need to glue them with a directory separator.  Cases to
         consider:
 
-        | sysroot         | separator | in_pathname    |
-        |-----------------+-----------+----------------|
-        | /some/dir       | /         | c:/foo/bar.dll |
-        | /some/dir       |           | /foo/bar.dll   |
-        | target:         |           | c:/foo/bar.dll |
-        | target:         |           | /foo/bar.dll   |
-        | target:some/dir | /         | c:/foo/bar.dll |
-        | target:some/dir |           | /foo/bar.dll   |
+       | sysroot         | separator | in_pathname    |
+       |-----------------+-----------+----------------|
+       | /some/dir       | /         | c:/foo/bar.dll |
+       | /some/dir       |           | /foo/bar.dll   |
+       | target:         |           | c:/foo/bar.dll |
+       | target:         |           | /foo/bar.dll   |
+       | target:some/dir | /         | c:/foo/bar.dll |
+       | target:some/dir |           | /foo/bar.dll   |
 
        IOW, we don't need to add a separator if IN_PATHNAME already
-       has one, or when the the sysroot is exactly "target:".
+       has one, or when the sysroot is exactly "target:".
        There's no need to check for drive spec explicitly, as we only
        get here if IN_PATHNAME is considered an absolute path.  */
       need_dir_separator = !(IS_DIR_SEPARATOR (in_pathname[0])
@@ -254,7 +221,8 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
     }
 
   /* Now see if we can open it.  */
-  found_file = gdb_open_cloexec (temp_pathname.get (), O_RDONLY | O_BINARY, 0);
+  found_file = gdb_open_cloexec (temp_pathname.get (),
+                                O_RDONLY | O_BINARY, 0).release ();
 
   /* If the search in gdb_sysroot failed, and the path name has a
      drive spec (e.g, c:/foo), try stripping ':' from the drive spec,
@@ -265,7 +233,7 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
       && sysroot != NULL
       && HAS_TARGET_DRIVE_SPEC (fskind, in_pathname))
     {
-      int need_dir_separator = !IS_DIR_SEPARATOR (in_pathname[2]);
+      bool need_dir_separator = !IS_DIR_SEPARATOR (in_pathname[2]);
       char drive[2] = { in_pathname[0], '\0' };
 
       temp_pathname.reset (concat (sysroot,
@@ -275,7 +243,7 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
                                   in_pathname + 2, (char *) NULL));
 
       found_file = gdb_open_cloexec (temp_pathname.get (),
-                                    O_RDONLY | O_BINARY, 0);
+                                    O_RDONLY | O_BINARY, 0).release ();
       if (found_file < 0)
        {
          /* If the search in gdb_sysroot still failed, try fully
@@ -289,7 +257,7 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
                                       in_pathname + 2, (char *) NULL));
 
          found_file = gdb_open_cloexec (temp_pathname.get (),
-                                        O_RDONLY | O_BINARY, 0);
+                                        O_RDONLY | O_BINARY, 0).release ();
        }
     }
 
@@ -318,8 +286,8 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
 
   /* If not found, and we're looking for a solib, search the
      solib_search_path (if any).  */
-  if (is_solib && found_file < 0 && solib_search_path != NULL)
-    found_file = openp (solib_search_path,
+  if (is_solib && found_file < 0 && !solib_search_path.empty ())
+    found_file = openp (solib_search_path.c_str (),
                        OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH,
                        in_pathname, O_RDONLY | O_BINARY, &temp_pathname);
 
@@ -327,8 +295,8 @@ solib_find_1 (const char *in_pathname, int *fd, int is_solib)
      solib_search_path (if any) for the basename only (ignoring the
      path).  This is to allow reading solibs from a path that differs
      from the opened path.  */
-  if (is_solib && found_file < 0 && solib_search_path != NULL)
-    found_file = openp (solib_search_path,
+  if (is_solib && found_file < 0 && !solib_search_path.empty ())
+    found_file = openp (solib_search_path.c_str (),
                        OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH,
                        target_lbasename (fskind, in_pathname),
                        O_RDONLY | O_BINARY, &temp_pathname);
@@ -377,9 +345,9 @@ exec_file_find (const char *in_pathname, int *fd)
   if (in_pathname == NULL)
     return NULL;
 
-  if (*gdb_sysroot != '\0' && IS_TARGET_ABSOLUTE_PATH (fskind, in_pathname))
+  if (!gdb_sysroot.empty () && IS_TARGET_ABSOLUTE_PATH (fskind, in_pathname))
     {
-      result = solib_find_1 (in_pathname, fd, 0);
+      result = solib_find_1 (in_pathname, fd, false);
 
       if (result == NULL && fskind == file_system_kind_dos_based)
        {
@@ -389,7 +357,7 @@ exec_file_find (const char *in_pathname, int *fd)
          strcpy (new_pathname, in_pathname);
          strcat (new_pathname, ".exe");
 
-         result = solib_find_1 (new_pathname, fd, 0);
+         result = solib_find_1 (new_pathname, fd, false);
        }
     }
   else
@@ -448,7 +416,7 @@ solib_find (const char *in_pathname, int *fd)
        }
     }
 
-  return solib_find_1 (in_pathname, fd, 1);
+  return solib_find_1 (in_pathname, fd, true);
 }
 
 /* Open and return a BFD for the shared library PATHNAME.  If FD is not -1,
@@ -502,19 +470,69 @@ solib_bfd_open (const char *pathname)
   /* Check bfd format.  */
   if (!bfd_check_format (abfd.get (), bfd_object))
     error (_("`%s': not in executable format: %s"),
-          bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ()));
+          bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ()));
 
   /* Check bfd arch.  */
   b = gdbarch_bfd_arch_info (target_gdbarch ());
   if (!b->compatible (b, bfd_get_arch_info (abfd.get ())))
-    warning (_("`%s': Shared library architecture %s is not compatible "
-               "with target architecture %s."), bfd_get_filename (abfd),
-             bfd_get_arch_info (abfd.get ())->printable_name,
-            b->printable_name);
+    error (_("`%s': Shared library architecture %s is not compatible "
+            "with target architecture %s."), bfd_get_filename (abfd.get ()),
+          bfd_get_arch_info (abfd.get ())->printable_name,
+          b->printable_name);
 
   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);
+}
+
+/* See solib.h.  */
+
+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
@@ -530,11 +548,40 @@ solib_bfd_open (const char *pathname)
 static int
 solib_map_sections (struct so_list *so)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
-  struct target_section *p;
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   gdb::unique_xmalloc_ptr<char> filename (tilde_expand (so->so_name));
   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);
+
+  /* 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)
+    {
+      bool mismatch = false;
+
+      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, &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 (abfd == NULL)
     return 0;
@@ -552,27 +599,25 @@ solib_map_sections (struct so_list *so)
     error (_("Shared library file name is too long."));
   strcpy (so->so_name, bfd_get_filename (so->abfd));
 
-  if (build_section_table (so->abfd, &so->sections, &so->sections_end))
-    {
-      error (_("Can't find the file sections in `%s': %s"),
-            bfd_get_filename (so->abfd), bfd_errmsg (bfd_get_error ()));
-    }
+  if (so->sections == nullptr)
+    so->sections = new target_section_table;
+  *so->sections = build_section_table (so->abfd);
 
-  for (p = so->sections; p < so->sections_end; p++)
+  for (target_section &p : *so->sections)
     {
       /* Relocate the section binding addresses as recorded in the shared
-         object's file by the base address to which the object was actually
-         mapped.  */
-      ops->relocate_section_addresses (so, p);
+        object's file by the base address to which the object was actually
+        mapped.  */
+      ops->relocate_section_addresses (so, &p);
 
       /* If the target didn't provide information about the address
         range of the shared object, assume we want the location of
         the .text section.  */
       if (so->addr_low == 0 && so->addr_high == 0
-         && strcmp (p->the_bfd_section->name, ".text") == 0)
+         && strcmp (p.the_bfd_section->name, ".text") == 0)
        {
-         so->addr_low = p->addr;
-         so->addr_high = p->endaddr;
+         so->addr_low = p.addr;
+         so->addr_high = p.endaddr;
        }
     }
 
@@ -580,7 +625,7 @@ solib_map_sections (struct so_list *so)
      section tables.  Do this immediately after mapping the object so
      that later nodes in the list can query this object, as is needed
      in solib-osf.c.  */
-  add_target_sections (so, so->sections, so->sections_end);
+  current_program_space->add_target_sections (so, *so->sections);
 
   return 1;
 }
@@ -597,13 +642,10 @@ solib_map_sections (struct so_list *so)
 static void
 clear_so (struct so_list *so)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
-  if (so->sections)
-    {
-      xfree (so->sections);
-      so->sections = so->sections_end = NULL;
-    }
+  delete so->sections;
+  so->sections = NULL;
 
   gdb_bfd_unref (so->abfd);
   so->abfd = NULL;
@@ -637,7 +679,7 @@ clear_so (struct so_list *so)
 void
 free_so (struct so_list *so)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   clear_so (so);
   ops->free_so (so);
@@ -646,18 +688,10 @@ free_so (struct so_list *so)
 }
 
 
-/* Return address of first so_list entry in master shared object list.  */
-struct so_list *
-master_so_list (void)
-{
-  return so_list_head;
-}
-
 /* Read in symbols for shared object SO.  If SYMFILE_VERBOSE is set in FLAGS,
-   be chatty about it.  Return non-zero if any symbols were actually
-   loaded.  */
+   be chatty about it.  Return true if any symbols were actually loaded.  */
 
-int
+bool
 solib_read_symbols (struct so_list *so, symfile_add_flags flags)
 {
   if (so->symbols_loaded)
@@ -674,56 +708,56 @@ solib_read_symbols (struct so_list *so, symfile_add_flags flags)
 
       flags |= current_inferior ()->symfile_flags;
 
-      TRY
+      try
        {
-         struct section_addr_info *sap;
-
          /* Have we already loaded this shared object?  */
-         ALL_OBJFILES (so->objfile)
+         so->objfile = nullptr;
+         for (objfile *objfile : current_program_space->objfiles ())
            {
-             if (filename_cmp (objfile_name (so->objfile), so->so_name) == 0
-                 && so->objfile->addr_low == so->addr_low)
-               break;
+             if (filename_cmp (objfile_name (objfile), so->so_name) == 0
+                 && objfile->addr_low == so->addr_low)
+               {
+                 so->objfile = objfile;
+                 break;
+               }
            }
          if (so->objfile == NULL)
            {
-             sap = build_section_addr_info_from_section_table (so->sections,
-                                                               so->sections_end);
-             so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name,
-                                                     flags, sap, OBJF_SHARED,
-                                                     NULL);
+             section_addr_info sap
+               = build_section_addr_info_from_section_table (*so->sections);
+             gdb_bfd_ref_ptr tmp_bfd
+               (gdb_bfd_ref_ptr::new_reference (so->abfd));
+             so->objfile = symbol_file_add_from_bfd (tmp_bfd, so->so_name,
+                                                     flags, &sap,
+                                                     OBJF_SHARED, NULL);
              so->objfile->addr_low = so->addr_low;
-             free_section_addr_info (sap);
            }
 
          so->symbols_loaded = 1;
        }
-      CATCH (e, RETURN_MASK_ERROR)
+      catch (const gdb_exception_error &e)
        {
          exception_fprintf (gdb_stderr, e, _("Error while reading shared"
                                              " library symbols for %s:\n"),
                             so->so_name);
        }
-      END_CATCH
 
-      return 1;
+      return true;
     }
 
-  return 0;
+  return false;
 }
 
-/* Return 1 if KNOWN->objfile is used by any other so_list object in the
-   SO_LIST_HEAD list.  Return 0 otherwise.  */
+/* Return true if KNOWN->objfile is used by any other so_list object
+   in the list of shared libraries.  Return false otherwise.  */
 
-static int
+static bool
 solib_used (const struct so_list *const known)
 {
-  const struct so_list *pivot;
-
-  for (pivot = so_list_head; pivot != NULL; pivot = pivot->next)
+  for (const struct so_list *pivot : current_program_space->solibs ())
     if (pivot != known && pivot->objfile == known->objfile)
-      return 1;
-  return 0;
+      return true;
+  return false;
 }
 
 /* See solib.h.  */
@@ -731,32 +765,32 @@ solib_used (const struct so_list *const known)
 void
 update_solib_list (int from_tty)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
   struct so_list *inferior = ops->current_sos();
   struct so_list *gdb, **gdb_link;
 
   /* We can reach here due to changing solib-search-path or the
      sysroot, before having any inferior.  */
-  if (target_has_execution && !ptid_equal (inferior_ptid, null_ptid))
+  if (target_has_execution () && inferior_ptid != null_ptid)
     {
       struct inferior *inf = current_inferior ();
 
       /* If we are attaching to a running process for which we
         have not opened a symbol file, we may be able to get its
         symbols now!  */
-      if (inf->attach_flag && symfile_objfile == NULL)
+      if (inf->attach_flag
+         && current_program_space->symfile_object_file == NULL)
        {
-         TRY
+         try
            {
              ops->open_symbol_file_object (from_tty);
            }
-         CATCH (ex, RETURN_MASK_ALL)
+         catch (const gdb_exception &ex)
            {
              exception_fprintf (gdb_stderr, ex,
                                 "Error reading attached "
                                 "process's symbol file.\n");
            }
-         END_CATCH
        }
     }
 
@@ -784,8 +818,8 @@ update_solib_list (int from_tty)
      the time we're done walking GDB's list, the inferior's list
      contains only the new shared objects, which we then add.  */
 
-  gdb = so_list_head;
-  gdb_link = &so_list_head;
+  gdb = current_program_space->so_list;
+  gdb_link = &current_program_space->so_list;
   while (gdb)
     {
       struct so_list *i = inferior;
@@ -811,8 +845,8 @@ update_solib_list (int from_tty)
        }
 
       /* If the shared object appears on the inferior's list too, then
-         it's still loaded, so we don't need to do anything.  Delete
-         it from the inferior's list, and leave it on GDB's list.  */
+        it's still loaded, so we don't need to do anything.  Delete
+        it from the inferior's list, and leave it on GDB's list.  */
       if (i)
        {
          *i_link = i->next;
@@ -826,21 +860,20 @@ update_solib_list (int from_tty)
        {
          /* Notify any observer that the shared object has been
             unloaded before we remove it from GDB's tables.  */
-         observer_notify_solib_unloaded (gdb);
+         gdb::observers::solib_unloaded.notify (gdb);
 
-         VEC_safe_push (char_ptr, current_program_space->deleted_solibs,
-                        xstrdup (gdb->so_name));
+         current_program_space->deleted_solibs.push_back (gdb->so_name);
 
          *gdb_link = gdb->next;
 
          /* Unless the user loaded it explicitly, free SO's objfile.  */
          if (gdb->objfile && ! (gdb->objfile->flags & OBJF_USERLOADED)
              && !solib_used (gdb))
-           delete gdb->objfile;
+           gdb->objfile->unlink ();
 
          /* Some targets' section tables might be referring to
             sections from so->abfd; remove them.  */
-         remove_target_sections (gdb);
+         current_program_space->remove_target_sections (gdb);
 
          free_so (gdb);
          gdb = *gdb_link;
@@ -865,9 +898,9 @@ update_solib_list (int from_tty)
        {
 
          i->pspace = current_program_space;
-         VEC_safe_push (so_list_ptr, current_program_space->added_solibs, i);
+         current_program_space->added_solibs.push_back (i);
 
-         TRY
+         try
            {
              /* Fill in the rest of the `struct so_list' node.  */
              if (!solib_map_sections (i))
@@ -878,17 +911,16 @@ update_solib_list (int from_tty)
                }
            }
 
-         CATCH (e, RETURN_MASK_ERROR)
+         catch (const gdb_exception_error &e)
            {
              exception_fprintf (gdb_stderr, e,
                                 _("Error while mapping shared "
                                   "library sections:\n"));
            }
-         END_CATCH
 
          /* Notify any observer that the shared object has been
             loaded now that we've added it to GDB's tables.  */
-         observer_notify_solib_loaded (i);
+         gdb::observers::solib_loaded.notify (i);
        }
 
       /* If a library was not found, issue an appropriate warning
@@ -917,17 +949,22 @@ Do you need \"set solib-search-path\" or \"set sysroot\"?"),
 
    Uses a fairly simplistic heuristic approach where we check
    the file name against "/libpthread".  This can lead to false
-   positives, but this should be good enough in practice.  */
+   positives, but this should be good enough in practice.
 
-int
+   As of glibc-2.34, functions formerly residing in libpthread have
+   been moved to libc, so "/libc." needs to be checked too.  (Matching
+   the "." will avoid matching libraries such as libcrypt.) */
+
+bool
 libpthread_name_p (const char *name)
 {
-  return (strstr (name, "/libpthread") != NULL);
+  return (strstr (name, "/libpthread") != NULL
+          || strstr (name, "/libc.") != NULL );
 }
 
 /* Return non-zero if SO is the libpthread shared library.  */
 
-static int
+static bool
 libpthread_solib_p (struct so_list *so)
 {
   return libpthread_name_p (so->so_name);
@@ -945,17 +982,15 @@ libpthread_solib_p (struct so_list *so)
 void
 solib_add (const char *pattern, int from_tty, int readsyms)
 {
-  struct so_list *gdb;
-
   if (print_symbol_loading_p (from_tty, 0, 0))
     {
       if (pattern != NULL)
        {
-         printf_unfiltered (_("Loading symbols for shared libraries: %s\n"),
-                            pattern);
+         gdb_printf (_("Loading symbols for shared libraries: %s\n"),
+                     pattern);
        }
       else
-       printf_unfiltered (_("Loading symbols for shared libraries.\n"));
+       gdb_printf (_("Loading symbols for shared libraries.\n"));
     }
 
   current_program_space->solib_add_generation++;
@@ -974,25 +1009,25 @@ solib_add (const char *pattern, int from_tty, int readsyms)
      symbols for any that match the pattern --- or any whose symbols
      aren't already loaded, if no pattern was given.  */
   {
-    int any_matches = 0;
-    int loaded_any_symbols = 0;
+    bool any_matches = false;
+    bool loaded_any_symbols = false;
     symfile_add_flags add_flags = SYMFILE_DEFER_BP_RESET;
 
     if (from_tty)
-        add_flags |= SYMFILE_VERBOSE;
+       add_flags |= SYMFILE_VERBOSE;
 
-    for (gdb = so_list_head; gdb; gdb = gdb->next)
+    for (struct so_list *gdb : current_program_space->solibs ())
       if (! pattern || re_exec (gdb->so_name))
        {
-          /* Normally, we would read the symbols from that library
-             only if READSYMS is set.  However, we're making a small
-             exception for the pthread library, because we sometimes
-             need the library symbols to be loaded in order to provide
-             thread support (x86-linux for instance).  */
-          const int add_this_solib =
-            (readsyms || libpthread_solib_p (gdb));
-
-         any_matches = 1;
+         /* Normally, we would read the symbols from that library
+            only if READSYMS is set.  However, we're making a small
+            exception for the pthread library, because we sometimes
+            need the library symbols to be loaded in order to provide
+            thread support (x86-linux for instance).  */
+         const int add_this_solib =
+           (readsyms || libpthread_solib_p (gdb));
+
+         any_matches = true;
          if (add_this_solib)
            {
              if (gdb->symbols_loaded)
@@ -1000,11 +1035,11 @@ solib_add (const char *pattern, int from_tty, int readsyms)
                  /* If no pattern was given, be quiet for shared
                     libraries we have already loaded.  */
                  if (pattern && (from_tty || info_verbose))
-                   printf_unfiltered (_("Symbols already loaded for %s\n"),
-                                      gdb->so_name);
+                   gdb_printf (_("Symbols already loaded for %s\n"),
+                               gdb->so_name);
                }
              else if (solib_read_symbols (gdb, add_flags))
-               loaded_any_symbols = 1;
+               loaded_any_symbols = true;
            }
        }
 
@@ -1012,7 +1047,7 @@ solib_add (const char *pattern, int from_tty, int readsyms)
       breakpoint_re_set ();
 
     if (from_tty && pattern && ! any_matches)
-      printf_unfiltered
+      gdb_printf
        ("No loaded shared libraries match the pattern `%s'.\n", pattern);
 
     if (loaded_any_symbols)
@@ -1032,8 +1067,7 @@ solib_add (const char *pattern, int from_tty, int readsyms)
 static void
 info_sharedlibrary_command (const char *pattern, int from_tty)
 {
-  struct so_list *so = NULL;   /* link map state variable */
-  int so_missing_debug_info = 0;
+  bool so_missing_debug_info = false;
   int addr_width;
   int nr_libs;
   struct gdbarch *gdbarch = target_gdbarch ();
@@ -1055,7 +1089,8 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
   /* ui_out_emit_table table_emitter needs to know the number of rows,
      so we need to make two passes over the libs.  */
 
-  for (nr_libs = 0, so = so_list_head; so; so = so->next)
+  nr_libs = 0;
+  for (struct so_list *so : current_program_space->solibs ())
     {
       if (so->so_name[0])
        {
@@ -1076,7 +1111,7 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
 
     uiout->table_body ();
 
-    ALL_SO_LIBS (so)
+    for (struct so_list *so : current_program_space->solibs ())
       {
        if (! so->so_name[0])
          continue;
@@ -1096,17 +1131,17 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
            uiout->field_skip ("to");
          }
 
-       if (! interp_ui_out (top_level_interpreter ())->is_mi_like_p ()
+       if (! top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ()
            && so->symbols_loaded
            && !objfile_has_symbols (so->objfile))
          {
-           so_missing_debug_info = 1;
+           so_missing_debug_info = true;
            uiout->field_string ("syms-read", "Yes (*)");
          }
        else
          uiout->field_string ("syms-read", so->symbols_loaded ? "Yes" : "No");
 
-       uiout->field_string ("name", so->so_name);
+       uiout->field_string ("name", so->so_name, file_name_style.style ());
 
        uiout->text ("\n");
       }
@@ -1127,19 +1162,20 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
     }
 }
 
-/* Return 1 if ADDRESS lies within SOLIB.  */
+/* See solib.h.  */
 
-int
+bool
 solib_contains_address_p (const struct so_list *const solib,
                          CORE_ADDR address)
 {
-  struct target_section *p;
+  if (solib->sections == nullptr)
+    return false;
 
-  for (p = solib->sections; p < solib->sections_end; p++)
-    if (p->addr <= address && address < p->endaddr)
-      return 1;
+  for (target_section &p : *solib->sections)
+    if (p.addr <= address && address < p.endaddr)
+      return true;
 
-  return 0;
+  return false;
 }
 
 /* If ADDRESS is in a shared lib in program space PSPACE, return its
@@ -1153,7 +1189,7 @@ solib_contains_address_p (const struct so_list *const solib,
    breakpoints which are in shared libraries that are not currently
    mapped in.  */
 
-char *
+const char *
 solib_name_from_address (struct program_space *pspace, CORE_ADDR address)
 {
   struct so_list *so = NULL;
@@ -1165,21 +1201,17 @@ solib_name_from_address (struct program_space *pspace, CORE_ADDR address)
   return (0);
 }
 
-/* Return whether the data starting at VADDR, size SIZE, must be kept
-   in a core file for shared libraries loaded before "gcore" is used
-   to be handled correctly when the core file is loaded.  This only
-   applies when the section would otherwise not be kept in the core
-   file (in particular, for readonly sections).  */
+/* See solib.h.  */
 
-int
+bool
 solib_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   if (ops->keep_data_in_core)
-    return ops->keep_data_in_core (vaddr, size);
+    return ops->keep_data_in_core (vaddr, size) != 0;
   else
-    return 0;
+    return false;
 }
 
 /* Called by free_all_symtabs */
@@ -1187,17 +1219,17 @@ solib_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
 void
 clear_solib (void)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   disable_breakpoints_in_shlibs ();
 
-  while (so_list_head)
+  while (current_program_space->so_list)
     {
-      struct so_list *so = so_list_head;
+      struct so_list *so = current_program_space->so_list;
 
-      so_list_head = so->next;
-      observer_notify_solib_unloaded (so);
-      remove_target_sections (so);
+      current_program_space->so_list = so->next;
+      gdb::observers::solib_unloaded.notify (so);
+      current_program_space->remove_target_sections (so);
       free_so (so);
     }
 
@@ -1212,20 +1244,19 @@ clear_solib (void)
 void
 solib_create_inferior_hook (int from_tty)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   ops->solib_create_inferior_hook (from_tty);
 }
 
-/* Check to see if an address is in the dynamic loader's dynamic
-   symbol resolution code.  Return 1 if so, 0 otherwise.  */
+/* See solib.h.  */
 
-int
+bool
 in_solib_dynsym_resolve_code (CORE_ADDR pc)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
-  return ops->in_dynsym_resolve_code (pc);
+  return ops->in_dynsym_resolve_code (pc) != 0;
 }
 
 /* Implements the "sharedlibrary" command.  */
@@ -1259,7 +1290,7 @@ no_shared_libraries (const char *ignored, int from_tty)
 void
 update_solib_breakpoints (void)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   if (ops->update_breakpoints != NULL)
     ops->update_breakpoints ();
@@ -1270,12 +1301,12 @@ update_solib_breakpoints (void)
 void
 handle_solib_event (void)
 {
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+  const struct target_so_ops *ops = gdbarch_so_ops (target_gdbarch ());
 
   if (ops->handle_event != NULL)
     ops->handle_event ();
 
-  clear_program_space_solib_cache (current_inferior ()->pspace);
+  current_inferior ()->pspace->clear_solib_cache ();
 
   /* Check for any newly added shared libraries if we're supposed to
      be adding them automatically.  Switch terminal for any messages
@@ -1291,15 +1322,13 @@ handle_solib_event (void)
 static void
 reload_shared_libraries_1 (int from_tty)
 {
-  struct so_list *so;
-
   if (print_symbol_loading_p (from_tty, 0, 0))
-    printf_unfiltered (_("Loading symbols for shared libraries.\n"));
+    gdb_printf (_("Loading symbols for shared libraries.\n"));
 
-  for (so = so_list_head; so != NULL; so = so->next)
+  for (struct so_list *so : current_program_space->solibs ())
     {
-      char *found_pathname = NULL;
-      int was_loaded = so->symbols_loaded;
+      const char *found_pathname = NULL;
+      bool was_loaded = so->symbols_loaded != 0;
       symfile_add_flags add_flags = SYMFILE_DEFER_BP_RESET;
 
       if (from_tty)
@@ -1319,8 +1348,8 @@ reload_shared_libraries_1 (int from_tty)
        {
          if (so->objfile && ! (so->objfile->flags & OBJF_USERLOADED)
              && !solib_used (so))
-           delete so->objfile;
-         remove_target_sections (so);
+           so->objfile->unlink ();
+         current_program_space->remove_target_sections (so);
          clear_so (so);
        }
 
@@ -1330,21 +1359,20 @@ reload_shared_libraries_1 (int from_tty)
          && (!was_loaded
              || filename_cmp (found_pathname, so->so_name) != 0))
        {
-         int got_error = 0;
+         bool got_error = false;
 
-         TRY
+         try
            {
              solib_map_sections (so);
            }
 
-         CATCH (e, RETURN_MASK_ERROR)
+         catch (const gdb_exception_error &e)
            {
              exception_fprintf (gdb_stderr, e,
                                 _("Error while mapping "
                                   "shared library sections:\n"));
-             got_error = 1;
+             got_error = true;
            }
-         END_CATCH
 
            if (!got_error
                && (auto_solib_add || was_loaded || libpthread_solib_p (so)))
@@ -1361,7 +1389,7 @@ reload_shared_libraries (const char *ignored, int from_tty,
 
   reload_shared_libraries_1 (from_tty);
 
-  ops = solib_ops (target_gdbarch ());
+  ops = gdbarch_so_ops (target_gdbarch ());
 
   /* Creating inferior hooks here has two purposes.  First, if we reload 
      shared libraries then the address of solib breakpoint we've computed
@@ -1372,7 +1400,7 @@ reload_shared_libraries (const char *ignored, int from_tty,
      Absent this call, if we've just connected to a target and set 
      solib-absolute-prefix or solib-search-path, we'll lose all information
      about ld.so.  */
-  if (target_has_execution)
+  if (target_has_execution ())
     {
       /* Reset or free private data structures not associated with
         so_list entries.  */
@@ -1415,20 +1443,20 @@ gdb_sysroot_changed (const char *ignored, int from_tty,
   const char *old_prefix = "remote:";
   const char *new_prefix = TARGET_SYSROOT_PREFIX;
 
-  if (startswith (gdb_sysroot, old_prefix))
+  if (startswith (gdb_sysroot.c_str (), old_prefix))
     {
-      static int warning_issued = 0;
+      static bool warning_issued = false;
 
       gdb_assert (strlen (old_prefix) == strlen (new_prefix));
-      memcpy (gdb_sysroot, new_prefix, strlen (new_prefix));
+      gdb_sysroot = new_prefix + gdb_sysroot.substr (strlen (old_prefix));
 
       if (!warning_issued)
        {
          warning (_("\"%s\" is deprecated, use \"%s\" instead."),
                   old_prefix, new_prefix);
-         warning (_("sysroot set to \"%s\"."), gdb_sysroot);
+         warning (_("sysroot set to \"%s\"."), gdb_sysroot.c_str ());
 
-         warning_issued = 1;
+         warning_issued = true;
        }
     }
 
@@ -1439,26 +1467,11 @@ static void
 show_auto_solib_add (struct ui_file *file, int from_tty,
                     struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("Autoloading of shared library symbols is %s.\n"),
-                   value);
+  gdb_printf (file, _("Autoloading of shared library symbols is %s.\n"),
+             value);
 }
 
 
-/* Handler for library-specific lookup of global symbol NAME in OBJFILE.  Call
-   the library-specific handler if it is installed for the current target.  */
-
-struct block_symbol
-solib_global_lookup (struct objfile *objfile,
-                    const char *name,
-                    const domain_enum domain)
-{
-  const struct target_so_ops *ops = solib_ops (target_gdbarch ());
-
-  if (ops->lookup_lib_global_symbol != NULL)
-    return ops->lookup_lib_global_symbol (objfile, name, domain);
-  return (struct block_symbol) {NULL, NULL};
-}
-
 /* Lookup the value for a specific symbol from dynamic symbol table.  Look
    up symbol from ABFD.  MATCH_SYM is a callback function to determine
    whether to pick up a symbol.  DATA is the input of this callback
@@ -1477,8 +1490,8 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
     {
       unsigned int i;
 
-      asymbol **symbol_table = (asymbol **) xmalloc (storage_needed);
-      struct cleanup *back_to = make_cleanup (xfree, symbol_table);
+      gdb::def_vector<asymbol *> storage (storage_needed / sizeof (asymbol *));
+      asymbol **symbol_table = storage.data ();
       unsigned int number_of_symbols =
        bfd_canonicalize_symtab (abfd, symbol_table);
 
@@ -1492,20 +1505,19 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
              symaddr = sym->value;
 
              /* Some ELF targets fiddle with addresses of symbols they
-                consider special.  They use minimal symbols to do that
-                and this is needed for correct breakpoint placement,
-                but we do not have full data here to build a complete
-                minimal symbol, so just set the address and let the
-                targets cope with that.  */
+                consider special.  They use minimal symbols to do that
+                and this is needed for correct breakpoint placement,
+                but we do not have full data here to build a complete
+                minimal symbol, so just set the address and let the
+                targets cope with that.  */
              if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
                  && gdbarch_elf_make_msymbol_special_p (gdbarch))
                {
-                 struct minimal_symbol msym;
+                 struct minimal_symbol msym {};
 
-                 memset (&msym, 0, sizeof (msym));
-                 SET_MSYMBOL_VALUE_ADDRESS (&msym, symaddr);
+                 msym.set_value_address (symaddr);
                  gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym);
-                 symaddr = MSYMBOL_VALUE_RAW_ADDRESS (&msym);
+                 symaddr = msym.value_raw_address ();
                }
 
              /* BFD symbols are section relative.  */
@@ -1513,12 +1525,150 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
              break;
            }
        }
-      do_cleanups (back_to);
     }
 
   return symaddr;
 }
 
+/* See solib.h.  */
+
+int
+gdb_bfd_scan_elf_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr,
+                        CORE_ADDR *ptr_addr)
+{
+  int arch_size, step, sect_size;
+  long current_dyntag;
+  CORE_ADDR dyn_ptr, dyn_addr;
+  gdb_byte *bufend, *bufstart, *buf;
+  Elf32_External_Dyn *x_dynp_32;
+  Elf64_External_Dyn *x_dynp_64;
+  struct bfd_section *sect;
+
+  if (abfd == NULL)
+    return 0;
+
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return 0;
+
+  arch_size = bfd_get_arch_size (abfd);
+  if (arch_size == -1)
+    return 0;
+
+  /* Find the start address of the .dynamic section.  */
+  sect = bfd_get_section_by_name (abfd, ".dynamic");
+  if (sect == NULL)
+    return 0;
+
+  bool found = false;
+  for (const target_section &target_section
+        : current_program_space->target_sections ())
+    if (sect == target_section.the_bfd_section)
+      {
+       dyn_addr = target_section.addr;
+       found = true;
+       break;
+      }
+  if (!found)
+    {
+      /* ABFD may come from OBJFILE acting only as a symbol file without being
+        loaded into the target (see add_symbol_file_command).  This case is
+        such fallback to the file VMA address without the possibility of
+        having the section relocated to its actual in-memory address.  */
+
+      dyn_addr = bfd_section_vma (sect);
+    }
+
+  /* Read in .dynamic from the BFD.  We will get the actual value
+     from memory later.  */
+  sect_size = bfd_section_size (sect);
+  buf = bufstart = (gdb_byte *) alloca (sect_size);
+  if (!bfd_get_section_contents (abfd, sect,
+                                buf, 0, sect_size))
+    return 0;
+
+  /* Iterate over BUF and scan for DYNTAG.  If found, set PTR and return.  */
+  step = (arch_size == 32) ? sizeof (Elf32_External_Dyn)
+                          : sizeof (Elf64_External_Dyn);
+  for (bufend = buf + sect_size;
+       buf < bufend;
+       buf += step)
+  {
+    if (arch_size == 32)
+      {
+       x_dynp_32 = (Elf32_External_Dyn *) buf;
+       current_dyntag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_tag);
+       dyn_ptr = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_un.d_ptr);
+      }
+    else
+      {
+       x_dynp_64 = (Elf64_External_Dyn *) buf;
+       current_dyntag = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_tag);
+       dyn_ptr = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_un.d_ptr);
+      }
+    if (current_dyntag == DT_NULL)
+      return 0;
+    if (current_dyntag == desired_dyntag)
+      {
+       /* If requested, try to read the runtime value of this .dynamic
+          entry.  */
+       if (ptr)
+         {
+           struct type *ptr_type;
+           gdb_byte ptr_buf[8];
+           CORE_ADDR ptr_addr_1;
+
+           ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+           ptr_addr_1 = dyn_addr + (buf - bufstart) + arch_size / 8;
+           if (target_read_memory (ptr_addr_1, ptr_buf, arch_size / 8) == 0)
+             dyn_ptr = extract_typed_address (ptr_buf, ptr_type);
+           *ptr = dyn_ptr;
+           if (ptr_addr)
+             *ptr_addr = dyn_addr + (buf - bufstart);
+         }
+       return 1;
+      }
+  }
+
+  return 0;
+}
+
+/* See solib.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+gdb_bfd_read_elf_soname (const char *filename)
+{
+  gdb_bfd_ref_ptr abfd = gdb_bfd_open (filename, gnutarget);
+
+  if (abfd == nullptr)
+    return {};
+
+  /* Check that ABFD is an ET_DYN ELF file.  */
+  if (!bfd_check_format (abfd.get (), bfd_object)
+      || !(bfd_get_file_flags (abfd.get ()) & DYNAMIC))
+    return {};
+
+  CORE_ADDR idx;
+  if (!gdb_bfd_scan_elf_dyntag (DT_SONAME, abfd.get (), &idx, nullptr))
+    return {};
+
+  struct bfd_section *dynstr = bfd_get_section_by_name (abfd.get (), ".dynstr");
+  int sect_size = bfd_section_size (dynstr);
+  if (dynstr == nullptr || sect_size <= idx)
+    return {};
+
+  /* Read soname from the string table.  */
+  gdb::byte_vector dynstr_buf;
+  if (!gdb_bfd_get_full_section_contents (abfd.get (), dynstr, &dynstr_buf))
+    return {};
+
+  /* Ensure soname is null-terminated before returning a copy.  */
+  char *soname = (char *) dynstr_buf.data () + idx;
+  if (strnlen (soname, sect_size - idx) == sect_size - idx)
+    return {};
+
+  return make_unique_xstrdup (soname);
+}
+
 /* Lookup the value for a specific symbol from symbol table.  Look up symbol
    from ABFD.  MATCH_SYM is a callback function to determine whether to pick
    up a symbol.  DATA is the input of this callback function.  Return NULL
@@ -1536,8 +1686,8 @@ bfd_lookup_symbol_from_dyn_symtab (bfd *abfd,
   if (storage_needed > 0)
     {
       unsigned int i;
-      asymbol **symbol_table = (asymbol **) xmalloc (storage_needed);
-      struct cleanup *back_to = make_cleanup (xfree, symbol_table);
+      gdb::def_vector<asymbol *> storage (storage_needed / sizeof (asymbol *));
+      asymbol **symbol_table = storage.data ();
       unsigned int number_of_symbols =
        bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
 
@@ -1552,7 +1702,6 @@ bfd_lookup_symbol_from_dyn_symtab (bfd *abfd,
              break;
            }
        }
-      do_cleanups (back_to);
     }
   return symaddr;
 }
@@ -1578,35 +1727,39 @@ gdb_bfd_lookup_symbol (bfd *abfd,
   return symaddr;
 }
 
-/* SO_LIST_HEAD may contain user-loaded object files that can be removed
-   out-of-band by the user.  So upon notification of free_objfile remove
-   all references to any user-loaded file that is about to be freed.  */
+/* The shared library list may contain user-loaded object files that
+   can be removed out-of-band by the user.  So upon notification of
+   free_objfile remove all references to any user-loaded file that is
+   about to be freed.  */
 
 static void
 remove_user_added_objfile (struct objfile *objfile)
 {
-  struct so_list *so;
-
   if (objfile != 0 && objfile->flags & OBJF_USERLOADED)
     {
-      for (so = so_list_head; so != NULL; so = so->next)
+      for (struct so_list *so : current_program_space->solibs ())
        if (so->objfile == objfile)
          so->objfile = NULL;
     }
 }
 
+void _initialize_solib ();
 void
-_initialize_solib (void)
+_initialize_solib ()
 {
-  solib_data = gdbarch_data_register_pre_init (solib_init);
-
-  observer_attach_free_objfile (remove_user_added_objfile);
+  gdb::observers::free_objfile.attach (remove_user_added_objfile,
+                                      "solib");
+  gdb::observers::inferior_execd.attach ([] (inferior *inf)
+    {
+      solib_create_inferior_hook (0);
+    }, "solib");
 
   add_com ("sharedlibrary", class_files, sharedlibrary_command,
           _("Load shared object library symbols for files matching REGEXP."));
-  add_info ("sharedlibrary", info_sharedlibrary_command,
-           _("Status of loaded shared object libraries."));
-  add_info_alias ("dll", "sharedlibrary", 1);
+  cmd_list_element *info_sharedlibrary_cmd
+    = add_info ("sharedlibrary", info_sharedlibrary_command,
+               _("Status of loaded shared object libraries."));
+  add_info_alias ("dll", info_sharedlibrary_cmd, 1);
   add_com ("nosharedlibrary", class_files, no_shared_libraries,
           _("Unload all shared object library symbols."));
 
@@ -1623,20 +1776,21 @@ inferior.  Otherwise, symbols must be loaded manually, using \
                           show_auto_solib_add,
                           &setlist, &showlist);
 
-  add_setshow_optional_filename_cmd ("sysroot", class_support,
-                                    &gdb_sysroot, _("\
+  set_show_commands sysroot_cmds
+    = add_setshow_optional_filename_cmd ("sysroot", class_support,
+                                        &gdb_sysroot, _("\
 Set an alternate system root."), _("\
 Show the current system root."), _("\
 The system root is used to load absolute shared library symbol files.\n\
 For other (relative) files, you can add directories using\n\
 `set solib-search-path'."),
-                                    gdb_sysroot_changed,
-                                    NULL,
-                                    &setlist, &showlist);
+                                        gdb_sysroot_changed,
+                                        NULL,
+                                        &setlist, &showlist);
 
-  add_alias_cmd ("solib-absolute-prefix", "sysroot", class_support, 0,
+  add_alias_cmd ("solib-absolute-prefix", sysroot_cmds.set, class_support, 0,
                 &setlist);
-  add_alias_cmd ("solib-absolute-prefix", "sysroot", class_support, 0,
+  add_alias_cmd ("solib-absolute-prefix", sysroot_cmds.show, class_support, 0,
                 &showlist);
 
   add_setshow_optional_filename_cmd ("solib-search-path", class_support,
@@ -1650,4 +1804,12 @@ PATH and LD_LIBRARY_PATH."),
                                     reload_shared_libraries,
                                     show_solib_search_path,
                                     &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("solib", class_maintenance,
+                          &debug_solib, _("\
+Set solib debugging."), _("\
+Show solib debugging."), _("\
+When true, solib-related debugging output is enabled."),
+                           nullptr, nullptr,
+                           &setdebuglist, &showdebuglist);
 }