From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19524 invoked by alias); 23 Sep 2004 04:57:29 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 19503 invoked from network); 23 Sep 2004 04:57:24 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sourceware.org with SMTP; 23 Sep 2004 04:57:24 -0000 Received: from drow by nevyn.them.org with local (Exim 4.34 #1 (Debian)) id 1CALfY-00038l-AC; Thu, 23 Sep 2004 00:57:24 -0400 Date: Thu, 23 Sep 2004 04:57:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Cc: jimb@redhat.com Subject: [rfa/dwarf] Support for attributes pointing to a different CU Message-ID: <20040923045723.GA11871@nevyn.them.org> Mail-Followup-To: gdb-patches@sources.redhat.com, jimb@redhat.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.5.1+cvs20040105i X-SW-Source: 2004-09/txt/msg00362.txt.bz2 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 * 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;