]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
* dwarf2read.c: Include "splay-tree.h".
authorDaniel Jacobowitz <drow@false.org>
Sat, 21 Feb 2004 20:17:22 +0000 (20:17 +0000)
committerDaniel Jacobowitz <drow@false.org>
Sat, 21 Feb 2004 20:17:22 +0000 (20:17 +0000)
(struct dwarf2_cu): Add splay tree for partial DIEs.
(struct partial_die_info): Move after struct attribute.
Add has_specification, spec_attr, die_parent, die_child,
and die_sibling fields.
(load_partial_dies): New function.
(load_partial_die): New function, broken out from read_partial_die.
Correct setting of part_die->offset.  Save any specification
attributes for later.
(read_partial_die): Look up DIEs in the splay tree.
(dwarf2_build_psymtabs_hard): Initialize partial_dies.  Call
load_partial_die to read in the compilation unit DIE.  Call
load_partial_dies.  Free the splay tree after use.
(scan_partial_symbols): Follow the die_sibling chain.
(add_partial_structure): Use die_child and die_sibling instead of
read_partial_die and locate_pdi_sibling.
(add_partial_enumeration): Likewise.
(locate_pdi_sibling): Use load_partial_die instead of
read_partial_die.
(is_type_tag): New function.

* Makefile.in (dwarf2read.o): Update dependencies.

gdb/ChangeLog.intercu [new file with mode: 0644]
gdb/Makefile.in
gdb/dwarf2read.c

diff --git a/gdb/ChangeLog.intercu b/gdb/ChangeLog.intercu
new file mode 100644 (file)
index 0000000..d126553
--- /dev/null
@@ -0,0 +1,24 @@
+2004-02-21  Daniel Jacobowitz  <drow@mvista.com>
+
+       * dwarf2read.c: Include "splay-tree.h".
+       (struct dwarf2_cu): Add splay tree for partial DIEs.
+       (struct partial_die_info): Move after struct attribute.
+       Add has_specification, spec_attr, die_parent, die_child,
+       and die_sibling fields.
+       (load_partial_dies): New function.
+       (load_partial_die): New function, broken out from read_partial_die.
+       Correct setting of part_die->offset.  Save any specification
+       attributes for later.
+       (read_partial_die): Look up DIEs in the splay tree.
+       (dwarf2_build_psymtabs_hard): Initialize partial_dies.  Call
+       load_partial_die to read in the compilation unit DIE.  Call
+       load_partial_dies.  Free the splay tree after use.
+       (scan_partial_symbols): Follow the die_sibling chain.
+       (add_partial_structure): Use die_child and die_sibling instead of
+       read_partial_die and locate_pdi_sibling.
+       (add_partial_enumeration): Likewise.
+       (locate_pdi_sibling): Use load_partial_die instead of
+       read_partial_die.
+       (is_type_tag): New function.
+
+       * Makefile.in (dwarf2read.o): Update dependencies.
index 7e179a83d5e7b168df29b8d830089640c50d31cb..2e444a6e8f388f822f2a96773e42c314fb98ac4d 100644 (file)
@@ -1706,7 +1706,8 @@ dwarf2read.o: dwarf2read.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
        $(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) $(demangle_h) \
        $(expression_h) $(filenames_h) $(macrotab_h) $(language_h) \
        $(complaints_h) $(bcache_h) $(dwarf2expr_h) $(dwarf2loc_h) \
-       $(cp_support_h) $(gdb_string_h) $(gdb_assert_h)
+       $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \
+       $(splay_tree_h)
 dwarfread.o: dwarfread.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(objfiles_h) \
        $(elf_dwarf_h) $(buildsym_h) $(demangle_h) $(expression_h) \
        $(language_h) $(complaints_h) $(gdb_string_h)
index 46c3cf4ed7e28df2c43dde5c75ed72b7dc18ff92..10e41a5bcfc27866aefbd76a0a9b6de6476ad55e 100644 (file)
@@ -44,6 +44,7 @@
 #include "dwarf2expr.h"
 #include "dwarf2loc.h"
 #include "cp-support.h"
+#include "splay-tree.h"
 
 #include <fcntl.h>
 #include "gdb_string.h"
@@ -258,6 +259,8 @@ struct dwarf2_cu
      FT_NUM_MEMBERS compile time constant, which is the number of predefined
      fundamental types gdb knows how to construct.  */
   struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */
+
+  splay_tree partial_dies;
 };
 
 /* The line number information for a compilation unit (found in the
@@ -304,26 +307,6 @@ struct line_header
   char *statement_program_start, *statement_program_end;
 };
 
-/* When we construct a partial symbol table entry we only
-   need this much information. */
-struct partial_die_info
-  {
-    enum dwarf_tag tag;
-    unsigned char has_children;
-    unsigned char is_external;
-    unsigned char is_declaration;
-    unsigned char has_type;
-    unsigned int offset;
-    unsigned int abbrev;
-    char *name;
-    int has_pc_info;
-    CORE_ADDR lowpc;
-    CORE_ADDR highpc;
-    struct dwarf_block *locdesc;
-    unsigned int language;
-    char *sibling;
-  };
-
 /* This data structure holds the information of an abbrev. */
 struct abbrev_info
   {
@@ -402,6 +385,29 @@ struct dwarf_block
     char *data;
   };
 
+/* When we construct a partial symbol table entry we only
+   need this much information. */
+struct partial_die_info
+  {
+    enum dwarf_tag tag;
+    unsigned char has_children;
+    unsigned char is_external;
+    unsigned char is_declaration;
+    unsigned char has_type;
+    unsigned char has_specification;
+    unsigned int offset;
+    unsigned int abbrev;
+    char *name;
+    int has_pc_info;
+    CORE_ADDR lowpc;
+    CORE_ADDR highpc;
+    struct dwarf_block *locdesc;
+    unsigned int language;
+    char *sibling;
+    struct attribute spec_attr;
+    struct partial_die_info *die_parent, *die_child, *die_sibling;
+  };
+
 #ifndef ATTR_ALLOC_CHUNK
 #define ATTR_ALLOC_CHUNK 4
 #endif
@@ -678,9 +684,14 @@ static void dwarf2_empty_abbrev_table (void *);
 static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int,
                                                 struct dwarf2_cu *);
 
-static char *read_partial_die (struct partial_die_info *,
+static void load_partial_dies (bfd *, char *, struct dwarf2_cu *);
+
+static char *load_partial_die (struct partial_die_info *,
                               bfd *, char *, struct dwarf2_cu *);
 
+static void read_partial_die (struct partial_die_info *,
+                             bfd *, char *, struct dwarf2_cu *);
+
 static char *read_full_die (struct die_info **, bfd *, char *,
                            struct dwarf2_cu *, int *);
 
@@ -1236,12 +1247,14 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
 
       cu.list_in_scope = &file_symbols;
 
+      cu.partial_dies = NULL;
+
       /* Read the abbrevs for this compilation unit into a table */
       dwarf2_read_abbrevs (abfd, &cu);
       make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs);
 
       /* Read the compilation unit die */
-      info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr,
+      info_ptr = load_partial_die (&comp_unit_die, abfd, info_ptr,
                                   &cu);
 
       /* Set the language we're debugging */
@@ -1283,9 +1296,13 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
          lowpc = ((CORE_ADDR) -1);
          highpc = ((CORE_ADDR) 0);
 
+         load_partial_dies (abfd, info_ptr, &cu);
+
          info_ptr = scan_partial_symbols (info_ptr, &lowpc, &highpc,
                                           &cu, NULL);
 
+         splay_tree_delete (cu.partial_dies);
+
          /* If we didn't find a lowpc, set it to highpc to avoid
             complaints from `maint check'.  */
          if (lowpc == ((CORE_ADDR) -1))
@@ -1333,19 +1350,19 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
 {
   struct objfile *objfile = cu->objfile;
   bfd *abfd = objfile->obfd;
-  struct partial_die_info pdi;
+  struct partial_die_info pdi, *pdi_p;
 
   /* Now, march along the PDI's, descending into ones which have
      interesting children but skipping the children of the other ones,
      until we reach the end of the compilation unit.  */
 
-  while (1)
-    {
-      /* This flag tells whether or not info_ptr has gotten updated
-        inside the loop.  */
-      int info_ptr_updated = 0;
+  read_partial_die (&pdi, abfd, info_ptr, cu);
+  pdi_p = &pdi;
 
-      info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
+  while (pdi_p != NULL)
+    {
+      /* FIXME */
+      read_partial_die (&pdi, abfd, pdi_p->offset + dwarf_info_buffer, cu);
 
       /* Anonymous namespaces have no name but have interesting
         children, so we need to look at them.  Ditto for anonymous
@@ -1387,7 +1404,6 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
                {
                  info_ptr = add_partial_structure (&pdi, info_ptr, cu,
                                                    namespace);
-                 info_ptr_updated = 1;
                }
              break;
            case DW_TAG_enumeration_type:
@@ -1395,7 +1411,6 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
                {
                  info_ptr = add_partial_enumeration (&pdi, info_ptr, cu,
                                                      namespace);
-                 info_ptr_updated = 1;
                }
              break;
            case DW_TAG_base_type:
@@ -1412,13 +1427,13 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
                namespace = "";
              info_ptr = add_partial_namespace (&pdi, info_ptr, lowpc, highpc,
                                                cu, namespace);
-             info_ptr_updated = 1;
              break;
            default:
              break;
            }
        }
 
+      /* FIXME unnecessary now */
       if (pdi.tag == 0)
        break;
 
@@ -1430,8 +1445,13 @@ scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc,
         only pdi.tag but also whether or not pdi.name is NULL) that
         this seems like the easiest way to handle the issue.  */
 
+      /*
       if (!info_ptr_updated)
        info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu);
+      */
+      pdi_p = pdi_p->die_sibling;
+      // if (pdi_p)
+      // fprintf_unfiltered (gdb_stderr, "scan: Advancing to DIE %x\n", pdi_p->offset);
     }
 
   return info_ptr;
@@ -1690,35 +1710,27 @@ add_partial_structure (struct partial_die_info *struct_pdi, char *info_ptr,
          places other than the tree structure of dies if there's any
          chance that a DW_AT_specification is involved. :-( */
 
-      char *next_child = info_ptr;
+      struct partial_die_info *child_pdi = struct_pdi->die_child;
 
-      while (1)
+      while (child_pdi != NULL)
        {
-         struct partial_die_info child_pdi;
-
-         next_child = read_partial_die (&child_pdi, abfd, next_child,
-                                        cu);
-         if (!child_pdi.tag)
-           break;
-         if (child_pdi.tag == DW_TAG_subprogram)
+         if (child_pdi->tag == DW_TAG_subprogram)
            {
-             actual_class_name = class_name_from_physname (child_pdi.name);
+             actual_class_name = class_name_from_physname (child_pdi->name);
              if (actual_class_name != NULL)
                struct_pdi->name = actual_class_name;
              break;
            }
-         else
-           {
-             next_child = locate_pdi_sibling (&child_pdi, next_child,
-                                              abfd, cu);
-           }
+
+         child_pdi = child_pdi->die_sibling;
        }
     }
 
   add_partial_symbol (struct_pdi, cu, namespace);
   xfree (actual_class_name);
 
-  return locate_pdi_sibling (struct_pdi, info_ptr, abfd, cu);
+  return (struct_pdi->offset + dwarf_info_buffer);
+  /* return locate_pdi_sibling (struct_pdi, info_ptr, abfd, cu); */
 }
 
 /* Read a partial die corresponding to an enumeration type.  */
@@ -1729,20 +1741,19 @@ add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr,
 {
   struct objfile *objfile = cu->objfile;
   bfd *abfd = objfile->obfd;
-  struct partial_die_info pdi;
+  struct partial_die_info *pdi_p;
 
   if (enum_pdi->name != NULL)
     add_partial_symbol (enum_pdi, cu, namespace);
   
-  while (1)
+  pdi_p = enum_pdi->die_child;
+  while (pdi_p)
     {
-      info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
-      if (pdi.tag == 0)
-       break;
-      if (pdi.tag != DW_TAG_enumerator || pdi.name == NULL)
+      if (pdi_p->tag != DW_TAG_enumerator || pdi_p->name == NULL)
        complaint (&symfile_complaints, "malformed enumerator DIE ignored");
       else
-       add_partial_symbol (&pdi, cu, namespace);
+       add_partial_symbol (pdi_p, cu, namespace);
+      pdi_p = pdi_p->die_sibling;
     }
 
   return info_ptr;
@@ -1772,8 +1783,8 @@ locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr,
   while (1)
     {
       struct partial_die_info pdi;
-      
-      info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu);
+
+      info_ptr = load_partial_die (&pdi, abfd, info_ptr, cu);
 
       if (pdi.tag == 0)
        return info_ptr;
@@ -4282,21 +4293,166 @@ dwarf2_lookup_abbrev (unsigned int number, struct dwarf2_cu *cu)
   return NULL;
 }
 
+/* Returns nonzero if TAG represents a type.  */
+
+static int
+is_type_tag (int tag)
+{ 
+  switch (tag)
+    {
+    case DW_TAG_array_type:
+    case DW_TAG_class_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_string_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_union_type:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_set_type:
+    case DW_TAG_subrange_type:
+    case DW_TAG_base_type:
+    case DW_TAG_const_type:
+    case DW_TAG_file_type:
+    case DW_TAG_packed_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_typedef:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+#if 0
+/* Returns non-zero if PART_DIE might be referenced via DW_AT_specification
+   or DW_AT_abstract_origin.  */
+
+static int
+maybe_specification_partial_die (struct partial_die_info *part_die)
+{
+  if (is_type_tag (part_die->tag))
+    return 1;
+
+  /* FIXME: How does DW_AT_abstract_origin play into this?  Is it
+     possible to reference abstract origin in another CU (probably);
+     will they all be declarations (probably not?).
+
+     Understand this issue before posting patch.  */
+  if (part_die->is_declaration && !part_die->has_specification)
+    return 1;
+
+  /* FIXME: That's all GCC checks (is_symbol_die); but GCC can emit
+     DW_AT_specification for non-declarations.  I think they ought to
+     be tagged as declarations... */
+
+  return 0;
+}
+#endif
+
+/* Load all DIEs that are interesting for partial symbols into memory.  */
+
+static void
+load_partial_dies (bfd *abfd, char *info_ptr, struct dwarf2_cu *cu)
+{
+  struct partial_die_info *part_die;
+  struct partial_die_info *parent_die, *last_die;
+
+  /* FIXME: Obviously we need a nesting level passed in for incremental use.  */
+  int nesting_level = 1;
+
+  /* But if we do incremental what do we do with this??? */
+  parent_die = NULL;
+  last_die = NULL;
+
+  /* FIXME: All sorts of memory management issues.  */
+  cu->partial_dies = splay_tree_new (splay_tree_compare_ints, NULL,
+                                    (splay_tree_delete_value_fn) xfree);
+  part_die = xmalloc (sizeof (struct partial_die_info));
+
+  while (1)
+    {
+      //      fprintf_unfiltered (gdb_stderr, "Loading DIE %x\n", info_ptr - dwarf_info_buffer);
+      info_ptr = load_partial_die (part_die, abfd, info_ptr, cu);
+
+      if (part_die->tag == 0)
+       {
+         if (--nesting_level == 0)
+           {
+             xfree (part_die);
+             return;
+           }
+         last_die = parent_die;
+         parent_die = parent_die->die_parent;
+         continue;
+       }
+
+      /* Check whether this DIE is interesting enough to save.  */
+      if (!is_type_tag (part_die->tag)
+         && part_die->tag != DW_TAG_enumerator
+         && part_die->tag != DW_TAG_subprogram
+         && part_die->tag != DW_TAG_variable
+         && part_die->tag != DW_TAG_namespace)
+       {
+         /* Otherwise we skip to the next sibling, if any.  */
+         info_ptr = locate_pdi_sibling (part_die, info_ptr, abfd, cu);
+         continue;
+       }
+
+      /* We'll save this DIE so link it in.  */
+      part_die->die_parent = parent_die;
+      part_die->die_sibling = NULL;
+      part_die->die_child = NULL;
+
+      if (last_die && last_die == parent_die)
+       last_die->die_child = part_die;
+      else if (last_die)
+       last_die->die_sibling = part_die;
+
+      last_die = part_die;
+
+      //      fprintf_unfiltered (gdb_stderr, "Inserting DIE %x\n", part_die->offset);
+      splay_tree_insert (cu->partial_dies, part_die->offset,
+                        (splay_tree_value) part_die);
+      part_die = xmalloc (sizeof (struct partial_die_info));
+
+      /* For some DIEs we want to follow their children (if any).  */
+      if (last_die->tag == DW_TAG_namespace
+         || last_die->tag == DW_TAG_enumeration_type
+         || last_die->tag == DW_TAG_class_type
+         || last_die->tag == DW_TAG_structure_type)
+       {
+         if (last_die->has_children)
+           {
+             nesting_level++;
+             parent_die = last_die;
+             continue;
+           }
+       }
+
+      /* Otherwise we skip to the next sibling, if any.  */
+      info_ptr = locate_pdi_sibling (last_die, info_ptr, abfd, cu);
+
+      /* Back to the top, do it again.  */
+    }
+}
+
 /* Read a minimal amount of information into the minimal die structure.  */
 
 static char *
-read_partial_die (struct partial_die_info *part_die, bfd *abfd,
+load_partial_die (struct partial_die_info *part_die, bfd *abfd,
                  char *info_ptr, struct dwarf2_cu *cu)
 {
   unsigned int abbrev_number, bytes_read, i;
   struct abbrev_info *abbrev;
   struct attribute attr;
-  struct attribute spec_attr;
-  int found_spec_attr = 0;
   int has_low_pc_attr = 0;
   int has_high_pc_attr = 0;
 
   *part_die = zeroed_partial_die;
+
+  part_die->offset = info_ptr - dwarf_info_buffer;
+
   abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
   info_ptr += bytes_read;
   if (!abbrev_number)
@@ -4308,7 +4464,7 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd,
       error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number,
                      bfd_get_filename (abfd));
     }
-  part_die->offset = info_ptr - dwarf_info_buffer;
+
   part_die->tag = abbrev->tag;
   part_die->has_children = abbrev->has_children;
   part_die->abbrev = abbrev_number;
@@ -4368,8 +4524,8 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd,
          break;
        case DW_AT_abstract_origin:
        case DW_AT_specification:
-         found_spec_attr = 1;
-         spec_attr = attr;
+         part_die->has_specification = 1;
+         part_die->spec_attr = attr;
          break;
        case DW_AT_sibling:
          /* Ignore absolute siblings, they might point outside of
@@ -4385,16 +4541,58 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd,
        }
     }
 
+  /* When using the GNU linker, .gnu.linkonce. sections are used to
+     eliminate duplicate copies of functions and vtables and such.
+     The linker will arbitrarily choose one and discard the others.
+     The AT_*_pc values for such functions refer to local labels in
+     these sections.  If the section from that file was discarded, the
+     labels are not in the output, so the relocs get a value of 0.
+     If this is a discarded function, mark the pc bounds as invalid,
+     so that GDB will ignore it.  */
+  if (has_low_pc_attr && has_high_pc_attr
+      && part_die->lowpc < part_die->highpc
+      && (part_die->lowpc != 0
+         || (bfd_get_file_flags (abfd) & HAS_RELOC)))
+    part_die->has_pc_info = 1;
+  return info_ptr;
+}
+
+/* Like load_partial_die, but also patch up the partial DIE's name
+   according to its specification if necessary.  */
+/* FIXME: I've over-eagerly removed calls to this.  The fixup has to happen
+   sometime.  */
+static void
+read_partial_die (struct partial_die_info *part_die, bfd *abfd,
+                 char *info_ptr, struct dwarf2_cu *cu)
+{
+  struct partial_die_info *lookup_die = NULL;
+
+  if (cu->partial_dies)
+    {
+      splay_tree_node node;
+      node = splay_tree_lookup (cu->partial_dies,
+                               info_ptr - dwarf_info_buffer);
+      if (node == NULL)
+       internal_error (__FILE__, __LINE__,
+                       "could not find partial DIE in cache\n");
+
+      lookup_die = (struct partial_die_info *) node->value;
+
+      *part_die = *lookup_die;
+    }
+  else
+    info_ptr = load_partial_die (part_die, abfd, info_ptr, cu);
+
   /* If we found a reference attribute and the die has no name, try
      to find a name in the referred to die.  */
 
-  if (found_spec_attr && part_die->name == NULL)
+  if (part_die->has_specification && part_die->name == NULL)
     {
       struct partial_die_info spec_die;
       char *spec_ptr;
 
       spec_ptr = dwarf_info_buffer
-       + dwarf2_get_ref_die_offset (&spec_attr, cu);
+       + dwarf2_get_ref_die_offset (&part_die->spec_attr, cu);
       read_partial_die (&spec_die, abfd, spec_ptr, cu);
       if (spec_die.name)
        {
@@ -4405,21 +4603,6 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd,
            part_die->is_external = spec_die.is_external;
        }
     }
-
-  /* When using the GNU linker, .gnu.linkonce. sections are used to
-     eliminate duplicate copies of functions and vtables and such.
-     The linker will arbitrarily choose one and discard the others.
-     The AT_*_pc values for such functions refer to local labels in
-     these sections.  If the section from that file was discarded, the
-     labels are not in the output, so the relocs get a value of 0.
-     If this is a discarded function, mark the pc bounds as invalid,
-     so that GDB will ignore it.  */
-  if (has_low_pc_attr && has_high_pc_attr
-      && part_die->lowpc < part_die->highpc
-      && (part_die->lowpc != 0
-         || (bfd_get_file_flags (abfd) & HAS_RELOC)))
-    part_die->has_pc_info = 1;
-  return info_ptr;
 }
 
 /* Read the die from the .debug_info section buffer.  Set DIEP to