/* Handle shared libraries for GDB, the GNU Debugger.
- Copyright (C) 1990-2020 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 "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 "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
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. */
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 ();
- 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
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 sysroot is exactly "target:".
}
/* 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,
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
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 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);
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);
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, false);
/* 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.get ()),
- 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
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;
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. */
+ 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
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);
+ current_program_space->add_target_sections (so, *so->sections);
return 1;
}
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;
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);
{
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;
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;
/* 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
{
}
/* 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;
/* 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;
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.
+
+ 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. */
{
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++;
symfile_add_flags add_flags = SYMFILE_DEFER_BP_RESET;
if (from_tty)
- add_flags |= SYMFILE_VERBOSE;
+ add_flags |= SYMFILE_VERBOSE;
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));
+ /* 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 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;
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)
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;
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;
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 ();
current_program_space->so_list = so->next;
gdb::observers::solib_unloaded.notify (so);
- remove_target_sections (so);
+ current_program_space->remove_target_sections (so);
free_so (so);
}
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);
}
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;
}
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 ();
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
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 ())
{
if (so->objfile && ! (so->objfile->flags & OBJF_USERLOADED)
&& !solib_used (so))
so->objfile->unlink ();
- remove_target_sections (so);
+ current_program_space->remove_target_sections (so);
clear_so (so);
}
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
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 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 = true;
}
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);
}
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 {};
- 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. */
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
void
_initialize_solib ()
{
- solib_data = gdbarch_data_register_pre_init (solib_init);
-
- gdb::observers::free_objfile.attach (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."));
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,
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);
}