/* 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, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1990-2003, 2005-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "solib.h"
#include "interps.h"
#include "filesystem.h"
+#include "gdb_bfd.h"
/* Architecture-specific operations. */
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). */
+ PATHNAME must be malloc'ed by the caller. It will be freed by this
+ function. If unsuccessful, the FD will be closed (unless FD was
+ -1). */
bfd *
solib_bfd_fopen (char *pathname, int fd)
}
else
{
- abfd = bfd_fopen (pathname, gnutarget, FOPEN_RB, fd);
+ abfd = gdb_bfd_fopen (pathname, gnutarget, FOPEN_RB, fd);
if (abfd)
bfd_set_cacheable (abfd, 1);
- else if (fd != -1)
- close (fd);
}
if (!abfd)
pathname, bfd_errmsg (bfd_get_error ()));
}
+ xfree (pathname);
+
return abfd;
}
/* Check bfd format. */
if (!bfd_check_format (abfd, bfd_object))
{
- bfd_close (abfd);
- make_cleanup (xfree, found_pathname);
+ make_cleanup_bfd_unref (abfd);
error (_("`%s': not in executable format: %s"),
- found_pathname, bfd_errmsg (bfd_get_error ()));
+ bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ()));
}
/* Check bfd arch. */
b = gdbarch_bfd_arch_info (target_gdbarch);
if (!b->compatible (b, bfd_get_arch_info (abfd)))
warning (_("`%s': Shared library architecture %s is not compatible "
- "with target architecture %s."), found_pathname,
+ "with target architecture %s."), bfd_get_filename (abfd),
bfd_get_arch_info (abfd)->printable_name, b->printable_name);
return abfd;
return 0;
/* Leave bfd open, core_xfer_memory and "info files" need it. */
- so->abfd = gdb_bfd_ref (abfd);
+ so->abfd = abfd;
/* copy full path name into so_name, so that later symbol_file_add
can find it. */
{
volatile struct gdb_exception e;
+ flags |= current_inferior ()->symfile_flags;
+
TRY_CATCH (e, RETURN_MASK_ERROR)
{
struct section_addr_info *sap;
return 0;
}
+/* Return 1 if KNOWN->objfile is used by any other so_list object in the
+ SO_LIST_HEAD list. Return 0 otherwise. */
+
+static int
+solib_used (const struct so_list *const known)
+{
+ const struct so_list *pivot;
+
+ for (pivot = so_list_head; pivot != NULL; pivot = pivot->next)
+ if (pivot != known && pivot->objfile == known->objfile)
+ return 1;
+ return 0;
+}
+
/* Synchronize GDB's shared object list with inferior's.
Extract the list of currently loaded shared objects from the
unloaded before we remove it from GDB's tables. */
observer_notify_solib_unloaded (gdb);
+ VEC_safe_push (char_ptr, current_program_space->deleted_solibs,
+ xstrdup (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))
+ if (gdb->objfile && ! (gdb->objfile->flags & OBJF_USERLOADED)
+ && !solib_used (gdb))
free_objfile (gdb->objfile);
/* Some targets' section tables might be referring to
volatile struct gdb_exception e;
i->pspace = current_program_space;
+ VEC_safe_push (so_list_ptr, current_program_space->added_solibs, i);
TRY_CATCH (e, RETURN_MASK_ERROR)
{
{
found_pathname = xstrdup (bfd_get_filename (abfd));
make_cleanup (xfree, found_pathname);
- gdb_bfd_close_or_warn (abfd);
+ gdb_bfd_unref (abfd);
}
/* If this shared library is no longer associated with its previous
|| (found_pathname != NULL
&& filename_cmp (found_pathname, so->so_name) != 0))
{
- if (so->objfile && ! (so->objfile->flags & OBJF_USERLOADED))
+ if (so->objfile && ! (so->objfile->flags & OBJF_USERLOADED)
+ && !solib_used (so))
free_objfile (so->objfile);
remove_target_sections (so->abfd);
free_so_symbols (so);
return 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
+ function. Return NULL if symbol is not found. */
+
+CORE_ADDR
+gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
+ int (*match_sym) (asymbol *, void *),
+ void *data)
+{
+ long storage_needed = bfd_get_symtab_upper_bound (abfd);
+ CORE_ADDR symaddr = 0;
+
+ if (storage_needed > 0)
+ {
+ unsigned int i;
+
+ asymbol **symbol_table = (asymbol **) xmalloc (storage_needed);
+ struct cleanup *back_to = make_cleanup (xfree, symbol_table);
+ unsigned int number_of_symbols =
+ bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ asymbol *sym = *symbol_table++;
+
+ if (match_sym (sym, data))
+ {
+ /* BFD symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+
+ return symaddr;
+}
+
+/* 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
+ if symbol is not found. */
+
+static CORE_ADDR
+bfd_lookup_symbol_from_dyn_symtab (bfd *abfd,
+ int (*match_sym) (asymbol *, void *),
+ void *data)
+{
+ long storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+ CORE_ADDR symaddr = 0;
+
+ if (storage_needed > 0)
+ {
+ unsigned int i;
+ asymbol **symbol_table = (asymbol **) xmalloc (storage_needed);
+ struct cleanup *back_to = make_cleanup (xfree, symbol_table);
+ unsigned int number_of_symbols =
+ bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ asymbol *sym = *symbol_table++;
+
+ if (match_sym (sym, data))
+ {
+ /* BFD symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+ return symaddr;
+}
+
+/* Lookup the value for a specific symbol from symbol table and 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 function. Return NULL if symbol is not
+ found. */
+
+CORE_ADDR
+gdb_bfd_lookup_symbol (bfd *abfd,
+ int (*match_sym) (asymbol *, void *),
+ void *data)
+{
+ CORE_ADDR symaddr = gdb_bfd_lookup_symbol_from_symtab (abfd, match_sym, data);
+
+ /* On FreeBSD, the dynamic linker is stripped by default. So we'll
+ have to check the dynamic string table too. */
+ if (symaddr == 0)
+ symaddr = bfd_lookup_symbol_from_dyn_symtab (abfd, match_sym, data);
+
+ return symaddr;
+}
extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */