--- 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 +#include +#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); }