gdb/ 2014-10-01 Jan Kratochvil Fix 100x slowdown regression on DWZ files. * dwarf2read.c (struct dwarf2_per_objfile): Add lineinfo_hash. (struct dwarf2_lineinfo, dwarf2_lineinfo_hash, dwarf2_lineinfo_eq): New. (struct dwarf2_cu): Add lineinfo. (handle_DW_AT_stmt_list): Use dwarf2_per_objfile->lineinfo_hash, set cu->lineinfo. (new_symbol_full): Use cu->lineinfo. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 9d0ee13..b24c133 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -309,8 +309,51 @@ struct dwarf2_per_objfile /* The CUs we recently read. */ VEC (dwarf2_per_cu_ptr) *just_read_cus; + + /* Table containing struct dwarf2_lineinfo. */ + htab_t lineinfo_hash; +}; + +/* Table mapping .debug_line offsets to any symtab where they are + instantiated. */ + +struct dwarf2_lineinfo +{ + /* Offset of line number information in .debug_line section. */ + sect_offset offset; + unsigned offset_in_dwz : 1; + + /* Number of entries in file_to_symtab array. */ + unsigned file_to_symtab_count; + + /* struct is sized to contain FILE_TO_SYMTAB_COUNT elements of this array. + Map each DW_AT_decl_file entry to any instantiation of matching symtab. + This array is numbered from zero, DW_AT_decl_file is numbered from one. */ + struct symtab *file_to_symtab[1]; }; +/* Hash function for a dwarf2_lineinfo. */ + +static hashval_t +dwarf2_lineinfo_hash (const void *item) +{ + const struct dwarf2_lineinfo *ofs = item; + + return ofs->offset.sect_off ^ ofs->offset_in_dwz; +} + +/* Equality function for a dwarf2_lineinfo. */ + +static int +dwarf2_lineinfo_eq (const void *item_lhs, const void *item_rhs) +{ + const struct dwarf2_lineinfo *ofs_lhs = item_lhs; + const struct dwarf2_lineinfo *ofs_rhs = item_rhs; + + return (ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off + && ofs_lhs->offset_in_dwz == ofs_rhs->offset_in_dwz); +} + static struct dwarf2_per_objfile *dwarf2_per_objfile; /* Default names of the debugging sections. */ @@ -489,6 +532,10 @@ struct dwarf2_cu /* Header data from the line table, during full symbol processing. */ struct line_header *line_header; + /* Table mapping .debug_line offsets to any symtab where they are + instantiated. It contains subset of LINE_HEADER information. */ + struct dwarf2_lineinfo *lineinfo; + /* A list of methods which need to have physnames computed after all type information has been read. */ VEC (delayed_method_info) *method_list; @@ -8975,24 +9022,61 @@ static void handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu, const char *comp_dir, CORE_ADDR lowpc) /* ARI: editCase function */ { + struct objfile *objfile = dwarf2_per_objfile->objfile; struct attribute *attr; + unsigned int line_offset; + struct dwarf2_lineinfo lineinfo; + struct line_header *line_header; + unsigned u; + void **slot; gdb_assert (! cu->per_cu->is_debug_types); attr = dwarf2_attr (die, DW_AT_stmt_list, cu); - if (attr) + if (attr == NULL) + return; + + line_offset = DW_UNSND (attr); + + if (dwarf2_per_objfile->lineinfo_hash == NULL) { - unsigned int line_offset = DW_UNSND (attr); - struct line_header *line_header - = dwarf_decode_line_header (line_offset, cu); + dwarf2_per_objfile->lineinfo_hash = + htab_create_alloc_ex (127, dwarf2_lineinfo_hash, dwarf2_lineinfo_eq, + NULL, &objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); + } - if (line_header) - { - cu->line_header = line_header; - make_cleanup (free_cu_line_header, cu); - dwarf_decode_lines (line_header, comp_dir, cu, NULL, lowpc); - } + lineinfo.offset.sect_off = line_offset; + lineinfo.offset_in_dwz = cu->per_cu->is_dwz; + slot = htab_find_slot (dwarf2_per_objfile->lineinfo_hash, &lineinfo, INSERT); + + /* For DW_TAG_compile_unit we need info like symtab::linetable which + is not present in *SLOT. */ + if (die->tag == DW_TAG_partial_unit && *slot != NULL) + { + cu->lineinfo = *slot; + return; } + + line_header = dwarf_decode_line_header (line_offset, cu); + if (line_header == NULL) + return; + cu->line_header = line_header; + make_cleanup (free_cu_line_header, cu); + dwarf_decode_lines (line_header, comp_dir, cu, NULL, lowpc); + + cu->lineinfo = obstack_alloc (&objfile->objfile_obstack, + (sizeof (*cu->lineinfo) + + (sizeof (*cu->lineinfo->file_to_symtab) + * (line_header->num_file_names - 1)))); + cu->lineinfo->offset.sect_off = line_offset; + cu->lineinfo->offset_in_dwz = cu->per_cu->is_dwz; + cu->lineinfo->file_to_symtab_count = line_header->num_file_names; + for (u = 0; u < cu->lineinfo->file_to_symtab_count; u++) + cu->lineinfo->file_to_symtab[u] = line_header->file_names[u].symtab; + if (*slot == NULL) + *slot = cu->lineinfo; } /* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */ @@ -17870,17 +17954,12 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, { int file_index = DW_UNSND (attr); - if (cu->line_header == NULL - || file_index > cu->line_header->num_file_names) + if (cu->lineinfo == NULL + || file_index > cu->lineinfo->file_to_symtab_count) complaint (&symfile_complaints, _("file index out of range")); else if (file_index > 0) - { - struct file_entry *fe; - - fe = &cu->line_header->file_names[file_index - 1]; - SYMBOL_SYMTAB (sym) = fe->symtab; - } + SYMBOL_SYMTAB (sym) = cu->lineinfo->file_to_symtab[file_index - 1]; } switch (die->tag)