From: Petr Machata Date: Mon, 30 Nov 2009 07:57:01 +0000 (+0100) Subject: dwarflint: Make abbrev table map const X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=79e683449614ed6c5f3ad20025c13436e4789a7e;p=thirdparty%2Felfutils.git dwarflint: Make abbrev table map const --- diff --git a/src/dwarflint/check_debug_abbrev.cc b/src/dwarflint/check_debug_abbrev.cc index 246904574..68d3f2223 100644 --- a/src/dwarflint/check_debug_abbrev.cc +++ b/src/dwarflint/check_debug_abbrev.cc @@ -52,7 +52,8 @@ abbrev_table_free (struct abbrev_table *abbr) } struct abbrev * -abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code) +abbrev_table_find_abbrev (struct abbrev_table const *abbrevs, + uint64_t abbrev_code) { size_t a = 0; size_t b = abbrevs->size; @@ -74,18 +75,6 @@ abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code) return NULL; } -bool -check_debug_abbrev::check_no_abbreviations () const -{ - bool ret = abbrevs.begin () == abbrevs.end (); - if (ret) - { - where wh = WHERE (sec_abbrev, NULL); - wr_error (&wh, ": no abbreviations.\n"); - } - return ret; -} - namespace { struct cmp_abbrev @@ -105,353 +94,376 @@ namespace << pri::attr (name) << " with invalid form " << pri::form (form) << '.' << std::endl; } -} - -check_debug_abbrev::check_debug_abbrev (dwarflint &lint) - : _m_sec_abbr (lint.check (_m_sec_abbr)) -{ - read_ctx ctx; - read_ctx_init (&ctx, _m_sec_abbr->sect.data, - _m_sec_abbr->file.other_byte_order); - - struct abbrev_table *section = NULL; - uint64_t first_attr_off = 0; - struct where where = WHERE (sec_abbrev, NULL); - - // Tolerate failure here. - read_cu_headers *cu_headers = lint.toplev_check (); - dwarf_version_h ver = NULL; - if (cu_headers == NULL) - { - wr_error (where) - << "couldn't get CU header info; assuming CUs are of latest DWARF flavor." - << std::endl; - ver = get_latest_dwarf_version (); - } - where.addr1 = 0; - - while (true) - { - /* If we get EOF at this point, either the CU was improperly - terminated, or there were no data to begin with. */ - if (read_ctx_eof (&ctx)) - { - if (!check_no_abbreviations ()) - wr_error (&where, ": missing zero to mark end-of-table.\n"); - break; - } - uint64_t abbr_off; - uint64_t abbr_code; + bool + check_no_abbreviations (check_debug_abbrev::abbrev_map const &abbrevs) + { + bool ret = abbrevs.begin () == abbrevs.end (); + if (ret) { - uint64_t prev_abbr_off = (uint64_t)-1; - uint64_t prev_abbr_code = (uint64_t)-1; - uint64_t zero_seq_off = (uint64_t)-1; + where wh = WHERE (sec_abbrev, NULL); + wr_error (&wh, ": no abbreviations.\n"); + } + return ret; + } - do - { - abbr_off = read_ctx_get_offset (&ctx); - where_reset_2 (&where, abbr_off); + check_debug_abbrev::abbrev_map + load_debug_abbrev (dwarflint &lint, + struct sec §, + elf_file &file) + { + check_debug_abbrev::abbrev_map abbrevs; - /* Abbreviation code. */ - if (!checked_read_uleb128 (&ctx, &abbr_code, &where, "abbrev code")) - throw check_base::failed (); + read_ctx ctx; + read_ctx_init (&ctx, sect.data, file.other_byte_order); - /* Note: we generally can't tell the difference between - empty table and (excessive) padding. But NUL byte(s) - at the very beginning of section are almost certainly - the first case. */ - if (zero_seq_off == (uint64_t)-1 - && abbr_code == 0 - && (prev_abbr_code == 0 - || abbrevs.empty ())) - zero_seq_off = abbr_off; - - if (abbr_code != 0) - break; - else - section = NULL; - - prev_abbr_code = abbr_code; - prev_abbr_off = abbr_off; - } - while (!read_ctx_eof (&ctx) - /* On EOF, shift the offset so that beyond-EOF - end-position is printed for padding warning. - Necessary as our end position is exclusive. */ - || ((abbr_off += 1), false)); + struct abbrev_table *section = NULL; + uint64_t first_attr_off = 0; + struct where where = WHERE (sec_abbrev, NULL); - if (zero_seq_off != (uint64_t)-1) + // Tolerate failure here. + read_cu_headers *cu_headers = lint.toplev_check (); + dwarf_version_h ver = NULL; + if (cu_headers == NULL) + { + wr_error (where) + << "couldn't load CU headers; assuming CUs are of latest DWARF flavor." + << std::endl; + ver = get_latest_dwarf_version (); + } + where.addr1 = 0; + + while (true) + { + /* If we get EOF at this point, either the CU was improperly + terminated, or there were no data to begin with. */ + if (read_ctx_eof (&ctx)) { - struct where wh = WHERE (where.section, NULL); - wr_message_padding_0 (mc_abbrevs | mc_header, - &wh, zero_seq_off, abbr_off); + if (!check_no_abbreviations (abbrevs)) + wr_error (&where, ": missing zero to mark end-of-table.\n"); + break; } - } - if (read_ctx_eof (&ctx)) + uint64_t abbr_off; + uint64_t abbr_code; { - /* It still may have been empty. */ - check_no_abbreviations (); - break; - } + uint64_t prev_abbr_off = (uint64_t)-1; + uint64_t prev_abbr_code = (uint64_t)-1; + uint64_t zero_seq_off = (uint64_t)-1; - /* OK, we got some genuine abbreviation. See if we need to - allocate a new section. */ - if (section == NULL) - { - abbrev_table t; - WIPE (t); - section = &abbrevs.insert (std::make_pair (abbr_off, t)).first->second; - section->offset = abbr_off; + do + { + abbr_off = read_ctx_get_offset (&ctx); + where_reset_2 (&where, abbr_off); + + /* Abbreviation code. */ + if (!checked_read_uleb128 (&ctx, &abbr_code, &where, "abbrev code")) + throw check_base::failed (); + + /* Note: we generally can't tell the difference between + empty table and (excessive) padding. But NUL byte(s) + at the very beginning of section are almost certainly + the first case. */ + if (zero_seq_off == (uint64_t)-1 + && abbr_code == 0 + && (prev_abbr_code == 0 + || abbrevs.empty ())) + zero_seq_off = abbr_off; + + if (abbr_code != 0) + break; + else + section = NULL; - where_reset_1 (&where, abbr_off); - where_reset_2 (&where, abbr_off); + prev_abbr_code = abbr_code; + prev_abbr_off = abbr_off; + } + while (!read_ctx_eof (&ctx) + /* On EOF, shift the offset so that beyond-EOF + end-position is printed for padding warning. + Necessary as our end position is exclusive. */ + || ((abbr_off += 1), false)); - // Find CU that uses this abbrev table, so that we know what - // version to validate against. - if (cu_headers != NULL) + if (zero_seq_off != (uint64_t)-1) { - ver = NULL; - cu_head const *other_head = NULL; - for (std::vector ::const_iterator it - = cu_headers->cu_headers.begin (); - it != cu_headers->cu_headers.end (); ++it) - if (it->abbrev_offset == abbr_off) - { - section->used = true; - dwarf_version_h nver = get_dwarf_version (it->version); - if (ver == NULL) - ver = nver; - else if (nver != ver) - { - wr_error (it->where) - << " and " << other_head->where << " both use " - << where << ", but each has a different version (" - << it->version << " vs. " << other_head->version - << ")." << std::endl; - - // Arbitrarily pick newer version. - if (it->version > other_head->version) - ver = nver; - } - - other_head = &*it; - } - - if (ver == NULL) - { - // This is hard error, we can't validate abbrev - // table without knowing what version to use. - wr_error (where) - << "abbreviation table is never used." << std::endl; - ver = get_latest_dwarf_version (); - } + struct where wh = WHERE (where.section, NULL); + wr_message_padding_0 (mc_abbrevs | mc_header, + &wh, zero_seq_off, abbr_off); } - assert (ver != NULL); } - struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code); - if (unlikely (original != NULL)) - wr_error (where) - << "duplicate abbrev code " << abbr_code - << "; already defined at " << original->where << '.' << std::endl; + if (read_ctx_eof (&ctx)) + { + /* It still may have been empty. */ + check_no_abbreviations (abbrevs); + break; + } - struct abbrev fake; - struct abbrev *cur; - /* Don't actually save this abbrev if it's duplicate. */ - if (likely (original == NULL)) - { - REALLOC (section, abbr); - cur = section->abbr + section->size++; - } - else - cur = &fake; - WIPE (*cur); + /* OK, we got some genuine abbreviation. See if we need to + allocate a new section. */ + if (section == NULL) + { + abbrev_table t; + WIPE (t); + section = &abbrevs.insert (std::make_pair (abbr_off, t)).first->second; + section->offset = abbr_off; - cur->code = abbr_code; - cur->where = where; + where_reset_1 (&where, abbr_off); + where_reset_2 (&where, abbr_off); - /* Abbreviation tag. */ - uint64_t abbr_tag; - if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag")) - throw check_base::failed (); + // Find CU that uses this abbrev table, so that we know what + // version to validate against. + if (cu_headers != NULL) + { + ver = NULL; + cu_head const *other_head = NULL; + for (std::vector ::const_iterator it + = cu_headers->cu_headers.begin (); + it != cu_headers->cu_headers.end (); ++it) + if (it->abbrev_offset == abbr_off) + { + section->used = true; + dwarf_version_h nver = get_dwarf_version (it->version); + if (ver == NULL) + ver = nver; + else if (nver != ver) + { + wr_error (it->where) + << " and " << other_head->where << " both use " + << where << ", but each has a different version (" + << it->version << " vs. " << other_head->version + << ")." << std::endl; + + // Arbitrarily pick newer version. + if (it->version > other_head->version) + ver = nver; + } + + other_head = &*it; + } + + if (ver == NULL) + { + // This is hard error, we can't validate abbrev + // table without knowing what version to use. + wr_error (where) + << "abbreviation table is never used." << std::endl; + ver = get_latest_dwarf_version (); + } + } + assert (ver != NULL); + } - if (abbr_tag > DW_TAG_hi_user) - { + struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code); + if (unlikely (original != NULL)) wr_error (where) - << "invalid abbrev tag " << pri::hex (abbr_tag) - << '.' << std::endl; - throw check_base::failed (); - } - cur->tag = (typeof (cur->tag))abbr_tag; + << "duplicate abbrev code " << abbr_code + << "; already defined at " << original->where << '.' << std::endl; - /* Abbreviation has_children. */ - uint8_t has_children; - if (!read_ctx_read_ubyte (&ctx, &has_children)) - { - wr_error (&where, ": can't read abbrev has_children.\n"); - throw check_base::failed (); - } + struct abbrev fake; + struct abbrev *cur; + /* Don't actually save this abbrev if it's duplicate. */ + if (likely (original == NULL)) + { + REALLOC (section, abbr); + cur = section->abbr + section->size++; + } + else + cur = &fake; + WIPE (*cur); - if (has_children != DW_CHILDREN_no - && has_children != DW_CHILDREN_yes) - { - wr_error (where) - << "invalid has_children value " << pri::hex (cur->has_children) - << '.' << std::endl; + cur->code = abbr_code; + cur->where = where; + + /* Abbreviation tag. */ + uint64_t abbr_tag; + if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag")) throw check_base::failed (); - } - cur->has_children = has_children == DW_CHILDREN_yes; - - bool null_attrib; - uint64_t sibling_attr = 0; - bool low_pc = false; - bool high_pc = false; - bool ranges = false; - do - { - uint64_t attr_off = read_ctx_get_offset (&ctx); - uint64_t attrib_name, attrib_form; - if (first_attr_off == 0) - first_attr_off = attr_off; - /* Shift to match elfutils reporting. */ - where_reset_3 (&where, attr_off - first_attr_off); - - /* Load attribute name and form. */ - if (!checked_read_uleb128 (&ctx, &attrib_name, &where, - "attribute name")) + + if (abbr_tag > DW_TAG_hi_user) + { + wr_error (where) + << "invalid abbrev tag " << pri::hex (abbr_tag) + << '.' << std::endl; throw check_base::failed (); + } + cur->tag = (typeof (cur->tag))abbr_tag; - if (!checked_read_uleb128 (&ctx, &attrib_form, &where, - "attribute form")) + /* Abbreviation has_children. */ + uint8_t has_children; + if (!read_ctx_read_ubyte (&ctx, &has_children)) + { + wr_error (&where, ": can't read abbrev has_children.\n"); throw check_base::failed (); + } - null_attrib = attrib_name == 0 && attrib_form == 0; + if (has_children != DW_CHILDREN_no + && has_children != DW_CHILDREN_yes) + { + wr_error (where) + << "invalid has_children value " << pri::hex (cur->has_children) + << '.' << std::endl; + throw check_base::failed (); + } + cur->has_children = has_children == DW_CHILDREN_yes; - /* Now if both are zero, this was the last attribute. */ - if (!null_attrib) - { - /* Otherwise validate name and form. */ - if (attrib_name > DW_AT_hi_user) - { - wr_error (where) - << "invalid name " << pri::hex (attrib_name) - << '.' << std::endl; - throw check_base::failed (); - } + bool null_attrib; + uint64_t sibling_attr = 0; + bool low_pc = false; + bool high_pc = false; + bool ranges = false; + do + { + uint64_t attr_off = read_ctx_get_offset (&ctx); + uint64_t attrib_name, attrib_form; + if (first_attr_off == 0) + first_attr_off = attr_off; + /* Shift to match elfutils reporting. */ + where_reset_3 (&where, attr_off - first_attr_off); + + /* Load attribute name and form. */ + if (!checked_read_uleb128 (&ctx, &attrib_name, &where, + "attribute name")) + throw check_base::failed (); - if (!ver->form_allowed (attrib_form)) - { - wr_error (where) - << "invalid form " << pri::hex (attrib_form) - << '.' << std::endl; - throw check_base::failed (); - } - } + if (!checked_read_uleb128 (&ctx, &attrib_form, &where, + "attribute form")) + throw check_base::failed (); - REALLOC (cur, attribs); + null_attrib = attrib_name == 0 && attrib_form == 0; - struct abbrev_attrib *acur = cur->attribs + cur->size++; - WIPE (*acur); + /* Now if both are zero, this was the last attribute. */ + if (!null_attrib) + { + /* Otherwise validate name and form. */ + if (attrib_name > DW_AT_hi_user) + { + wr_error (where) + << "invalid name " << pri::hex (attrib_name) + << '.' << std::endl; + throw check_base::failed (); + } - /* We do structural checking of sibling attribute, so make - sure our assumptions in actual DIE-loading code are - right. We expect at most one DW_AT_sibling attribute, - with form from reference class, but only CU-local, not - DW_FORM_ref_addr. */ - if (attrib_name == DW_AT_sibling) - { - if (sibling_attr != 0) - wr_error (where) - << "another DW_AT_sibling attribute in one abbreviation " - << "(first was " << pri::hex (sibling_attr) << ")." - << std::endl; - else - { - assert (attr_off > 0); - sibling_attr = attr_off; - - if (!cur->has_children) - wr_message (where, - cat (mc_die_rel, mc_acc_bloat, mc_impact_1)) - << "excessive DW_AT_sibling attribute at childless abbrev." - << std::endl; - } + if (!ver->form_allowed (attrib_form)) + { + wr_error (where) + << "invalid form " << pri::hex (attrib_form) + << '.' << std::endl; + throw check_base::failed (); + } + } - switch (check_sibling_form (ver, attrib_form)) - { - case -1: - wr_message (where, cat (mc_die_rel, mc_impact_2)) - << "DW_AT_sibling attribute with form DW_FORM_ref_addr." - << std::endl; - break; + REALLOC (cur, attribs); + + struct abbrev_attrib *acur = cur->attribs + cur->size++; + WIPE (*acur); - case -2: + /* We do structural checking of sibling attribute, so make + sure our assumptions in actual DIE-loading code are + right. We expect at most one DW_AT_sibling attribute, + with form from reference class, but only CU-local, not + DW_FORM_ref_addr. */ + if (attrib_name == DW_AT_sibling) + { + if (sibling_attr != 0) wr_error (where) - << "DW_AT_sibling attribute with non-reference form " - << pri::form (attrib_form) << '.' << std::endl; - }; - } - /* Similar for DW_AT_location and friends. */ - else if (is_location_attrib (attrib_name)) - { - if (!dwver_form_allowed (ver, attrib_name, attrib_form)) - complain_invalid_form (where, attrib_name, attrib_form, - "location attribute"); - } - /* Similar for DW_AT_ranges. */ - else if (attrib_name == DW_AT_ranges - || attrib_name == DW_AT_stmt_list) - { - if (attrib_form != DW_FORM_data4 - && attrib_form != DW_FORM_data8 - && attrib_form != DW_FORM_sec_offset - && attrib_form != DW_FORM_indirect) - complain_invalid_form (where, attrib_name, attrib_form); - if (attrib_name == DW_AT_ranges) - ranges = true; - } - /* Similar for DW_AT_{low,high}_pc, plus also make sure we - don't see high_pc without low_pc. */ - else if (attrib_name == DW_AT_low_pc - || attrib_name == DW_AT_high_pc) - { - if (attrib_form != DW_FORM_addr - && attrib_form != DW_FORM_ref_addr) - complain_invalid_form (where, attrib_name, attrib_form); - - if (attrib_name == DW_AT_low_pc) - low_pc = true; - else if (attrib_name == DW_AT_high_pc) - high_pc = true; - } + << "another DW_AT_sibling attribute in one abbreviation " + << "(first was " << pri::hex (sibling_attr) << ")." + << std::endl; + else + { + assert (attr_off > 0); + sibling_attr = attr_off; + + if (!cur->has_children) + wr_message (where, + cat (mc_die_rel, mc_acc_bloat, mc_impact_1)) + << "excessive DW_AT_sibling attribute at childless abbrev." + << std::endl; + } - acur->name = attrib_name; - acur->form = attrib_form; - acur->where = where; - } - while (!null_attrib); + switch (check_sibling_form (ver, attrib_form)) + { + case -1: + wr_message (where, cat (mc_die_rel, mc_impact_2)) + << "DW_AT_sibling attribute with form DW_FORM_ref_addr." + << std::endl; + break; + + case -2: + wr_error (where) + << "DW_AT_sibling attribute with non-reference form " + << pri::form (attrib_form) << '.' << std::endl; + }; + } + /* Similar for DW_AT_location and friends. */ + else if (is_location_attrib (attrib_name)) + { + if (!dwver_form_allowed (ver, attrib_name, attrib_form)) + complain_invalid_form (where, attrib_name, attrib_form, + "location attribute"); + } + /* Similar for DW_AT_ranges. */ + else if (attrib_name == DW_AT_ranges + || attrib_name == DW_AT_stmt_list) + { + if (attrib_form != DW_FORM_data4 + && attrib_form != DW_FORM_data8 + && attrib_form != DW_FORM_sec_offset + && attrib_form != DW_FORM_indirect) + complain_invalid_form (where, attrib_name, attrib_form); + if (attrib_name == DW_AT_ranges) + ranges = true; + } + /* Similar for DW_AT_{low,high}_pc, plus also make sure we + don't see high_pc without low_pc. */ + else if (attrib_name == DW_AT_low_pc + || attrib_name == DW_AT_high_pc) + { + if (attrib_form != DW_FORM_addr + && attrib_form != DW_FORM_ref_addr) + complain_invalid_form (where, attrib_name, attrib_form); + + if (attrib_name == DW_AT_low_pc) + low_pc = true; + else if (attrib_name == DW_AT_high_pc) + high_pc = true; + } + + acur->name = attrib_name; + acur->form = attrib_form; + acur->where = where; + } + while (!null_attrib); - where_reset_2 (&where, where.addr2); // drop addr 3 - if (high_pc && !low_pc) - wr_error (where) - << "the abbrev has DW_AT_high_pc without also having DW_AT_low_pc." - << std::endl; - else if (high_pc && ranges) - wr_error (where) - << "the abbrev has DW_AT_high_pc & DW_AT_low_pc, " - << "but also has DW_AT_ranges." << std::endl; - } + where_reset_2 (&where, where.addr2); // drop addr 3 + if (high_pc && !low_pc) + wr_error (where) + << "the abbrev has DW_AT_high_pc without also having DW_AT_low_pc." + << std::endl; + else if (high_pc && ranges) + wr_error (where) + << "the abbrev has DW_AT_high_pc & DW_AT_low_pc, " + << "but also has DW_AT_ranges." << std::endl; + } - abbrev_table *last = NULL; - for (abbrev_map::iterator it = abbrevs.begin (); it != abbrevs.end (); ++it) - { - std::sort (it->second.abbr, it->second.abbr + it->second.size, - cmp_abbrev ()); - if (last != NULL) - last->next = &it->second; - last = &it->second; - } + abbrev_table *last = NULL; + for (check_debug_abbrev::abbrev_map::iterator it = abbrevs.begin (); + it != abbrevs.end (); ++it) + { + std::sort (it->second.abbr, it->second.abbr + it->second.size, + cmp_abbrev ()); + if (last != NULL) + last->next = &it->second; + last = &it->second; + } + + return abbrevs; + } } +check_debug_abbrev::check_debug_abbrev (dwarflint &lint) + : _m_sec_abbr (lint.check (_m_sec_abbr)) + , abbrevs (load_debug_abbrev (lint, _m_sec_abbr->sect, _m_sec_abbr->file)) +{ +} diff --git a/src/dwarflint/check_debug_info.cc b/src/dwarflint/check_debug_info.cc index dda8b5a13..f4b12237c 100644 --- a/src/dwarflint/check_debug_info.cc +++ b/src/dwarflint/check_debug_info.cc @@ -35,6 +35,7 @@ #include #include +#include #include "../libdw/dwarf.h" #include "messages.h" @@ -96,8 +97,8 @@ namespace else if (ref_cu == it) /* This is technically not a problem, so long as the reference is valid, which it is. But warn about this - anyway, perhaps local reference could be formed on fewer - number of bytes. */ + anyway, perhaps local reference could be formed on + smaller number of bytes. */ wr_message (mc_impact_2 | mc_acc_suboptimal | mc_die_rel, &ref->who, ": local reference to " PRI_DIE " formed as global.\n", @@ -426,7 +427,7 @@ namespace struct elf_file *file, struct read_ctx *ctx, struct cu *cu, - struct abbrev_table *abbrevs, + struct abbrev_table const *abbrevs, Elf_Data *strings, struct ref_record *local_die_refs, struct coverage *strings_coverage, @@ -954,55 +955,56 @@ namespace return got_die ? 1 : 0; } +} - bool - check_cu_structural (struct elf_file *file, - struct read_ctx *ctx, - struct cu *const cu, - check_debug_abbrev::abbrev_map &abbrev_tables, - Elf_Data *strings, - struct coverage *strings_coverage, - struct relocation_data *reloc, - struct cu_coverage *cu_coverage) - { - if (dump_die_offsets) - fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL)); - bool retval = true; +bool +check_debug_info::check_cu_structural (struct elf_file *file, + struct read_ctx *ctx, + struct cu *const cu, + Elf_Data *strings, + struct coverage *strings_coverage, + struct relocation_data *reloc, + struct cu_coverage *cu_coverage) +{ + check_debug_abbrev::abbrev_map const &abbrev_tables = _m_abbrevs->abbrevs; - dwarf_version_h ver = get_dwarf_version (cu->head->version); - assert (ver != NULL); + if (dump_die_offsets) + fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL)); + bool retval = true; - /* Look up Abbrev table for this CU. */ - check_debug_abbrev::abbrev_map::iterator abbrev_it - = abbrev_tables.find (cu->head->abbrev_offset); - if (abbrev_it == abbrev_tables.end ()) - { - wr_error (cu->head->where) - << "couldn't find abbrev section with offset " - << pri::addr (cu->head->abbrev_offset) << '.' << std::endl; - return false; - } - struct abbrev_table &abbrevs = abbrev_it->second; + dwarf_version_h ver = get_dwarf_version (cu->head->version); + assert (ver != NULL); + + /* Look up Abbrev table for this CU. */ + check_debug_abbrev::abbrev_map::const_iterator abbrev_it + = abbrev_tables.find (cu->head->abbrev_offset); + if (abbrev_it == abbrev_tables.end ()) + { + wr_error (cu->head->where) + << "couldn't find abbrev section with offset " + << pri::addr (cu->head->abbrev_offset) << '.' << std::endl; + return false; + } + struct abbrev_table const &abbrevs = abbrev_it->second; - /* Read DIEs. */ - struct ref_record local_die_refs; - WIPE (local_die_refs); + /* Read DIEs. */ + struct ref_record local_die_refs; + WIPE (local_die_refs); - cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset; - if (read_die_chain (ver, file, ctx, cu, &abbrevs, strings, - &local_die_refs, strings_coverage, - (reloc != NULL && reloc->size > 0) ? reloc : NULL, - cu_coverage) < 0) - { - abbrevs.skip_check = true; - retval = false; - } - else if (!check_die_references (cu, &local_die_refs)) + cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset; + if (read_die_chain (ver, file, ctx, cu, &abbrevs, strings, + &local_die_refs, strings_coverage, + (reloc != NULL && reloc->size > 0) ? reloc : NULL, + cu_coverage) < 0) + { + _m_abbr_skip.push_back (abbrevs.offset); retval = false; + } + else if (!check_die_references (cu, &local_die_refs)) + retval = false; - ref_record_free (&local_die_refs); - return retval; - } + ref_record_free (&local_die_refs); + return retval; } read_cu_headers::read_cu_headers (dwarflint &lint) @@ -1015,10 +1017,10 @@ read_cu_headers::read_cu_headers (dwarflint &lint) struct cu * check_debug_info::check_info_structural (struct elf_file *file, - struct sec *sec, Elf_Data *strings) { std::vector const &cu_headers = _m_cu_headers->cu_headers; + sec &sec = _m_sec_info->sect; struct ref_record die_refs; WIPE (die_refs); @@ -1032,12 +1034,12 @@ check_debug_info::check_info_structural (struct elf_file *file, strings_coverage = &strings_coverage_mem; } - struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL; + struct relocation_data *reloc = sec.rel.size > 0 ? &sec.rel : NULL; if (reloc != NULL) relocation_reset (reloc); struct read_ctx ctx; - read_ctx_init (&ctx, sec->data, file->other_byte_order); + read_ctx_init (&ctx, sec.data, file->other_byte_order); for (std::vector ::const_iterator it = cu_headers.begin (); it != cu_headers.end (); ++it) { @@ -1058,7 +1060,7 @@ check_debug_info::check_info_structural (struct elf_file *file, read_ctx_init_sub (&cu_ctx, &ctx, ctx.ptr, cu_end); cu_ctx.ptr += head.head_size; - if (!check_cu_structural (file, &cu_ctx, cur, _m_abbrevs->abbrevs, + if (!check_cu_structural (file, &cu_ctx, cur, strings, strings_coverage, reloc, &cu_cov)) { @@ -1091,14 +1093,16 @@ check_debug_info::check_info_structural (struct elf_file *file, } else /* Did we consume all the relocations? */ - relocation_skip_rest (&sec->rel, sec->id); + relocation_skip_rest (&sec.rel, sec.id); /* If we managed to read up everything, now do abbrev usage analysis. */ for (check_debug_abbrev::abbrev_map::const_iterator it = _m_abbrevs->abbrevs.begin (); it != _m_abbrevs->abbrevs.end (); ++it) - if (it->second.used && !it->second.skip_check) + if (it->second.used + && std::find (_m_abbr_skip.begin (), _m_abbr_skip.end (), + it->first) == _m_abbr_skip.end ()) for (size_t i = 0; i < it->second.size; ++i) if (!it->second.abbr[i].used) wr_message (it->second.abbr[i].where, @@ -1156,8 +1160,7 @@ check_debug_info::check_debug_info (dwarflint &lint) { memset (&cu_cov, 0, sizeof (cu_cov)); - cu *chain = check_info_structural (&_m_sec_info->file, &_m_sec_info->sect, - _m_sec_str->sect.data); + cu *chain = check_info_structural (&_m_sec_info->file, _m_sec_str->sect.data); if (chain == NULL) throw check_base::failed (); diff --git a/src/dwarflint/checks-low.hh b/src/dwarflint/checks-low.hh index b6905d14d..87690b03e 100644 --- a/src/dwarflint/checks-low.hh +++ b/src/dwarflint/checks-low.hh @@ -81,14 +81,12 @@ class check_debug_abbrev { section *_m_sec_abbr; - bool check_no_abbreviations () const; - public: - explicit check_debug_abbrev (dwarflint &lint); - // offset -> abbreviations typedef std::map< ::Dwarf_Off, abbrev_table> abbrev_map; - abbrev_map abbrevs; + abbrev_map const abbrevs; + + explicit check_debug_abbrev (dwarflint &lint); }; static reg reg_debug_abbrev; @@ -101,8 +99,19 @@ class check_debug_info check_debug_abbrev *_m_abbrevs; read_cu_headers *_m_cu_headers; + // Abbreviation table with that offset had user(s) that failed + // validation. Check for unused abbrevs should be skipped. + std::vector< ::Dwarf_Off> _m_abbr_skip; + + bool check_cu_structural (struct elf_file *file, + struct read_ctx *ctx, + struct cu *const cu, + Elf_Data *strings, + struct coverage *strings_coverage, + struct relocation_data *reloc, + struct cu_coverage *cu_coverage); + struct cu *check_info_structural (elf_file *file, - struct sec *sec, Elf_Data *strings); public: diff --git a/src/dwarflint/low.h b/src/dwarflint/low.h index ee345aa6d..98612a879 100644 --- a/src/dwarflint/low.h +++ b/src/dwarflint/low.h @@ -88,14 +88,11 @@ extern "C" size_t size; size_t alloc; bool used; /* There are CUs using this table. */ - bool skip_check; /* There were errors during loading one of the - CUs that use this table. Check for unused - abbrevs should be skipped. */ }; // xxx some of that will go away extern void abbrev_table_free (struct abbrev_table *abbr); - extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table *abbrevs, + extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table const *abbrevs, uint64_t abbrev_code); extern bool read_rel (struct elf_file *file, struct sec *sec, Elf_Data *reldata, bool elf_64);