sim: mips: merge mips64vr4300 with existing multi-run build
[binutils-gdb.git] / gdb / solib.c
index 8bcbfa22df1a2813b75371ea5fa4b7601be3e29e..59fd866b652982b8332a7029e7da42dfdf2ada95 100644 (file)
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 #include "symtab.h"
 #include "bfd.h"
+#include "build-id.h"
 #include "symfile.h"
 #include "objfiles.h"
 #include "gdbcore.h"
 #include "filesystem.h"
 #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"
+#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
@@ -103,9 +67,9 @@ 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.  */
@@ -153,7 +117,7 @@ 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 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 ();
@@ -519,6 +483,56 @@ 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);
+}
+
+/* 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
@@ -534,10 +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 ());
+  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;
@@ -598,7 +642,7 @@ 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 ());
 
   delete so->sections;
   so->sections = NULL;
@@ -635,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);
@@ -681,7 +725,9 @@ solib_read_symbols (struct so_list *so, symfile_add_flags flags)
            {
              section_addr_info sap
                = build_section_addr_info_from_section_table (*so->sections);
-             so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name,
+             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;
@@ -719,7 +765,7 @@ 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;
 
@@ -940,11 +986,11 @@ solib_add (const char *pattern, int from_tty, int readsyms)
     {
       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++;
@@ -989,8 +1035,8 @@ 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 = true;
@@ -1001,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)
@@ -1143,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;
@@ -1160,7 +1206,7 @@ solib_name_from_address (struct program_space *pspace, CORE_ADDR address)
 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) != 0;
@@ -1173,7 +1219,7 @@ 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 ();
 
@@ -1198,7 +1244,7 @@ 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);
 }
@@ -1208,7 +1254,7 @@ solib_create_inferior_hook (int from_tty)
 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) != 0;
 }
@@ -1244,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 ();
@@ -1255,7 +1301,7 @@ 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 ();
@@ -1277,7 +1323,7 @@ static void
 reload_shared_libraries_1 (int from_tty)
 {
   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 (struct so_list *so : current_program_space->solibs ())
     {
@@ -1343,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
@@ -1421,8 +1467,8 @@ 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);
 }
 
 
@@ -1469,9 +1515,9 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
                {
                  struct minimal_symbol 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.  */
@@ -1586,6 +1632,43 @@ gdb_bfd_scan_elf_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr,
   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
@@ -1664,8 +1747,6 @@ void _initialize_solib ();
 void
 _initialize_solib ()
 {
-  solib_data = gdbarch_data_register_pre_init (solib_init);
-
   gdb::observers::free_objfile.attach (remove_user_added_objfile,
                                       "solib");
   gdb::observers::inferior_execd.attach ([] (inferior *inf)
@@ -1723,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);
 }