*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / objfiles.c
index 795d53b3f547326f7ea5ab506a875ef173eef6e5..109a66eb15a1cece4a317e6f44ca6018a99f2989 100644 (file)
@@ -50,6 +50,7 @@
 #include "addrmap.h"
 #include "arch-utils.h"
 #include "exec.h"
+#include "observer.h"
 
 /* Prototypes for local functions */
 
@@ -64,6 +65,11 @@ 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 */
 
+/* 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.  */
@@ -175,7 +181,7 @@ allocate_objfile (bfd *abfd, int flags)
      that any data that is reference is saved in the per-objfile data
      region. */
 
-  objfile->obfd = abfd;
+  objfile->obfd = gdb_bfd_ref (abfd);
   if (objfile->name != NULL)
     {
       xfree (objfile->name);
@@ -229,6 +235,8 @@ allocate_objfile (bfd *abfd, int flags)
   /* Save passed in flag bits. */
   objfile->flags |= flags;
 
+  objfiles_changed_p = 1;  /* Rebuild section map next time we need it.  */
+
   return (objfile);
 }
 
@@ -271,7 +279,26 @@ init_entry_point_info (struct objfile *objfile)
 CORE_ADDR
 entry_point_address (void)
 {
-  return symfile_objfile ? symfile_objfile->ei.entry_point : 0;
+  struct gdbarch *gdbarch;
+  CORE_ADDR entry_point;
+
+  if (symfile_objfile == NULL)
+    return 0;
+
+  gdbarch = get_objfile_arch (symfile_objfile);
+
+  entry_point = symfile_objfile->ei.entry_point;
+
+  /* Make certain that the address points at real code, and not a
+     function descriptor.  */
+  entry_point = gdbarch_convert_from_func_ptr_addr (gdbarch, entry_point,
+                                                   &current_target);
+
+  /* Remove any ISA markers, so that this matches entries in the
+     symbol table.  */
+  entry_point = gdbarch_addr_bits_remove (gdbarch, entry_point);
+
+  return entry_point;
 }
 
 /* Create the terminating entry of OBJFILE's minimal symbol table.
@@ -425,16 +452,7 @@ free_objfile (struct objfile *objfile)
   /* Discard any data modules have associated with the objfile.  */
   objfile_free_data (objfile);
 
-  /* We always close the bfd, unless the OBJF_KEEPBFD flag is set.  */
-
-  if (objfile->obfd != NULL && !(objfile->flags & OBJF_KEEPBFD))
-    {
-      char *name = bfd_get_filename (objfile->obfd);
-      if (!bfd_close (objfile->obfd))
-       warning (_("cannot close \"%s\": %s"),
-                name, bfd_errmsg (bfd_get_error ()));
-      xfree (name);
-    }
+  gdb_bfd_unref (objfile->obfd);
 
   /* Remove it from the chain of all objfiles. */
 
@@ -495,6 +513,7 @@ free_objfile (struct objfile *objfile)
   obstack_free (&objfile->objfile_obstack, 0);
   xfree (objfile);
   objfile = NULL;
+  objfiles_changed_p = 1;  /* Rebuild section map next time we need it.  */
 }
 
 static void
@@ -570,6 +589,10 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
        continue;
 
       bv = BLOCKVECTOR (s);
+      if (BLOCKVECTOR_MAP (bv))
+       addrmap_relocate (BLOCKVECTOR_MAP (bv),
+                         ANOFFSET (delta, s->block_line_section));
+
       for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
        {
          struct block *b;
@@ -579,9 +602,6 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
          b = BLOCKVECTOR_BLOCK (bv, i);
          BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
          BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
-          if (BLOCKVECTOR_MAP (bv))
-            addrmap_relocate (BLOCKVECTOR_MAP (bv),
-                              ANOFFSET (delta, s->block_line_section));
 
          ALL_BLOCK_SYMBOLS (b, iter, sym)
            {
@@ -646,12 +666,6 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
      to be out of order.  */
   msymbols_sort (objfile);
 
-  {
-    int i;
-    for (i = 0; i < objfile->num_sections; ++i)
-      (objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i);
-  }
-
   if (objfile->ei.entry_point != ~(CORE_ADDR) 0)
     {
       /* Relocate ei.entry_point with its section offset, use SECT_OFF_TEXT
@@ -664,6 +678,15 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
         objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
     }
 
+  {
+    int i;
+    for (i = 0; i < objfile->num_sections; ++i)
+      (objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i);
+  }
+
+  /* Rebuild section map next time we need it.  */
+  objfiles_changed_p = 1;
+
   /* Update the table in exec_ops, used to read memory.  */
   ALL_OBJFILE_OSECTIONS (objfile, s)
     {
@@ -756,23 +779,161 @@ have_minimal_symbols (void)
   return 0;
 }
 
+/* Qsort comparison function.  */
+
+static int
+qsort_cmp (const void *a, const void *b)
+{
+  const struct obj_section *sect1 = *(const struct obj_section **) a;
+  const struct obj_section *sect2 = *(const struct obj_section **) b;
+  const CORE_ADDR sect1_addr = obj_section_addr (sect1);
+  const CORE_ADDR sect2_addr = obj_section_addr (sect2);
+
+  if (sect1_addr < sect2_addr)
+    {
+      gdb_assert (obj_section_endaddr (sect1) <= sect2_addr);
+      return -1;
+    }
+  else if (sect1_addr > sect2_addr)
+    {
+      gdb_assert (sect1_addr >= obj_section_endaddr (sect2));
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Select "better" obj_section to keep.  We prefer the one that came from
+   the real object, rather than the one from separate debuginfo.
+   Most of the time the two sections are exactly identical, but with
+   prelinking the .rel.dyn section in the real object may have different
+   size.  */
+
+static struct obj_section *
+preferred_obj_section (struct obj_section *a, struct obj_section *b)
+{
+  gdb_assert (obj_section_addr (a) == obj_section_addr (b));
+  gdb_assert ((a->objfile->separate_debug_objfile == b->objfile)
+             || (b->objfile->separate_debug_objfile == a->objfile));
+  gdb_assert ((a->objfile->separate_debug_objfile_backlink == b->objfile)
+             || (b->objfile->separate_debug_objfile_backlink == a->objfile));
+
+  if (a->objfile->separate_debug_objfile != NULL)
+    return a;
+  return b;
+}
+
+/* Update PMAP, PMAP_SIZE with non-TLS sections from all objfiles.  */
+
+static void
+update_section_map (struct obj_section ***pmap, int *pmap_size)
+{
+  int map_size, i, j;
+  struct obj_section *s, **map;
+  struct objfile *objfile;
+
+  gdb_assert (objfiles_changed_p != 0);
+
+  map = *pmap;
+  xfree (map);
+
+#define insert_p(objf, sec) \
+  ((bfd_get_section_flags ((objf)->obfd, (sec)->the_bfd_section) \
+    & SEC_THREAD_LOCAL) == 0)
+
+  map_size = 0;
+  ALL_OBJSECTIONS (objfile, s)
+    if (insert_p (objfile, s))
+      map_size += 1;
+
+  map = xmalloc (map_size * sizeof (*map));
+
+  i = 0;
+  ALL_OBJSECTIONS (objfile, s)
+    if (insert_p (objfile, s))
+      map[i++] = s;
+
+#undef insert_p
+
+  qsort (map, map_size, sizeof (*map), qsort_cmp);
+
+  /* With separate debuginfo files, we may have up to two (almost)
+     identical copies of some obj_sections in the map.
+     Filter out duplicates.  */
+  for (i = 0, j = 0; i < map_size; ++i)
+    {
+      struct obj_section *sect1 = map[i];
+      struct obj_section *sect2 = (i + 1 < map_size) ? map[i + 1] : NULL;
+
+      if (sect2 == NULL
+         || obj_section_addr (sect1) != obj_section_addr (sect2))
+       map[j++] = sect1;
+      else
+       {
+         map[j++] = preferred_obj_section (sect1, sect2);
+         ++i;
+       }
+    }
+
+  if (j < map_size)
+    {
+      /* Some duplicates were eliminated.
+        The new size shouldn't be less than half of the original. */
+      gdb_assert (map_size / 2 <= j);
+      map_size = j;
+
+      map = xrealloc (map, map_size * sizeof (*map));  /* Trim excess space.  */
+    }
+  else
+    gdb_assert (j == map_size);
+
+  *pmap = map;
+  *pmap_size = map_size;
+}
+
+/* Bsearch comparison function. */
+
+static int
+bsearch_cmp (const void *key, const void *elt)
+{
+  const CORE_ADDR pc = *(CORE_ADDR *) key;
+  const struct obj_section *section = *(const struct obj_section **) elt;
+
+  if (pc < obj_section_addr (section))
+    return -1;
+  if (pc < obj_section_endaddr (section))
+    return 0;
+  return 1;
+}
+
 /* Returns a section whose range includes PC or NULL if none found.   */
 
 struct obj_section *
 find_pc_section (CORE_ADDR pc)
 {
-  struct obj_section *s;
-  struct objfile *objfile;
+  static struct obj_section **sections;
+  static int num_sections;
+
+  struct obj_section *s, **sp;
 
   /* Check for mapped overlay section first.  */
   s = find_pc_mapped_section (pc);
   if (s)
     return s;
 
-  ALL_OBJSECTIONS (objfile, s)
-    if (obj_section_addr (s) <= pc && pc < obj_section_endaddr (s))
-      return s;
+  if (objfiles_changed_p != 0)
+    {
+      update_section_map (&sections, &num_sections);
 
+      /* Don't need updates to section map until objfiles are added
+         or removed.  */
+      objfiles_changed_p = 0;
+    }
+
+  sp = (struct obj_section **) bsearch (&pc, sections, num_sections,
+                                       sizeof (*sections), bsearch_cmp);
+  if (sp != NULL)
+    return *sp;
   return NULL;
 }
 
@@ -891,3 +1052,61 @@ objfile_data (struct objfile *objfile, const struct objfile_data *data)
   gdb_assert (data->index < objfile->num_data);
   return objfile->data[data->index];
 }
+
+/* Set objfiles_changed_p so section map will be rebuilt next time it
+   is used.  Called by reread_symbols.  */
+
+void
+objfiles_changed (void)
+{
+  objfiles_changed_p = 1;  /* Rebuild section map next time we need it.  */
+}
+
+/* Add reference to ABFD.  Returns ABFD.  */
+struct bfd *
+gdb_bfd_ref (struct bfd *abfd)
+{
+  int *p_refcount = bfd_usrdata (abfd);
+
+  if (p_refcount != NULL)
+    {
+      *p_refcount += 1;
+      return abfd;
+    }
+
+  p_refcount = xmalloc (sizeof (*p_refcount));
+  *p_refcount = 1;
+  bfd_usrdata (abfd) = p_refcount;
+
+  return abfd;
+}
+
+/* Unreference and possibly close ABFD.  */
+void
+gdb_bfd_unref (struct bfd *abfd)
+{
+  int *p_refcount;
+  char *name;
+
+  if (abfd == NULL)
+    return;
+
+  p_refcount = bfd_usrdata (abfd);
+
+  /* Valid range for p_refcount: a pointer to int counter, which has a
+     value of 1 (single owner) or 2 (shared).  */
+  gdb_assert (*p_refcount == 1 || *p_refcount == 2);
+
+  *p_refcount -= 1;
+  if (*p_refcount > 0)
+    return;
+
+  xfree (p_refcount);
+  bfd_usrdata (abfd) = NULL;  /* Paranoia.  */
+
+  name = bfd_get_filename (abfd);
+  if (!bfd_close (abfd))
+    warning (_("cannot close \"%s\": %s"),
+            name, bfd_errmsg (bfd_get_error ()));
+  xfree (name);
+}
This page took 0.051053 seconds and 4 git commands to generate.