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]

[rfa/dwarf] Support for attributes pointing to a different CU


This is the last logical piece I could break out of the intercu support. 
We're almost there.  Only things left after this are dependence tracking
and the queueing of multiple full CUs - 400 lines or so.

The core change of this patch is in follow_die_ref.  Instead of taking an
offset and returning a DIE, it now takes an attribute and the CU in which
the attribute was found, and returns a DIE and the CU in which the DIE
was found.

The bulky text change of this patch is in dwarf2_attr.  It divides into two
interfaces: anywhere that we are prepared to find a reference to another
DIE, we need to call dwarf2_attr_with_cu instead.  Then, any further
operations on the returned reference need to be sure to use the returned CU.
The reason for this is a little subtle - we're returning a reference.  If
the reference is, for example, DW_FORM_ref4, then it's an offset within some
particular CU.  If the attribute containing this reference was found by
chasing DW_AT_specification, and DW_AT_specification was DW_FORM_ref_addr,
then the return value of dwarf2_attr_with_cu is a relative offset to a
different CU than the caller passed in.  So if we are going to follow the
reference, we need to know the compilation unit in which it resides.

A lot of places call dwarf2_attr_with_cu and ignore the result.  That's
because they don't keep the result (just compare it against NULL), or
because they don't actually cope with the case of a reference (variable
array bounds, for instance).  The error() there will probably turn up a few
more cases that need to accept this, but I wanted this to be a noisy
failure.

OK?

-- 
Daniel Jacobowitz

2004-09-23  Daniel Jacobowitz  <dan@debian.org>

	* dwarf2read.c (dwarf2_attr_with_cu): Renamed from dwarf2_attr.
	Add SPEC_CU argument and set it.  Update call to follow_die_ref.
	(dwarf2_attr): New function.
	(die_specification): Add SPEC_CU argument.  Update call to
	follow_die_ref.
	(dwarf2_extension): Likewise.
	(follow_die_ref): Take more abstract arguments.  Issue an error
	for DW_FORM_ref_addr.
	(read_func_scope): Update call to die_specification.  Pass SPEC_CU
	to determine_prefix.
	(determine_class_name): Likewise.
	(dwarf2_add_member_fn): Use dwarf2_attr_with_cu.
	(read_namespace, namespace_name): Update calls to dwarf2_extension.
	Use SPEC_CU.
	(read_subrange_type): Use dwarf2_attr_with_cu.
	(die_is_declaration, new_symbol): Likewise.
	(die_type, die_containing_type): Likewise.  Update call to
	follow_die_ref.

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.163
diff -u -p -r1.163 dwarf2read.c
--- dwarf2read.c	21 Sep 2004 15:04:41 -0000	1.163
+++ dwarf2read.c	23 Sep 2004 04:40:29 -0000
@@ -807,13 +807,19 @@ static void set_cu_language (unsigned in
 static struct attribute *dwarf2_attr (struct die_info *, unsigned int,
 				      struct dwarf2_cu *);
 
+static struct attribute *dwarf2_attr_with_cu (struct die_info *,
+					      unsigned int,
+					      struct dwarf2_cu *,
+					      struct dwarf2_cu **);
+
 static int dwarf2_flag_true_p (struct die_info *die, unsigned name,
                                struct dwarf2_cu *cu);
 
 static int die_is_declaration (struct die_info *, struct dwarf2_cu *cu);
 
 static struct die_info *die_specification (struct die_info *die,
-					   struct dwarf2_cu *);
+					   struct dwarf2_cu *,
+					   struct dwarf2_cu **);
 
 static void free_line_header (struct line_header *lh);
 
@@ -953,7 +959,8 @@ static char *dwarf2_linkage_name (struct
 static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *);
 
 static struct die_info *dwarf2_extension (struct die_info *die,
-					  struct dwarf2_cu *);
+					  struct dwarf2_cu *,
+					  struct dwarf2_cu **);
 
 static char *dwarf_tag_name (unsigned int);
 
@@ -988,7 +995,9 @@ static unsigned int dwarf2_get_ref_die_o
 
 static int dwarf2_get_attr_constant_value (struct attribute *, int);
 
-static struct die_info *follow_die_ref (unsigned int);
+static struct die_info *follow_die_ref (struct attribute *,
+					struct dwarf2_cu *,
+					struct dwarf2_cu **);
 
 static struct type *dwarf2_fundamental_type (struct objfile *, int,
 					     struct dwarf2_cu *);
@@ -2723,7 +2732,8 @@ read_func_scope (struct die_info *die, s
   if (cu->language == language_cplus
       || cu->language == language_java)
     {
-      struct die_info *spec_die = die_specification (die, cu);
+      struct dwarf2_cu *spec_cu;
+      struct die_info *spec_die = die_specification (die, cu, &spec_cu);
 
       /* NOTE: carlton/2004-01-23: We have to be careful in the
          presence of DW_AT_specification.  For example, with GCC 3.4,
@@ -2749,7 +2759,7 @@ read_func_scope (struct die_info *die, s
 	
       if (spec_die != NULL)
 	{
-	  char *specification_prefix = determine_prefix (spec_die, cu);
+	  char *specification_prefix = determine_prefix (spec_die, spec_cu);
 	  processing_current_prefix = specification_prefix;
 	  back_to = make_cleanup (xfree, specification_prefix);
 	}
@@ -3351,6 +3361,7 @@ dwarf2_add_member_fn (struct field_info 
   char *fieldname;
   char *physname;
   struct nextfnfield *new_fnfield;
+  struct dwarf2_cu *spec_cu;
 
   /* Get name of member function.  */
   attr = dwarf2_attr (die, DW_AT_name, cu);
@@ -3431,7 +3442,7 @@ dwarf2_add_member_fn (struct field_info 
 	       physname);
 
   /* Get fcontext from DW_AT_containing_type if present.  */
-  if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
+  if (dwarf2_attr_with_cu (die, DW_AT_containing_type, cu, &spec_cu) != NULL)
     fnp->fcontext = die_containing_type (die, cu);
 
   /* dwarf2 doesn't have stubbed physical names, so the setting of is_const
@@ -3658,13 +3669,16 @@ read_structure_type (struct die_info *di
 	dwarf2_attach_fields_to_type (&fi, type, cu);
       if (fi.nfnfields)
 	{
+	  struct dwarf2_cu *spec_cu;
+
 	  dwarf2_attach_fn_fields_to_type (&fi, type, cu);
 
 	  /* Get the type which refers to the base class (possibly this
 	     class itself) which contains the vtable pointer for the current
 	     class from the DW_AT_containing_type attribute.  */
 
-	  if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
+	  if (dwarf2_attr_with_cu (die, DW_AT_containing_type,
+				   cu, &spec_cu) != NULL)
 	    {
 	      struct type *t = die_containing_type (die, cu);
 
@@ -3802,7 +3816,8 @@ static char *
 determine_class_name (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct cleanup *back_to = NULL;
-  struct die_info *spec_die = die_specification (die, cu);
+  struct dwarf2_cu *spec_cu;
+  struct die_info *spec_die = die_specification (die, cu, &spec_cu);
   char *new_prefix = NULL;
 
   /* If this is the definition of a class that is declared by another
@@ -3810,7 +3825,7 @@ determine_class_name (struct die_info *d
      read_func_scope for a similar example.  */
   if (spec_die != NULL)
     {
-      char *specification_prefix = determine_prefix (spec_die, cu);
+      char *specification_prefix = determine_prefix (spec_die, spec_cu);
       processing_current_prefix = specification_prefix;
       back_to = make_cleanup (xfree, specification_prefix);
     }
@@ -4113,6 +4128,7 @@ read_namespace (struct die_info *die, st
   int is_anonymous;
   struct die_info *current_die;
   struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+  struct dwarf2_cu *spec_cu;
 
   name = namespace_name (die, &is_anonymous, cu);
 
@@ -4133,7 +4149,7 @@ read_namespace (struct die_info *die, st
      before.  Also, add a using directive if it's an anonymous
      namespace.  */
 
-  if (dwarf2_extension (die, cu) == NULL)
+  if (dwarf2_extension (die, cu, &spec_cu) == NULL)
     {
       struct type *type;
 
@@ -4177,14 +4193,15 @@ namespace_name (struct die_info *die, in
 {
   struct die_info *current_die;
   const char *name = NULL;
+  struct dwarf2_cu *spec_cu;
 
   /* Loop through the extensions until we find a name.  */
 
-  for (current_die = die;
+  for (current_die = die, spec_cu = cu;
        current_die != NULL;
-       current_die = dwarf2_extension (die, cu))
+       current_die = dwarf2_extension (die, spec_cu, &spec_cu))
     {
-      name = dwarf2_name (current_die, cu);
+      name = dwarf2_name (current_die, spec_cu);
       if (name != NULL)
 	break;
     }
@@ -4588,6 +4605,7 @@ read_subrange_type (struct die_info *die
   struct attribute *attr;
   int low = 0;
   int high = -1;
+  struct dwarf2_cu *spec_cu;
   
   /* If we have already decoded this die, then nothing more to do.  */
   if (die->type)
@@ -4610,11 +4628,14 @@ read_subrange_type (struct die_info *die
       low = 1;
     }
 
-  attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
+  /* FIXME: For variable sized arrays either of these could be
+     a variable rather than a constant value.  We'll allow it,
+     but we don't know how to handle it.  */
+  attr = dwarf2_attr_with_cu (die, DW_AT_lower_bound, cu, &spec_cu);
   if (attr)
     low = dwarf2_get_attr_constant_value (attr, 0);
 
-  attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
+  attr = dwarf2_attr_with_cu (die, DW_AT_upper_bound, cu, &spec_cu);
   if (attr)
     {       
       if (attr->form == DW_FORM_block1)
@@ -5946,7 +5967,8 @@ set_cu_language (unsigned int lang, stru
 /* Return the named attribute or NULL if not there.  */
 
 static struct attribute *
-dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
+dwarf2_attr_with_cu (struct die_info *die, unsigned int name,
+		     struct dwarf2_cu *cu, struct dwarf2_cu **spec_cu)
 {
   unsigned int i;
   struct attribute *spec = NULL;
@@ -5955,6 +5977,26 @@ dwarf2_attr (struct die_info *die, unsig
     {
       if (die->attrs[i].name == name)
 	{
+	  /* If our caller did not expect a reference, but got one,
+	     we can't continue.  We won't be able to understand the
+	     data, and if the reference was to a different compilation
+	     unit we'd get garbage following any references from the
+	     returned DIE.  */
+	  if (spec_cu == NULL
+	      && (die->attrs[i].form == DW_FORM_ref_addr
+		  || die->attrs[i].form == DW_FORM_ref1
+		  || die->attrs[i].form == DW_FORM_ref2
+		  || die->attrs[i].form == DW_FORM_ref4
+		  || die->attrs[i].form == DW_FORM_ref8
+		  || die->attrs[i].form == DW_FORM_ref_udata))
+	    error ("Dwarf Error: attempt to follow a reference "
+		   "from DIE at 0x%lx [in module %s] discards "
+		   "compilation unit", (long) die->offset,
+		   bfd_get_filename (cu->objfile->obfd));
+
+	  if (spec_cu != NULL)
+	    *spec_cu = cu;
+
 	  return &die->attrs[i];
 	}
       if (die->attrs[i].name == DW_AT_specification
@@ -5963,16 +6005,23 @@ dwarf2_attr (struct die_info *die, unsig
     }
   if (spec)
     {
-      struct die_info *ref_die =
-      follow_die_ref (dwarf2_get_ref_die_offset (spec, cu));
+      struct dwarf2_cu *ref_cu;
+      struct die_info *ref_die = follow_die_ref (spec, cu, &ref_cu);
 
-      if (ref_die)
-	return dwarf2_attr (ref_die, name, cu);
+      return dwarf2_attr_with_cu (ref_die, name, ref_cu, spec_cu);
     }
 
   return NULL;
 }
 
+/* Return the named attribute or NULL if not there.  */
+
+static struct attribute *
+dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
+{
+  return dwarf2_attr_with_cu (die, name, cu, NULL);
+}
+
 /* Return non-zero iff the attribute NAME is defined for the given DIE,
    and holds a non-zero value.  This function should only be used for
    DW_FORM_flag attributes.  */
@@ -5988,6 +6037,8 @@ dwarf2_flag_true_p (struct die_info *die
 static int
 die_is_declaration (struct die_info *die, struct dwarf2_cu *cu)
 {
+  struct dwarf2_cu *spec_cu;
+
   /* A DIE is a declaration if it has a DW_AT_declaration attribute
      which value is non-zero.  However, we have to be careful with
      DIEs having a DW_AT_specification attribute, because dwarf2_attr()
@@ -5996,21 +6047,23 @@ die_is_declaration (struct die_info *die
      to a different DIE referenced by the specification attribute,
      even though the given DIE does not have a declaration attribute.  */
   return (dwarf2_flag_true_p (die, DW_AT_declaration, cu)
-	  && dwarf2_attr (die, DW_AT_specification, cu) == NULL);
+	  && ! dwarf2_attr_with_cu (die, DW_AT_specification, cu, &spec_cu));
 }
 
 /* Return the die giving the specification for DIE, if there is
    one.  */
 
 static struct die_info *
-die_specification (struct die_info *die, struct dwarf2_cu *cu)
+die_specification (struct die_info *die, struct dwarf2_cu *cu,
+		   struct dwarf2_cu **spec_cu)
 {
-  struct attribute *spec_attr = dwarf2_attr (die, DW_AT_specification, cu);
+  struct attribute *spec_attr
+    = dwarf2_attr_with_cu (die, DW_AT_specification, cu, spec_cu);
 
   if (spec_attr == NULL)
     return NULL;
   else
-    return follow_die_ref (dwarf2_get_ref_die_offset (spec_attr, cu));
+    return follow_die_ref (spec_attr, *spec_cu, spec_cu);
 }
 
 /* Free the line_header structure *LH, and any arrays and strings it
@@ -6664,6 +6717,8 @@ new_symbol (struct die_info *die, struct
 	    }
 	  else
 	    {
+	      struct dwarf2_cu *spec_cu;
+
 	      /* We do not know the address of this symbol.
 	         If it is an external symbol and we have type information
 	         for it, enter the symbol as a LOC_UNRESOLVED symbol.
@@ -6672,7 +6727,8 @@ new_symbol (struct die_info *die, struct
 	         referenced.  */
 	      attr2 = dwarf2_attr (die, DW_AT_external, cu);
 	      if (attr2 && (DW_UNSND (attr2) != 0)
-		  && dwarf2_attr (die, DW_AT_type, cu) != NULL)
+		  && dwarf2_attr_with_cu (die, DW_AT_type,
+					  cu, &spec_cu) != NULL)
 		{
 		  SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
 		  add_symbol_to_list (sym, &global_symbols);
@@ -6941,9 +6997,9 @@ die_type (struct die_info *die, struct d
   struct type *type;
   struct attribute *type_attr;
   struct die_info *type_die;
-  unsigned int ref;
+  struct dwarf2_cu *spec_cu;
 
-  type_attr = dwarf2_attr (die, DW_AT_type, cu);
+  type_attr = dwarf2_attr_with_cu (die, DW_AT_type, cu, &spec_cu);
   if (!type_attr)
     {
       /* A missing DW_AT_type represents a void type.  */
@@ -6951,16 +7007,16 @@ die_type (struct die_info *die, struct d
     }
   else
     {
-      ref = dwarf2_get_ref_die_offset (type_attr, cu);
-      type_die = follow_die_ref (ref);
+      type_die = follow_die_ref (type_attr, spec_cu, &spec_cu);
       if (!type_die)
 	{
-	  error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", 
-			  ref, cu->objfile->name);
+	  error ("Dwarf Error: Cannot find referent from DIE "
+		 "at offset %d [in module %s]",
+		 die->offset, cu->objfile->name);
 	  return NULL;
 	}
     }
-  type = tag_type_to_type (type_die, cu);
+  type = tag_type_to_type (type_die, spec_cu);
   if (!type)
     {
       dump_die (type_die);
@@ -6979,20 +7035,19 @@ die_containing_type (struct die_info *di
   struct type *type = NULL;
   struct attribute *type_attr;
   struct die_info *type_die = NULL;
-  unsigned int ref;
+  struct dwarf2_cu *spec_cu;
 
-  type_attr = dwarf2_attr (die, DW_AT_containing_type, cu);
+  type_attr = dwarf2_attr_with_cu (die, DW_AT_containing_type, cu, &spec_cu);
   if (type_attr)
     {
-      ref = dwarf2_get_ref_die_offset (type_attr, cu);
-      type_die = follow_die_ref (ref);
+      type_die = follow_die_ref (type_attr, spec_cu, &spec_cu);
       if (!type_die)
 	{
-	  error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref, 
-			  cu->objfile->name);
+	  error ("Dwarf Error: Cannot find referent from DIE at offset %d "
+		 "[in module %s]", die->offset, cu->objfile->name);
 	  return NULL;
 	}
-      type = tag_type_to_type (type_die, cu);
+      type = tag_type_to_type (type_die, spec_cu);
     }
   if (!type)
     {
@@ -7372,21 +7427,21 @@ dwarf2_name (struct die_info *die, struc
    is none.  */
 
 static struct die_info *
-dwarf2_extension (struct die_info *die, struct dwarf2_cu *cu)
+dwarf2_extension (struct die_info *die, struct dwarf2_cu *cu,
+		  struct dwarf2_cu **spec_cu)
 {
   struct attribute *attr;
   struct die_info *extension_die;
-  unsigned int ref;
 
-  attr = dwarf2_attr (die, DW_AT_extension, cu);
+  attr = dwarf2_attr_with_cu (die, DW_AT_extension, cu, spec_cu);
   if (attr == NULL)
     return NULL;
 
-  ref = dwarf2_get_ref_die_offset (attr, cu);
-  extension_die = follow_die_ref (ref);
+  extension_die = follow_die_ref (attr, *spec_cu, spec_cu);
   if (!extension_die)
     {
-      error ("Dwarf Error: Cannot find referent at offset %d.", ref);
+      error ("Dwarf Error: Cannot find referent from DIE at offset %d.",
+	     die->offset);
     }
 
   return extension_die;
@@ -8342,19 +8397,31 @@ dwarf2_get_attr_constant_value (struct a
 }
 
 static struct die_info *
-follow_die_ref (unsigned int offset)
+follow_die_ref (struct attribute *attr, struct dwarf2_cu *cu,
+		struct dwarf2_cu **spec_cu)
 {
   struct die_info *die;
+  unsigned int offset;
   int h;
+  struct die_info temp_die;
+
+  offset = dwarf2_get_ref_die_offset (attr, cu);
+
+  if (attr->form == DW_FORM_ref_addr
+      && (DW_ADDR (attr) < cu->header.offset
+	  || DW_ADDR (attr) >= cu->header.offset + cu->header.length))
+    {
+      error ("Dwarf Error: unsupported inter-compilation-unit reference");
+    }
+  else
+    *spec_cu = cu;
 
   h = (offset % REF_HASH_SIZE);
   die = die_ref_table[h];
   while (die)
     {
       if (die->offset == offset)
-	{
-	  return die;
-	}
+	return die;
       die = die->next_ref;
     }
   return NULL;


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