/* GDB routines for manipulating objfiles.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Cygnus Support, using pieces from other GDB modules.
/* Externally visible variables that are owned by this module.
See declarations in objfile.h for more info. */
-struct objfile *object_files; /* Linked list of all objfiles */
struct objfile *current_objfile; /* For symbol file being read in */
-struct objfile *symfile_objfile; /* Main symbol table loaded from */
struct objfile *rt_common_objfile; /* For runtime common symbols */
+struct objfile_pspace_info
+{
+ int objfiles_changed_p;
+ struct obj_section **sections;
+ int num_sections;
+};
+
+/* Per-program-space data key. */
+static const struct program_space_data *objfiles_pspace_data;
+
+static void
+objfiles_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+ struct objfile_pspace_info *info;
+
+ info = program_space_data (pspace, objfiles_pspace_data);
+ if (info != NULL)
+ {
+ xfree (info->sections);
+ xfree (info);
+ }
+}
+
+/* Get the current svr4 data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct objfile_pspace_info *
+get_objfile_pspace_data (struct program_space *pspace)
+{
+ struct objfile_pspace_info *info;
+
+ info = program_space_data (pspace, objfiles_pspace_data);
+ if (info == NULL)
+ {
+ info = XZALLOC (struct objfile_pspace_info);
+ set_program_space_data (pspace, objfiles_pspace_data, info);
+ }
+
+ return info;
+}
+
/* Records whether any objfiles appeared or disappeared since we last updated
address to obj section map. */
-static int objfiles_changed_p;
-
/* Locate all mappable sections of a BFD file.
objfile_p_char is a char * to get it through
bfd_map_over_sections; we cast it back to its proper type. */
struct objfile *
allocate_objfile (bfd *abfd, int flags)
{
- struct objfile *objfile = NULL;
- struct objfile *last_one = NULL;
-
- /* If we don't support mapped symbol files, didn't ask for the file to be
- mapped, or failed to open the mapped file for some reason, then revert
- back to an unmapped objfile. */
+ struct objfile *objfile;
- if (objfile == NULL)
- {
- objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
- memset (objfile, 0, sizeof (struct objfile));
- objfile->psymbol_cache = bcache_xmalloc ();
- objfile->macro_cache = bcache_xmalloc ();
- /* We could use obstack_specify_allocation here instead, but
- gdb_obstack.h specifies the alloc/dealloc functions. */
- obstack_init (&objfile->objfile_obstack);
- terminate_minimal_symbol_table (objfile);
- }
+ objfile = (struct objfile *) xzalloc (sizeof (struct objfile));
+ objfile->psymbol_cache = bcache_xmalloc ();
+ objfile->macro_cache = bcache_xmalloc ();
+ objfile->filename_cache = bcache_xmalloc ();
+ /* We could use obstack_specify_allocation here instead, but
+ gdb_obstack.h specifies the alloc/dealloc functions. */
+ obstack_init (&objfile->objfile_obstack);
+ terminate_minimal_symbol_table (objfile);
objfile_alloc_data (objfile);
objfile->name = xstrdup ("<<anonymous objfile>>");
}
+ objfile->pspace = current_program_space;
+
/* Initialize the section indexes for this objfile, so that we can
later detect if they are used w/o being properly assigned to. */
object_files = objfile;
else
{
+ struct objfile *last_one;
+
for (last_one = object_files;
last_one->next;
last_one = last_one->next);
/* Save passed in flag bits. */
objfile->flags |= flags;
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
+ /* Rebuild section map next time we need it. */
+ get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
- return (objfile);
+ return objfile;
}
/* Retrieve the gdbarch associated with OBJFILE. */
/* Executable file -- record its entry point so we'll recognize
the startup file because it contains the entry point. */
objfile->ei.entry_point = bfd_get_start_address (objfile->obfd);
+ objfile->ei.entry_point_p = 1;
}
else if (bfd_get_file_flags (objfile->obfd) & DYNAMIC
&& bfd_get_start_address (objfile->obfd) != 0)
- /* Some shared libraries may have entry points set and be
- runnable. There's no clear way to indicate this, so just check
- for values other than zero. */
- objfile->ei.entry_point = bfd_get_start_address (objfile->obfd);
+ {
+ /* Some shared libraries may have entry points set and be
+ runnable. There's no clear way to indicate this, so just check
+ for values other than zero. */
+ objfile->ei.entry_point = bfd_get_start_address (objfile->obfd);
+ objfile->ei.entry_point_p = 1;
+ }
else
{
/* Examination of non-executable.o files. Short-circuit this stuff. */
- objfile->ei.entry_point = INVALID_ENTRY_POINT;
+ objfile->ei.entry_point_p = 0;
}
}
-/* Get current entry point address. */
+/* If there is a valid and known entry point, function fills *ENTRY_P with it
+ and returns non-zero; otherwise it returns zero. */
-CORE_ADDR
-entry_point_address (void)
+int
+entry_point_address_query (CORE_ADDR *entry_p)
{
struct gdbarch *gdbarch;
CORE_ADDR entry_point;
- if (symfile_objfile == NULL)
+ if (symfile_objfile == NULL || !symfile_objfile->ei.entry_point_p)
return 0;
gdbarch = get_objfile_arch (symfile_objfile);
symbol table. */
entry_point = gdbarch_addr_bits_remove (gdbarch, entry_point);
- return entry_point;
+ *entry_p = entry_point;
+ return 1;
+}
+
+/* Get current entry point address. Call error if it is not known. */
+
+CORE_ADDR
+entry_point_address (void)
+{
+ CORE_ADDR retval;
+
+ if (!entry_point_address_query (&retval))
+ error (_("Entry point address is not known."));
+
+ return retval;
}
/* Create the terminating entry of OBJFILE's minimal symbol table.
}
}
+/* Iterator on PARENT and every separate debug objfile of PARENT.
+ The usage pattern is:
+ for (objfile = parent;
+ objfile;
+ objfile = objfile_separate_debug_iterate (parent, objfile))
+ ...
+*/
+
+struct objfile *
+objfile_separate_debug_iterate (const struct objfile *parent,
+ const struct objfile *objfile)
+{
+ struct objfile *res;
+
+ res = objfile->separate_debug_objfile;
+ if (res)
+ return res;
+
+ res = objfile->separate_debug_objfile_link;
+ if (res)
+ return res;
+
+ /* Common case where there is no separate debug objfile. */
+ if (objfile == parent)
+ return NULL;
+
+ for (res = objfile->separate_debug_objfile_backlink;
+ res != parent;
+ res = res->separate_debug_objfile_backlink)
+ {
+ gdb_assert (res != NULL);
+ if (res->separate_debug_objfile_link)
+ return res->separate_debug_objfile_link;
+ }
+ return NULL;
+}
/* Put one object file before a specified on in the global list.
This can be used to make sure an object file is destroyed before
_("unlink_objfile: objfile already unlinked"));
}
+/* Add OBJFILE as a separate debug objfile of PARENT. */
+
+void
+add_separate_debug_objfile (struct objfile *objfile, struct objfile *parent)
+{
+ gdb_assert (objfile && parent);
+
+ /* Must not be already in a list. */
+ gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
+ gdb_assert (objfile->separate_debug_objfile_link == NULL);
+
+ objfile->separate_debug_objfile_backlink = parent;
+ objfile->separate_debug_objfile_link = parent->separate_debug_objfile;
+ parent->separate_debug_objfile = objfile;
+
+ /* Put the separate debug object before the normal one, this is so that
+ usage of the ALL_OBJFILES_SAFE macro will stay safe. */
+ put_objfile_before (objfile, parent);
+}
+
+/* Free all separate debug objfile of OBJFILE, but don't free OBJFILE
+ itself. */
+
+void
+free_objfile_separate_debug (struct objfile *objfile)
+{
+ struct objfile *child;
+
+ for (child = objfile->separate_debug_objfile; child;)
+ {
+ struct objfile *next_child = child->separate_debug_objfile_link;
+ free_objfile (child);
+ child = next_child;
+ }
+}
/* Destroy an objfile and all the symtabs and psymtabs under it. Note
that as much as possible is allocated on the objfile_obstack
void
free_objfile (struct objfile *objfile)
{
- if (objfile->separate_debug_objfile)
- {
- free_objfile (objfile->separate_debug_objfile);
- }
-
+ /* Free all separate debug objfiles. */
+ free_objfile_separate_debug (objfile);
+
if (objfile->separate_debug_objfile_backlink)
{
/* We freed the separate debug file, make sure the base objfile
doesn't reference it. */
- objfile->separate_debug_objfile_backlink->separate_debug_objfile = NULL;
+ struct objfile *child;
+
+ child = objfile->separate_debug_objfile_backlink->separate_debug_objfile;
+
+ if (child == objfile)
+ {
+ /* OBJFILE is the first child. */
+ objfile->separate_debug_objfile_backlink->separate_debug_objfile =
+ objfile->separate_debug_objfile_link;
+ }
+ else
+ {
+ /* Find OBJFILE in the list. */
+ while (1)
+ {
+ if (child->separate_debug_objfile_link == objfile)
+ {
+ child->separate_debug_objfile_link =
+ objfile->separate_debug_objfile_link;
+ break;
+ }
+ child = child->separate_debug_objfile_link;
+ gdb_assert (child);
+ }
+ }
}
/* Remove any references to this objfile in the global value
/* Free the obstacks for non-reusable objfiles */
bcache_xfree (objfile->psymbol_cache);
bcache_xfree (objfile->macro_cache);
+ bcache_xfree (objfile->filename_cache);
if (objfile->demangled_names_hash)
htab_delete (objfile->demangled_names_hash);
obstack_free (&objfile->objfile_obstack, 0);
+
+ /* Rebuild section map next time we need it. */
+ get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+
xfree (objfile);
- objfile = NULL;
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
}
static void
}
\f
/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
- entries in new_offsets. */
-void
-objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
+ entries in new_offsets. SEPARATE_DEBUG_OBJFILE is not touched here.
+ Return non-zero iff any change happened. */
+
+static int
+objfile_relocate1 (struct objfile *objfile, struct section_offsets *new_offsets)
{
struct obj_section *s;
struct section_offsets *delta =
something_changed = 1;
}
if (!something_changed)
- return;
+ return 0;
}
/* OK, get all the symtabs. */
}
}
+ if (objfile->psymtabs_addrmap)
+ addrmap_relocate (objfile->psymtabs_addrmap,
+ ANOFFSET (delta, SECT_OFF_TEXT (objfile)));
+
{
struct partial_symtab *p;
to be out of order. */
msymbols_sort (objfile);
- if (objfile->ei.entry_point != ~(CORE_ADDR) 0)
+ if (objfile->ei.entry_point_p)
{
/* Relocate ei.entry_point with its section offset, use SECT_OFF_TEXT
only as a fallback. */
}
/* Rebuild section map next time we need it. */
- objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
obj_section_addr (s));
}
+ /* Data changed. */
+ return 1;
+}
+
+/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
+ entries in new_offsets. Process also OBJFILE's SEPARATE_DEBUG_OBJFILEs.
+
+ The number and ordering of sections does differ between the two objfiles.
+ Only their names match. Also the file offsets will differ (objfile being
+ possibly prelinked but separate_debug_objfile is probably not prelinked) but
+ the in-memory absolute address as specified by NEW_OFFSETS must match both
+ files. */
+
+void
+objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
+{
+ struct objfile *debug_objfile;
+ int changed = 0;
+
+ changed |= objfile_relocate1 (objfile, new_offsets);
+
+ for (debug_objfile = objfile->separate_debug_objfile;
+ debug_objfile;
+ debug_objfile = objfile_separate_debug_iterate (objfile, debug_objfile))
+ {
+ struct section_addr_info *objfile_addrs;
+ struct section_offsets *new_debug_offsets;
+ int new_debug_num_sections;
+ struct cleanup *my_cleanups;
+
+ objfile_addrs = build_section_addr_info_from_objfile (objfile);
+ my_cleanups = make_cleanup (xfree, objfile_addrs);
+
+ /* Here OBJFILE_ADDRS contain the correct absolute addresses, the
+ relative ones must be already created according to debug_objfile. */
+
+ addr_info_make_relative (objfile_addrs, debug_objfile->obfd);
+
+ gdb_assert (debug_objfile->num_sections
+ == bfd_count_sections (debug_objfile->obfd));
+ new_debug_offsets = xmalloc (SIZEOF_N_SECTION_OFFSETS
+ (debug_objfile->num_sections));
+ make_cleanup (xfree, new_debug_offsets);
+ relative_addr_info_to_section_offsets (new_debug_offsets,
+ debug_objfile->num_sections,
+ objfile_addrs);
+
+ changed |= objfile_relocate1 (debug_objfile, new_debug_offsets);
+
+ do_cleanups (my_cleanups);
+ }
+
/* Relocate breakpoints as necessary, after things are relocated. */
- breakpoint_re_set ();
+ if (changed)
+ breakpoint_re_set ();
}
\f
/* Return non-zero if OBJFILE has partial symbols. */
return objfile->symtabs != NULL;
}
+/* Return non-zero if OBJFILE has full or partial symbols, either directly
+ or through a separate debug file. */
+
+int
+objfile_has_symbols (struct objfile *objfile)
+{
+ struct objfile *o;
+
+ for (o = objfile; o; o = objfile_separate_debug_iterate (objfile, o))
+ if (objfile_has_partial_symbols (o) || objfile_has_full_symbols (o))
+ return 1;
+ return 0;
+}
+
+
/* Many places in gdb want to test just to see if we have any partial
symbols available. This function returns zero if none are currently
available, nonzero otherwise. */
TLS, overlay and overlapping sections. */
static void
-update_section_map (struct obj_section ***pmap, int *pmap_size)
+update_section_map (struct program_space *pspace,
+ struct obj_section ***pmap, int *pmap_size)
{
int alloc_size, map_size, i;
struct obj_section *s, **map;
struct objfile *objfile;
- gdb_assert (objfiles_changed_p != 0);
+ gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
map = *pmap;
xfree (map);
alloc_size = 0;
- ALL_OBJSECTIONS (objfile, s)
- if (insert_section_p (objfile->obfd, s->the_bfd_section))
- alloc_size += 1;
+ ALL_PSPACE_OBJFILES (pspace, objfile)
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ if (insert_section_p (objfile->obfd, s->the_bfd_section))
+ alloc_size += 1;
+
+ /* This happens on detach/attach (e.g. in gdb.base/attach.exp). */
+ if (alloc_size == 0)
+ {
+ *pmap = NULL;
+ *pmap_size = 0;
+ return;
+ }
map = xmalloc (alloc_size * sizeof (*map));
i = 0;
- ALL_OBJSECTIONS (objfile, s)
- if (insert_section_p (objfile->obfd, s->the_bfd_section))
- map[i++] = s;
+ ALL_PSPACE_OBJFILES (pspace, objfile)
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ if (insert_section_p (objfile->obfd, s->the_bfd_section))
+ map[i++] = s;
qsort (map, alloc_size, sizeof (*map), qsort_cmp);
map_size = filter_debuginfo_sections(map, alloc_size);
struct obj_section *
find_pc_section (CORE_ADDR pc)
{
- static struct obj_section **sections;
- static int num_sections;
-
+ struct objfile_pspace_info *pspace_info;
struct obj_section *s, **sp;
/* Check for mapped overlay section first. */
if (s)
return s;
- if (objfiles_changed_p != 0)
+ pspace_info = get_objfile_pspace_data (current_program_space);
+ if (pspace_info->objfiles_changed_p != 0)
{
- update_section_map (§ions, &num_sections);
+ update_section_map (current_program_space,
+ &pspace_info->sections,
+ &pspace_info->num_sections);
- /* Don't need updates to section map until objfiles are added
- or removed. */
- objfiles_changed_p = 0;
+ /* Don't need updates to section map until objfiles are added,
+ removed or relocated. */
+ pspace_info->objfiles_changed_p = 0;
}
- sp = (struct obj_section **) bsearch (&pc, sections, num_sections,
- sizeof (*sections), bsearch_cmp);
+ /* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
+ bsearch be non-NULL. */
+ if (pspace_info->sections == NULL)
+ {
+ gdb_assert (pspace_info->num_sections == 0);
+ return NULL;
+ }
+
+ sp = (struct obj_section **) bsearch (&pc,
+ pspace_info->sections,
+ pspace_info->num_sections,
+ sizeof (*pspace_info->sections),
+ bsearch_cmp);
if (sp != NULL)
return *sp;
return NULL;
void
objfiles_changed (void)
{
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
+ /* Rebuild section map next time we need it. */
+ get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1;
}
/* Add reference to ABFD. Returns ABFD. */
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_objfiles;
+
+void
+_initialize_objfiles (void)
+{
+ objfiles_pspace_data
+ = register_program_space_data_with_cleanup (objfiles_pspace_data_cleanup);
+}