/* Handle shared libraries for GDB, the GNU Debugger.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008
+ 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GDB.
#include "solist.h"
#include "observer.h"
#include "readline/readline.h"
+#include "remote.h"
+#include "solib.h"
/* Architecture-specific operations. */
GLOBAL FUNCTION
- solib_open -- Find a shared library file and open it.
+ solib_find -- Find a shared library file.
SYNOPSIS
- int solib_open (char *in_patname, char **found_pathname);
+ char *solib_find (char *in_pathname, int *fd);
DESCRIPTION
RETURNS
- file handle for opened solib, or -1 for failure. */
+ Full pathname of the shared library file, or NULL if not found.
+ (The pathname is malloc'ed; it needs to be freed by the caller.)
+ *FD is set to either -1 or an open file handle for the library. */
-int
-solib_open (char *in_pathname, char **found_pathname)
+char *
+solib_find (char *in_pathname, int *fd)
{
struct target_so_ops *ops = solib_ops (target_gdbarch);
int found_file = -1;
char *temp_pathname = NULL;
- char *p = in_pathname;
int gdb_sysroot_is_empty;
gdb_sysroot_is_empty = (gdb_sysroot == NULL || *gdb_sysroot == 0);
strcat (temp_pathname, in_pathname);
}
+ /* Handle remote files. */
+ if (remote_filename_p (temp_pathname))
+ {
+ *fd = -1;
+ return xstrdup (temp_pathname);
+ }
+
/* Now see if we can open it. */
found_file = open (temp_pathname, O_RDONLY | O_BINARY, 0);
/* If not found, search the solib_search_path (if any). */
if (found_file < 0 && solib_search_path != NULL)
found_file = openp (solib_search_path, OPF_TRY_CWD_FIRST,
- in_pathname, O_RDONLY | O_BINARY, 0, &temp_pathname);
+ in_pathname, O_RDONLY | O_BINARY, &temp_pathname);
/* If not found, next search the 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 (found_file < 0 && solib_search_path != NULL)
found_file = openp (solib_search_path, OPF_TRY_CWD_FIRST,
- lbasename (in_pathname), O_RDONLY | O_BINARY, 0,
+ lbasename (in_pathname), O_RDONLY | O_BINARY,
&temp_pathname);
/* If not found, try to use target supplied solib search method */
/* If not found, next search the inferior's $PATH environment variable. */
if (found_file < 0 && gdb_sysroot_is_empty)
found_file = openp (get_in_environ (inferior_environ, "PATH"),
- OPF_TRY_CWD_FIRST, in_pathname, O_RDONLY | O_BINARY, 0,
+ OPF_TRY_CWD_FIRST, in_pathname, O_RDONLY | O_BINARY,
&temp_pathname);
/* If not found, next search the inferior's $LD_LIBRARY_PATH
environment variable. */
if (found_file < 0 && gdb_sysroot_is_empty)
found_file = openp (get_in_environ (inferior_environ, "LD_LIBRARY_PATH"),
- OPF_TRY_CWD_FIRST, in_pathname, O_RDONLY | O_BINARY, 0,
+ OPF_TRY_CWD_FIRST, in_pathname, O_RDONLY | O_BINARY,
&temp_pathname);
- /* Done. If not found, tough luck. Return found_file and
- (optionally) found_pathname. */
- if (temp_pathname)
+ *fd = found_file;
+ return temp_pathname;
+}
+
+/* Open and return a BFD for the shared library PATHNAME. If FD is not -1,
+ it is used as file handle to open the file. Throws an error if the file
+ could not be opened. Handles both local and remote file access.
+
+ PATHNAME must be malloc'ed by the caller. If successful, the new BFD's
+ name will point to it. If unsuccessful, PATHNAME will be freed and the
+ FD will be closed (unless FD was -1). */
+
+bfd *
+solib_bfd_fopen (char *pathname, int fd)
+{
+ bfd *abfd;
+
+ if (remote_filename_p (pathname))
{
- if (found_pathname != NULL)
- *found_pathname = temp_pathname;
- else
- xfree (temp_pathname);
+ gdb_assert (fd == -1);
+ abfd = remote_bfd_open (pathname, gnutarget);
+ }
+ else
+ {
+ abfd = bfd_fopen (pathname, gnutarget, FOPEN_RB, fd);
+
+ if (abfd)
+ bfd_set_cacheable (abfd, 1);
+ else if (fd != -1)
+ close (fd);
}
- return found_file;
+
+ if (!abfd)
+ {
+ make_cleanup (xfree, pathname);
+ error (_("Could not open `%s' as an executable file: %s"),
+ pathname, bfd_errmsg (bfd_get_error ()));
+ }
+
+ return abfd;
+}
+
+/* Find shared library PATHNAME and open a BFD for it. */
+
+bfd *
+solib_bfd_open (char *pathname)
+{
+ struct target_so_ops *ops = solib_ops (target_gdbarch);
+ char *found_pathname;
+ int found_file;
+ bfd *abfd;
+
+ /* Use target-specific override if present. */
+ if (ops->bfd_open)
+ return ops->bfd_open (pathname);
+
+ /* Search for shared library file. */
+ found_pathname = solib_find (pathname, &found_file);
+ if (found_pathname == NULL)
+ perror_with_name (pathname);
+
+ /* Open bfd for shared library. */
+ abfd = solib_bfd_fopen (found_pathname, found_file);
+
+ /* Check bfd format. */
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ bfd_close (abfd);
+ make_cleanup (xfree, found_pathname);
+ error (_("`%s': not in executable format: %s"),
+ found_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+
+ return abfd;
}
{
struct so_list *so = (struct so_list *) arg; /* catch_errors bogon */
char *filename;
- char *scratch_pathname;
- int scratch_chan;
- struct section_table *p;
+ struct target_section *p;
struct cleanup *old_chain;
bfd *abfd;
filename = tilde_expand (so->so_name);
-
old_chain = make_cleanup (xfree, filename);
- scratch_chan = solib_open (filename, &scratch_pathname);
-
- if (scratch_chan < 0)
- {
- perror_with_name (filename);
- }
-
- /* Leave scratch_pathname allocated. abfd->name will point to it. */
- abfd = bfd_fopen (scratch_pathname, gnutarget, FOPEN_RB, scratch_chan);
- if (!abfd)
- {
- close (scratch_chan);
- error (_("Could not open `%s' as an executable file: %s"),
- scratch_pathname, bfd_errmsg (bfd_get_error ()));
- }
+ abfd = solib_bfd_open (filename);
+ do_cleanups (old_chain);
/* Leave bfd open, core_xfer_memory and "info files" need it. */
so->abfd = abfd;
- bfd_set_cacheable (abfd, 1);
/* copy full path name into so_name, so that later symbol_file_add
can find it */
- if (strlen (scratch_pathname) >= SO_NAME_MAX_PATH_SIZE)
- error (_("Full path name length of shared library exceeds SO_NAME_MAX_PATH_SIZE in so_list structure."));
- strcpy (so->so_name, scratch_pathname);
+ if (strlen (bfd_get_filename (abfd)) >= SO_NAME_MAX_PATH_SIZE)
+ error (_("Shared library file name is too long."));
+ strcpy (so->so_name, bfd_get_filename (abfd));
- if (!bfd_check_format (abfd, bfd_object))
- {
- error (_("\"%s\": not in executable format: %s."),
- scratch_pathname, bfd_errmsg (bfd_get_error ()));
- }
if (build_section_table (abfd, &so->sections, &so->sections_end))
{
error (_("Can't find the file sections in `%s': %s"),
}
}
- /* Free the file names, close the file now. */
- do_cleanups (old_chain);
-
return (1);
}
sap = build_section_addr_info_from_section_table (so->sections,
so->sections_end);
- so->objfile = symbol_file_add (so->so_name, so->from_tty,
- sap, 0, OBJF_SHARED);
+ so->objfile = symbol_file_add_from_bfd (so->abfd, so->from_tty,
+ sap, 0, OBJF_SHARED | OBJF_KEEPBFD);
free_section_addr_info (sap);
return (1);
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 (attach_flag &&
- symfile_objfile == NULL)
- catch_errors (ops->open_symbol_file_object, &from_tty,
- "Error reading attached process's symbol file.\n",
- RETURN_MASK_ALL);
+ /* 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))
+ {
+ 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)
+ catch_errors (ops->open_symbol_file_object, &from_tty,
+ "Error reading attached process's symbol file.\n",
+ RETURN_MASK_ALL);
+ }
/* GDB and the inferior's dynamic linker each maintain their own
list of currently loaded shared objects; we want to bring the
}
}
-/* Return non-zero if SO is the libpthread shared library.
+
+/* Return non-zero if NAME is the libpthread shared library.
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. */
+int
+libpthread_name_p (const char *name)
+{
+ return (strstr (name, "/libpthread") != NULL);
+}
+
+/* Return non-zero if SO is the libpthread shared library. */
+
static int
libpthread_solib_p (struct so_list *so)
{
- return (strstr (so->so_name, "/libpthread") != NULL);
+ return libpthread_name_p (so->so_name);
}
/* GLOBAL FUNCTION
}
}
+/* Return 1 if ADDRESS lies within SOLIB. */
+
+int
+solib_contains_address_p (const struct so_list *const solib,
+ CORE_ADDR address)
+{
+ struct target_section *p;
+
+ for (p = solib->sections; p < solib->sections_end; p++)
+ if (p->addr <= address && address < p->endaddr)
+ return 1;
+
+ return 0;
+}
+
/*
GLOBAL FUNCTION
- solib_address -- check to see if an address is in a shared lib
+ solib_name_from_address -- if an address is in a shared lib, return
+ its name.
SYNOPSIS
- char * solib_address (CORE_ADDR address)
+ char * solib_name_from_address (CORE_ADDR address)
DESCRIPTION
*/
char *
-solib_address (CORE_ADDR address)
+solib_name_from_address (CORE_ADDR address)
{
struct so_list *so = 0; /* link map state variable */
for (so = so_list_head; so; so = so->next)
- {
- struct section_table *p;
-
- for (p = so->sections; p < so->sections_end; p++)
- {
- if (p->addr <= address && address < p->endaddr)
- return (so->so_name);
- }
- }
+ if (solib_contains_address_p (so, address))
+ return (so->so_name);
return (0);
}
{
struct so_list *so = so_list_head;
so_list_head = so->next;
+ observer_notify_solib_unloaded (so);
if (so->abfd)
remove_target_sections (so->abfd);
free_so (so);
void
no_shared_libraries (char *ignored, int from_tty)
{
- objfile_purge_solibs ();
+ /* The order of the two routines below is important: clear_solib notifies
+ the solib_unloaded observers, and some of these observers might need
+ access to their associated objfiles. Therefore, we can not purge the
+ solibs' objfiles before clear_solib has been called. */
+
clear_solib ();
+ objfile_purge_solibs ();
}
static void
{
no_shared_libraries (NULL, from_tty);
solib_add (NULL, from_tty, NULL, auto_solib_add);
+ /* Creating inferior hooks here has two purposes. First, if we reload
+ shared libraries then the address of solib breakpoint we've computed
+ previously might be no longer valid. For example, if we forgot to set
+ solib-absolute-prefix and are setting it right now, then the previous
+ breakpoint address is plain wrong. Second, installing solib hooks
+ also implicitly figures were ld.so is and loads symbols for it.
+ 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)
+ {
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
+#else
+ solib_create_inferior_hook ();
+#endif
+ }
+ /* We have unloaded and then reloaded debug info for all shared libraries.
+ However, frames may still reference them, for example a frame's
+ unwinder might still point of DWARF FDE structures that are now freed.
+ Reinit frame cache to avoid crashing. */
+ reinit_frame_cache ();
}
static void