This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA/dwarf] Partial DIE support for specifications


I'm relatively new to gdb hacking.  Does it mean that
inter-compilation-unit references will work and
-feliminate-dwarf2-dups will work?  That would be great :)

Just today I ported my version of the inter-cu patch to gdb CVS
(what coincidence).  Anyway I'm quite busy these days, and the patch
isn't exactly efficient, nor do I know enough about DWARF-2 to make it
work in all but the most common cases, so I'm glad someone good at
that finally have the time to hack this.

Anyway I'll attach my version of the patch here, which should make
-feliminate-dwarf2-dups work.  Not that anyone should read that (I'm
not attempting to fork...), but I welcome advice from old-schoolers
about hacking in large software projects like this in general --- just
don't humiliate me too much if I have some fundamental misunderstanding :)

P.S. I'm Wang Qingchuan, and I just finished the copyright assignment
process (#156541).  Seems that it will just become a memorial.

P.P.S.  Better CC me since I'm not normally subscribed to the list.

--- dwarf2read.c.orig	2004-04-03 18:21:12.000000000 +0800
+++ dwarf2read.c	2004-04-03 23:49:53.000000000 +0800
@@ -50,6 +50,9 @@
 #include "gdb_assert.h"
 #include <sys/types.h>
 
+#include <stdlib.h>
+#include "splay-tree.h"
+
 /* A note on memory usage for this file.
    
    At the present time, this code reads the debug info sections into
@@ -202,6 +205,23 @@ asection *dwarf_eh_frame_section;
 #define ABBREV_HASH_SIZE 121
 #endif
 
+/* An array of cu_list_entry's, sorted according to offset.
+   Each entry corresponds to a compilation unit (an included file) in a .o file. */
+struct cu_list
+{
+  unsigned ncu;
+  struct cu_list_entry *cus;
+};
+
+/* Some supplementary information about a compilation unit to facilitate
+   incremental loading. */
+struct cu_list_entry
+{
+  unsigned offset, length;
+  struct partial_symtab *pst;
+  splay_tree deps; /* Direct dependencies only.  The key is the index of the dependency in the cu_list. */
+};
+
 /* The data in a compilation unit header, after target2host
    translation, looks like this.  */
 struct comp_unit_head
@@ -391,6 +411,7 @@ struct die_info
     struct die_info *parent;	/* Its parent, if any.  */
 
     struct type *type;		/* Cached type information */
+    unsigned cu_idx;            /* The compilation unit index (in cu_list) containing this die. */
   };
 
 /* Attributes have a name and a value */
@@ -471,10 +492,15 @@ struct dwarf2_pinfo
     /* Offset in .debug_info for this compilation unit. */
 
     unsigned long dwarf_info_offset;
+    
+    struct cu_list *cu_list;
+    unsigned cu_entry_idx; /* The index of the compilation unit within cu_list */
   };
 
 #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
 #define DWARF_INFO_OFFSET(p) (PST_PRIVATE(p)->dwarf_info_offset)
+#define CU_LIST(p) (PST_PRIVATE(p)->cu_list)
+#define CU_ENTRY_IDX(p) (PST_PRIVATE(p)->cu_entry_idx)
 
 /* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte,
    but this would require a corresponding change in unpack_field_as_long
@@ -676,6 +702,8 @@ static void set_cu_language (unsigned in
 
 static struct attribute *dwarf2_attr (struct die_info *, unsigned int,
 				      struct dwarf2_cu *);
+static struct attribute *dwarf2_attr0 (struct die_info *, unsigned int,
+				       unsigned *pcu_idx);
 
 static int die_is_declaration (struct die_info *, struct dwarf2_cu *cu);
 
@@ -848,6 +876,8 @@ static unsigned int dwarf2_get_ref_die_o
 
 static int dwarf2_get_attr_constant_value (struct attribute *, int);
 
+static unsigned int dwarf2_get_ref_die_offset_for_cu (struct attribute *attr, unsigned cu_idx);
+     
 static struct die_info *follow_die_ref (unsigned int);
 
 static struct type *dwarf2_fundamental_type (struct objfile *, int,
@@ -880,6 +910,10 @@ dwarf2_symbol_mark_computed (struct attr
 static char *skip_one_die (char *info_ptr, struct abbrev_info *abbrev,
 			   struct dwarf2_cu *cu);
 
+static int cu_dep_compare(splay_tree_key pa, splay_tree_key pb);
+
+static char *add_die_deps (bfd *abfd, char *info_ptr, struct dwarf2_cu *cu);
+
 /* Try to locate the sections we need for DWARF 2 debugging
    information and return true if we have enough to do something.  */
 
@@ -1103,6 +1137,22 @@ read_comp_unit_head (struct comp_unit_he
 /* Build the partial symbol table by doing a quick pass through the
    .debug_info and .debug_abbrev sections.  */
 
+/* Used when building psymtabs, and when converting psymtabs to symtabs. */
+static struct cu_list *cur_cu_list;
+static struct cu_list_entry *cur_cu_entry;
+
+static void *
+alloc_from_obstack (int size, void *pobs)
+{
+  return obstack_alloc ((struct obstack *) pobs, size);
+}
+
+static void
+free_from_obstack (void *p, void *pobs)
+{
+}
+
+/* Builds a psymtab for each compilation unit in OBJFILE, and make a cu_list for them. */
 static void
 dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
 {
@@ -1116,6 +1166,10 @@ dwarf2_build_psymtabs_hard (struct objfi
   struct cleanup *back_to;
   CORE_ADDR lowpc, highpc, baseaddr;
 
+  unsigned ncu, i;
+  struct cu_list_entry *cus_priv;
+  struct cu_list *cu_list_priv; /* Will be linked into the psymtab */
+
   info_ptr = dwarf2_per_objfile->info_buffer;
   abbrev_ptr = dwarf2_per_objfile->abbrev_buffer;
 
@@ -1150,6 +1204,40 @@ dwarf2_build_psymtabs_hard (struct objfi
   obstack_init (&dwarf2_tmp_obstack);
   back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
 
+  /* Allocate the cu_list */
+  ncu = 0;
+  while (info_ptr < dwarf2_per_objfile->info_buffer + dwarf2_per_objfile->info_size)
+    {
+      struct dwarf2_cu cu;
+      struct cu_list_entry ent;
+      
+      beg_of_comp_unit = info_ptr;
+
+      cu.objfile = objfile;
+      info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+
+      ent.offset = beg_of_comp_unit - dwarf2_per_objfile->info_buffer;
+      ent.length = cu.header.length + cu.header.initial_length_size;
+      ent.pst = NULL;
+      ent.deps = NULL; /* allocate it later to avoid interfering with obstack_grow */
+      obstack_grow (&objfile->objfile_obstack, &ent, sizeof(ent));
+      ncu++;
+
+      info_ptr = beg_of_comp_unit + cu.header.length 
+                                  + cu.header.initial_length_size;
+    }
+
+  cus_priv = (struct cu_list_entry *) obstack_finish(&objfile->objfile_obstack);
+  /* This tree is never freed explicitly, therefore we have to use the obstack */
+  for (i = 0; i < ncu; i++)
+    cus_priv[i].deps = splay_tree_new_with_allocator (cu_dep_compare, NULL, NULL,
+						      alloc_from_obstack, free_from_obstack,
+						      &objfile->objfile_obstack);
+  cu_list_priv = (struct cu_list *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct cu_list));
+  cu_list_priv->ncu = ncu;
+  cu_list_priv->cus = cus_priv;
+  cur_cu_list = cu_list_priv;
+
   /* Since the objects we're extracting from .debug_info vary in
      length, only the individual functions to extract them (like
      read_comp_unit_head and read_partial_die) can really know whether
@@ -1163,6 +1251,8 @@ dwarf2_build_psymtabs_hard (struct objfi
 
      For this loop condition, simply checking whether there's any data
      left at all should be sufficient.  */
+  i = 0;
+  info_ptr = dwarf2_per_objfile->info_buffer;
   while (info_ptr < (dwarf2_per_objfile->info_buffer
 		     + dwarf2_per_objfile->info_size))
     {
@@ -1170,6 +1260,7 @@ dwarf2_build_psymtabs_hard (struct objfi
       struct dwarf2_cu cu;
       beg_of_comp_unit = info_ptr;
 
+      cur_cu_entry = &cus_priv[i];
       cu.objfile = objfile;
       info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
 
@@ -1228,6 +1319,10 @@ dwarf2_build_psymtabs_hard (struct objfi
       /* Store the function that reads in the rest of the symbol table */
       pst->read_symtab = dwarf2_psymtab_to_symtab;
 
+      CU_LIST (pst) = cu_list_priv;
+      CU_ENTRY_IDX (pst) = i;
+      cus_priv[i].pst = pst;
+      
       /* Check if comp unit has_children.
          If so, read the rest of the partial symbols from this comp unit.
          If not, there's no more debug_info for this comp unit. */
@@ -1261,6 +1356,11 @@ dwarf2_build_psymtabs_hard (struct objfi
 	(objfile->static_psymbols.list + pst->statics_offset);
       sort_pst_symbols (pst);
 
+      /* Build dependency table */
+      info_ptr = cu.header.first_die_ptr;
+      while (info_ptr < beg_of_comp_unit + cu.header.length + cu.header.initial_length_size)
+	info_ptr = add_die_deps (abfd, info_ptr, &cu);
+      
       /* If there is already a psymtab or symtab for a file of this
          name, remove it. (If there is a symtab, more drastic things
          also happen.) This happens in VxWorks.  */
@@ -1270,7 +1370,13 @@ dwarf2_build_psymtabs_hard (struct objfi
                                   + cu.header.initial_length_size;
 
       do_cleanups (back_to_inner);
+      i++;
     }
+
+  gdb_assert (i == ncu);
+  cur_cu_list = NULL;
+  cur_cu_entry = NULL;
+  
   do_cleanups (back_to);
 }
 
@@ -1882,7 +1988,9 @@ dwarf2_psymtab_to_symtab (struct partial
     {
       if (pst->readin)
 	{
+#if 0 /* The psymtab may have already been loaded as a dependency of some other psymtab */
 	  warning ("bug: psymtab for %s is already read in.", pst->filename);
+#endif
 	}
       else
 	{
@@ -1901,12 +2009,78 @@ dwarf2_psymtab_to_symtab (struct partial
     }
 }
 
+/* An array containing all (including indirect) dependencies of the psymtab being read in.
+   Each entry is an index in the cu_list.
+   This array is never freed, always reused.
+*/
+static unsigned *dep_list = NULL, dep_list_size = 0;
+static unsigned dep_list_len = 0;
+/* Contains the same information.  I use this so that we don't have duplicate entries in
+   dep_list (that would just be unclean). */
+static splay_tree all_deps;
+
+static void
+dep_list_add (unsigned idx)
+{
+  if (dep_list_len >= dep_list_size)
+    {
+      if (dep_list_size == 0)
+	{
+	  dep_list_size = 4;
+	  dep_list = (unsigned *) xmalloc (dep_list_size * sizeof(unsigned));
+	}
+      else
+	{
+	  dep_list_size = dep_list_len * 2;
+	  dep_list = (unsigned *) xrealloc (dep_list, dep_list_size * sizeof(unsigned));
+	}
+    }
+  dep_list[dep_list_len] = idx;
+  dep_list_len++;
+}
+
+static void process_dep (unsigned idx);
+
+static int
+process_subdeps (splay_tree_node node, void *p)
+{
+  process_dep ((unsigned) node->key);
+  return 0;
+}
+
+/* Find all the dependencies of a compilation unit, starting from the one whose
+   index in the cu_list is IDX. */
+static void
+process_dep (unsigned idx)
+{
+  struct cu_list_entry *cu_entry;
+  splay_tree cur_deps;
+
+  /* Already processed?  Or being processed at a parent level due to a circular reference? */
+  if (splay_tree_lookup (all_deps, (splay_tree_key) idx) == NULL)
+    {
+      if (info_verbose) printf_filtered ("* Start processing %u.\n", idx);
+      splay_tree_insert (all_deps, (splay_tree_key) idx, (splay_tree_value) NULL);
+      cu_entry = &cur_cu_list->cus[idx];
+      cur_deps = cu_entry->deps;
+      /* Process them if they have not been processed */
+      splay_tree_foreach (cur_deps, process_subdeps, NULL);
+      dep_list_add (idx);
+      if (info_verbose) printf_filtered ("* Done processing %u.\n", idx);
+    }
+}
+
+/* The index of the cu corresponding to the psymtab currently being filled. */
+static unsigned cur_cu_idx = ~0UL;
+
 static void
 psymtab_to_symtab_1 (struct partial_symtab *pst)
 {
   struct objfile *objfile = pst->objfile;
   bfd *abfd = objfile->obfd;
-  struct dwarf2_cu cu;
+  /* To make the cleanup functions happy, we mustn't reuse the same struct dwarf2_cu */
+  struct dwarf2_cu *tmp_cus;
+  struct die_info **die_lists;
   struct die_info *dies;
   unsigned long offset;
   CORE_ADDR lowpc, highpc;
@@ -1916,86 +2090,133 @@ psymtab_to_symtab_1 (struct partial_symt
   struct cleanup *back_to;
   struct attribute *attr;
   CORE_ADDR baseaddr;
+  unsigned i, idx;
 
   dwarf2_per_objfile = objfile_data (pst->objfile, dwarf2_objfile_data_key);
 
-  /* Set local variables from the partial symbol table info.  */
-  offset = DWARF_INFO_OFFSET (pst);
-
-  info_ptr = dwarf2_per_objfile->info_buffer + offset;
-  baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
-
-  /* We're in the global namespace.  */
-  processing_current_prefix = "";
-
   obstack_init (&dwarf2_tmp_obstack);
   back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
 
+  cur_cu_list = CU_LIST (pst);
+  idx = CU_ENTRY_IDX (pst);
+
+  /* Fill dep_list */
+  all_deps = splay_tree_new_with_allocator (cu_dep_compare, NULL, NULL,
+					    alloc_from_obstack, free_from_obstack, &dwarf2_tmp_obstack);
+  dep_list_len = 0;
+  process_dep (idx);
+  splay_tree_delete (all_deps); /* should do nothing since we allocate from obstacks */
+
   buildsym_init ();
   make_cleanup (really_free_pendings, NULL);
 
-  cu.objfile = objfile;
+  /* Reset die reference table; we are
+     building new ones now.  */
+  dwarf2_empty_hash_tables ();
+  
+  die_lists = obstack_alloc (&dwarf2_tmp_obstack, dep_list_len * sizeof (struct die_info *));
+  tmp_cus = obstack_alloc (&dwarf2_tmp_obstack, dep_list_len * sizeof (struct dwarf2_cu));
 
-  /* read in the comp_unit header  */
-  info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+  /* Pass 1: build ref_table */
+  for (i = 0; i < dep_list_len; i++)
+    {
+      idx = dep_list[i];
+      cur_cu_idx = idx;
+      pst = cur_cu_list->cus[idx].pst;
 
-  /* Read the abbrevs for this compilation unit  */
-  dwarf2_read_abbrevs (abfd, &cu);
-  make_cleanup (dwarf2_free_abbrev_table, &cu);
+      if (info_verbose) printf_filtered ("* Start building reference table for %u.\n", idx);
+      /* Set local variables from the partial symbol table info.  */
+      offset = DWARF_INFO_OFFSET (pst);
 
-  cu.header.offset = offset;
+      info_ptr = dwarf2_per_objfile->info_buffer + offset;
+      baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-  cu.list_in_scope = &file_symbols;
+      /* We're in the global namespace.  */
+      processing_current_prefix = "";
 
-  dies = read_comp_unit (info_ptr, abfd, &cu);
+      tmp_cus[i].objfile = objfile;
 
-  make_cleanup_free_die_list (dies);
+      /* read in the comp_unit header  */
+      info_ptr = read_comp_unit_head (&tmp_cus[i].header, info_ptr, abfd);
 
-  /* Find the base address of the compilation unit for range lists and
-     location lists.  It will normally be specified by DW_AT_low_pc.
-     In DWARF-3 draft 4, the base address could be overridden by
-     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
-     compilation units with discontinuous ranges.  */
+      /* Read the abbrevs for this compilation unit  */
+      dwarf2_read_abbrevs (abfd, &tmp_cus[i]);
+      make_cleanup (dwarf2_free_abbrev_table, &tmp_cus[i]);
 
-  cu.header.base_known = 0;
-  cu.header.base_address = 0;
+      die_lists[i] = read_comp_unit (info_ptr, abfd, &tmp_cus[i]);
+      make_cleanup_free_die_list (die_lists[i]);
 
-  attr = dwarf2_attr (dies, DW_AT_entry_pc, &cu);
-  if (attr)
-    {
-      cu.header.base_address = DW_ADDR (attr);
-      cu.header.base_known = 1;
+      if (info_verbose) printf_filtered ("* Done building reference table for %u.\n", idx);
     }
-  else
+
+  /* Pass 2: do the actual work */
+  for (i = 0; i < dep_list_len; i++)
     {
-      attr = dwarf2_attr (dies, DW_AT_low_pc, &cu);
+      idx = dep_list[i];
+      cur_cu_idx = idx; /* should be unnecessary */
+      pst = cur_cu_list->cus[idx].pst;
+      if (pst->readin) continue;
+
+      if (info_verbose) printf_filtered ("* Start loading %u.\n", idx);
+      /* Set local variables from the partial symbol table info.  */
+      offset = DWARF_INFO_OFFSET (pst);
+      baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
+
+      /* We needn't repeat the stuff done in pass 1 */
+      tmp_cus[i].header.offset = offset;
+      tmp_cus[i].list_in_scope = &file_symbols;
+
+      dies = die_lists[i];
+
+      /* Find the base address of the compilation unit for range lists and
+	 location lists.  It will normally be specified by DW_AT_low_pc.
+	 In DWARF-3 draft 4, the base address could be overridden by
+	 DW_AT_entry_pc.  It's been removed, but GCC still uses this for
+	 compilation units with discontinuous ranges.  */
+
+      tmp_cus[i].header.base_known = 0;
+      tmp_cus[i].header.base_address = 0;
+
+      attr = dwarf2_attr (dies, DW_AT_entry_pc, &tmp_cus[i]);
       if (attr)
 	{
-	  cu.header.base_address = DW_ADDR (attr);
-	  cu.header.base_known = 1;
+	  tmp_cus[i].header.base_address = DW_ADDR (attr);
+	  tmp_cus[i].header.base_known = 1;
+	}
+      else
+	{
+	  attr = dwarf2_attr (dies, DW_AT_low_pc, &tmp_cus[i]);
+	  if (attr)
+	    {
+	      tmp_cus[i].header.base_address = DW_ADDR (attr);
+	      tmp_cus[i].header.base_known = 1;
+	    }
 	}
-    }
-
-  /* Do line number decoding in read_file_scope () */
-  process_die (dies, &cu);
-
-  /* Some compilers don't define a DW_AT_high_pc attribute for the
-     compilation unit.  If the DW_AT_high_pc is missing, synthesize
-     it, by scanning the DIE's below the compilation unit.  */
-  get_scope_pc_bounds (dies, &lowpc, &highpc, &cu);
 
-  symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));
+      /* Do line number decoding in read_file_scope () */
+      process_die (dies, &tmp_cus[i]);
 
-  /* Set symtab language to language from DW_AT_language.
-     If the compilation is from a C file generated by language preprocessors,
-     do not set the language if it was already deduced by start_subfile.  */
-  if (symtab != NULL
-      && !(cu.language == language_c && symtab->language != language_c))
-    {
-      symtab->language = cu.language;
+      /* Some compilers don't define a DW_AT_high_pc attribute for the
+	 compilation unit.  If the DW_AT_high_pc is missing, synthesize
+	 it, by scanning the DIE's below the compilation unit.  */
+      get_scope_pc_bounds (dies, &lowpc, &highpc, &tmp_cus[i]);
+
+      symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));
+
+      /* Set symtab language to language from DW_AT_language.
+	 If the compilation is from a C file generated by language preprocessors,
+	 do not set the language if it was already deduced by start_subfile.  */
+      if (symtab != NULL
+	  && !(tmp_cus[i].language == language_c && symtab->language != language_c))
+	{
+	  symtab->language = tmp_cus[i].language;
+	}
+      pst->symtab = symtab;
+      pst->readin = 1;
+      if (info_verbose) printf_filtered ("* Done loading %u.\n", idx);
     }
-  pst->symtab = symtab;
-  pst->readin = 1;
+  cur_cu_idx = ~0UL;
+  cur_cu_list = NULL;
 
   do_cleanups (back_to);
 }
@@ -4145,10 +4366,6 @@ read_subrange_type (struct die_info *die
 static struct die_info *
 read_comp_unit (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu)
 {
-  /* Reset die reference table; we are
-     building new ones now.  */
-  dwarf2_empty_hash_tables ();
-
   return read_die_and_children (info_ptr, abfd, cu, &info_ptr, NULL);
 }
 
@@ -4416,6 +4633,98 @@ dwarf2_lookup_abbrev (unsigned int numbe
 
 /* Read a minimal amount of information into the minimal die structure.  */
 
+/* Used during the bsearch that finds the compilation unit containing a reference */
+static int
+cu_list_compare (const void *pa, const void *pb)
+{
+  const struct cu_list_entry
+    *a = (const struct cu_list_entry *) pa,
+    *b = (const struct cu_list_entry *) pb;
+  if (a->offset >= b->offset && a->offset < (b->offset + b->length)) return 0;
+  else if (b->offset >= a->offset && b->offset < (a->offset + a->length)) return 0;
+  else if (a->offset < b->offset) return -1;
+  else return 1;
+}
+
+static int
+cu_dep_compare (splay_tree_key pa, splay_tree_key pb)
+{
+  unsigned a = (unsigned) pa, b = (unsigned) pb;
+  return (a > b) - (a < b);
+}
+
+/* Add the compilation unit containing the referenced data as a dependency of cur_cu_entry */
+static void
+add_dep (struct attribute *attr, struct dwarf2_cu *cu)
+{
+  struct cu_list_entry tmp, *ent;
+  unsigned idx;
+  
+  tmp.offset = dwarf2_get_ref_die_offset(attr, cu);
+  tmp.length = 0;
+  if (cu_list_compare(&tmp, cur_cu_entry) == 0) return; /* We don't need self-dependencies */
+  ent = bsearch(&tmp, cur_cu_list->cus, cur_cu_list->ncu, sizeof(struct cu_list_entry), cu_list_compare);
+  if (ent == NULL)
+    error("Dwarf Error: Invalid referent offset %u.", tmp.offset);
+  else
+    {
+      gdb_assert(ent != cur_cu_entry);
+      idx = ent - cur_cu_list->cus;
+      if (splay_tree_lookup (cur_cu_entry->deps, (splay_tree_key) idx) == NULL)
+	{
+	  splay_tree_insert (cur_cu_entry->deps, (splay_tree_key) idx, (splay_tree_value) NULL);
+	  if (info_verbose)
+	    printf_filtered ("* Added dependency %u for %u (ref offset <%x>).\n",
+			     idx, cur_cu_entry - cur_cu_list->cus, tmp.offset);
+	}
+    }
+}
+
+/* Adds all external references in attributes as references. */
+static char *
+add_die_deps (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;
+
+  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+  info_ptr += bytes_read;
+  if (!abbrev_number)
+    return info_ptr;
+
+  abbrev = dwarf2_lookup_abbrev (abbrev_number, cu);
+  if (!abbrev)
+    {
+      error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number,
+		      bfd_get_filename (abfd));
+    }
+
+  for (i = 0; i < abbrev->num_attrs; ++i)
+    {
+      info_ptr = read_attribute (&attr, &abbrev->attrs[i], abfd, info_ptr, cu);
+
+      /* Store the data if it is of an attribute we want to keep in a
+         partial symbol table.  */
+      switch (attr.name)
+	{
+	case DW_AT_type:
+	case DW_AT_containing_type:
+	case DW_AT_abstract_origin:
+	case DW_AT_specification:
+	case DW_AT_extension:
+	  add_dep(&attr, cu);
+	  break;
+	}
+    }
+
+  return info_ptr;
+}
+
 static char *
 read_partial_die (struct partial_die_info *part_die, bfd *abfd,
 		  char *info_ptr, struct dwarf2_cu *cu)
@@ -4503,6 +4812,8 @@ read_partial_die (struct partial_die_inf
 	  found_spec_attr = 1;
 	  spec_attr = attr;
 	  break;
+	case DW_AT_extension:
+	  break;
 	case DW_AT_sibling:
 	  /* Ignore absolute siblings, they might point outside of
 	     the current compile unit.  */
@@ -5111,14 +5422,19 @@ set_cu_language (unsigned int lang, stru
   cu->language_defn = language_def (cu->language);
 }
 
-/* Return the named attribute or NULL if not there.  */
+/* Return the named attribute or NULL if not there.
+   If pcu_idx is not NULL, it is set to the compilation unit index corresponding
+   to the die containing the actual attribute definition (i.e., after redirections
+   by DW_AT_spec).
+*/
 
 static struct attribute *
-dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
+dwarf2_attr0 (struct die_info *die, unsigned int name, unsigned *pcu_idx)
 {
   unsigned int i;
   struct attribute *spec = NULL;
 
+  if (pcu_idx) *pcu_idx = die->cu_idx; /* could be changed in further indirections */
   for (i = 0; i < die->num_attrs; ++i)
     {
       if (die->attrs[i].name == name)
@@ -5132,15 +5448,25 @@ dwarf2_attr (struct die_info *die, unsig
   if (spec)
     {
       struct die_info *ref_die =
-      follow_die_ref (dwarf2_get_ref_die_offset (spec, cu));
+      follow_die_ref (dwarf2_get_ref_die_offset_for_cu (spec, die->cu_idx));
 
       if (ref_die)
-	return dwarf2_attr (ref_die, name, cu);
+	return dwarf2_attr0 (ref_die, name, pcu_idx);
     }
 
   return NULL;
 }
 
+
+/*
+  The "cu" parameter seems to be unused, since we already have die->cu_idx.
+*/
+static struct attribute *
+dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
+{
+  return dwarf2_attr0 (die, name, NULL);
+}
+
 static int
 die_is_declaration (struct die_info *die, struct dwarf2_cu *cu)
 {
@@ -6046,8 +6372,9 @@ die_type (struct die_info *die, struct d
   struct attribute *type_attr;
   struct die_info *type_die;
   unsigned int ref;
+  unsigned cu_idx;
 
-  type_attr = dwarf2_attr (die, DW_AT_type, cu);
+  type_attr = dwarf2_attr0 (die, DW_AT_type, &cu_idx);
   if (!type_attr)
     {
       /* A missing DW_AT_type represents a void type.  */
@@ -6055,7 +6382,7 @@ die_type (struct die_info *die, struct d
     }
   else
     {
-      ref = dwarf2_get_ref_die_offset (type_attr, cu);
+      ref = dwarf2_get_ref_die_offset_for_cu (type_attr, cu_idx);
       type_die = follow_die_ref (ref);
       if (!type_die)
 	{
@@ -6084,11 +6411,12 @@ die_containing_type (struct die_info *di
   struct attribute *type_attr;
   struct die_info *type_die = NULL;
   unsigned int ref;
+  unsigned cu_idx;
 
-  type_attr = dwarf2_attr (die, DW_AT_containing_type, cu);
+  type_attr = dwarf2_attr0 (die, DW_AT_containing_type, &cu_idx);
   if (type_attr)
     {
-      ref = dwarf2_get_ref_die_offset (type_attr, cu);
+      ref = dwarf2_get_ref_die_offset_for_cu (type_attr, cu_idx);
       type_die = follow_die_ref (ref);
       if (!type_die)
 	{
@@ -6457,12 +6785,13 @@ dwarf2_extension (struct die_info *die, 
   struct attribute *attr;
   struct die_info *extension_die;
   unsigned int ref;
+  unsigned cu_idx;
 
-  attr = dwarf2_attr (die, DW_AT_extension, cu);
+  attr = dwarf2_attr0 (die, DW_AT_extension, &cu_idx);
   if (attr == NULL)
     return NULL;
 
-  ref = dwarf2_get_ref_die_offset (attr, cu);
+  ref = dwarf2_get_ref_die_offset_for_cu (attr, cu_idx);
   extension_die = follow_die_ref (ref);
   if (!extension_die)
     {
@@ -7375,7 +7704,7 @@ dwarf2_empty_hash_tables (void)
 }
 
 static unsigned int
-dwarf2_get_ref_die_offset (struct attribute *attr, struct dwarf2_cu *cu)
+dwarf2_get_ref_die_offset0 (struct attribute *attr, unsigned base)
 {
   unsigned int result = 0;
 
@@ -7389,7 +7718,7 @@ dwarf2_get_ref_die_offset (struct attrib
     case DW_FORM_ref4:
     case DW_FORM_ref8:
     case DW_FORM_ref_udata:
-      result = cu->header.offset + DW_UNSND (attr);
+      result = base + DW_UNSND (attr);
       break;
     default:
       complaint (&symfile_complaints,
@@ -7399,6 +7728,25 @@ dwarf2_get_ref_die_offset (struct attrib
   return result;
 }
 
+/* Can only be used when one compilation unit is processed at a time. */
+static unsigned int
+dwarf2_get_ref_die_offset (struct attribute *attr, struct dwarf2_cu *cu)
+{
+  return dwarf2_get_ref_die_offset0 (attr, cu->header.offset);
+}
+
+/* This one supports inter-compilation-unit references.  Can only be used when
+   cur_cu_list is defined (for example, when actually loading the symbols).
+   
+   The compilation unit cu_idx (which should contain the attribute value)
+   is used as the base address.
+*/
+static unsigned int
+dwarf2_get_ref_die_offset_for_cu (struct attribute *attr, unsigned cu_idx)
+{
+  return dwarf2_get_ref_die_offset0 (attr, cur_cu_list->cus[cu_idx].offset);
+}
+
 /* Return the constant value held by the given attribute.  Return -1
    if the value held by the attribute is not constant.  */
 
@@ -7724,6 +8072,7 @@ dwarf_alloc_die (void)
 
   die = (struct die_info *) xmalloc (sizeof (struct die_info));
   memset (die, 0, sizeof (struct die_info));
+  die->cu_idx = cur_cu_idx;
   return (die);
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]