check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
: _m_sec_abbr (lint.check (_m_sec_abbr))
{
- // xxx Hmm, we need to know a dwarf version to consider which
- // attributes are legal for DW_AT_sibling. But there's no way to
- // get it, we need to parse abbrevs first to parse info. We could
- // peek to info to get CU version/table offset mapping though, but
- // for the time being, just take version 2.
- dwarf_version_h ver = get_dwarf_version (2);
-
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)
where_reset_1 (&where, abbr_off);
where_reset_2 (&where, abbr_off);
+
+ // 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);
}
struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code);
std::vector <cu_head> ret;
while (!read_ctx_eof (&ctx))
{
- std::cout << "head " << read_ctx_get_offset (&ctx)
- << ' ' << pri::hex (read_ctx_get_offset (&ctx)) << std::endl;
const unsigned char *cu_begin = ctx.ptr;
struct where where = WHERE (sec_info, NULL);
where_reset_1 (&where, read_ctx_get_offset (&ctx));
return false;
}
- abbrevs->used = true;
-
/* Read DIEs. */
struct ref_record local_die_refs;
WIPE (local_die_refs);
struct sec *sec,
struct abbrev_table *abbrev_chain,
Elf_Data *strings,
- struct cu_coverage *cu_coverage)
+ struct cu_coverage *cu_coverage,
+ std::vector <cu_head> const &cu_headers)
{
struct ref_record die_refs;
WIPE (die_refs);
}
struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
- // xxx temporary static xxx
- static std::vector <cu_head> cu_headers = read_info_headers (file, sec, reloc);
if (reloc != NULL)
relocation_reset (reloc);
it != cu_headers.end (); ++it)
{
cu_head const &head = *it;
- std::cout << "read " << pri::hex (head.offset) << std::endl;
where const &where = head.where;
struct cu *cur = (cu *)xcalloc (1, sizeof (*cur));
cur->head = &head;
analysis. */
for (struct abbrev_table *abbrevs = abbrev_chain;
abbrevs != NULL; abbrevs = abbrevs->next)
- {
- if (!abbrevs->used)
- {
- struct where wh = WHERE (sec_abbrev, NULL);
- where_reset_1 (&wh, abbrevs->offset);
- wr_message (mc_impact_4 | mc_acc_bloat | mc_abbrevs, &wh,
- ": abbreviation table is never used.\n");
- }
- else if (!abbrevs->skip_check)
- for (size_t i = 0; i < abbrevs->size; ++i)
- if (!abbrevs->abbr[i].used)
- wr_message (mc_impact_3 | mc_acc_bloat | mc_abbrevs,
- &abbrevs->abbr[i].where,
- ": abbreviation is never used.\n");
- }
+ if (abbrevs->used && !abbrevs->skip_check)
+ for (size_t i = 0; i < abbrevs->size; ++i)
+ if (!abbrevs->abbr[i].used)
+ wr_message (mc_impact_3 | mc_acc_bloat | mc_abbrevs,
+ &abbrevs->abbr[i].where,
+ ": abbreviation is never used.\n");
}
}
}
+read_cu_headers::read_cu_headers (dwarflint &lint)
+ : _m_sec_info (lint.check (_m_sec_info))
+ , cu_headers (read_info_headers (&_m_sec_info->file,
+ &_m_sec_info->sect,
+ _m_sec_info->reldata ()))
+{
+}
+
check_debug_info::check_debug_info (dwarflint &lint)
: _m_sec_info (lint.check (_m_sec_info))
, _m_sec_abbrev (lint.check (_m_sec_abbrev))
, _m_sec_str (lint.check (_m_sec_str))
, _m_abbrevs (lint.check (_m_abbrevs))
+ , _m_cu_headers (lint.check (_m_cu_headers))
{
memset (&cu_cov, 0, sizeof (cu_cov));
- /* xxx wrap C routine before proper loading is in place. */
cu *chain = check_info_structural
(&_m_sec_info->file, &_m_sec_info->sect,
&_m_abbrevs->abbrevs.begin ()->second,
- _m_sec_str->sect.data, &cu_cov);
+ _m_sec_str->sect.data, &cu_cov,
+ _m_cu_headers->cu_headers);
if (chain == NULL)
throw check_base::failed ();
sec §
elf_file &file;
section_base (dwarflint &lint, section_id secid);
+
+ relocation_data *reldata () const
+ {
+ return sect.rel.size > 0 ? §.rel : NULL;
+ }
};
template<section_id sec_id>
{}
};
+/** The pass for reading basic .debug_info data -- the layout of
+ sections and their headers. */
+class read_cu_headers
+ : public check<read_cu_headers>
+{
+ section<sec_info> *_m_sec_info;
+
+public:
+ std::vector<cu_head> const cu_headers;
+ explicit read_cu_headers (dwarflint &lint);
+};
+
class check_debug_abbrev
: public check<check_debug_abbrev>
{
section<sec_abbrev> *_m_sec_abbr;
+
bool check_no_abbreviations () const;
public:
section<sec_abbrev> *_m_sec_abbrev;
section<sec_str> *_m_sec_str;
check_debug_abbrev *_m_abbrevs;
+ read_cu_headers *_m_cu_headers;
public:
// The check pass adds all low_pc/high_pc ranges loaded from DIE