}
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;
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
<< 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<read_cu_headers> ();
- 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<read_cu_headers> ();
+ 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 <cu_head>::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 <cu_head>::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))
+{
+}
#include <cassert>
#include <sstream>
+#include <algorithm>
#include "../libdw/dwarf.h"
#include "messages.h"
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",
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,
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)
struct cu *
check_debug_info::check_info_structural (struct elf_file *file,
- struct sec *sec,
Elf_Data *strings)
{
std::vector <cu_head> const &cu_headers = _m_cu_headers->cu_headers;
+ sec &sec = _m_sec_info->sect;
struct ref_record die_refs;
WIPE (die_refs);
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 <cu_head>::const_iterator it = cu_headers.begin ();
it != cu_headers.end (); ++it)
{
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))
{
}
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,
{
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 ();