--- dwarf2read.c 2004/01/09 16:38:02 1.1 +++ dwarf2read.c 2004/01/10 14:14:22 @@ -50,6 +50,9 @@ #include "gdb_assert.h" #include +#include +#include + #ifndef DWARF2_REG_TO_REGNUM #define DWARF2_REG_TO_REGNUM(REG) (REG) #endif @@ -173,6 +176,19 @@ #define ABBREV_HASH_SIZE 121 #endif +struct cu_list +{ + unsigned ncu; + struct cu_list_entry *cus; +}; + +struct cu_list_entry +{ + unsigned offset, length; + struct partial_symtab *pst; + void *deps; /* direct dependencies; organized in a tree as in tsearch() */ +}; + /* The data in a compilation unit header, after target2host translation, looks like this. */ struct comp_unit_head @@ -333,6 +349,7 @@ struct die_info *parent; /* Its parent, if any. */ struct type *type; /* Cached type information */ + unsigned cu_idx; }; /* Attributes have a name and a value */ @@ -506,6 +523,9 @@ /* Size of dwarf locations buffer for the objfile. */ unsigned int dwarf_loc_size; + + struct cu_list *cu_list; + unsigned cu_entry_idx; }; #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private) @@ -523,6 +543,8 @@ #define DWARF_RANGES_SIZE(p) (PST_PRIVATE(p)->dwarf_ranges_size) #define DWARF_LOC_BUFFER(p) (PST_PRIVATE(p)->dwarf_loc_buffer) #define DWARF_LOC_SIZE(p) (PST_PRIVATE(p)->dwarf_loc_size) +#define CU_LIST(p) (PST_PRIVATE(p)->cu_list) +#define CU_ENTRY_IDX(p) (PST_PRIVATE(p)->cu_entry_idx) /* Maintain an array of referenced fundamental types for the current compilation unit being read. For DWARF version 1, we have to construct @@ -739,6 +761,7 @@ static void set_cu_language (unsigned int); static struct attribute *dwarf_attr (struct die_info *, unsigned int); +static struct attribute *dwarf_attr0 (struct die_info *die, unsigned int name, unsigned *pcu_idx); static int die_is_declaration (struct die_info *); @@ -885,6 +908,8 @@ static unsigned int dwarf2_get_ref_die_offset (struct attribute *); +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); @@ -912,6 +937,12 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); +static int cu_dep_compare(const void *pa, const void *pb); + +static void cu_dep_destroy(void *p); + +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. */ @@ -1128,6 +1159,9 @@ /* Build the partial symbol table by doing a quick pass through the .debug_info and .debug_abbrev sections. */ +static struct cu_list *cur_cu_list; +static struct cu_list_entry *cur_cu_entry; + static void dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) { @@ -1141,6 +1175,12 @@ struct cleanup *back_to; CORE_ADDR lowpc, highpc; + static struct cu_list_entry *cus = NULL; + static unsigned cus_size = 0; + unsigned ncu, i; + struct cu_list_entry *cus_priv; + struct cu_list *cu_list_priv; + info_ptr = dwarf_info_buffer; abbrev_ptr = dwarf_abbrev_buffer; @@ -1175,6 +1215,42 @@ obstack_init (&dwarf2_tmp_obstack); back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL); + /* FIXME: should use obstack growth functions */ + ncu = 0; + while (info_ptr < dwarf_info_buffer + dwarf_info_size) + { + struct dwarf2_cu cu; + beg_of_comp_unit = info_ptr; + + cu.objfile = objfile; + info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd); + + if (ncu >= cus_size) { + if (cus_size == 0) { + cus_size = 4; + cus = (struct cu_list_entry *) xmalloc(cus_size * sizeof(struct cu_list_entry)); + } else { + cus_size = ncu * 2; + cus = (struct cu_list_entry *) xrealloc(cus, cus_size * sizeof(struct cu_list_entry)); + } + } + cus[ncu].offset = beg_of_comp_unit - dwarf_info_buffer; + cus[ncu].length = cu.header.length + cu.header.initial_length_size; + cus[ncu].pst = NULL; + cus[ncu].deps = NULL; /* FIXME: free deps after use */ + ncu++; + + info_ptr = beg_of_comp_unit + cu.header.length + + cu.header.initial_length_size; + } + info_ptr = dwarf_info_buffer; + cus_priv = obstack_alloc (&objfile->psymbol_obstack, ncu * sizeof (struct cu_list_entry)); + memcpy(cus_priv, cus, ncu * sizeof (struct cu_list_entry)); + cu_list_priv = obstack_alloc (&objfile->psymbol_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 dwarf_info_buffer vary in length, only the individual functions to extract them (like read_comp_unit_head and read_partial_die) can really know whether @@ -1188,11 +1264,13 @@ For this loop condition, simply checking whether there's any data left at all should be sufficient. */ + i = 0; while (info_ptr < dwarf_info_buffer + dwarf_info_size) { 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); @@ -1263,6 +1341,10 @@ /* 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. */ @@ -1296,6 +1378,11 @@ (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. */ @@ -1303,7 +1390,12 @@ info_ptr = beg_of_comp_unit + cu.header.length + cu.header.initial_length_size; + i++; } + + gdb_assert(i == ncu); + cur_cu_list = NULL; + cur_cu_entry = NULL; do_cleanups (back_to); } @@ -1653,7 +1745,9 @@ { if (pst->readin) { +#if 0 warning ("bug: psymtab for %s is already read in.", pst->filename); +#endif } else { @@ -1672,12 +1766,65 @@ } } +static unsigned *dep_list = NULL, dep_list_size = 0; +static unsigned dep_list_len = 0; +static void *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 void +process_subdeps (const void *p, VISIT visit, int level) +{ + unsigned idx = (unsigned) * (const void *const *) p; + + process_dep(idx); +} + +static void +process_dep (unsigned idx) +{ + struct cu_list_entry *cu_entry; + void *cur_deps; + + /* Already processed? Or being processed at a parent level due to a circular reference? */ + if (! tfind ((const void *) idx, &all_deps, cu_dep_compare)) { + if (info_verbose) printf_filtered ("* Start processing %u.\n", idx); + tsearch ((const void *) idx, &all_deps, cu_dep_compare); + cu_entry = &cur_cu_list->cus[idx]; + cur_deps = cu_entry->deps; + /* Process them if they have not been processed */ + twalk (cur_deps, process_subdeps); + dep_list_add (idx); + if (info_verbose) printf_filtered ("* Done processing %u.\n", idx); + } +} + +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; + struct die_info **die_lists; struct die_info *dies; unsigned long offset; CORE_ADDR lowpc, highpc; @@ -1687,6 +1834,33 @@ struct cleanup *back_to; struct attribute *attr; + unsigned i, idx; + + 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); + + all_deps = NULL; + dep_list_len = 0; + process_dep (idx); + tdestroy (all_deps, cu_dep_destroy); + + buildsym_init (); + make_cleanup (really_free_pendings, NULL); + + dwarf2_empty_hash_tables (); + + die_lists = obstack_alloc (&dwarf2_tmp_obstack, dep_list_len * sizeof (struct die_info *)); + + /* Pass 1: build the reference table */ + for (i = 0; i < dep_list_len; i++) { + idx = dep_list[i]; + cur_cu_idx = idx; + pst = cur_cu_list->cus[idx].pst; + + 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); dwarf_info_buffer = DWARF_INFO_BUFFER (pst); @@ -1706,11 +1881,49 @@ cu_header_offset = offset; info_ptr = dwarf_info_buffer + offset; - obstack_init (&dwarf2_tmp_obstack); - back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL); + cu.objfile = objfile; - buildsym_init (); - make_cleanup (really_free_pendings, NULL); + /* read in the comp_unit header */ + info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd); + + /* Read the abbrevs for this compilation unit */ + dwarf2_read_abbrevs (abfd, &cu); + make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs); + + die_lists[i] = read_comp_unit (info_ptr, abfd, &cu); + + make_cleanup_free_die_list (die_lists[i]); + + if (info_verbose) printf_filtered ("* Done building reference table for %u.\n", idx); + } + + /* Pass 2: do the actual work */ + for (i = 0; i < dep_list_len; i++) { + 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); + dwarf_info_buffer = DWARF_INFO_BUFFER (pst); + dwarf_abbrev_buffer = DWARF_ABBREV_BUFFER (pst); + dwarf_abbrev_size = DWARF_ABBREV_SIZE (pst); + dwarf_line_buffer = DWARF_LINE_BUFFER (pst); + dwarf_line_size = DWARF_LINE_SIZE (pst); + dwarf_str_buffer = DWARF_STR_BUFFER (pst); + dwarf_str_size = DWARF_STR_SIZE (pst); + dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst); + dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst); + dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst); + dwarf_ranges_size = DWARF_RANGES_SIZE (pst); + dwarf_loc_buffer = DWARF_LOC_BUFFER (pst); + dwarf_loc_size = DWARF_LOC_SIZE (pst); + baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile)); + + cu_header_offset = offset; + info_ptr = dwarf_info_buffer + offset; cu.objfile = objfile; @@ -1721,9 +1934,7 @@ dwarf2_read_abbrevs (abfd, &cu); make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs); - dies = read_comp_unit (info_ptr, abfd, &cu); - - make_cleanup_free_die_list (dies); + 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. @@ -1789,6 +2000,10 @@ } pst->symtab = symtab; pst->readin = 1; + if (info_verbose) printf_filtered ("* Done loading %u.\n", idx); + } + cur_cu_idx = ~0UL; + cur_cu_list = NULL; do_cleanups (back_to); } @@ -3686,8 +3901,6 @@ { /* 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); } @@ -3954,6 +4167,99 @@ /* Read a minimal amount of information into the minimal die structure. */ +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(const void *pa, const void *pb) +{ + unsigned a = (unsigned) pa, b = (unsigned) pb; + return (a > b) - (a < b); +} + +static void +cu_dep_destroy(void *p) +{ +} + +static void +add_dep(struct attribute *attr) +{ + struct cu_list_entry tmp, *ent; + unsigned idx; + + tmp.offset = dwarf2_get_ref_die_offset(attr); + 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; + /* Adds the element if it does not already exist */ + if (! tfind ((const void *) idx, &cur_cu_entry->deps, cu_dep_compare)) { + tsearch ((const void *) idx, &cur_cu_entry->deps, cu_dep_compare); + if (info_verbose) + printf_filtered ("* Added dependency %u for %u (ref offset <%x>).\n", + idx, cur_cu_entry - cur_cu_list->cus, tmp.offset); + } + } +} + +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); + break; + } + } + + return info_ptr; +} + static char * read_partial_die (struct partial_die_info *part_die, bfd *abfd, char *info_ptr, struct dwarf2_cu *cu) @@ -4041,6 +4347,8 @@ 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. */ @@ -4632,14 +4940,18 @@ 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 * -dwarf_attr (struct die_info *die, unsigned int name) +dwarf_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; /* not the final value */ for (i = 0; i < die->num_attrs; ++i) { if (die->attrs[i].name == name) @@ -4653,15 +4965,21 @@ if (spec) { struct die_info *ref_die = - follow_die_ref (dwarf2_get_ref_die_offset (spec)); + follow_die_ref (dwarf2_get_ref_die_offset_for_cu (spec, die->cu_idx)); if (ref_die) - return dwarf_attr (ref_die, name); + return dwarf_attr0 (ref_die, name, pcu_idx); } return NULL; } +static struct attribute * +dwarf_attr (struct die_info *die, unsigned int name) +{ + return dwarf_attr0(die, name, NULL); +} + static int die_is_declaration (struct die_info *die) { @@ -5475,8 +5793,9 @@ struct attribute *type_attr; struct die_info *type_die; unsigned int ref; + unsigned cu_idx; - type_attr = dwarf_attr (die, DW_AT_type); + type_attr = dwarf_attr0 (die, DW_AT_type, &cu_idx); if (!type_attr) { /* A missing DW_AT_type represents a void type. */ @@ -5484,7 +5803,7 @@ } else { - ref = dwarf2_get_ref_die_offset (type_attr); + ref = dwarf2_get_ref_die_offset_for_cu (type_attr, cu_idx); type_die = follow_die_ref (ref); if (!type_die) { @@ -5513,11 +5832,12 @@ struct attribute *type_attr; struct die_info *type_die = NULL; unsigned int ref; + unsigned cu_idx; - type_attr = dwarf_attr (die, DW_AT_containing_type); + type_attr = dwarf_attr0 (die, DW_AT_containing_type, &cu_idx); if (type_attr) { - ref = dwarf2_get_ref_die_offset (type_attr); + ref = dwarf2_get_ref_die_offset_for_cu (type_attr, cu_idx); type_die = follow_die_ref (ref); if (!type_die) { @@ -5783,12 +6103,13 @@ struct attribute *attr; struct die_info *extension_die; unsigned int ref; + unsigned cu_idx; - attr = dwarf_attr (die, DW_AT_extension); + attr = dwarf_attr0 (die, DW_AT_extension, &cu_idx); if (attr == NULL) return NULL; - ref = dwarf2_get_ref_die_offset (attr); + ref = dwarf2_get_ref_die_offset_for_cu (attr, cu_idx); extension_die = follow_die_ref (ref); if (!extension_die) { @@ -6701,7 +7022,7 @@ } static unsigned int -dwarf2_get_ref_die_offset (struct attribute *attr) +dwarf2_get_ref_die_offset0 (struct attribute *attr, unsigned base) { unsigned int result = 0; @@ -6715,7 +7036,7 @@ 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, @@ -6725,6 +7046,22 @@ return result; } +/* can only be used when one compilation unit is processed at a time + (so it cannot be used when actually loading the symbols) */ +static unsigned int +dwarf2_get_ref_die_offset (struct attribute *attr) +{ + return dwarf2_get_ref_die_offset0 (attr, cu_header_offset); +} + +/* can only be used when cur_cu_list is defined (for example, when actually loading + the symbols) */ +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); +} + static struct die_info * follow_die_ref (unsigned int offset) { @@ -7026,6 +7363,7 @@ die = (struct die_info *) xmalloc (sizeof (struct die_info)); memset (die, 0, sizeof (struct die_info)); + die->cu_idx = cur_cu_idx; return (die); }