From: Petr Machata Date: Fri, 20 Nov 2009 19:39:49 +0000 (+0100) Subject: dwarflint: Extract CU header loading into pass of its own X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0b0d5e1803497e699d9a4991f6ec9a8ed63ddb32;p=thirdparty%2Felfutils.git dwarflint: Extract CU header loading into pass of its own * Use separately loaded CU headers to select a DWARF version to validate abbreviation table against. --- diff --git a/src/dwarflint/check_debug_abbrev.cc b/src/dwarflint/check_debug_abbrev.cc index f72b39d63..246904574 100644 --- a/src/dwarflint/check_debug_abbrev.cc +++ b/src/dwarflint/check_debug_abbrev.cc @@ -110,13 +110,6 @@ namespace 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); @@ -124,6 +117,17 @@ check_debug_abbrev::check_debug_abbrev (dwarflint &lint) 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) @@ -203,6 +207,48 @@ check_debug_abbrev::check_debug_abbrev (dwarflint &lint) 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 ::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); diff --git a/src/dwarflint/check_debug_info.cc b/src/dwarflint/check_debug_info.cc index 2870d7444..85b927b6f 100644 --- a/src/dwarflint/check_debug_info.cc +++ b/src/dwarflint/check_debug_info.cc @@ -115,8 +115,6 @@ namespace std::vector 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)); @@ -257,8 +255,6 @@ namespace return false; } - abbrevs->used = true; - /* Read DIEs. */ struct ref_record local_die_refs; WIPE (local_die_refs); @@ -284,7 +280,8 @@ namespace struct sec *sec, struct abbrev_table *abbrev_chain, Elf_Data *strings, - struct cu_coverage *cu_coverage) + struct cu_coverage *cu_coverage, + std::vector const &cu_headers) { struct ref_record die_refs; WIPE (die_refs); @@ -300,8 +297,6 @@ namespace } struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL; - // xxx temporary static xxx - static std::vector cu_headers = read_info_headers (file, sec, reloc); if (reloc != NULL) relocation_reset (reloc); @@ -311,7 +306,6 @@ namespace 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; @@ -367,21 +361,12 @@ namespace 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"); } @@ -426,19 +411,28 @@ namespace } } +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 (); diff --git a/src/dwarflint/checks-low.hh b/src/dwarflint/checks-low.hh index 9f3655842..5a7b4ba1a 100644 --- a/src/dwarflint/checks-low.hh +++ b/src/dwarflint/checks-low.hh @@ -18,6 +18,11 @@ public: sec § elf_file &file; section_base (dwarflint &lint, section_id secid); + + relocation_data *reldata () const + { + return sect.rel.size > 0 ? §.rel : NULL; + } }; template @@ -31,10 +36,23 @@ public: {} }; +/** The pass for reading basic .debug_info data -- the layout of + sections and their headers. */ +class read_cu_headers + : public check +{ + section *_m_sec_info; + +public: + std::vector const cu_headers; + explicit read_cu_headers (dwarflint &lint); +}; + class check_debug_abbrev : public check { section *_m_sec_abbr; + bool check_no_abbreviations () const; public: @@ -53,6 +71,7 @@ class check_debug_info section *_m_sec_abbrev; section *_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 diff --git a/src/dwarflint/tables.cc b/src/dwarflint/tables.cc index c9e9cf06a..3b3d8e6f0 100644 --- a/src/dwarflint/tables.cc +++ b/src/dwarflint/tables.cc @@ -376,6 +376,12 @@ get_dwarf_version (unsigned version) }; } +dwarf_version_h +get_latest_dwarf_version () +{ + return &dwarf4; +} + bool dwver_form_valid (dwarf_version const *ver, int form) { diff --git a/src/dwarflint/tables.h b/src/dwarflint/tables.h index f5f36bf3a..7bfe2d932 100644 --- a/src/dwarflint/tables.h +++ b/src/dwarflint/tables.h @@ -40,6 +40,9 @@ extern "C" dwarf_version_h get_dwarf_version (unsigned version) __attribute__ ((pure)); + dwarf_version_h get_latest_dwarf_version () + __attribute__ ((pure)); + bool dwver_form_valid (dwarf_version_h ver, int form); bool dwver_form_allowed (dwarf_version_h ver, int attr, int form);