From: Petr Machata Date: Tue, 19 Apr 2011 15:29:41 +0000 (+0200) Subject: dwarflint: Revamp location reporting X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=60420a4194c1e88051bcb231371d3d46cdfbf027;p=thirdparty%2Felfutils.git dwarflint: Revamp location reporting - Drop struct where, introduce class locus, which is an abstract interface that the real locus classes implement. Locus classes are still used as values, no heap allocation was necessary, although if polymorphism is necessary, loci can simply be new'ed and put in a vector etc. - Formatting of most loci was kept the way it was, but some formats have been improved. For example, DIE and abbrev loci now use attribute name directly to point to the attribute in question. - Low-level allocation helpers (mostly WIPE) were dropped and replaced with constructors on those structures. Placement new has to be used in a couple places to initialize data where REALLOC is still used. - Functions that used to take struct where * now take locus const &. The code was updated throughout. - Values not corresponding to sections were removed from enum section_id. Part was dropped outright, because they were there just to support WHEREs, rel_* was moved to new class rel_target. - Convert addr_recort, ref_record to classes inheriting off std::vector. ref_record in fact became ref_record_T and is now parametrized by locus type. --- diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am index 2a964603c..8b2f99fc6 100644 --- a/dwarflint/Makefile.am +++ b/dwarflint/Makefile.am @@ -48,6 +48,7 @@ dwarflint_SOURCES = \ checks.hh checks_i.hh \ coverage.cc coverage.hh \ cu_coverage.cc cu_coverage.hh cu_coverage_i.hh \ + die_locus.cc die_locus.hh \ dwarf_2.cc dwarf_2.hh \ dwarf_3.cc dwarf_3.hh \ dwarf_4.cc dwarf_4.hh \ @@ -60,6 +61,7 @@ dwarflint_SOURCES = \ expected-at.cc expected.hh \ files.cc files.hh \ highlevel_check.cc highlevel_check.hh highlevel_check_i.hh \ + locus.cc locus.hh \ main.cc \ messages.cc messages.hh \ misc.cc misc.hh \ @@ -69,7 +71,6 @@ dwarflint_SOURCES = \ reloc.cc reloc.hh \ section_id.cc section_id.hh \ sections.cc sections.hh sections_i.hh \ - where.c where.h \ wrap.cc wrap.hh \ \ check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev_i.hh \ @@ -95,10 +96,12 @@ dwarflint_SOURCES = \ locstats_SOURCES = \ locstats.cc \ + die_locus.cc die_locus.hh \ files.cc files.hh \ + locus.cc locus.hh \ option.cc option.hh option_i.hh \ - pri.cc pri.hh \ - where.c where.h + section_id.cc section_id.hh \ + pri.cc pri.hh tests_test_coverage_SOURCES = tests/test-coverage.cc coverage.cc pri.cc \ ../src/dwarfstrings.c diff --git a/dwarflint/addr-record.cc b/dwarflint/addr-record.cc index ec31eba2e..220f4b1dc 100644 --- a/dwarflint/addr-record.cc +++ b/dwarflint/addr-record.cc @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2009,2010 Red Hat, Inc. + Copyright (C) 2009,2010,2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -24,18 +24,17 @@ . */ #include "addr-record.hh" -#include "misc.hh" size_t -addr_record_find_addr (struct addr_record *ar, uint64_t addr) +addr_record::find (uint64_t addr) const { size_t a = 0; - size_t b = ar->size; + size_t b = size (); while (a < b) { size_t i = (a + b) / 2; - uint64_t v = ar->addrs[i]; + uint64_t v = (*this)[i]; if (v > addr) b = i; @@ -49,51 +48,21 @@ addr_record_find_addr (struct addr_record *ar, uint64_t addr) } bool -addr_record_has_addr (struct addr_record *ar, uint64_t addr) +addr_record::has_addr (uint64_t addr) const { - if (ar->size == 0 - || addr < ar->addrs[0] - || addr > ar->addrs[ar->size - 1]) + if (begin () == end () + || addr < front () + || addr > back ()) return false; - size_t a = addr_record_find_addr (ar, addr); - return a < ar->size && ar->addrs[a] == addr; + const_iterator it = begin () + find (addr); + return it != end () && *it == addr; } void -addr_record_add (struct addr_record *ar, uint64_t addr) +addr_record::add (uint64_t addr) { - size_t a = addr_record_find_addr (ar, addr); - if (a >= ar->size || ar->addrs[a] != addr) - { - REALLOC (ar, addrs); - size_t len = ar->size - a; - memmove (ar->addrs + a + 1, ar->addrs + a, len * sizeof (*ar->addrs)); - - ar->addrs[a] = addr; - ar->size++; - } -} - -void -addr_record_free (struct addr_record *ar) -{ - if (ar != NULL) - free (ar->addrs); -} - -void -ref_record_add (struct ref_record *rr, uint64_t addr, struct where *referrer) -{ - REALLOC (rr, refs); - struct ref *ref = rr->refs + rr->size++; - ref->addr = addr; - ref->who = *referrer; -} - -void -ref_record_free (struct ref_record *rr) -{ - if (rr != NULL) - free (rr->refs); + iterator it = begin () + find (addr); + if (it == end () || *it != addr) + insert (it, addr); } diff --git a/dwarflint/addr-record.hh b/dwarflint/addr-record.hh index 1542ff314..4bbd0c51d 100644 --- a/dwarflint/addr-record.hh +++ b/dwarflint/addr-record.hh @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2009,2010 Red Hat, Inc. + Copyright (C) 2009,2010,2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -28,55 +28,55 @@ #include #include -#include "where.h" -#ifdef __cplusplus -extern "C" -{ -#else -# include -#endif - - /* Functions and data structures for address record handling. We - use that to check that all DIE references actually point to an - existing die, not somewhere mid-DIE, where it just happens to be - interpretable as a DIE. */ +#include - struct addr_record - { - size_t size; - size_t alloc; - uint64_t *addrs; - }; +#include "locus.hh" - size_t addr_record_find_addr (struct addr_record *ar, uint64_t addr); - bool addr_record_has_addr (struct addr_record *ar, uint64_t addr); - void addr_record_add (struct addr_record *ar, uint64_t addr); - void addr_record_free (struct addr_record *ar); +/// Address record is used to check that all DIE references actually +/// point to an existing die, not somewhere mid-DIE, where it just +/// happens to be interpretable as a DIE. This is stored as sorted +/// array for quick lookup and duplicate removal. +struct addr_record + : private std::vector +{ + typedef std::vector _super_t; + size_t find (uint64_t addr) const; - /* Functions and data structures for reference handling. Just like - the above, we use this to check validity of DIE references. - Unlike the above, this is not stored as sorted set, but simply as - an array of records, because duplicates are unlikely. */ +public: + bool has_addr (uint64_t addr) const; + void add (uint64_t addr); +}; - struct ref - { - uint64_t addr; // Referree address - struct where who; // Referrer - }; +/// One reference for use in ref_record, parametrized by locus type. +template +struct ref_T +{ + uint64_t addr; // Referee address + L who; // Referrer - struct ref_record - { - size_t size; - size_t alloc; - struct ref *refs; - }; + ref_T () + : addr (-1) + {} - void ref_record_add (struct ref_record *rr, uint64_t addr, - struct where *referrer); - void ref_record_free (struct ref_record *rr); + ref_T (uint64_t a_addr, L const &a_who) + : addr (a_addr) + , who (a_who) + {} +}; -#ifdef __cplusplus -} -#endif +/// Reference record is used to check validity of DIE references. +/// Unlike the above, this is not stored as sorted set, but simply as +/// an array of records, because duplicates are unlikely. +template +class ref_record_T + : private std::vector > +{ + typedef std::vector > _super_t; +public: + using _super_t::const_iterator; + using _super_t::begin; + using _super_t::end; + using _super_t::push_back; +}; #endif//DWARFLINT_ADDR_RECORD_H diff --git a/dwarflint/check_debug_abbrev.cc b/dwarflint/check_debug_abbrev.cc index 3b5e3bab6..849e50533 100644 --- a/dwarflint/check_debug_abbrev.cc +++ b/dwarflint/check_debug_abbrev.cc @@ -43,6 +43,57 @@ #include "messages.hh" #include "misc.hh" +char const * +locus_simple_fmt::abbr_offset_n () +{ + return "abbr. offset"; +} + +abbrev_attrib_locus::abbrev_attrib_locus (uint64_t abbr_offset, + uint64_t attr_offset, + int a_name) + : _m_abbr_offset (abbr_offset) + , _m_attr_offset (attr_offset) + , _m_name (a_name) +{} + +abbrev_attrib_locus::abbrev_attrib_locus (abbrev_attrib_locus const ©) + : _m_abbr_offset (copy._m_abbr_offset) + , _m_attr_offset (copy._m_attr_offset) + , _m_name (copy._m_name) +{} + +std::string +abbrev_attrib_locus::name () const +{ + return pri::attr_name (_m_name); +} + +void +abbrev_attrib_locus::set_name (int a_name) +{ + _m_name = a_name; +} + +abbrev_attrib_locus +abbrev_attrib_locus::non_symbolic () +{ + return abbrev_attrib_locus (_m_abbr_offset, _m_attr_offset); +} + +std::string +abbrev_attrib_locus::format (bool brief) const +{ + std::stringstream ss; + if (!brief) + ss << section_name[sec_abbrev] << ": "; + if (_m_name != -1) + ss << "abbr. 0x" << std::hex << _m_abbr_offset << ", attr. " << name (); + else + ss << "abbr. attribute 0x" << std::hex << _m_attr_offset; + return ss.str (); +} + checkdescriptor const * check_debug_abbrev::descriptor () { @@ -114,14 +165,12 @@ namespace }; void - complain (where const *where, - int attrib_name, int form_name, + complain (locus const &loc, int form_name, bool indirect, char const *qualifier) { - wr_error (*where) - << "attribute " << elfutils::dwarf::attributes::name (attrib_name) - << " with " << qualifier << (indirect ? " indirect" : "") - << " form " << elfutils::dwarf::forms::name (form_name) + wr_error (loc) + << "attribute with " << qualifier << (indirect ? " indirect" : "") + << " form " << elfutils::dwarf::forms::identifier (form_name) << '.' << std::endl; } @@ -134,11 +183,9 @@ namespace // But since we got here, apparently there was a .debug_abbrev // section with size of more than 0 bytes, which is wasteful. if (ret) - { - where wh = WHERE (sec_abbrev, NULL); - wr_message (wh, mc_abbrevs | mc_impact_1 | mc_acc_bloat) - << "no abbreviations." << std::endl; - } + wr_message (section_locus (sec_abbrev), + mc_abbrevs | mc_impact_1 | mc_acc_bloat) + << "no abbreviations." << std::endl; return ret; } @@ -153,12 +200,10 @@ namespace struct abbrev_table *section = NULL; uint64_t first_attr_off = 0; - struct where where = WHERE (sec_abbrev, NULL); // Tolerate failure here. dwarf_version const *ver = NULL; static dwarf_version const *latest_ver = dwarf_version::get_latest (); - where.addr1 = 0; bool failed = false; while (true) @@ -168,7 +213,8 @@ namespace if (read_ctx_eof (&ctx)) { if (!check_no_abbreviations (abbrevs)) - wr_error (&where, ": missing zero to mark end-of-table.\n"); + wr_error (section_locus (sec_abbrev)) + << "missing zero to mark end-of-table.\n"; break; } @@ -181,10 +227,11 @@ namespace 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")) + if (!checked_read_uleb128 (&ctx, &abbr_code, + section_locus (sec_abbrev, abbr_off), + "abbrev code")) throw check_base::failed (); /* Note: we generally can't tell the difference between @@ -211,11 +258,9 @@ namespace || ((abbr_off += 1), false)); if (zero_seq_off != (uint64_t)-1) - { - struct where wh = WHERE (where.section, NULL); - wr_message_padding_0 (mc_abbrevs | mc_header, - &wh, zero_seq_off, abbr_off); - } + wr_message_padding_0 (mc_abbrevs | mc_header, + section_locus (sec_abbrev), + zero_seq_off, abbr_off); } if (read_ctx_eof (&ctx)) @@ -225,18 +270,16 @@ namespace break; } + abbrev_locus where (abbr_off); + /* 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; - 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) @@ -278,10 +321,9 @@ namespace ver = dwarf_version::get_latest (); } } - else if (ver == NULL) + else if (ver == NULL) // Only emit this once. { - struct where wh = WHERE (sec_info, NULL); - wr_error (wh) + wr_error (section_locus (sec_info)) << "couldn't load CU headers for processing .debug_abbrev; " "assuming latest DWARF flavor." << std::endl; @@ -291,30 +333,28 @@ namespace assert (ver != NULL); } - struct abbrev *original = section->find_abbrev (abbr_code); + abbrev *original = section->find_abbrev (abbr_code); + abbrev *cur; + abbrev fake (where); if (unlikely (original != NULL)) - wr_error (where) - << "duplicate abbrev code " << abbr_code - << "; already defined at " << original->where << '.' << std::endl; - - struct abbrev fake; - struct abbrev *cur; - /* Don't actually save this abbrev if it's duplicate. */ - if (likely (original == NULL)) + { + wr_error (where) << "duplicate abbrev code (first was at " + << original->where << ").\n"; + /* Don't actually save this abbrev if it's duplicate. */ + cur = &fake; + } + else { REALLOC (section, abbr); cur = section->abbr + section->size++; + new (cur) abbrev (where); } - else - cur = &fake; - WIPE (*cur); cur->code = abbr_code; - cur->where = where; /* Abbreviation tag. */ uint64_t abbr_tag; - if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag")) + if (!checked_read_uleb128 (&ctx, &abbr_tag, where, "abbrev tag")) throw check_base::failed (); if (abbr_tag > DW_TAG_hi_user) @@ -359,14 +399,14 @@ namespace /* Shift to match elfutils reporting. */ attr_off -= first_attr_off; - where_reset_3 (&where, attr_off); + abbrev_attrib_locus attr_locus (abbr_off, attr_off); /* Load attribute name and form. */ - if (!checked_read_uleb128 (&ctx, &attrib_name, &where, + if (!checked_read_uleb128 (&ctx, &attrib_name, attr_locus, "attribute name")) throw check_base::failed (); - if (!checked_read_uleb128 (&ctx, &attrib_form, &where, + if (!checked_read_uleb128 (&ctx, &attrib_form, attr_locus, "attribute form")) throw check_base::failed (); @@ -375,11 +415,12 @@ namespace REALLOC (cur, attribs); + attr_locus.set_name (attrib_name); struct abbrev_attrib *acur = cur->attribs + cur->size++; - WIPE (*acur); + new (acur) abbrev_attrib (); acur->name = attrib_name; acur->form = attrib_form; - acur->where = where; + acur->where = attr_locus; if (null_attrib) break; @@ -387,7 +428,8 @@ namespace /* Otherwise validate name and form. */ if (attrib_name == 0) { - wr_error (where) << "invalid attribute code 0." << std::endl; + wr_error (attr_locus.non_symbolic ()) + << "invalid attribute code 0." << std::endl; // We can handle this, so keep going. But this is not // kosher for high-level checks. failed = true; @@ -407,18 +449,18 @@ namespace if (attribute == NULL) // libdw should handle unknown attribute, as long as // the form is kosher, so don't fail the check. - wr_message (where, mc_abbrevs | mc_impact_1) + wr_message (attr_locus.non_symbolic (), + mc_abbrevs | mc_impact_1) << "invalid or unknown name " << pri::hex (attrib_name) << '.' << std::endl; else if (opt_nognu) - wr_message (where, mc_abbrevs | mc_impact_1) - << "attribute " << *attribute - << " from later DWARF version." + wr_message (attr_locus, mc_abbrevs | mc_impact_1) + << "attribute from later DWARF version." << std::endl; } form const *form = check_debug_abbrev::check_form - (ver, attribute, attrib_form, &where, false); + (ver, attribute, attrib_form, attr_locus, false); if (form == NULL) { // Error message has been emitted in check_form. @@ -430,11 +472,11 @@ namespace = seen.insert (std::make_pair (attrib_name, attr_off)); if (!inserted.second) { - wr_error (where) - << "duplicate attribute " - << elfutils::dwarf::attributes::name (attrib_name) + wr_error (attr_locus.non_symbolic ()) + << "duplicate attribute " << attr_locus.name () << " (first was at " << pri::hex (inserted.first->second) << ")." << std::endl; + // I think we may allow such files for high-level // consumption, so don't fail the check... if (attrib_name == DW_AT_sibling) @@ -442,13 +484,10 @@ namespace failed = true; } - if (attrib_name == DW_AT_sibling) - { - if (!cur->has_children) - wr_message (where, mc_die_rel | mc_acc_bloat | mc_impact_1) - << "superfluous DW_AT_sibling attribute at childless abbrev." - << std::endl; - } + if (attrib_name == DW_AT_sibling && !cur->has_children) + wr_message (attr_locus, mc_die_rel | mc_acc_bloat | mc_impact_1) + << "superfluous DW_AT_sibling attribute at childless abbrev." + << std::endl; if (attrib_name == DW_AT_ranges) ranges = true; else if (attrib_name == DW_AT_low_pc) @@ -458,7 +497,6 @@ namespace } 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." @@ -499,13 +537,12 @@ check_debug_abbrev::check_debug_abbrev (checkstack &stack, dwarflint &lint) form const * check_debug_abbrev::check_form (dwarf_version const *ver, attribute const *attribute, - int form_name, - where const *where, bool indirect) + int form_name, locus const &loc, bool indirect) { form const *form = ver->get_form (form_name); if (form == NULL) { - wr_error (*where) + wr_error (loc) << "invalid form " << pri::hex (form_name) << '.' << std::endl; return NULL; @@ -517,12 +554,12 @@ check_debug_abbrev::check_form (dwarf_version const *ver, int attrib_name = attribute->name (); if (!ver->form_allowed (attribute, form)) { - complain (where, attrib_name, form_name, indirect, "invalid"); + complain (loc, form_name, indirect, "invalid"); return NULL; } else if (attrib_name == DW_AT_sibling && sibling_form_suitable (ver, form) == sfs_long) - complain (where, attrib_name, form_name, indirect, "unsuitable"); + complain (loc, form_name, indirect, "unsuitable"); } return form; diff --git a/dwarflint/check_debug_abbrev.hh b/dwarflint/check_debug_abbrev.hh index 7fc1aefdf..54d03ce87 100644 --- a/dwarflint/check_debug_abbrev.hh +++ b/dwarflint/check_debug_abbrev.hh @@ -1,5 +1,5 @@ /* Low-level checking of .debug_abbrev. - Copyright (C) 2009, 2010 Red Hat, Inc. + Copyright (C) 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -31,20 +31,56 @@ #include "check_debug_info_i.hh" #include "dwarf_version_i.hh" +namespace locus_simple_fmt +{ + char const *abbr_offset_n (); +} + +typedef fixed_locus abbrev_locus; + +class abbrev_attrib_locus + : public locus +{ + uint64_t _m_abbr_offset; + uint64_t _m_attr_offset; + int _m_name; + +public: + explicit abbrev_attrib_locus (uint64_t abbr_offset = -1, + uint64_t attr_offset = -1, + int name = -1); + + abbrev_attrib_locus (abbrev_attrib_locus const ©); + + abbrev_attrib_locus non_symbolic (); + + void set_name (int name); + std::string format (bool brief = false) const; + std::string name () const; +}; + struct abbrev_attrib { - struct where where; + abbrev_attrib_locus where; uint16_t name; uint8_t form; + + abbrev_attrib () + : where () + , name (0) + , form (0) + {} }; struct abbrev { + abbrev_locus where; uint64_t code; - struct where where; /* Attributes. */ - struct abbrev_attrib *attribs; + abbrev_attrib *attribs; size_t size; size_t alloc; @@ -56,6 +92,17 @@ struct abbrev /* Whether some DIE uses this abbrev. */ bool used; + + explicit abbrev (abbrev_locus const &loc) + : where (loc) + , code (0) + , attribs (0) + , size (0) + , alloc (0) + , tag (0) + , has_children (false) + , used (false) + {} }; struct abbrev_table @@ -68,6 +115,15 @@ struct abbrev_table bool used; /* There are CUs using this table. */ abbrev *find_abbrev (uint64_t abbrev_code) const; + + abbrev_table () + : next (NULL) + , abbr (NULL) + , offset (0) + , size (0) + , alloc (0) + , used (false) + {} }; class check_debug_abbrev @@ -87,7 +143,7 @@ public: static form const *check_form (dwarf_version const *ver, attribute const *attr, int form_name, - where const *where, + locus const &loc, bool indirect); ~check_debug_abbrev (); diff --git a/dwarflint/check_debug_aranges.cc b/dwarflint/check_debug_aranges.cc index b95597022..cc2ce8c8f 100644 --- a/dwarflint/check_debug_aranges.cc +++ b/dwarflint/check_debug_aranges.cc @@ -42,6 +42,32 @@ #include "misc.hh" #include "pri.hh" +char const * +locus_simple_fmt::cudie_n () +{ + return "CU DIE"; +} + +std::string +arange_locus::format (bool brief) const +{ + std::stringstream ss; + if (!brief) + ss << section_name[sec_aranges] << ": "; + + if (_m_arange_offset != (Dwarf_Off)-1) + ss << "arange 0x" << std::hex << _m_arange_offset; + else if (_m_table_offset != (Dwarf_Off)-1) + ss << "table " << std::dec << _m_table_offset; + else + ss << "arange"; + + if (_m_cudie_locus != NULL) + ss << " (" << _m_cudie_locus->format (true) << ')'; + + return ss.str (); +} + checkdescriptor const * check_debug_aranges::descriptor () { @@ -119,7 +145,6 @@ hole (uint64_t start, uint64_t length, void *user) || !necessary_alignment (start, length, sec->shdr.sh_addralign)) { char buf[128]; - where where = WHERE (info.id, NULL); char const *what = info.what; char const *cu = "CU DIEs"; if (info.reverse) @@ -128,7 +153,7 @@ hole (uint64_t start, uint64_t length, void *user) what = cu; cu = tmp; } - wr_message (where, mc_aranges | mc_impact_3) + wr_message (section_locus (info.id), mc_aranges | mc_impact_3) << "addresses " << range_fmt (buf, sizeof (buf), start, start + length) << " are covered with " << cu << ", but not with " << what << "." << std::endl; @@ -163,13 +188,13 @@ compare_coverage (struct elf_file *file, inline static void aranges_coverage_add (struct coverage *aranges_coverage, uint64_t begin, uint64_t length, - struct where *where) + locus const &loc) { if (aranges_coverage->is_overlap (begin, length)) { char buf[128]; /* Not a show stopper, this shouldn't derail high-level. */ - wr_message (*where, mc_aranges | mc_impact_2 | mc_error) + wr_message (loc, mc_aranges | mc_impact_2 | mc_error) << "the range " << range_fmt (buf, sizeof buf, begin, begin + length) << " overlaps with another one." << std::endl; } @@ -196,8 +221,7 @@ check_aranges_structural (struct elf_file *file, while (!read_ctx_eof (&ctx)) { - struct where where = WHERE (sec_aranges, NULL); - where_reset_1 (&where, read_ctx_get_offset (&ctx)); + arange_locus where (read_ctx_get_offset (&ctx)); const unsigned char *atab_begin = ctx.ptr; /* Size. */ @@ -209,7 +233,7 @@ check_aranges_structural (struct elf_file *file, wr_error (&where, ": can't read table length.\n"); return false; } - if (!read_size_extra (&ctx, size32, &size, &offset_size, &where)) + if (!read_size_extra (&ctx, size32, &size, &offset_size, where)) return false; struct read_ctx sub_ctx; @@ -239,7 +263,7 @@ check_aranges_structural (struct elf_file *file, retval = false; goto next; } - if (!supported_version (version, 1, &where, 2)) + if (!supported_version (version, 1, where, 2)) { retval = false; goto next; @@ -257,9 +281,9 @@ check_aranges_structural (struct elf_file *file, struct relocation *rel; if ((rel = relocation_next (&sec->rel, ctx_offset, - &where, skip_mismatched))) + where, skip_mismatched))) relocate_one (file, &sec->rel, rel, offset_size, - &cu_offset, &where, sec_info, NULL); + &cu_offset, where, sec_info, NULL); else if (file->ehdr.e_type == ET_REL) wr_message (mc_impact_2 | mc_aranges | mc_reloc | mc_header, &where, PRI_LACK_RELOCATION, "debug info offset"); @@ -268,13 +292,10 @@ check_aranges_structural (struct elf_file *file, if (cu_chain != NULL && (cu = cu_find_cu (cu_chain, cu_offset)) == NULL) wr_error (&where, ": unresolved reference to " PRI_CU ".\n", cu_offset); - struct where where_cudie; + cudie_locus cudie_loc (cu != NULL ? cu->cudie_offset : -1); if (cu != NULL) { - where_cudie = WHERE (sec_info, NULL); - where_reset_1 (&where_cudie, cu->cudie_offset); - where.ref = &where_cudie; - where_cudie.formatting = wf_cudie; + where.set_cudie (&cudie_loc); if (cu->has_arange) wr_error (where) << "there has already been arange section for this CU." @@ -286,7 +307,7 @@ check_aranges_structural (struct elf_file *file, /* Address size. */ int address_size; error_code err = read_address_size (&sub_ctx, file->addr_64, - &address_size, &where); + &address_size, where); if (err != err_ok) retval = false; if (err == err_fatal) @@ -346,7 +367,7 @@ check_aranges_structural (struct elf_file *file, way, the better to catch structural errors accurately. So report arange offset instead. If this becomes a problem, we will achieve this by two-pass analysis. */ - where_reset_2 (&where, read_ctx_get_offset (&sub_ctx)); + where.set_arange (read_ctx_get_offset (&sub_ctx)); /* Record address. */ uint64_t address; @@ -360,11 +381,11 @@ check_aranges_structural (struct elf_file *file, } if ((rel = relocation_next (&sec->rel, ctx_offset, - &where, skip_mismatched))) + where, skip_mismatched))) { address_relocated = true; relocate_one (file, &sec->rel, rel, address_size, - &address, &where, rel_address, NULL); + &address, where, rel_target::rel_address, NULL); } else if (file->ehdr.e_type == ET_REL && address != 0) wr_message (mc_impact_2 | mc_aranges | mc_reloc, &where, @@ -389,18 +410,18 @@ check_aranges_structural (struct elf_file *file, wr_error (&where, ": zero-length address range.\n"); /* Skip coverage analysis if we have errors. */ else if (retval && aranges_coverage != NULL) - aranges_coverage_add (aranges_coverage, address, length, &where); + aranges_coverage_add (aranges_coverage, address, length, where); } if (sub_ctx.ptr != sub_ctx.end) { uint64_t start, end; - struct where wh = WHERE (where.section, NULL); + section_locus wh (sec_aranges); if (read_check_zero_padding (&sub_ctx, &start, &end)) - wr_message_padding_0 (mc_aranges, &wh, start, end); + wr_message_padding_0 (mc_aranges, wh, start, end); else { - wr_message_padding_n0 (mc_aranges | mc_error, &wh, + wr_message_padding_n0 (mc_aranges | mc_error, wh, start, start + size); retval = false; } diff --git a/dwarflint/check_debug_aranges.hh b/dwarflint/check_debug_aranges.hh index ea18350b9..109cf0bc9 100644 --- a/dwarflint/check_debug_aranges.hh +++ b/dwarflint/check_debug_aranges.hh @@ -1,5 +1,5 @@ /* Low-level checking of .debug_aranges. - Copyright (C) 2009, 2010 Red Hat, Inc. + Copyright (C) 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -31,6 +31,66 @@ #include "check_debug_info_i.hh" #include "cu_coverage_i.hh" +namespace locus_simple_fmt +{ + char const *cudie_n (); +}; + +class cudie_locus + : public fixed_locus +{ + typedef fixed_locus _super_t; +public: + template + cudie_locus (T const &die) + : _super_t (die.offset ()) + {} + + cudie_locus (Dwarf_Off offset) + : _super_t (offset) + {} +}; + +class arange_locus + : public locus +{ + Dwarf_Off _m_table_offset; + Dwarf_Off _m_arange_offset; + locus const *_m_cudie_locus; + +public: + explicit arange_locus (Dwarf_Off table_offset = -1, + Dwarf_Off arange_offset = -1) + : _m_table_offset (table_offset) + , _m_arange_offset (arange_offset) + , _m_cudie_locus (NULL) + {} + + explicit arange_locus (locus const &cudie_locus) + : _m_table_offset (-1) + , _m_arange_offset (-1) + , _m_cudie_locus (&cudie_locus) + {} + + void + set_cudie (locus const *cudie_locus) + { + _m_cudie_locus = cudie_locus; + } + + void + set_arange (Dwarf_Off arange_offset) + { + _m_arange_offset = arange_offset; + } + + std::string format (bool brief = false) const; +}; + class check_debug_aranges : public check { diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index c880fd92f..e415fb180 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -43,7 +43,6 @@ #include "check_debug_info.hh" #include "check_debug_line.hh" #include "check_debug_aranges.hh" -#include "misc.hh" checkdescriptor const * read_cu_headers::descriptor () @@ -110,21 +109,18 @@ namespace } bool - check_die_references (struct cu *cu, - struct ref_record *die_refs) + check_die_references (cu *cu, ref_record *die_refs) { bool retval = true; - for (size_t i = 0; i < die_refs->size; ++i) - { - struct ref *ref = die_refs->refs + i; - if (!addr_record_has_addr (&cu->die_addrs, ref->addr)) - { - wr_error (ref->who) - << "unresolved reference to " << pri::DIE (ref->addr) - << '.' << std::endl; - retval = false; - } - } + for (ref_record::const_iterator it = die_refs->begin (); + it != die_refs->end (); ++it) + if (!cu->die_addrs.has_addr (it->addr)) + { + wr_error (it->who) + << "unresolved reference to " << pri::DIE (it->addr) + << '.' << std::endl; + retval = false; + } return retval; } @@ -133,12 +129,12 @@ namespace { bool retval = true; for (struct cu *it = cu_chain; it != NULL; it = it->next) - for (size_t i = 0; i < it->die_refs.size; ++i) + for (ref_record::const_iterator rt = it->die_refs.begin (); + rt != it->die_refs.end (); ++rt) { - struct ref *ref = it->die_refs.refs + i; struct cu *ref_cu = NULL; for (struct cu *jt = cu_chain; jt != NULL; jt = jt->next) - if (addr_record_has_addr (&jt->die_addrs, ref->addr)) + if (jt->die_addrs.has_addr (rt->addr)) { ref_cu = jt; break; @@ -146,9 +142,9 @@ namespace if (ref_cu == NULL) { - wr_error (ref->who) + wr_error (rt->who) << "unresolved (non-CU-local) reference to " - << pri::hex (ref->addr) << '.' << std::endl; + << pri::hex (rt->addr) << '.' << std::endl; retval = false; } else if (ref_cu == it) @@ -156,8 +152,8 @@ namespace reference is valid, which it is. But warn about this anyway, perhaps local reference could be formed on smaller number of bytes. */ - wr_message (ref->who, mc_impact_2 | mc_acc_suboptimal | mc_die_rel) - << "local reference to " << pri::DIE (ref->addr) + wr_message (rt->who, mc_impact_2 | mc_acc_suboptimal | mc_die_rel) + << "local reference to " << pri::DIE (rt->addr) << " formed as global." << std::endl; } @@ -178,12 +174,8 @@ namespace while (!read_ctx_eof (&ctx)) { const unsigned char *cu_begin = ctx.ptr; - struct where where = WHERE (sec_info, NULL); - where_reset_1 (&where, read_ctx_get_offset (&ctx)); - - cu_head head; - head.offset = where.addr1; - head.where = where; + uint64_t offset = read_ctx_get_offset (&ctx); + cu_head head (offset); /* Reading CU head is a bit tricky, because we don't know if we have run into (superfluous but allowed) zero padding @@ -192,7 +184,7 @@ namespace if (!read_ctx_need_data (&ctx, 4) && read_check_zero_padding (&ctx, &off_start, &off_end)) { - wr_message_padding_0 (mc_info | mc_header, &where, + wr_message_padding_0 (mc_info | mc_header, head.where, off_start, off_end); break; } @@ -205,25 +197,25 @@ namespace uint32_t size32; if (!read_ctx_read_4ubyte (&ctx, &size32)) { - wr_error (where) << "can't read CU length." << std::endl; + wr_error (head.where) << "can't read CU length." << std::endl; throw check_base::failed (); } if (size32 == 0 && read_check_zero_padding (&ctx, &off_start, &off_end)) { - wr_message_padding_0 (mc_info | mc_header, &where, + wr_message_padding_0 (mc_info | mc_header, head.where, off_start, off_end); break; } Dwarf_Off cu_size; if (!read_size_extra (&ctx, size32, &cu_size, - &head.offset_size, &where)) + &head.offset_size, head.where)) throw check_base::failed (); if (!read_ctx_need_data (&ctx, cu_size)) { - wr_error (where) + wr_error (head.where) << "section doesn't have enough data to read CU of size " << cu_size << '.' << std::endl; throw check_base::failed (); @@ -243,7 +235,7 @@ namespace if (dwarf_version::get (version) == NULL) { wr_error (head.where) << "unsupported CU version " - << version << '.' << std::endl; + << version << '.' << std::endl; throw check_base::failed (); } if (version == 2 && head.offset_size == 8) // xxx? @@ -264,11 +256,11 @@ namespace } struct relocation *rel - = relocation_next (reloc, ctx_offset, &head.where, skip_ok); + = relocation_next (reloc, ctx_offset, head.where, skip_ok); if (rel != NULL) { relocate_one (file, reloc, rel, head.offset_size, - &head.abbrev_offset, &head.where, sec_abbrev, NULL); + &head.abbrev_offset, head.where, sec_abbrev, NULL); rel->invalid = true; // mark as invalid so it's skipped // next time we pass by this } @@ -278,7 +270,7 @@ namespace /* Address size. */ error_code err = read_address_size (&ctx, file->addr_64, - &head.address_size, &head.where); + &head.address_size, head.where); if (err == err_fatal) throw check_base::failed (); else if (err == err_nohl) @@ -290,7 +282,7 @@ namespace if (!read_ctx_skip (&ctx, head.size)) { - wr_error (where) << pri::not_enough ("next CU") << std::endl; + wr_error (head.where) << pri::not_enough ("next CU") << std::endl; throw check_base::failed (); } @@ -303,7 +295,7 @@ namespace return ret; } - section_id + rel_target reloc_target (form const *form, attribute const *attribute) { switch (form->name ()) @@ -318,12 +310,12 @@ namespace case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_entry_pc: - return rel_exec; + return rel_target::rel_exec; case DW_AT_const_value: /* Appears in some kernel modules. It's not allowed by the standard, but leave that for high-level checks. */ - return rel_address; + return rel_target::rel_address; }; break; @@ -391,15 +383,15 @@ namespace std::cout << "XXX don't know how to handle form=" << *form << ", at=" << *attribute << std::endl; - return rel_value; + return rel_target::rel_value; } struct value_check_cb_ctx { struct read_ctx *const ctx; - struct where *const where; + die_locus const *where; struct cu *const cu; - struct ref_record *local_die_refs; + ref_record *local_die_refs; Elf_Data *strings; struct coverage *strings_coverage; struct coverage *pc_coverage; @@ -426,15 +418,15 @@ namespace if (ctx->local_die_refs != NULL) /* Address holds a CU-local reference, so add CU offset to turn it into section offset. */ - ref_record_add (ctx->local_die_refs, - addr + ctx->cu->head->offset, ctx->where); + ctx->local_die_refs->push_back (ref (addr + ctx->cu->head->offset, + *ctx->where)); } /* Callback for global DIE references. */ void check_die_ref_global (uint64_t addr, struct value_check_cb_ctx const *ctx) { - ref_record_add (&ctx->cu->die_refs, addr, ctx->where); + ctx->cu->die_refs.push_back (ref (addr, *ctx->where)); } /* Callback for strp values. */ @@ -479,7 +471,7 @@ namespace << "rangeptr value " << pri::hex (value) << " not aligned to CU address size." << std::endl; *ctx->need_rangesp = true; - ref_record_add (&ctx->cu->range_refs, value, ctx->where); + ctx->cu->range_refs.push_back (ref (value, *ctx->where)); } /* Callback for lineptr values. */ @@ -489,21 +481,20 @@ namespace if (ctx->cu->stmt_list.addr != (uint64_t)-1) wr_error (*ctx->where) << "DW_AT_stmt_list mentioned twice in a CU." << std::endl; - ctx->cu->stmt_list.addr = value; - ctx->cu->stmt_list.who = *ctx->where; + ctx->cu->stmt_list = ref (value, *ctx->where); } /* Callback for locptr values. */ void check_locptr (uint64_t value, struct value_check_cb_ctx const *ctx) { - ref_record_add (&ctx->cu->loc_refs, value, ctx->where); + ctx->cu->loc_refs.push_back (ref (value, *ctx->where)); } void check_decl_file (uint64_t value, struct value_check_cb_ctx const *ctx) { - ref_record_add (&ctx->cu->decl_file_refs, value, ctx->where); + ctx->cu->decl_file_refs.push_back (ref (value, *ctx->where)); } /* The real sibling checking takes place down in read_die_chain. @@ -515,7 +506,7 @@ namespace if (addr == 0) { wr_error (*ctx->where) - << "DW_AT_sibling with a value of 0." << std::endl; + << "has a value of 0." << std::endl; // Don't let this up. *ctx->retval_p = -2; } @@ -533,14 +524,14 @@ namespace int read_die_chain (dwarf_version const *ver, elf_file const &file, - struct read_ctx *ctx, - struct cu *cu, - struct abbrev_table const *abbrevs, + read_ctx *ctx, + cu *cu, + abbrev_table const *abbrevs, Elf_Data *strings, - struct ref_record *local_die_refs, - struct coverage *strings_coverage, - struct relocation_data *reloc, - struct coverage *pc_coverage, + ref_record *local_die_refs, + coverage *strings_coverage, + relocation_data *reloc, + coverage *pc_coverage, bool *need_rangesp, unsigned level) { @@ -548,12 +539,11 @@ namespace uint64_t sibling_addr = 0; uint64_t die_off, prev_die_off = 0; struct abbrev *abbrev = NULL; - struct where where = WHERE (sec_info, NULL); unsigned long die_count = 0; int retval = 0; struct value_check_cb_ctx cb_ctx = { - ctx, &where, cu, + ctx, NULL, cu, local_die_refs, strings, strings_coverage, pc_coverage, @@ -563,20 +553,18 @@ namespace while (!read_ctx_eof (ctx)) { - where = cu->head->where; die_off = read_ctx_get_offset (ctx); /* Shift reported DIE offset by CU offset, to match the way readelf reports DIEs. */ - where_reset_2 (&where, die_off + cu->head->offset); + die_locus where (cu->head->offset + die_off); + cb_ctx.where = &where; uint64_t abbr_code; - if (!checked_read_uleb128 (ctx, &abbr_code, &where, "abbrev code")) + if (!checked_read_uleb128 (ctx, &abbr_code, where, "abbrev code")) return -1; -#define DEF_PREV_WHERE \ - struct where prev_where = where; \ - where_reset_2 (&prev_where, prev_die_off + cu->head->offset) +#define DEF_PREV_WHERE die_locus prev_where (cu->head->offset + prev_die_off) /* Check sibling value advertised last time through the loop. */ if (sibling_addr != 0) @@ -662,7 +650,7 @@ namespace } } - addr_record_add (&cu->die_addrs, cu->head->offset + die_off); + cu->die_addrs.add (cu->head->offset + die_off); uint64_t low_pc = (uint64_t)-1, high_pc = (uint64_t)-1; bool low_pc_relocated = false, high_pc_relocated = false; @@ -674,7 +662,7 @@ namespace for (struct abbrev_attrib *it = abbrev->attribs; it->name != 0 || it->form != 0; ++it) { - where.ref = &it->where; + where.set_attrib_name (it->name); int form_name = it->form; // In following, attribute may be NULL, but form never @@ -688,11 +676,11 @@ namespace { uint64_t value; if (!read_sc_value (&value, form->width (cu->head), - ctx, &where)) + ctx, where)) return -1; form_name = value; form = check_debug_abbrev::check_form - (ver, attribute, form_name, &where, true); + (ver, attribute, form_name, where, true); // N.B. check_form emits appropriate error messages. if (form == NULL) return -1; @@ -846,7 +834,7 @@ namespace storage_class_t storclass = form->storage_class (); if (!read_generic_value (ctx, form->width (cu->head), storclass, - &where, &value, &block)) + where, &value, &block)) { // Note that for fw_uleb and fw_sleb we report the // error the second time now. @@ -866,18 +854,18 @@ namespace // field? See check_debug_loc_range::op_read_form if (!check_location_expression (ver, file, &block, cu, - expr_start, reloc, value, &where)) + expr_start, reloc, value, where)) return -1; } else relocation_skip (reloc, read_ctx_get_offset (ctx), - &where, skip_mismatched); + where, skip_mismatched); } /* Relocate the value if appropriate. */ struct relocation *rel; if ((rel = relocation_next (reloc, ctx_offset, - &where, skip_mismatched))) + where, skip_mismatched))) { if (relocate == rel_no) wr_message (where, (mc_impact_4 | mc_die_other @@ -889,7 +877,7 @@ namespace if (attribute != NULL) { form_width_t width = form->width (cu->head); - relocate_one (&file, reloc, rel, width, &value, &where, + relocate_one (&file, reloc, rel, width, &value, where, reloc_target (form, attribute), symbolp); } @@ -899,7 +887,7 @@ namespace else { if (symbolp != NULL) - WIPE (*symbolp); + memset (*symbolp, 0, sizeof (**symbolp)); if (type_is_rel && (relocate == rel_require || (relocate == rel_nonzero @@ -931,7 +919,7 @@ namespace if (valuep != NULL) *valuep = value; } - where.ref = NULL; + where.set_attrib_name (-1); if (high_pc != (uint64_t)-1 && low_pc != (uint64_t)-1 && high_pc_relative) @@ -963,7 +951,7 @@ namespace else { if (!high_pc_relative) - check_range_relocations (mc_die_other, &where, + check_range_relocations (where, mc_die_other, &file, low_pc_symbol, high_pc_symbol, "DW_AT_low_pc and DW_AT_high_pc"); @@ -976,8 +964,6 @@ namespace } } - where.ref = &abbrev->where; - if (abbrev->has_children) { int st = read_die_chain (ver, file, ctx, cu, abbrevs, strings, @@ -1007,7 +993,7 @@ namespace } if (sibling_addr != 0) - wr_error (where) + wr_error (die_locus (cu->head->offset + prev_die_off)) << "this DIE should have had its sibling at " << pri::hex (sibling_addr) << ", but the DIE chain ended." << std::endl; @@ -1036,7 +1022,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, check_debug_abbrev::abbrev_map const &abbrev_tables = _m_abbrevs->abbrevs; if (dump_die_offsets) - fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL)); + fprintf (stderr, "%s: CU starts\n", cu->head->where.format ().c_str ()); bool retval = true; dwarf_version const *ver = dwarf_version::get (cu->head->version); @@ -1055,8 +1041,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, struct abbrev_table const &abbrevs = abbrev_it->second; /* Read DIEs. */ - struct ref_record local_die_refs; - WIPE (local_die_refs); + ref_record local_die_refs; cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset; int st = read_die_chain (ver, _m_file, ctx, cu, &abbrevs, strings, @@ -1074,7 +1059,6 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, else if (!check_die_references (cu, &local_die_refs)) retval = false; - ref_record_free (&local_die_refs); return retval; } @@ -1090,8 +1074,7 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) sec &sec = _m_sec_info->sect; Elf_Data *const strings = _m_sec_str->sect.data; - struct ref_record die_refs; - WIPE (die_refs); + ref_record die_refs; bool success = true; @@ -1109,7 +1092,7 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) it != cu_headers.end (); ++it) { cu_head const &head = *it; - where const &where = head.where; + cu_locus where = head.where; { cu cur; memset (&cur, 0, sizeof (cur)); @@ -1140,13 +1123,13 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) { uint64_t off_start, off_end; if (read_check_zero_padding (&cu_ctx, &off_start, &off_end)) - wr_message_padding_0 (mc_info, &where, off_start, off_end); + wr_message_padding_0 (mc_info, where, off_start, off_end); else { // Garbage coordinates: uint64_t start = read_ctx_get_offset (&ctx) + off_start; uint64_t end = read_ctx_get_offset (&ctx) + head.total_size; - wr_message_padding_n0 (mc_info, &where, start, end); + wr_message_padding_n0 (mc_info, where, start, end); } } @@ -1156,16 +1139,14 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) if (success) { + section_locus wh (sec_info); if (ctx.ptr != ctx.end) /* Did we read up everything? */ - { - where wh = WHERE (sec_info, NULL); - wr_message (mc_die_other | mc_impact_4, &wh, - ": CU lengths don't exactly match Elf_Data contents."); - } + wr_message (mc_die_other | mc_impact_4, &wh, + ": CU lengths don't exactly match Elf_Data contents."); else /* Did we consume all the relocations? */ - relocation_skip_rest (&sec.rel, sec.id); + relocation_skip_rest (&sec.rel, wh); /* If we managed to read up everything, now do abbrev usage analysis. */ @@ -1203,7 +1184,6 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) that's not necessary anymore. */ check_global_die_references (!cus.empty () ? &cus.front () : NULL); - ref_record_free (&die_refs); if (strings_coverage != NULL) { @@ -1225,15 +1205,6 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) check_debug_info::~check_debug_info () { - for (std::vector::iterator it = cus.begin (); - it != cus.end (); ++it) - { - addr_record_free (&it->die_addrs); - ref_record_free (&it->die_refs); - ref_record_free (&it->range_refs); - ref_record_free (&it->loc_refs); - ref_record_free (&it->decl_file_refs); - } } cu * @@ -1279,8 +1250,9 @@ check_debug_info_refs::check_debug_info_refs (checkstack &stack, it != _m_info->cus.end (); ++it) { if (it->stmt_list.addr == (uint64_t)-1) - for (size_t i = 0; i < it->decl_file_refs.size; ++i) - wr_error (it->decl_file_refs.refs[i].who) + for (ref_record::const_iterator jt = it->decl_file_refs.begin (); + jt != it->decl_file_refs.end (); ++jt) + wr_error (jt->who) << "references .debug_line table, but CU DIE lacks DW_AT_stmt_list." << std::endl; else if (_m_line == NULL diff --git a/dwarflint/check_debug_info.hh b/dwarflint/check_debug_info.hh index 2c93f09c7..e8dc85069 100644 --- a/dwarflint/check_debug_info.hh +++ b/dwarflint/check_debug_info.hh @@ -35,37 +35,64 @@ #include "check_debug_line_i.hh" #include "check_debug_aranges_i.hh" #include "sections_i.hh" +#include "die_locus.hh" + +typedef ref_T ref; +typedef ref_record_T ref_record; struct cu_head { - uint64_t offset; + Dwarf_Off offset; Dwarf_Off size; // Size of this CU. Dwarf_Off head_size; // Size from begin to 1st byte of CU. Dwarf_Off total_size; // size + head_size - int offset_size; // Offset size in this CU. - struct where where; // Where this section was defined. + int offset_size; // Offset size in this CU. Dwarf_Off abbrev_offset; // Abbreviation section that this CU uses. int version; // CU version int address_size; // Address size in bytes on the target machine. + + cu_locus where; + + explicit cu_head (Dwarf_Off a_offset) + : offset (a_offset) + , size (0) + , head_size (0) + , total_size (0) + , offset_size (0) + , abbrev_offset (0) + , version (0) + , address_size (0) + , where (a_offset) + {} }; struct cu { struct cu *next; // For compatibility with C level. // xxx will probably go away eventually - struct cu_head const *head; + cu_head const *head; uint64_t cudie_offset; uint64_t low_pc; // DW_AT_low_pc value of CU DIE, -1 if not present. - struct ref stmt_list; - struct addr_record die_addrs; // Addresses where DIEs begin in this CU. - struct ref_record die_refs; // DIE references into other CUs from this CU. - struct ref_record loc_refs; // references into .debug_loc from this CU. - struct ref_record range_refs; // references into .debug_ranges from this CU. - struct ref_record decl_file_refs; // values of DW_AT_decl_file in this CU. + ::ref stmt_list; + addr_record die_addrs; // Addresses where DIEs begin in this CU. + ref_record die_refs; // DIE references into other CUs from this CU. + ref_record loc_refs; // references into .debug_loc from this CU. + ref_record range_refs; // references into .debug_ranges from this CU. + ref_record decl_file_refs; // values of DW_AT_decl_file in this CU. bool has_arange; // Whether we saw arange section pointing at this CU. bool has_pubnames; // Likewise for pubnames. bool has_pubtypes; // Likewise for pubtypes. + + cu () + : next (NULL) + , head (NULL) + , cudie_offset (0) + , low_pc (0) + , has_arange (false) + , has_pubnames (false) + , has_pubtypes (false) + {} }; /** The pass for reading basic .debug_info data -- the layout of diff --git a/dwarflint/check_debug_line.cc b/dwarflint/check_debug_line.cc index 93637238e..d75aed2bd 100644 --- a/dwarflint/check_debug_line.cc +++ b/dwarflint/check_debug_line.cc @@ -23,6 +23,10 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "check_debug_line.hh" #include "check_debug_info.hh" #include "sections.hh" @@ -97,15 +101,15 @@ namespace bool read_directory_index (include_directories_t &include_directories, files_t &files, read_ctx *ctx, const char *name, uint64_t *ptr, - where *where, bool &retval) + locus const &loc, bool &retval) { size_t nfile = files.size () + 1; if (!checked_read_uleb128 (ctx, ptr, - where, "directory index")) + loc, "directory index")) return false; if (*name == '/' && *ptr != 0) - wr_message (*where, mc_impact_2 | mc_line | mc_header) + wr_message (loc, mc_impact_2 | mc_line | mc_header) << "file #" << nfile << " has absolute pathname, but refers to directory != 0." << std::endl; @@ -113,7 +117,7 @@ namespace if (*ptr > include_directories.size ()) /* Not >=, dirs are indexed from 1. */ { - wr_message (*where, mc_impact_4 | mc_line | mc_header) + wr_message (loc, mc_impact_4 | mc_line | mc_header) << "file #" << nfile << " refers to directory #" << *ptr << ", which wasn't defined." << std::endl; @@ -128,11 +132,11 @@ namespace bool use_file (files_t &files, uint64_t file_idx, - where *where, char const *msg = "") + locus const &loc, char const *msg = "") { if (file_idx == 0 || file_idx > files.size ()) { - wr_error (*where) + wr_error (loc) << msg << "invalid file index " << file_idx << '.' << std::endl; return false; @@ -143,6 +147,18 @@ namespace } } +namespace +{ + char const * + table_n () + { + return "table"; + } + + typedef fixed_locus line_table_locus; +} + check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) : _m_sec (lint.check (stack, _m_sec)) , _m_info (lint.toplev_check (stack, _m_info)) @@ -156,9 +172,8 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) while (!read_ctx_eof (&ctx)) { - struct where where = WHERE (_m_sec->sect.id, NULL); uint64_t set_offset = read_ctx_get_offset (&ctx); - where_reset_1 (&where, set_offset); + line_table_locus where (set_offset); _m_line_tables.insert ((Dwarf_Off)set_offset); const unsigned char *set_begin = ctx.ptr; @@ -171,7 +186,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) wr_error (where) << "can't read table length." << std::endl; throw check_base::failed (); } - if (!read_size_extra (&ctx, size32, &size, &offset_size, &where)) + if (!read_size_extra (&ctx, size32, &size, &offset_size, where)) throw check_base::failed (); struct read_ctx sub_ctx; @@ -196,7 +211,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) success = false; goto next; } - if (!supported_version (version, 2, &where, 2, 3)) + if (!supported_version (version, 2, where, 2, 3)) goto skip; /* Header length. */ @@ -310,19 +325,19 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) uint64_t dir_idx; if (!read_directory_index (include_directories, files, - &sub_ctx, name, &dir_idx, &where, success)) + &sub_ctx, name, &dir_idx, where, success)) goto skip; /* Time of last modification. */ uint64_t timestamp; if (!checked_read_uleb128 (&sub_ctx, ×tamp, - &where, "timestamp of file entry")) + where, "timestamp of file entry")) goto skip; /* Size of the file. */ uint64_t file_size; if (!checked_read_uleb128 (&sub_ctx, &file_size, - &where, "file size of file entry")) + where, "file size of file entry")) goto skip; files.push_back ((struct file_t){name, dir_idx, false}); @@ -340,10 +355,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) if (it->stmt_list.addr == set_offset) { found = true; - for (size_t i = 0; i < it->decl_file_refs.size; ++i) - if (!use_file (files, - it->decl_file_refs.refs[i].addr, - &it->decl_file_refs.refs[i].who)) + for (ref_record::const_iterator + jt = it->decl_file_refs.begin (); + jt != it->decl_file_refs.end (); ++jt) + if (!use_file (files, jt->addr, jt->who)) success = false; } if (!found) @@ -368,14 +383,14 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) else if (sub_ctx.ptr < program_start) { /* Skip the rest of the header. */ - struct where wh = WHERE (sec_line, NULL); uint64_t off_start, off_end; if (read_check_zero_padding (&sub_ctx, &off_start, &off_end)) - wr_message_padding_0 (mc_line | mc_header, &wh, + wr_message_padding_0 (mc_line | mc_header, section_locus (sec_line), off_start, off_end); else - wr_message_padding_n0 (mc_line | mc_header, &wh, - off_start, program_start - sub_ctx.begin); + wr_message_padding_n0 + (mc_line | mc_header, section_locus (sec_line), + off_start, program_start - sub_ctx.begin); sub_ctx.ptr = program_start; } @@ -384,11 +399,11 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) bool seen_opcode = false; while (!read_ctx_eof (&sub_ctx)) { - where_reset_2 (&where, read_ctx_get_offset (&sub_ctx)); + section_locus op_where (sec_line, read_ctx_get_offset (&sub_ctx)); uint8_t opcode; if (!read_ctx_read_ubyte (&sub_ctx, &opcode)) { - wr_error (where) << "can't read opcode." << std::endl; + wr_error (op_where) << "can't read opcode." << std::endl; goto skip; } @@ -400,12 +415,12 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) case 0: { uint64_t skip_len; - if (!checked_read_uleb128 (&sub_ctx, &skip_len, &where, + if (!checked_read_uleb128 (&sub_ctx, &skip_len, op_where, "length of extended opcode")) goto skip; if (!read_ctx_need_data (&sub_ctx, skip_len)) { - wr_error (where) + wr_error (op_where) << "not enough data to read an opcode of length " << skip_len << '.' << std::endl; goto skip; @@ -414,7 +429,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) const unsigned char *next = sub_ctx.ptr + skip_len; if (!read_ctx_read_ubyte (&sub_ctx, &extended)) { - wr_error (where) + wr_error (op_where) << "can't read extended opcode." << std::endl; goto skip; } @@ -432,7 +447,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) uint64_t addr; if (!read_ctx_read_offset (&sub_ctx, addr_64, &addr)) { - wr_error (where) + wr_error (op_where) << "can't read operand of DW_LNE_set_address." << std::endl; goto skip; @@ -440,13 +455,14 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) struct relocation *rel; if ((rel = relocation_next (&_m_sec->sect.rel, ctx_offset, - &where, skip_mismatched))) + op_where, skip_mismatched))) relocate_one (&_m_sec->file, &_m_sec->sect.rel, rel, - addr_64 ? 8 : 4, - &addr, &where, rel_address, NULL); + addr_64 ? 8 : 4, &addr, op_where, + rel_target::rel_address, NULL); else if (_m_sec->file.ehdr.e_type == ET_REL) { - wr_message (where, mc_impact_2 | mc_line | mc_reloc) + wr_message (op_where, + mc_impact_2 | mc_line | mc_reloc) << pri::lacks_relocation ("DW_LNE_set_address") << '.' << std::endl; @@ -455,7 +471,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) } if (addr == 0) - wr_message (where, mc_line | mc_impact_1) + wr_message (op_where, mc_line | mc_impact_1) << "DW_LNE_set_address with zero operand." << std::endl; break; @@ -466,7 +482,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) /* XXX Is there anything interesting we should check here? */ uint64_t disc; - if (!checked_read_uleb128 (&sub_ctx, &disc, &where, + if (!checked_read_uleb128 (&sub_ctx, &disc, op_where, "set_discriminator operand")) goto skip; @@ -474,7 +490,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) sequence change. So setting to zero is never necessary. */ if (disc == 0) - wr_message (where, mc_line | mc_impact_1) + wr_message (op_where, mc_line | mc_impact_1) << "DW_LNE_set_discriminator with zero operand." << std::endl; break; @@ -485,7 +501,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) const char *name; if ((name = read_ctx_read_str (&sub_ctx)) == NULL) { - wr_error (where) + wr_error (op_where) << "can't read filename operand of DW_LNE_define_file." << std::endl; goto skip; @@ -493,7 +509,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) uint64_t dir_idx; if (!read_directory_index (include_directories, files, &sub_ctx, name, - &dir_idx, &where, success)) + &dir_idx, op_where, success)) goto skip; files.push_back ((struct file_t){name, dir_idx, false}); @@ -510,7 +526,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) #undef ONE_KNOWN_DW_LNE default: /* No we don't, emit a warning. */ - wr_message (where, mc_impact_2 | mc_line) + wr_message (op_where, mc_impact_2 | mc_line) << "unknown extended opcode 0x" << std::hex << +extended << std::dec << '.' << std::endl; @@ -519,7 +535,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) if (sub_ctx.ptr > next) { - wr_error (where) + wr_error (op_where) << "opcode claims that it has a size of " << skip_len << ", but in fact it has a size of " << (skip_len + (next - sub_ctx.ptr)) << '.' << std::endl; @@ -530,15 +546,15 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) uint64_t off_start, off_end; if (handled) { - struct where wh = WHERE (sec_line, NULL); if (read_check_zero_padding (&sub_ctx, &off_start, &off_end)) - wr_message_padding_0 (mc_line, &wh, - off_start, off_end); + wr_message_padding_0 + (mc_line, section_locus (sec_line), + off_start, off_end); else - wr_message_padding_n0 (mc_line, &wh, - off_start, - next - sub_ctx.begin); + wr_message_padding_n0 + (mc_line, section_locus (sec_line), + off_start, next - sub_ctx.begin); } sub_ctx.ptr = next; } @@ -550,7 +566,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) case DW_LNS_advance_line: { int64_t line_delta; - if (!checked_read_sleb128 (&sub_ctx, &line_delta, &where, + if (!checked_read_sleb128 (&sub_ctx, &line_delta, op_where, "DW_LNS_advance_line operand")) goto skip; } @@ -561,7 +577,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) uint16_t a; if (!read_ctx_read_2ubyte (&sub_ctx, &a)) { - wr_error (where) + wr_error (op_where) << "can't read operand of DW_LNS_fixed_advance_pc." << std::endl; goto skip; @@ -572,10 +588,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) case DW_LNS_set_file: { uint64_t file_idx; - if (!checked_read_uleb128 (&sub_ctx, &file_idx, &where, + if (!checked_read_uleb128 (&sub_ctx, &file_idx, op_where, "DW_LNS_set_file operand")) goto skip; - if (!use_file (files, file_idx, &where, "DW_LNS_set_file: ")) + if (!use_file (files, file_idx, op_where, "DW_LNS_set_file: ")) success = false; first_file = false; } @@ -599,7 +615,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) default: if (opcode < opcode_base) - wr_message (where, mc_impact_2 | mc_line) + wr_message (op_where, mc_impact_2 | mc_line) << "unknown standard opcode 0x" << std::hex << +opcode << std::dec << '.' << std::endl; @@ -616,13 +632,13 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) else sprintf (buf, "operand #%d of DW_LNE_%s", i, dwarf_line_extended_opcode_string (extended)); - if (!checked_read_uleb128 (&sub_ctx, &operand, &where, buf)) + if (!checked_read_uleb128 (&sub_ctx, &operand, op_where, buf)) goto skip; } if (first_file) { - if (!use_file (files, 1, &where, + if (!use_file (files, 1, op_where, "initial value of `file' register: ")) success = false; first_file = false; @@ -661,7 +677,6 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) << std::endl; } - struct where wh = WHERE (sec_line, NULL); if (!terminated && seen_opcode) wr_error (where) << "sequence of opcodes not terminated with DW_LNE_end_sequence." @@ -670,9 +685,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) { uint64_t off_start, off_end; if (read_check_zero_padding (&sub_ctx, &off_start, &off_end)) - wr_message_padding_0 (mc_line, &wh, off_start, off_end); + wr_message_padding_0 + (mc_line, section_locus (sec_line), off_start, off_end); else - wr_message_padding_n0 (mc_line, &wh, + wr_message_padding_n0 (mc_line, section_locus (sec_line), off_start, sub_ctx.end - sub_ctx.begin); } } @@ -683,7 +699,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) } if (success) - relocation_skip_rest (&_m_sec->sect.rel, _m_sec->sect.id); + relocation_skip_rest (&_m_sec->sect.rel, section_locus (_m_sec->sect.id)); else throw check_base::failed (); } diff --git a/dwarflint/check_debug_loc_range.cc b/dwarflint/check_debug_loc_range.cc index 74b4d272e..5d680815e 100644 --- a/dwarflint/check_debug_loc_range.cc +++ b/dwarflint/check_debug_loc_range.cc @@ -49,6 +49,32 @@ bool do_range_coverage = false; // currently no option +global_opt + opt_show_refs("\ +When validating .debug_loc and .debug_ranges, display information about \ +the DIE referring to the entry in consideration", "ref"); + +std::string +loc_range_locus::format (bool brief) const +{ + std::stringstream ss; + if (!brief) + ss << section_name[_m_sec] << ": "; + + if (_m_sec == sec_loc) + ss << "loclist"; + else + ss << "rangelist"; + + if (_m_offset != (Dwarf_Off)-1) + ss << " 0x" << std::hex << _m_offset; + + if (opt_show_refs) + ss << ", ref. by " << _m_refby.format (true); + + return ss.str (); +} + checkdescriptor const * check_debug_ranges::descriptor () { @@ -143,7 +169,7 @@ namespace struct hole_env { - struct where *where; + locus const &loc; uint64_t address; uint64_t end; }; @@ -154,7 +180,7 @@ namespace hole_env *env = (hole_env *)xenv; char buf[128], buf2[128]; assert (h_length != 0); - wr_error (env->where, + wr_error (&env->loc, ": portion %s of the range %s " "doesn't fall into any ALLOC section.\n", range_fmt (buf, sizeof buf, @@ -176,7 +202,6 @@ namespace { struct coverage_map_hole_info *info = (struct coverage_map_hole_info *)user; - struct where where = WHERE (info->info.section, NULL); const char *scnname = sco->sec->name; struct sec *sec = sco->sec; @@ -215,9 +240,10 @@ namespace return true; char buf[128]; - wr_message (info->info.category | mc_acc_suboptimal | mc_impact_4, &where, - ": addresses %s of section %s are not covered.\n", - range_fmt (buf, sizeof buf, begin + base, end + base), scnname); + wr_message (section_locus (info->info.section), + info->info.category | mc_acc_suboptimal | mc_impact_4) + << "addresses " << range_fmt (buf, sizeof buf, begin + base, end + base) + << " of section " << scnname << " are not covered.\n"; return true; } @@ -257,7 +283,7 @@ namespace coverage_map_add (struct coverage_map *coverage_map, uint64_t address, uint64_t length, - struct where *where, + locus const &loc, enum message_category cat) { bool found = false; @@ -285,7 +311,7 @@ namespace if (found && !crosses_boundary) { /* While probably not an error, it's very suspicious. */ - wr_message (cat | mc_impact_2, where, + wr_message (cat | mc_impact_2, &loc, ": the range %s crosses section boundaries.\n", range_fmt (buf, sizeof buf, address, end)); crosses_boundary = true; @@ -313,14 +339,14 @@ namespace && cov->is_overlap (cov_begin, cov_end - cov_begin)) { /* Not a show stopper, this shouldn't derail high-level. */ - wr_message (*where, cat | mc_aranges | mc_impact_2 | mc_error) + wr_message (loc, cat | mc_aranges | mc_impact_2 | mc_error) << "the range " << range_fmt (buf, sizeof buf, address, end) << " overlaps with another one." << std::endl; overlap = true; } if (sco->warn) - wr_message (cat | mc_impact_2, where, + wr_message (cat | mc_impact_2, &loc, ": the range %s covers section %s.\n", range_fmt (buf, sizeof buf, address, end), sco->sec->name); @@ -334,12 +360,12 @@ namespace if (!found) /* Not a show stopper. */ - wr_error (where, + wr_error (&loc, ": couldn't find a section that the range %s covers.\n", range_fmt (buf, sizeof buf, address, end)); else if (length > 0) { - hole_env env = {where, address, end}; + hole_env env = {loc, address, end}; range_cov.find_holes (0, length, range_hole, &env); } } @@ -354,7 +380,7 @@ namespace struct coverage_map *coverage_map, struct coverage *pc_coverage, uint64_t addr, - struct where const *wh, + locus const &loc, enum message_category cat) { char buf[128]; // messages @@ -368,7 +394,7 @@ namespace read_ctx_init (&ctx, parent_ctx->data, file->other_byte_order); if (!read_ctx_skip (&ctx, addr)) { - wr_error (wh, ": invalid reference outside the section " + wr_error (&loc, ": invalid reference outside the section " "%#" PRIx64 ", size only %#tx.\n", addr, ctx.end - ctx.begin); return false; @@ -379,7 +405,7 @@ namespace if (coverage->is_covered (addr, 1)) { - wr_error (wh, ": reference to %#" PRIx64 + wr_error (&loc, ": reference to %#" PRIx64 " points into another location or range list.\n", addr); retval = false; } @@ -391,8 +417,8 @@ namespace uint64_t base = cu->low_pc; while (!read_ctx_eof (&ctx)) { - struct where where = WHERE (sec->id, wh); - where_reset_1 (&where, read_ctx_get_offset (&ctx)); + uint64_t offset = read_ctx_get_offset (&ctx); + loc_range_locus where (sec->id, loc, offset); #define HAVE_OVERLAP \ do { \ @@ -418,11 +444,12 @@ namespace struct relocation *rel; if ((rel = relocation_next (&sec->rel, begin_off, - &where, skip_mismatched))) + where, skip_mismatched))) { begin_relocated = true; relocate_one (file, &sec->rel, rel, cu->head->address_size, - &begin_addr, &where, rel_value, &begin_symbol); + &begin_addr, where, rel_target::rel_value, + &begin_symbol); } /* end address */ @@ -442,18 +469,18 @@ namespace } if ((rel = relocation_next (&sec->rel, end_off, - &where, skip_mismatched))) + where, skip_mismatched))) { end_relocated = true; relocate_one (file, &sec->rel, rel, cu->head->address_size, - &end_addr, &where, rel_value, &end_symbol); + &end_addr, where, rel_target::rel_value, &end_symbol); if (begin_addr != escape) { if (!begin_relocated) wr_message (cat | mc_impact_2 | mc_reloc, &where, ": end of address range is relocated, but the beginning wasn't.\n"); else - check_range_relocations (cat, &where, file, + check_range_relocations (where, cat, file, begin_symbol, end_symbol, "begin and end address"); } @@ -492,7 +519,7 @@ namespace uint64_t address = begin_addr + base; uint64_t length = end_addr - begin_addr; if (coverage_map != NULL) - coverage_map_add (coverage_map, address, length, &where, cat); + coverage_map_add (coverage_map, address, length, where, cat); if (pc_coverage != NULL) pc_coverage->add (address, length); } @@ -516,7 +543,7 @@ namespace /* location expression itself */ uint64_t expr_start = read_ctx_get_offset (&ctx); if (!check_location_expression - (ver, *file, &ctx, cu, expr_start, &sec->rel, len, &where)) + (ver, *file, &ctx, cu, expr_start, &sec->rel, len, where)) return false; uint64_t expr_end = read_ctx_get_offset (&ctx); if (!overlap @@ -542,7 +569,7 @@ namespace } #undef HAVE_OVERLAP - coverage->add (where.addr1, read_ctx_get_offset (&ctx) - where.addr1); + coverage->add (offset, read_ctx_get_offset (&ctx) - offset); if (done) break; } @@ -552,9 +579,12 @@ namespace struct ref_cu { - struct ref ref; - struct cu *cu; - bool operator < (ref_cu const& other) const { + ::ref ref; + ::cu *cu; + + bool + operator < (ref_cu const& other) const + { return ref.addr < other.ref.addr; } }; @@ -581,7 +611,7 @@ namespace && (coverage_map = coverage_map_alloc_XA (file, sec->id == sec_loc)) == NULL) { - wr_error (WHERE (sec->id, NULL)) + wr_error (section_locus (sec->id)) << "couldn't read ELF, skipping coverage analysis." << std::endl; retval = false; } @@ -600,11 +630,12 @@ namespace ref_cu_vect refs; for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next) { - struct ref_record *rec + ref_record *rec = sec->id == sec_loc ? &cu->loc_refs : &cu->range_refs; - for (size_t i = 0; i < rec->size; ++i) + for (ref_record::const_iterator it = rec->begin (); + it != rec->end (); ++it) { - ref_cu ref = {rec->refs[i], cu}; + ref_cu ref = {*it, cu}; refs.push_back (ref); } } @@ -619,8 +650,8 @@ namespace { if (off == last_off) continue; - struct where wh = WHERE (sec->id, NULL); - relocation_skip (&sec->rel, off, &wh, skip_unref); + relocation_skip (&sec->rel, off, section_locus (sec->id), + skip_unref); } // xxx right now this is just so that we can ver->get_form @@ -636,7 +667,7 @@ namespace Perhaps that's undesirable. */ if (!check_loc_or_range_ref (ver, file, &ctx, it->cu, sec, &coverage, coverage_map, pc_coverage, - off, &it->ref.who, cat)) + off, it->ref.who, cat)) retval = false; last_off = off; } @@ -644,7 +675,7 @@ namespace if (retval) { - relocation_skip_rest (&sec->rel, sec->id); + relocation_skip_rest (&sec->rel, section_locus (sec->id)); /* We check that all CUs have the same address size when building the CU chain. So just take the address size of the first CU in @@ -753,7 +784,7 @@ namespace return true; } - static enum section_id + static rel_target reloc_target_loc (uint8_t opcode) { switch (opcode) @@ -763,7 +794,7 @@ namespace return sec_info; case DW_OP_addr: - return rel_address; + return rel_target::rel_address; case DW_OP_call_ref: assert (!"Can't handle call_ref!"); @@ -772,7 +803,7 @@ namespace std::cout << "XXX don't know how to handle opcode=" << elfutils::dwarf::ops::name (opcode) << std::endl; - return rel_value; + return rel_target::rel_value; } bool @@ -785,7 +816,7 @@ namespace form const *form, uint64_t *valuep, char const *str, - struct where *where) + locus const &where) { if (form == NULL) return true; @@ -797,7 +828,7 @@ namespace if (!read_generic_value (ctx, form->width (cu->head), storclass, where, valuep, NULL)) { - wr_error (*where) + wr_error (where) << "opcode \"" << elfutils::dwarf::ops::name (opcode) << "\": can't read " << str << " (form \"" << *form << "\")." << std::endl; @@ -817,7 +848,7 @@ namespace cu->head->address_size, valuep, where, reloc_target_loc (opcode), NULL); else - wr_error (where, ": relocation relocates a length field.\n"); + wr_error (where) << "relocation relocates a length field.\n"; } if (storclass == sc_block) { @@ -829,6 +860,28 @@ namespace } } +class locexpr_locus + : public locus +{ + uint64_t _m_offset; + locus const *_m_context; + +public: + explicit locexpr_locus (uint64_t offset, locus const *context) + : _m_offset (offset) + , _m_context (context) + {} + + std::string + format (bool) const + { + std::stringstream ss; + ss << _m_context + << " (location expression offset 0x" << std::hex << _m_offset << ")"; + return ss.str (); + } +}; + bool check_location_expression (dwarf_version const *ver, elf_file const &file, @@ -837,28 +890,26 @@ check_location_expression (dwarf_version const *ver, uint64_t init_off, struct relocation_data *reloc, size_t length, - struct where *wh) + locus const &loc) { struct read_ctx ctx; if (!read_ctx_init_sub (&ctx, parent_ctx, parent_ctx->ptr, parent_ctx->ptr + length)) { - wr_error (wh, PRI_NOT_ENOUGH, "location expression"); + wr_error (&loc, PRI_NOT_ENOUGH, "location expression"); return false; } - struct ref_record oprefs; - WIPE (oprefs); - - struct addr_record opaddrs; - WIPE (opaddrs); + typedef ref_T locexpr_ref; + typedef ref_record_T locexpr_ref_record; + locexpr_ref_record oprefs; + addr_record opaddrs; while (!read_ctx_eof (&ctx)) { - struct where where = WHERE (sec_locexpr, wh); uint64_t opcode_off = read_ctx_get_offset (&ctx) + init_off; - where_reset_1 (&where, opcode_off); - addr_record_add (&opaddrs, opcode_off); + locexpr_locus where (opcode_off, &loc); + opaddrs.add (opcode_off); uint8_t opcode; if (!read_ctx_read_ubyte (&ctx, &opcode)) @@ -879,9 +930,9 @@ check_location_expression (dwarf_version const *ver, uint64_t value1, value2; if (!op_read_form (file, &ctx, cu, init_off, reloc, - opcode, form1, &value1, "1st operand", &where) + opcode, form1, &value1, "1st operand", where) || !op_read_form (file, &ctx, cu, init_off, reloc, - opcode, form2, &value2, "2st operand", &where)) + opcode, form2, &value2, "2st operand", where)) goto out; switch (opcode) @@ -908,7 +959,7 @@ check_location_expression (dwarf_version const *ver, else { uint64_t off_after = read_ctx_get_offset (&ctx) + init_off; - ref_record_add (&oprefs, off_after + skip, &where); + oprefs.push_back (locexpr_ref (off_after + skip, where)); } break; @@ -937,17 +988,11 @@ check_location_expression (dwarf_version const *ver, } out: - for (size_t i = 0; i < oprefs.size; ++i) - { - struct ref *ref = oprefs.refs + i; - if (!addr_record_has_addr (&opaddrs, ref->addr)) - wr_error (&ref->who, - ": unresolved reference to opcode at %#" PRIx64 ".\n", - ref->addr); - } - - addr_record_free (&opaddrs); - ref_record_free (&oprefs); + for (locexpr_ref_record::const_iterator it = oprefs.begin (); + it != oprefs.end (); ++it) + if (!opaddrs.has_addr (it->addr)) + wr_error (it->who) << "unresolved reference to opcode at " + << pri::hex (it->addr) << ".\n"; return true; } @@ -978,19 +1023,17 @@ found_hole (uint64_t start, uint64_t length, void *data) } } else - { - /* XXX: This actually lies when the unreferenced portion is - composed of sequences of zeroes and non-zeroes. */ - struct where wh = WHERE (info->section, NULL); - wr_message_padding_n0 (info->category, &wh, start, end); - } + /* XXX: This actually lies when the unreferenced portion is + composed of sequences of zeroes and non-zeroes. */ + wr_message_padding_n0 (info->category, section_locus (info->section), + start, end); return true; } void -check_range_relocations (enum message_category cat, - struct where *where, +check_range_relocations (locus const &loc, + enum message_category cat, struct elf_file const *file, GElf_Sym *begin_symbol, GElf_Sym *end_symbol, @@ -999,7 +1042,7 @@ check_range_relocations (enum message_category cat, if (begin_symbol != NULL && end_symbol != NULL && begin_symbol->st_shndx != end_symbol->st_shndx) - wr_message (cat | mc_impact_2 | mc_reloc, where, + wr_message (cat | mc_impact_2 | mc_reloc, &loc, ": %s relocated against different sections (%s and %s).\n", description, file->sec[begin_symbol->st_shndx].name, diff --git a/dwarflint/check_debug_loc_range.hh b/dwarflint/check_debug_loc_range.hh index 442191e63..2b04e6c03 100644 --- a/dwarflint/check_debug_loc_range.hh +++ b/dwarflint/check_debug_loc_range.hh @@ -1,5 +1,5 @@ /* Low-level checking of .debug_loc and .debug_range. - Copyright (C) 2009, 2010 Red Hat, Inc. + Copyright (C) 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -30,6 +30,23 @@ #include "coverage.hh" #include "dwarf_version_i.hh" +class loc_range_locus + : public locus +{ + locus const &_m_refby; + Dwarf_Off _m_offset; + section_id _m_sec; + +public: + loc_range_locus (section_id sec, locus const &refby, Dwarf_Off offset = -1) + : _m_refby (refby) + , _m_offset (offset) + , _m_sec ((assert (sec == sec_loc || sec == sec_ranges), sec)) + {} + + std::string format (bool brief) const; +}; + struct section_coverage { struct sec *sec; @@ -93,10 +110,10 @@ bool check_location_expression (dwarf_version const *ver, uint64_t init_off, struct relocation_data *reloc, size_t length, - struct where *wh); + locus const &loc); -void check_range_relocations (enum message_category cat, - struct where *where, +void check_range_relocations (locus const &loc, + enum message_category cat, struct elf_file const *file, GElf_Sym *begin_symbol, GElf_Sym *end_symbol, diff --git a/dwarflint/check_debug_pub.cc b/dwarflint/check_debug_pub.cc index c44cab4b0..3991814a3 100644 --- a/dwarflint/check_debug_pub.cc +++ b/dwarflint/check_debug_pub.cc @@ -23,6 +23,10 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "check_debug_pub.hh" #include "check_debug_info.hh" #include "sections.hh" @@ -31,13 +35,19 @@ #include "messages.hh" #include "misc.hh" +namespace +{ + bool check_pub_structural (elf_file const &file, sec §, + check_debug_info *cus); +} + template check_debug_pub::check_debug_pub (checkstack &stack, dwarflint &lint) : _m_sec (lint.check (stack, _m_sec)) , _m_file (_m_sec->file) , _m_cus (lint.toplev_check (stack, _m_cus)) { - check_pub_structural (); + check_pub_structural (_m_file, _m_sec->sect, _m_cus); } @@ -83,175 +93,176 @@ template check_debug_pub::check_debug_pub (checkstack &stack, static reg reg_debug_pubtypes; - -template -bool -check_debug_pub::check_pub_structural () +namespace { - struct read_ctx ctx; - read_ctx_init (&ctx, _m_sec->sect.data, _m_file.other_byte_order); - bool retval = true; - - while (!read_ctx_eof (&ctx)) - { - enum section_id sid = _m_sec->sect.id; - struct where where = WHERE (sid, NULL); - where_reset_1 (&where, read_ctx_get_offset (&ctx)); - const unsigned char *set_begin = ctx.ptr; - - /* Size. */ - uint32_t size32; - uint64_t size; - int offset_size; - if (!read_ctx_read_4ubyte (&ctx, &size32)) - { - wr_error (&where, ": can't read table length.\n"); - return false; - } - if (!read_size_extra (&ctx, size32, &size, &offset_size, &where)) - return false; - + bool + check_pub_structural (elf_file const &file, sec §, + check_debug_info *cus) + { + struct read_ctx ctx; + read_ctx_init (&ctx, sect.data, file.other_byte_order); + bool retval = true; + + while (!read_ctx_eof (&ctx)) { - struct read_ctx sub_ctx; - const unsigned char *set_end = ctx.ptr + size; - if (!read_ctx_init_sub (&sub_ctx, &ctx, set_begin, set_end)) - goto not_enough; - sub_ctx.ptr = ctx.ptr; - - /* Version. */ - uint16_t version; - if (!read_ctx_read_2ubyte (&sub_ctx, &version)) - { - wr_error (&where, ": can't read set version.\n"); - retval = false; - goto next; - } - if (!supported_version (version, 1, &where, 2)) - { - retval = false; - goto next; - } + enum section_id sid = sect.id; + section_locus where (sid, read_ctx_get_offset (&ctx)); + const unsigned char *set_begin = ctx.ptr; + + /* Size. */ + uint32_t size32; + uint64_t size; + int offset_size; + if (!read_ctx_read_4ubyte (&ctx, &size32)) + { + wr_error (&where, ": can't read table length.\n"); + return false; + } + if (!read_size_extra (&ctx, size32, &size, &offset_size, where)) + return false; - /* CU offset. */ - uint64_t cu_offset; /* Offset of related CU. */ - uint64_t ctx_offset = sub_ctx.ptr - ctx.begin; - if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_offset)) { - wr_error (&where, ": can't read debug info offset.\n"); - retval = false; - goto next; - } + struct read_ctx sub_ctx; + const unsigned char *set_end = ctx.ptr + size; + if (!read_ctx_init_sub (&sub_ctx, &ctx, set_begin, set_end)) + goto not_enough; + sub_ctx.ptr = ctx.ptr; + + /* Version. */ + uint16_t version; + if (!read_ctx_read_2ubyte (&sub_ctx, &version)) + { + wr_error (&where, ": can't read set version.\n"); + retval = false; + goto next; + } + if (!supported_version (version, 1, where, 2)) + { + retval = false; + goto next; + } - struct relocation *rel; - if ((rel = relocation_next (&_m_sec->sect.rel, ctx_offset, - &where, skip_mismatched))) - relocate_one (&_m_file, &_m_sec->sect.rel, rel, offset_size, - &cu_offset, &where, sec_info, NULL); - else if (_m_file.ehdr.e_type == ET_REL) - wr_message (mc_impact_2 | mc_pubtables | mc_reloc | mc_header, &where, - PRI_LACK_RELOCATION, "debug info offset"); - - struct cu *cu = NULL; - if (_m_cus != NULL && (cu = _m_cus->find_cu (cu_offset)) == NULL) - wr_error (where) - << "unresolved reference to " << pri::CU (cu_offset) - << '.' << std::endl; - // xxx this can be checked even without CU - if (cu != NULL) - { - where.ref = &cu->head->where; - bool *has = _m_sec->sect.id == sec_pubnames - ? &cu->has_pubnames : &cu->has_pubtypes; - if (*has) - wr_message (mc_impact_2 | mc_pubtables | mc_header, &where, - ": there has already been section for this CU.\n"); - else - *has = true; - } + /* CU offset. */ + uint64_t cu_offset; /* Offset of related CU. */ + { + uint64_t ctx_offset = sub_ctx.ptr - ctx.begin; + if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_offset)) + { + wr_error (&where, ": can't read debug info offset.\n"); + retval = false; + goto next; + } - /* Covered length. */ - uint64_t cu_len; - if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_len)) - { - wr_error (&where, ": can't read covered length.\n"); - retval = false; - goto next; - } - if (cu != NULL && cu_len != cu->head->total_size) - { - wr_error (where) - << "the table covers length " << cu_len << " but CU has length " - << cu->head->total_size << '.' << std::endl; - retval = false; - goto next; - } + struct relocation *rel; + if ((rel = relocation_next (§.rel, ctx_offset, + where, skip_mismatched))) + relocate_one (&file, §.rel, rel, offset_size, + &cu_offset, where, sec_info, NULL); + else if (file.ehdr.e_type == ET_REL) + wr_message (mc_impact_2 | mc_pubtables | mc_reloc | mc_header, &where, + PRI_LACK_RELOCATION, "debug info offset"); + } - /* Records... */ - while (!read_ctx_eof (&sub_ctx)) - { - ctx_offset = sub_ctx.ptr - ctx.begin; - where_reset_2 (&where, ctx_offset); + struct cu *cu = NULL; + if (cus != NULL && (cu = cus->find_cu (cu_offset)) == NULL) + wr_error (where) + << "unresolved reference to " << pri::CU (cu_offset) + << '.' << std::endl; + // xxx this can be checked even without CU + if (cu != NULL) + { + //where.ref = &cu->head->where; + bool *has = sect.id == sec_pubnames + ? &cu->has_pubnames : &cu->has_pubtypes; + if (*has) + wr_message (mc_impact_2 | mc_pubtables | mc_header, &where, + ": there has already been section for this CU.\n"); + else + *has = true; + } - uint64_t offset; - if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &offset)) + /* Covered length. */ + uint64_t cu_len; + if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_len)) { - wr_error (&where, ": can't read offset field.\n"); + wr_error (&where, ": can't read covered length.\n"); retval = false; goto next; } - if (offset == 0) - break; - - if (cu != NULL - && !addr_record_has_addr (&cu->die_addrs, - offset + cu->head->offset)) + if (cu != NULL && cu_len != cu->head->total_size) { wr_error (where) - << "unresolved reference to " << pri::DIE (offset) - << '.' << std::endl; + << "the table covers length " << cu_len << " but CU has length " + << cu->head->total_size << '.' << std::endl; retval = false; goto next; } - // xxx read_ctx_read_str??? - uint8_t c; - do - if (!read_ctx_read_ubyte (&sub_ctx, &c)) - { - wr_error (&where, ": can't read symbol name.\n"); - retval = false; - goto next; - } - while (c); - } + /* Records... */ + while (!read_ctx_eof (&sub_ctx)) + { + section_locus rec_where (sect.id, sub_ctx.ptr - ctx.begin); + + uint64_t offset; + if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &offset)) + { + wr_error (&rec_where, ": can't read offset field.\n"); + retval = false; + goto next; + } + if (offset == 0) + break; + + if (cu != NULL + && !cu->die_addrs.has_addr (offset + cu->head->offset)) + { + wr_error (rec_where) + << "unresolved reference to " << pri::DIE (offset) + << '.' << std::endl; + retval = false; + goto next; + } + + // xxx read_ctx_read_str??? + uint8_t c; + do + if (!read_ctx_read_ubyte (&sub_ctx, &c)) + { + wr_error (&rec_where, ": can't read symbol name.\n"); + retval = false; + goto next; + } + while (c); + } - sid = _m_sec->sect.id; - struct where wh = WHERE (sid, NULL); - if (sub_ctx.ptr != sub_ctx.end) - { - uint64_t off_start, off_end; - if (read_check_zero_padding (&sub_ctx, &off_start, &off_end)) - wr_message_padding_0 (mc_pubtables, &wh, off_start, off_end); - else - { - wr_message_padding_n0 (mc_pubtables | mc_error, &wh, - off_start, off_start + size); - retval = false; - } - } - } + if (sub_ctx.ptr != sub_ctx.end) + { + uint64_t off_start, off_end; + if (read_check_zero_padding (&sub_ctx, &off_start, &off_end)) + wr_message_padding_0 (mc_pubtables, section_locus (sect.id), + off_start, off_end); + else + { + wr_message_padding_n0 (mc_pubtables | mc_error, + section_locus (sect.id), + off_start, off_start + size); + retval = false; + } + } + } - next: - if (read_ctx_skip (&ctx, size)) - continue; + next: + if (read_ctx_skip (&ctx, size)) + continue; - not_enough: - wr_error (&where, PRI_NOT_ENOUGH, "next set"); - return false; - } + not_enough: + wr_error (&where, PRI_NOT_ENOUGH, "next set"); + return false; + } - if (retval) - relocation_skip_rest (&_m_sec->sect.rel, _m_sec->sect.id); + if (retval) + relocation_skip_rest (§.rel, section_locus (sect.id)); - return retval; + return retval; + } } diff --git a/dwarflint/check_debug_pub.hh b/dwarflint/check_debug_pub.hh index 86e430427..01caed5a1 100644 --- a/dwarflint/check_debug_pub.hh +++ b/dwarflint/check_debug_pub.hh @@ -41,8 +41,6 @@ protected: elf_file const &_m_file; check_debug_info *_m_cus; - bool check_pub_structural (); - public: // instantiated in .cc for each subclass check_debug_pub (checkstack &stack, dwarflint &lint); diff --git a/dwarflint/check_die_decl_call.cc b/dwarflint/check_die_decl_call.cc index 7bddad0d7..05f4b726f 100644 --- a/dwarflint/check_die_decl_call.cc +++ b/dwarflint/check_die_decl_call.cc @@ -64,19 +64,19 @@ namespace decl_file = attrs.find (DW_AT_decl_file); if (decl_column != attrs.end () && decl_line == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has decl_column, but NOT decl_line" << std::endl; if (decl_line != attrs.end () && decl_file == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has decl_line, but NOT decl_file" << std::endl; if (decl_file != attrs.end () && decl_line == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has decl_file, but NOT decl_line" << std::endl; @@ -90,19 +90,19 @@ namespace call_file = attrs.find (DW_AT_call_file); if (call_column != attrs.end () && call_line == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has call_column, but NOT call_line" << std::endl; if (call_line != attrs.end () && call_file == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has call_line, but NOT call_file" << std::endl; if (call_file != attrs.end () && call_line == attrs.end ()) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " has call_file, but NOT call_line" << std::endl; diff --git a/dwarflint/check_die_line_info.cc b/dwarflint/check_die_line_info.cc index d30453216..4f19113a7 100644 --- a/dwarflint/check_die_line_info.cc +++ b/dwarflint/check_die_line_info.cc @@ -98,7 +98,7 @@ namespace } if (! found) - wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) << " " << dwarf::attributes::name (pc.first) << "=0x" diff --git a/dwarflint/check_die_tree.cc b/dwarflint/check_die_tree.cc index 0e0b38d49..5aeea9eb5 100644 --- a/dwarflint/check_die_tree.cc +++ b/dwarflint/check_die_tree.cc @@ -97,7 +97,7 @@ public: r += reason; } - wr_error (to_where (*a_d_it)) + wr_error (die_locus (*a_d_it)) << "A check failed: " << (_m_cd->name () ?: "(nil)") << r << std::endl; } diff --git a/dwarflint/check_duplicate_DW_tag_variable.cc b/dwarflint/check_duplicate_DW_tag_variable.cc index 838e3f693..f916ac037 100644 --- a/dwarflint/check_duplicate_DW_tag_variable.cc +++ b/dwarflint/check_duplicate_DW_tag_variable.cc @@ -108,14 +108,14 @@ namespace varinfo &i = old->second; if ((declaration && i.decl != children.end ()) || (!declaration && i.def != children.end ())) - wr_message (to_where (*jt), mc_impact_3 | mc_die_other) + wr_message (die_locus (*jt), mc_impact_3 | mc_die_other) .id (descriptor ()) << "Re" << (declaration ? "declaration" : "definition") << " of variable '" << name << "', originally seen at " << pri::ref (declaration ? *i.decl : *i.def) << '.' << std::endl; else - wr_message (to_where (*jt), mc_impact_3 | mc_die_other) + wr_message (die_locus (*jt), mc_impact_3 | mc_die_other) .id (descriptor ()) << "Found " << (declaration ? "declaration" : "definition") diff --git a/dwarflint/check_dups_abstract_origin.cc b/dwarflint/check_dups_abstract_origin.cc index acb4274f8..47297ea7a 100644 --- a/dwarflint/check_dups_abstract_origin.cc +++ b/dwarflint/check_dups_abstract_origin.cc @@ -122,7 +122,7 @@ namespace if ((at2 = m.find ((*at).first)) != m.end () && ! duplicate_ok (entry.tag (), at2->first, attr.first, referree.tag (), at2->second == (*at).second)) - wr_message (to_where (entry), mc_impact_3 | mc_acc_bloat | mc_die_rel) + wr_message (die_locus (entry), mc_impact_3 | mc_acc_bloat | mc_die_rel) .id (descriptor ()) << dwarf::tags::name (entry.tag ()) << " attribute " << dwarf::attributes::name (at2->first) diff --git a/dwarflint/check_expected_trees.cc b/dwarflint/check_expected_trees.cc index a758c7c3f..1b8cb4e97 100644 --- a/dwarflint/check_expected_trees.cc +++ b/dwarflint/check_expected_trees.cc @@ -104,9 +104,7 @@ check_expected_trees::check_expected_trees (checkstack &stack, dwarflint &lint) void operator () (dwarf::compile_unit const &cu, dwarf::debug_info_entry const &parent) { - struct where where = WHERE (sec_info, NULL); - where_reset_1 (&where, cu.offset ()); - where_reset_2 (&where, parent.offset ()); + die_locus where (parent); int parent_tag = parent.tag (); @@ -204,7 +202,7 @@ check_expected_trees::check_expected_trees (checkstack &stack, dwarflint &lint) // XXX more specific class when has it catch (std::runtime_error &exc) { - wr_error (WHERE (sec_info, NULL)) + wr_error (section_locus (sec_info)) << "Exception while checking expected trees: " << exc.what () << std::endl; throw check_base::failed (); diff --git a/dwarflint/check_linkage_external_die.cc b/dwarflint/check_linkage_external_die.cc index d615afaef..74d2ad4be 100644 --- a/dwarflint/check_linkage_external_die.cc +++ b/dwarflint/check_linkage_external_die.cc @@ -133,7 +133,7 @@ namespace && entry.tag () != DW_TAG_union_type) || attrs.find (DW_AT_name) != attrs.end ())) { - wr_message (to_where (entry), + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal | mc_die_other) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) @@ -152,7 +152,7 @@ namespace if (attrs.find (DW_AT_declaration) == attrs.end () && is_external (it)) { - wr_message (to_where (entry), + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal | mc_die_other) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) @@ -165,7 +165,7 @@ namespace { // Global symbol in symbol table, not marked external. // Always bad. - wr_message (to_where (entry), + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal | mc_die_other) .id (descriptor ()) << elfutils::dwarf::tags::name (entry.tag ()) diff --git a/dwarflint/check_matching_ranges.cc b/dwarflint/check_matching_ranges.cc index 6f2f4eb67..12e2d06cb 100644 --- a/dwarflint/check_matching_ranges.cc +++ b/dwarflint/check_matching_ranges.cc @@ -43,8 +43,7 @@ namespace static checkdescriptor cd (checkdescriptor::create ("check_matching_ranges") .description ( -"Check that the ranges in .debug_aranges and .debug_ranges match.\n" -)); +"Check that the ranges in .debug_aranges and .debug_ranges match.\n")); return &cd; } @@ -63,20 +62,15 @@ check_matching_ranges::check_matching_ranges (checkstack &stack, try { - struct where where_ref = WHERE (sec_info, NULL); - struct where where_ar = WHERE (sec_aranges, NULL); - where_ar.ref = &where_ref; - struct where where_r = WHERE (sec_ranges, NULL); - where_r.ref = &where_ref; char buf[128]; - const dwarf::aranges_map &aranges = dw.aranges (); for (dwarf::aranges_map::const_iterator i = aranges.begin (); i != aranges.end (); ++i) { const dwarf::compile_unit &cu = i->first; - where_reset_1 (&where_ref, 0); - where_reset_2 (&where_ref, cu.offset ()); + cudie_locus where_ref (cu); + loc_range_locus where_r (sec_ranges, where_ref); + arange_locus where_ar (where_ref); std::set cu_aranges = i->second, @@ -114,7 +108,7 @@ check_matching_ranges::check_matching_ranges (checkstack &stack, // XXX more specific class when has it catch (std::runtime_error &exc) { - wr_error (WHERE (sec_info, NULL)) + wr_error (section_locus (sec_info)) << "Exception while checking matching ranges: " << exc.what () << std::endl; throw check_base::failed (); diff --git a/dwarflint/check_nodebug.cc b/dwarflint/check_nodebug.cc index a5ed1c19a..e5443976a 100644 --- a/dwarflint/check_nodebug.cc +++ b/dwarflint/check_nodebug.cc @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2009,2010 Red Hat, Inc. + Copyright (C) 2009,2010,2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -53,7 +53,7 @@ public: private: void not_available (section_id sec_id) { - wr_error (WHERE (sec_id, NULL)) + wr_error (section_locus (sec_id)) << "data not found." << std::endl; } diff --git a/dwarflint/check_range_out_of_scope.cc b/dwarflint/check_range_out_of_scope.cc index c0312917a..cae7c8443 100644 --- a/dwarflint/check_range_out_of_scope.cc +++ b/dwarflint/check_range_out_of_scope.cc @@ -31,7 +31,6 @@ #include "coverage.hh" #include "pri.hh" #include "check_debug_loc_range.hh" -#include "misc.hh" using elfutils::dwarf; @@ -46,7 +45,7 @@ namespace static void recursively_validate (dwarf::compile_unit const &cu, dwarf::debug_info_entry const &die, ranges_t const &ranges, - where const &wh_parent); + locus const &wh_parent); public: static checkdescriptor const *descriptor () { @@ -73,7 +72,7 @@ check_range_out_of_scope::check_range_out_of_scope (checkstack &stack, dwarflint class dwarf::compile_units_type const &cus = dw.compile_units (); ranges_t r; r.push_back (std::make_pair (0, -1)); - where wh = WHERE (sec_info, NULL); + section_locus wh (sec_info); for (dwarf::compile_units_type::const_iterator it = cus.begin (); it != cus.end (); ++it) recursively_validate (*it, *it, r, wh); @@ -81,7 +80,7 @@ check_range_out_of_scope::check_range_out_of_scope (checkstack &stack, dwarflint // XXX more specific class when has it catch (std::runtime_error &exc) { - wr_error (WHERE (sec_info, NULL)) + wr_error (section_locus (sec_info)) << "Exception while checking ranges out of scope: " << exc.what () << std::endl; throw check_base::failed (); @@ -93,11 +92,9 @@ check_range_out_of_scope::recursively_validate (dwarf::compile_unit const &cu, dwarf::debug_info_entry const &die, ranges_t const &ranges, - where const &wh_parent) + locus const &wh_parent) { - where wh = WHERE (sec_info, NULL); - where_reset_1 (&wh, cu.offset ()); - where_reset_2 (&wh, die.offset ()); + die_locus wh (die); ::Dwarf_Addr low_pc = 0; ::Dwarf_Addr high_pc = ::noaddr; diff --git a/dwarflint/check_self_referential_die.cc b/dwarflint/check_self_referential_die.cc index e81560aa6..752fdfbb2 100644 --- a/dwarflint/check_self_referential_die.cc +++ b/dwarflint/check_self_referential_die.cc @@ -65,7 +65,7 @@ namespace { dwarf::debug_info_entry ref = *val.reference (); if (ref.identity () == entry.identity ()) - wr_message (to_where (entry), + wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal | mc_die_rel) .id (descriptor ()) << dwarf::tags::name (entry.tag ()) diff --git a/dwarflint/checked_read.cc b/dwarflint/checked_read.cc index 14831ecb1..b2b14682c 100644 --- a/dwarflint/checked_read.cc +++ b/dwarflint/checked_read.cc @@ -39,13 +39,13 @@ bool read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep, - int *offset_sizep, struct where *where) + int *offset_sizep, locus const &loc) { if (size32 == DWARF3_LENGTH_64_BIT) { if (!read_ctx_read_8ubyte (ctx, sizep)) { - wr_error (where, ": can't read 64bit CU length.\n"); + wr_error (loc) << "can't read 64bit CU length.\n"; return false; } @@ -53,8 +53,8 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep, } else if (size32 >= DWARF3_LENGTH_MIN_ESCAPE_CODE) { - wr_error (where, ": unrecognized CU length escape value: " - "%" PRIx32 ".\n", size32); + wr_error (loc) + << "unrecognized CU length escape value: " << size32 << ".\n"; return false; } else @@ -67,15 +67,13 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep, } error_code -read_address_size (struct read_ctx *ctx, - bool addr_64, - int *address_sizep, - struct where const *where) +read_address_size (struct read_ctx *ctx, bool addr_64, + int *address_sizep, locus const &loc) { uint8_t address_size; if (!read_ctx_read_ubyte (ctx, &address_size)) { - wr_error (where, ": can't read address size.\n"); + wr_error (loc) << "can't read address size.\n"; return err_fatal; } @@ -84,18 +82,16 @@ read_address_size (struct read_ctx *ctx, { /* Keep going. Deduce the address size from ELF header, and try to parse it anyway. */ - wr_error (where, - ": invalid address size: %d (only 4 or 8 allowed).\n", - address_size); + wr_error (loc) << "invalid address size: " << (int)address_size + << " (only 4 or 8 allowed).\n"; address_size = addr_64 ? 8 : 4; ret = err_nohl; } else if ((address_size == 8) != addr_64) { /* Keep going, we may still be able to parse it. */ - wr_error (where, - ": CU reports address size of %d in %d-bit ELF.\n", - address_size, addr_64 ? 64 : 32); + wr_error (loc) << "CU reports address size of " << address_size + << " in " << (addr_64 ? 64 : 32) << "-bit ELF.\n"; ret = err_nohl; } @@ -105,59 +101,59 @@ read_address_size (struct read_ctx *ctx, bool checked_read_uleb128 (read_ctx *ctx, uint64_t *ret, - where const *where, const char *what) + locus const &loc, const char *what) { const unsigned char *ptr = ctx->ptr; int st = read_ctx_read_uleb128 (ctx, ret); if (st < 0) - wr_error (where, ": can't read %s.\n", what); + wr_error (loc) << "can't read " << what << ".\n"; else if (st > 0) { char buf[19]; // 16 hexa digits, "0x", terminating zero sprintf (buf, "%#" PRIx64, *ret); - wr_format_leb128_message (where, what, buf, ptr, ctx->ptr); + wr_format_leb128_message (loc, what, buf, ptr, ctx->ptr); } return st >= 0; } bool checked_read_sleb128 (read_ctx *ctx, int64_t *ret, - where const *where, const char *what) + locus const &loc, const char *what) { const unsigned char *ptr = ctx->ptr; int st = read_ctx_read_sleb128 (ctx, ret); if (st < 0) - wr_error (where, ": can't read %s.\n", what); + wr_error (loc) << "can't read " << what << ".\n"; else if (st > 0) { char buf[20]; // sign, "0x", 16 hexa digits, terminating zero int64_t val = *ret; sprintf (buf, "%s%#" PRIx64, val < 0 ? "-" : "", val < 0 ? -val : val); - wr_format_leb128_message (where, what, buf, ptr, ctx->ptr); + wr_format_leb128_message (loc, what, buf, ptr, ctx->ptr); } return st >= 0; } bool checked_read_leb128 (read_ctx *ctx, form_width_t width, uint64_t *ret, - where const *where, const char *what) + locus const &loc, const char *what) { assert (width == fw_sleb || width == fw_uleb); if (width == fw_sleb) { int64_t svalue; - if (!checked_read_sleb128 (ctx, &svalue, where, what)) + if (!checked_read_sleb128 (ctx, &svalue, loc, what)) return false; *ret = (uint64_t) svalue; return true; } else - return checked_read_uleb128 (ctx, ret, where, what); + return checked_read_uleb128 (ctx, ret, loc, what); } bool read_sc_value (uint64_t *valuep, form_width_t width, - read_ctx *ctx, where const *where) + read_ctx *ctx, locus const &loc) { switch (width) { @@ -174,7 +170,7 @@ read_sc_value (uint64_t *valuep, form_width_t width, case fw_uleb: case fw_sleb: return checked_read_leb128 (ctx, width, valuep, - where, "attribute value"); + loc, "attribute value"); case fw_unknown: ; @@ -185,13 +181,13 @@ read_sc_value (uint64_t *valuep, form_width_t width, bool read_generic_value (read_ctx *ctx, form_width_t width, storage_class_t storclass, - where const *where, uint64_t *valuep, read_ctx *blockp) + locus const &loc, uint64_t *valuep, read_ctx *blockp) { uint64_t value; if (storclass == sc_value || storclass == sc_block) { - if (!read_sc_value (&value, width, ctx, where)) + if (!read_sc_value (&value, width, ctx, loc)) return false; if (valuep != NULL) *valuep = value; diff --git a/dwarflint/checked_read.hh b/dwarflint/checked_read.hh index 1e0deda8c..99941e8a2 100644 --- a/dwarflint/checked_read.hh +++ b/dwarflint/checked_read.hh @@ -27,7 +27,7 @@ #define DWARFLINT_CHECKED_READ_HH #include "readctx.hh" -#include "where.h" +#include "locus.hh" #include "dwarf_version.hh" enum error_code @@ -38,28 +38,26 @@ enum error_code }; bool read_size_extra (read_ctx *ctx, uint32_t size32, uint64_t *sizep, - int *offset_sizep, where *where); + int *offset_sizep, locus const &loc); /// Read address size and return it via address_sizep and return 0. /// Address size may be 4 or 8; for other values it's set depending or /// addr_64, and err_nohl is returned. -error_code read_address_size (read_ctx *ctx, - bool addr_64, - int *address_sizep, - where const *where); +error_code read_address_size (read_ctx *ctx, bool addr_64, + int *address_sizep, locus const &loc); bool checked_read_uleb128 (read_ctx *ctx, uint64_t *ret, - where const *where, const char *what); + locus const &loc, const char *what); bool checked_read_sleb128 (read_ctx *ctx, int64_t *ret, - where const *where, const char *what); + locus const &loc, const char *what); bool checked_read_leb128 (read_ctx *ctx, form_width_t width, uint64_t *ret, - where const *where, const char *what); + locus const &loc, const char *what); /// Read value depending on the form width and storage class. bool read_sc_value (uint64_t *valuep, form_width_t width, - read_ctx *ctx, where const *where); + read_ctx *ctx, locus const &loc); /// Read value depending on the form width and storage class. /// Value is returned via VALUEP, if that is non-NULL; for block @@ -68,7 +66,7 @@ bool read_sc_value (uint64_t *valuep, form_width_t width, /// itself. bool read_generic_value (read_ctx *ctx, form_width_t width, storage_class_t storclass, - where const *where, uint64_t *valuep, + locus const &loc, uint64_t *valuep, read_ctx *blockp); #endif//DWARFLINT_CHECKED_READ_HH diff --git a/dwarflint/checks.hh b/dwarflint/checks.hh index a280dfd63..4827cb7f4 100644 --- a/dwarflint/checks.hh +++ b/dwarflint/checks.hh @@ -26,7 +26,7 @@ #ifndef DWARFLINT_CHECKS_HH #define DWARFLINT_CHECKS_HH -#include "where.h" +#include "locus.hh" #include "dwarflint.hh" #include "checkdescriptor.hh" #include "messages.hh" diff --git a/dwarflint/coverage.cc b/dwarflint/coverage.cc index 6d4109b96..f9194057a 100644 --- a/dwarflint/coverage.cc +++ b/dwarflint/coverage.cc @@ -29,7 +29,6 @@ #endif #include "coverage.hh" -#include "misc.hh" #include "pri.hh" #include diff --git a/dwarflint/cu_coverage.cc b/dwarflint/cu_coverage.cc index c09ecabda..4f87e0c4f 100644 --- a/dwarflint/cu_coverage.cc +++ b/dwarflint/cu_coverage.cc @@ -23,6 +23,10 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "cu_coverage.hh" #include "check_debug_info.hh" #include "check_debug_loc_range.hh" diff --git a/dwarflint/die_locus.cc b/dwarflint/die_locus.cc new file mode 100644 index 000000000..e27d0e2e6 --- /dev/null +++ b/dwarflint/die_locus.cc @@ -0,0 +1,53 @@ +/* + Copyright (C) 2011 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "die_locus.hh" +#include "pri.hh" + +char const * +locus_simple_fmt::cu_n () +{ + return "CU"; +} + +std::string +die_locus::format (bool brief) const +{ + std::stringstream ss; + if (!brief) + ss << section_name[sec_info] << ": "; + + ss << "DIE 0x" << std::hex << _m_offset; + + if (_m_attrib_name != -1) + ss << ", attr. " << pri::attr_name (_m_attrib_name); + + return ss.str (); +} + diff --git a/dwarflint/die_locus.hh b/dwarflint/die_locus.hh new file mode 100644 index 000000000..0c57d4f54 --- /dev/null +++ b/dwarflint/die_locus.hh @@ -0,0 +1,68 @@ +/* + Copyright (C) 2011 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifndef _DWARFLINT_DIE_LOCUS_H_ +#define _DWARFLINT_DIE_LOCUS_H_ + +#include "locus.hh" +#include "../libdw/c++/dwarf" + +namespace locus_simple_fmt +{ + char const *cu_n (); +}; + +typedef fixed_locus cu_locus; + +class die_locus + : public locus +{ + Dwarf_Off _m_offset; + int _m_attrib_name; + +public: + explicit die_locus (Dwarf_Off offset = -1, int attrib_name = -1) + : _m_offset (offset) + , _m_attrib_name (attrib_name) + {} + + template + explicit die_locus (T const &die, int attrib_name = -1) + : _m_offset (die.offset ()) + , _m_attrib_name (attrib_name) + {} + + void + set_attrib_name (int attrib_name) + { + _m_attrib_name = attrib_name; + } + + std::string format (bool brief = false) const; +}; + +#endif /* _DWARFLINT_DIE_LOCUS_H_ */ diff --git a/dwarflint/elf_file.hh b/dwarflint/elf_file.hh index d283e7877..e315247ec 100644 --- a/dwarflint/elf_file.hh +++ b/dwarflint/elf_file.hh @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files. - Copyright (C) 2008, 2009, 2010 Red Hat, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -40,6 +40,13 @@ struct sec Elf_Data *data; /* May be NULL if data in this section are missing or not substantial. */ enum section_id id; + + sec () + : scn (NULL) + , name (NULL) + , data (NULL) + , id (sec_invalid) + {} }; struct elf_file diff --git a/dwarflint/highlevel_check.hh b/dwarflint/highlevel_check.hh index 007756a41..66d6e38c2 100644 --- a/dwarflint/highlevel_check.hh +++ b/dwarflint/highlevel_check.hh @@ -31,6 +31,8 @@ #endif #include "checks.hh" +#include "check_debug_info.hh" + #include "../libdw/c++/dwarf" #include "../libdwfl/libdwfl.h" @@ -82,14 +84,4 @@ public: {} }; -template -inline where -to_where (T const &die) -{ - where ret = WHERE (sec_info, NULL); - where_reset_1 (&ret, 0); - where_reset_2 (&ret, die.offset ()); - return ret; -} - #endif//DWARFLINT_CHECKS_HIGH_HH diff --git a/dwarflint/locstats.cc b/dwarflint/locstats.cc index 614563eb4..8a8a05284 100644 --- a/dwarflint/locstats.cc +++ b/dwarflint/locstats.cc @@ -513,10 +513,7 @@ process(Dwarf *c_dw, dwarf const &dw) } catch (::error const &e) { - struct where where = WHERE (sec_info, NULL); - where_reset_1 (&where, it.cu ().offset ()); - where_reset_2 (&where, die.offset ()); - std::cerr << "error: " << where << ": " + std::cerr << "error: " << die_locus (die) << ": " << e.what () << '.' << std::endl; continue; } diff --git a/dwarflint/locus.cc b/dwarflint/locus.cc new file mode 100644 index 000000000..553e7d8b7 --- /dev/null +++ b/dwarflint/locus.cc @@ -0,0 +1,72 @@ +/* Pedantic checking of DWARF files + Copyright (C) 2008,2009,2010,2011 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include "locus.hh" +#include "section_id.hh" +#include +#include + +std::ostream & +operator << (std::ostream &os, locus const &loc) +{ + os << loc.format (); + return os; +} + +char const * +locus_simple_fmt::offset_n () +{ + return "offset"; +} + +void +locus_simple_fmt::hex (std::ostream &ss, uint64_t off) +{ + ss << "0x" << std::hex << off; +} + +void +locus_simple_fmt::dec (std::ostream &ss, uint64_t off) +{ + ss << std::dec << off; +} + +std::string +simple_locus_aux::format_simple_locus (char const *(*N) (), + void (*F) (std::ostream &, uint64_t), + bool brief, section_id sec, uint64_t off) +{ + std::stringstream ss; + if (!brief) + ss << section_name[sec]; + if (off != (uint64_t)-1) + { + if (!brief) + ss << ": "; + ss << N() << " "; + F (ss, off); + } + return ss.str (); +} diff --git a/dwarflint/locus.hh b/dwarflint/locus.hh new file mode 100644 index 000000000..4557c2a7c --- /dev/null +++ b/dwarflint/locus.hh @@ -0,0 +1,112 @@ +/* Pedantic checking of DWARF files + Copyright (C) 2009,2010,2011 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifndef DWARFLINT_WHERE_HH +#define DWARFLINT_WHERE_HH + +#include "section_id.hh" + +#include +#include +#include + +/// Instances of the locus subclasses are used as pointers into +/// debuginfo for documentation purposes (messages and errors). They +/// are usually tiny structures, and should be used as values, but we +/// need the abstract interface to be able to format them, and copy +/// them into ref_record. +class locus +{ +public: + virtual std::string format (bool brief = false) const = 0; + virtual ~locus () {} +}; + +std::ostream &operator << (std::ostream &os, locus const &loc); + +/// Helper class for simple_locus to reduce the template bloat. +class simple_locus_aux +{ +protected: + static std::string format_simple_locus (char const *(*N) (), + void (*F) (std::ostream &, uint64_t), + bool brief, section_id sec, + uint64_t off); +}; + +/// Template for quick construction of straightforward locus +/// subclasses (one address, one way of formatting). N should be a +/// function that returns the name of the argument. +/// locus_simple_fmt::hex, locus_simple_fmt::dec would be candidate +/// parameters for argument F. +template +class simple_locus + : public locus + , private simple_locus_aux +{ + section_id _m_sec; + uint64_t _m_offset; + +public: + explicit simple_locus (section_id sec, uint64_t offset = -1) + : _m_sec (sec) + , _m_offset (offset) + {} + + std::string + format (bool brief = false) const + { + return format_simple_locus (N, F, brief, _m_sec, _m_offset); + } +}; + +/// Constructor of simple_locus that fixes the section_id argument. +template +class fixed_locus + : public simple_locus +{ +public: + explicit fixed_locus (uint64_t offset = -1) + : simple_locus (S, offset) + {} +}; + +namespace locus_simple_fmt +{ + char const *offset_n (); + void hex (std::ostream &ss, uint64_t off); + void dec (std::ostream &ss, uint64_t off); +} + +/// Straightforward locus for cases where either offset is not +/// necessary at all, or if it is present, it's simply shown as +/// "offset: 0xf00". +typedef simple_locus section_locus; + +#endif//DWARFLINT_WHERE_HH diff --git a/dwarflint/lowlevel_checks.cc b/dwarflint/lowlevel_checks.cc index 987c56dfb..bbfe6764a 100644 --- a/dwarflint/lowlevel_checks.cc +++ b/dwarflint/lowlevel_checks.cc @@ -23,6 +23,10 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "lowlevel_checks.hh" #include "sections.hh" #include "check_debug_info.hh" diff --git a/dwarflint/main.cc b/dwarflint/main.cc index 548a15f54..70bea21b9 100644 --- a/dwarflint/main.cc +++ b/dwarflint/main.cc @@ -135,13 +135,6 @@ global_opt global_opt be_tolerant ("Be somewhat more tolerant.", "tolerant"); -// xxx as soon as where is in c++, this can move there -global_opt - opt_show_refs("\ -When validating .debug_loc and .debug_ranges, display information about \ -the DIE referring to the entry in consideration", "ref"); -extern "C" bool show_refs () { return (bool)opt_show_refs; } - int main (int argc, char *argv[]) { diff --git a/dwarflint/messages.cc b/dwarflint/messages.cc index 995220c3f..c696aca4d 100644 --- a/dwarflint/messages.cc +++ b/dwarflint/messages.cc @@ -24,7 +24,6 @@ . */ #include "messages.hh" -#include "misc.hh" #include "coverage.hh" #include "option.hh" @@ -217,9 +216,7 @@ operator<< (std::ostream &o, __attribute__ ((unused)) message_criteria const &cr void message_criteria::operator *= (message_criteria const &rhs) { - struct message_criteria ret; - WIPE (ret); - + message_criteria ret; for (size_t i = 0; i < size (); ++i) for (size_t j = 0; j < rhs.size (); ++j) { @@ -247,34 +244,32 @@ message_criteria::and_not (message_term const &term) } static void -wr_verror (const struct where *wh, const char *format, va_list ap) +wr_verror (locus const &loc, const char *format, va_list ap) { - printf ("error: %s", where_fmt (wh, NULL)); + printf ("error: %s", loc.format ().c_str ()); vprintf (format, ap); - where_fmt_chain (wh, "error"); ++error_count; } static void -wr_vwarning (const struct where *wh, const char *format, va_list ap) +wr_vwarning (locus const &loc, const char *format, va_list ap) { - printf ("%s", where_fmt (wh, NULL)); + printf ("%s", loc.format ().c_str ()); vprintf (format, ap); - where_fmt_chain (wh, "warning"); ++error_count; } void -wr_error (const struct where *wh, const char *format, ...) +wr_error (locus const *loc, const char *format, ...) { va_list ap; va_start (ap, format); - wr_verror (wh, format, ap); + wr_verror (*loc, format, ap); va_end (ap); } void -wr_message (unsigned long category, const struct where *wh, +wr_message (unsigned long category, locus const *loc, const char *format, ...) { va_list ap; @@ -286,9 +281,9 @@ wr_message (unsigned long category, const struct where *wh, if (whether && message_accept (&warning_criteria, category)) { if (message_accept (&error_criteria, category)) - wr_verror (wh, format, ap); + wr_verror (*loc, format, ap); else - wr_vwarning (wh, format, ap); + wr_vwarning (*loc, format, ap); } va_end (ap); } @@ -336,9 +331,9 @@ message_count_filter::should_emit (void const *key) } message_context::message_context (message_count_filter *filter, - where const *where, char const *prefix) + locus const *loc, char const *prefix) : _m_filter (filter) - , _m_where (where) + , _m_loc (loc) , _m_prefix (prefix) {} @@ -353,8 +348,8 @@ message_context::when (bool whether) const std::ostream &ret = get_stream (); ret << _m_prefix; - if (_m_where) - ret << *_m_where << ": "; + if (_m_loc != NULL) + ret << _m_loc->format () << ": "; return ret; } else @@ -412,22 +407,23 @@ wr_error () } std::ostream & -wr_error (where const &wh) +wr_error (locus const &loc) { - return wr_error () << wh << ": "; + std::string fmt = loc.format (); + return wr_error () << fmt << ": "; } message_context -message_context::filter_message (where const *wh, message_category category) +message_context::filter_message (locus const *loc, message_category category) { if (!message_accept (&warning_criteria, category)) return message_context (NULL, NULL, NULL); else if (message_accept (&error_criteria, category)) return message_context (message_count_filter::inst (), - wh, "error: "); + loc, "error: "); else return message_context (message_count_filter::inst (), - wh, "warning: "); + loc, "warning: "); } message_context @@ -437,24 +433,24 @@ wr_message (message_category category) } message_context -wr_message (where const &wh, message_category category) +wr_message (locus const &loc, message_category category) { - return message_context::filter_message (&wh, category); + return message_context::filter_message (&loc, category); } void wr_format_padding_message (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end, char const *kind) { char msg[128]; - wr_message (*wh, category) + wr_message (loc, category) << range_fmt (msg, sizeof msg, start, end) << ": " << kind << "." << std::endl; } void -wr_format_leb128_message (struct where const *where, +wr_format_leb128_message (locus const &loc, const char *what, const char *purpose, const unsigned char *begin, const unsigned char *end) @@ -464,28 +460,28 @@ wr_format_leb128_message (struct where const *where, char *ptr = buf; for (; begin < end; ++begin) ptr += sprintf (ptr, " %02x", *begin); - wr_message (*where, category) + wr_message (loc, category) << what << ": value " << purpose << " encoded as `" << (buf + 1) << "'." << std::endl; } void wr_message_padding_0 (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end) { wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, - wh, start, end, + loc, start, end, "unnecessary padding with zero bytes"); } void wr_message_padding_n0 (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end) { wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, - wh, start, end, + loc, start, end, "unreferenced non-zero bytes"); } diff --git a/dwarflint/messages.hh b/dwarflint/messages.hh index 6e85d4299..88ed3a849 100644 --- a/dwarflint/messages.hh +++ b/dwarflint/messages.hh @@ -26,7 +26,7 @@ #ifndef DWARFLINT_MESSAGES_HH #define DWARFLINT_MESSAGES_HH -#include "where.h" +#include "locus.hh" #include "libdw.h" #include #include @@ -114,30 +114,30 @@ std::ostream &operator<< (std::ostream &o, message_criteria const &criteria); message_criteria operator ! (message_term const &); -extern void wr_error (const struct where *wh, const char *format, ...) +extern void wr_error (locus const *wh, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -extern void wr_message (unsigned long category, const struct where *wh, +extern void wr_message (unsigned long category, locus const *loc, const char *format, ...) __attribute__ ((format (printf, 3, 4))); extern void wr_format_padding_message (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end, char const *kind); -extern void wr_format_leb128_message (struct where const *where, +extern void wr_format_leb128_message (locus const &loc, const char *what, const char *purpose, const unsigned char *begin, const unsigned char *end); extern void wr_message_padding_0 (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end); extern void wr_message_padding_n0 (message_category category, - struct where const *wh, + locus const &loc, uint64_t start, uint64_t end); extern bool message_accept (struct message_criteria const *cri, @@ -191,18 +191,18 @@ class message_context static bool _m_last_emitted; message_count_filter *_m_filter; - where const *_m_where; + locus const *_m_loc; char const *_m_prefix; - friend message_context wr_message (where const &wh, message_category cat); + friend message_context wr_message (locus const &loc, message_category cat); friend message_context wr_message (message_category cat); friend bool wr_prev_emitted (); message_context (message_count_filter *filter, - where const *where, char const *prefix); + locus const *loc, char const *prefix); public: - static message_context filter_message (where const *wh, + static message_context filter_message (locus const *loc, message_category category); std::ostream &operator << (char const *message); @@ -231,9 +231,9 @@ public: std::ostream &when_prev () const; }; -std::ostream &wr_error (where const &wh); +std::ostream &wr_error (locus const &loc); std::ostream &wr_error (); -message_context wr_message (where const &wh, message_category cat); +message_context wr_message (locus const &loc, message_category cat); message_context wr_message (message_category cat); void wr_reset_counters (); bool wr_prev_emitted (); diff --git a/dwarflint/misc.cc b/dwarflint/misc.cc index 497ee114e..895732fc9 100644 --- a/dwarflint/misc.cc +++ b/dwarflint/misc.cc @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2008, 2009, 2010 Red Hat, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -45,11 +45,11 @@ necessary_alignment (uint64_t start, uint64_t length, uint64_t align) bool supported_version (unsigned version, - size_t num_supported, struct where *where, ...) + size_t num_supported, locus const &loc, ...) { bool retval = false; va_list ap; - va_start (ap, where); + va_start (ap, loc); for (size_t i = 0; i < num_supported; ++i) { unsigned v = va_arg (ap, unsigned); @@ -62,7 +62,7 @@ supported_version (unsigned version, va_end (ap); if (!retval) - wr_error (where, ": unsupported version %d.\n", version); + wr_error (loc) << "unsupported version " << version << ".\n"; return retval; } diff --git a/dwarflint/misc.hh b/dwarflint/misc.hh index fac9526d2..6be3dbd5a 100644 --- a/dwarflint/misc.hh +++ b/dwarflint/misc.hh @@ -27,7 +27,7 @@ #define DWARFLINT_MISC_HH #include -#include "where.h" +#include "locus.hh" extern "C" { @@ -49,14 +49,12 @@ extern "C" } \ } while (0) -#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ)) - bool address_aligned (uint64_t addr, uint64_t align); bool necessary_alignment (uint64_t start, uint64_t length, uint64_t align); bool supported_version (unsigned version, - size_t num_supported, struct where *where, ...); + size_t num_supported, locus const &loc, ...); #define UNREACHABLE assert (!"unreachable") diff --git a/dwarflint/pri.cc b/dwarflint/pri.cc index de01463f9..6f289ab8d 100644 --- a/dwarflint/pri.cc +++ b/dwarflint/pri.cc @@ -64,3 +64,10 @@ pri::operator << (std::ostream &os, pri::range const &obj) return os << "[" << pri::addr (obj.start) << ", " << pri::addr (obj.end) << ")"; } + +std::string +pri::attr_name (int name) +{ + assert (name != -1); + return elfutils::dwarf::attributes::name (name); +} diff --git a/dwarflint/pri.hh b/dwarflint/pri.hh index 67705f40c..cef1ba9a6 100644 --- a/dwarflint/pri.hh +++ b/dwarflint/pri.hh @@ -114,6 +114,8 @@ namespace pri friend std::ostream &operator << (std::ostream &os, range const &obj); }; std::ostream &operator << (std::ostream &os, range const &obj); + + std::string attr_name (int name); } #endif//DWARFLINT_PRI_H diff --git a/dwarflint/readctx.hh b/dwarflint/readctx.hh index 29fc451c0..2a1a39f3b 100644 --- a/dwarflint/readctx.hh +++ b/dwarflint/readctx.hh @@ -29,11 +29,6 @@ #include #include "../libelf/libelf.h" -#ifdef __cplusplus -extern "C" -{ -#endif - /* Functions and data structures related to bounds-checked reading. */ @@ -82,8 +77,5 @@ bool read_ctx_eof (struct read_ctx *ctx); bool read_check_zero_padding (struct read_ctx *ctx, uint64_t *ret_off_start, uint64_t *ret_off_end); -#ifdef __cplusplus -} -#endif #endif diff --git a/dwarflint/reloc.cc b/dwarflint/reloc.cc index 2e23248b8..563077cc4 100644 --- a/dwarflint/reloc.cc +++ b/dwarflint/reloc.cc @@ -31,25 +31,69 @@ #include "messages.hh" #include "misc.hh" #include "readctx.hh" +#include "pri.hh" #include #include #include -#include +#include -static struct where -where_from_reloc (struct relocation_data *reloc, struct where const *ref) +namespace { - struct where where - = WHERE (reloc->type == SHT_REL ? sec_rel : sec_rela, NULL); - where_reset_1 (&where, reloc->rel[reloc->index].offset); - where.ref = ref; - return where; + class reloc_locus + : public locus + { + locus const &_m_ref; + size_t _m_index; + uint64_t _m_offset; + int _m_type; + + public: + reloc_locus (int type, locus const &ref, uint64_t offset) + : _m_ref (ref) + , _m_index (-1) + , _m_offset (offset) + , _m_type (type) + { + } + + reloc_locus (int type, locus const &ref, unsigned index) + : _m_ref (ref) + , _m_index (index) + , _m_offset (-1) + , _m_type (type) + { + } + + void + set_offset (uint64_t offset) + { + _m_offset = offset; + } + + virtual std::string + format (bool) const + { + std::stringstream ss; + ss << (_m_type == SHT_REL ? ".rel" : ".rela") << " "; + if (_m_offset != (uint64_t)-1) + ss << pri::hex (_m_offset); + else + { + assert (_m_index != (size_t)-1); + ss << "#" << _m_index; + } + + // Do non-brief formatting of referee + ss << " of " << _m_ref.format (); + return ss.str (); + } + }; } relocation * relocation_next (relocation_data *reloc, uint64_t offset, - struct where const *where, enum skip_type st) + locus const &loc, enum skip_type st) { if (reloc == NULL || reloc->rel == NULL) return NULL; @@ -71,8 +115,7 @@ relocation_next (relocation_data *reloc, uint64_t offset, { if (st != skip_ok) { - struct where reloc_where = where_from_reloc (reloc, where); - where_reset_2 (&reloc_where, rel->offset); + reloc_locus reloc_where (reloc->type, loc, rel->offset); wr_error (reloc_where) << (st == skip_unref ? "relocation targets unreferenced portion of the section." @@ -94,10 +137,10 @@ relocation_next (relocation_data *reloc, uint64_t offset, matching that offset is immediately yielded. */ void relocation_skip (struct relocation_data *reloc, uint64_t offset, - struct where const *where, enum skip_type st) + locus const &loc, enum skip_type st) { if (reloc != NULL && reloc->rel != NULL) - relocation_next (reloc, offset - 1, where, st); + relocation_next (reloc, offset - 1, loc, st); } void @@ -109,15 +152,11 @@ relocation_reset (struct relocation_data *reloc) /* Skip all the remaining relocations. */ void -relocation_skip_rest (struct relocation_data *reloc, - enum section_id id) +relocation_skip_rest (relocation_data *reloc, + locus const &loc) { if (reloc->rel != NULL) - { - where wh = WHERE (id, NULL); - relocation_next (reloc, (uint64_t)-1, &wh, - skip_mismatched); - } + relocation_next (reloc, (uint64_t)-1, loc, skip_mismatched); } static void @@ -126,8 +165,8 @@ do_one_relocation (elf_file const *file, relocation *rel, unsigned rel_width, uint64_t *value, - where const &reloc_where, - section_id offset_into, + reloc_locus const &reloc_where, + rel_target reltgt, GElf_Sym *symbol, GElf_Sym **symptr) { @@ -189,23 +228,23 @@ do_one_relocation (elf_file const *file, } /* It's target value, not section offset. */ - if (offset_into == rel_value - || offset_into == rel_address - || offset_into == rel_exec) + if (reltgt == rel_target::rel_value + || reltgt == rel_target::rel_address + || reltgt == rel_target::rel_exec) { /* If a target value is what's expected, then complain if it's not either SHN_ABS, an SHF_ALLOC section, or SHN_UNDEF. For data forms of address_size, an SHN_UNDEF reloc is acceptable, otherwise reject it. */ if (!(section_index == SHN_ABS - || (offset_into == rel_address + || (reltgt == rel_target::rel_address && (section_index == SHN_UNDEF || section_index == SHN_COMMON)))) { - if (offset_into != rel_address && section_index == SHN_UNDEF) + if (reltgt != rel_target::rel_address && section_index == SHN_UNDEF) wr_error (&reloc_where, - ": relocation of an address is formed using SHN_UNDEF symbol" - " (symtab index %d).\n", rel->symndx); + ": relocation of an address is formed using SHN_UNDEF symbol" + " (symtab index %d).\n", rel->symndx); else { require_valid_section_index; @@ -214,7 +253,7 @@ do_one_relocation (elf_file const *file, wr_message (mc_reloc | mc_impact_3, &reloc_where, ": associated section %s isn't SHF_ALLOC.\n", file->sec[section_index].name); - if (offset_into == rel_exec + if (reltgt == rel_target::rel_exec && (shdr->sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR) /* This may still be kosher, but it's suspicious. */ wr_message (mc_reloc | mc_impact_2, &reloc_where, @@ -226,13 +265,14 @@ do_one_relocation (elf_file const *file, else { require_valid_section_index; - if (file->sec[section_index].id != offset_into) + section_id secid = file->sec[section_index].id; + if (reltgt != secid) // If symtab[symndx].st_shndx does not match the expected // debug section's index, complain. wr_error (reloc_where) << "relocation references section " << (file->sec[section_index].name ?: "") << ", but " - << WHERE (offset_into, NULL) << " was expected." << std::endl; + << section_locus (secid) << " was expected." << std::endl; } /* Only do the actual relocation if we have ET_REL files. For @@ -257,16 +297,14 @@ relocate_one (struct elf_file const *file, struct relocation_data *reloc, struct relocation *rel, unsigned width, uint64_t *value, - struct where const *where, - enum section_id offset_into, GElf_Sym **symptr) + locus const &loc, + rel_target reltgt, + GElf_Sym **symptr) { if (rel->invalid) return; - struct where reloc_where = where_from_reloc (reloc, where); - where_reset_2 (&reloc_where, rel->offset); - struct where reloc_ref_where = reloc_where; - reloc_ref_where.next = where; + reloc_locus reloc_where (reloc->type, loc, rel->offset); GElf_Sym symbol_mem, *symbol; if (symptr != NULL) @@ -277,10 +315,10 @@ relocate_one (struct elf_file const *file, else symbol = &symbol_mem; - if (offset_into == sec_invalid) + if (reltgt == sec_invalid) { - wr_message (mc_impact_3 | mc_reloc, &reloc_ref_where, - ": relocates a datum that shouldn't be relocated.\n"); + wr_message (reloc_where, mc_impact_3 | mc_reloc) + << "relocates a datum that shouldn't be relocated.\n"; return; } @@ -314,14 +352,14 @@ relocate_one (struct elf_file const *file, }; if (rel_width != width) - wr_error (&reloc_ref_where, - ": %d-byte relocation relocates %d-byte datum.\n", - rel_width, width); + wr_error (reloc_where) + << rel_width << "-byte relocation relocates " + << width << "-byte datum.\n"; // Tolerate if we failed to obtain the symbol table. if (reloc->symdata != NULL) do_one_relocation (file, reloc, rel, rel_width, value, - reloc_where, offset_into, symbol, symptr); + reloc_where, reltgt, symbol, symptr); } static GElf_Rela * @@ -371,17 +409,15 @@ read_rel (struct elf_file *file, : (is_rela ? sizeof (Elf32_Rela) : sizeof (Elf32_Rel)); size_t count = reldata->d_size / entrysize; - struct where parent = WHERE (sec->id, NULL); - struct where where = WHERE (is_rela ? sec_rela : sec_rel, NULL); - where.ref = &parent; + section_locus parent (sec->id); for (unsigned i = 0; i < count; ++i) { - where_reset_1 (&where, i); + reloc_locus where (sec->rel.type, parent, i); REALLOC (&sec->rel, rel); struct relocation *cur = sec->rel.rel + sec->rel.size++; - WIPE (*cur); + new (cur) relocation (); GElf_Rela rela_mem, *rela = get_rel_or_rela (reldata, i, &rela_mem, sec->rel.type); @@ -405,7 +441,7 @@ read_rel (struct elf_file *file, cur->symndx = GELF_R_SYM (rela->r_info); cur->type = cur_type; - where_reset_2 (&where, cur->offset); + where.set_offset (cur->offset); Elf_Type type = ebl_reloc_simple_type (file->ebl, cur->type); int width; diff --git a/dwarflint/reloc.hh b/dwarflint/reloc.hh index d7685c6fe..d35580fce 100644 --- a/dwarflint/reloc.hh +++ b/dwarflint/reloc.hh @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files. - Copyright (C) 2008, 2009, 2010 Red Hat, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ #ifndef DWARFLINT_RELOC_H #define DWARFLINT_RELOC_H -#include "where.h" +#include "locus.hh" #include "elf_file_i.hh" #include #include @@ -40,6 +40,14 @@ struct relocation bool invalid; /* Whether this one relocation should be ignored. Necessary so that we don't report invalid & missing relocation twice. */ + + relocation () + : offset (0) + , addend (0) + , symndx (0) + , type (0) + , invalid (false) + {} }; struct relocation_data @@ -54,6 +62,15 @@ struct relocation_data size_t size; size_t alloc; size_t index; /* Current index. */ + + relocation_data () + : symdata (NULL) + , type (SHT_NULL) + , rel (NULL) + , size (0) + , alloc (0) + , index (0) + {} }; enum skip_type @@ -63,28 +80,79 @@ enum skip_type skip_ok, }; +struct rel_target +{ + enum target + { + rel_value, /* For relocations, this denotes that the + relocation is applied to target value, not a + section offset. */ + rel_address, /* Same as above, but for addresses. */ + rel_exec, /* Some as above, but we expect EXEC bit. */ + }; + +private: + bool _m_is_section; + union + { + section_id _m_section; + target _m_target; + }; + +public: + rel_target (section_id sec) + : _m_is_section (true) + , _m_section (sec) + {} + + rel_target (target t) + : _m_is_section (false) + , _m_target (t) + {} + + bool + operator== (section_id sec) + { + return _m_is_section && _m_section == sec; + } + + bool + operator== (target tgt) + { + return !_m_is_section && _m_target == tgt; + } + + template + bool + operator!= (T t) + { + return !(*this == t); + } +}; + bool read_rel (struct elf_file *file, struct sec *sec, Elf_Data *reldata, bool elf_64); relocation *relocation_next (struct relocation_data *reloc, uint64_t offset, - struct where const *where, + locus const &loc, enum skip_type st); void relocation_reset (struct relocation_data *reloc); void relocation_skip (struct relocation_data *reloc, uint64_t offset, - struct where const *where, enum skip_type st); + locus const &loc, enum skip_type st); void relocation_skip_rest (struct relocation_data *reloc, - enum section_id id); + locus const &loc); void relocate_one (struct elf_file const *file, struct relocation_data *reloc, struct relocation *rel, unsigned width, uint64_t *value, - struct where const *where, - enum section_id offset_into, GElf_Sym **symptr); + locus const &loc, + rel_target reltgt, + GElf_Sym **symptr); #define PRI_LACK_RELOCATION ": %s seems to lack a relocation.\n" diff --git a/dwarflint/section_id.hh b/dwarflint/section_id.hh index 4b937d7fd..bd005c302 100644 --- a/dwarflint/section_id.hh +++ b/dwarflint/section_id.hh @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2009, 2010 Red Hat, Inc. + Copyright (C) 2009, 2010, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -45,22 +45,9 @@ enum section_id /* Debuginfo sections: */ #define SEC(n) sec_##n, DEBUGINFO_SECTIONS - count_debuginfo_sections, #undef SEC - /* Non-debuginfo sections: */ - sec_rel = count_debuginfo_sections, - sec_rela, - - // XXX the following should really be split out to different enum - /* Non-sections: */ - sec_locexpr, /* Not a section, but a portion of file that - contains a location expression. */ - rel_value, /* For relocations, this denotes that the - relocation is applied to taget value, not a - section offset. */ - rel_address, /* Same as above, but for addresses. */ - rel_exec, /* Some as above, but we expect EXEC bit. */ + count_debuginfo_sections }; // section_name[0] is for sec_invalid. The last index is for diff --git a/dwarflint/sections.cc b/dwarflint/sections.cc index 6f9f25461..a1c1aab95 100644 --- a/dwarflint/sections.cc +++ b/dwarflint/sections.cc @@ -246,7 +246,7 @@ namespace /* Section 0 is special, skip it. */ REALLOC (file, sec); - file->sec[file->size++].id = sec_invalid; + new (file->sec + file->size++) sec (); if (false) { @@ -266,6 +266,7 @@ namespace REALLOC (file, sec); size_t curndx = file->size++; struct sec *cursec = file->sec + curndx; + new (cursec) sec (); GElf_Shdr *shdr = gelf_getshdr (scn, &cursec->shdr); if (shdr == NULL) @@ -285,9 +286,9 @@ namespace secentry *entry = secinfo.get (scnname); cursec->scn = scn; - cursec->id = entry != NULL ? entry->id : sec_invalid; + if (entry != NULL) + cursec->id = entry->id; cursec->name = scnname; - cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0}; /* Dwarf section. */ if (entry != NULL) @@ -385,7 +386,7 @@ namespace struct sec *sec = file->sec + cur->secndx; sec->rel.type = cur->reltype; if (sec->data == NULL) - wr_error (WHERE (sec->id, NULL)) + wr_error (section_locus (sec->id)) << "this data-less section has a relocation section." << std::endl; else if (read_rel (file, sec, cur->reldata, file->addr_64)) @@ -395,7 +396,7 @@ namespace if (secentry *str = secinfo.get (".debug_str")) if (str->reldata != NULL) - wr_message (WHERE (sec_str, NULL), mc_impact_2 | mc_elf) + wr_message (section_locus (sec_str), mc_impact_2 | mc_elf) << "there's a relocation section associated with this section." << std::endl; } diff --git a/dwarflint/tests/run-DW_AT-later-version.sh b/dwarflint/tests/run-DW_AT-later-version.sh index 3565dc88c..00b9a3533 100755 --- a/dwarflint/tests/run-DW_AT-later-version.sh +++ b/dwarflint/tests/run-DW_AT-later-version.sh @@ -30,7 +30,7 @@ srcdir=$srcdir/tests testfiles DW_AT-later-version testrun_compare ./dwarflint --nognu DW_AT-later-version <). -error: .rela.debug_info: offset 0xc00: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x1100: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x1500: invalid relocation 256 (). -error: .rela.debug_info: offset 0x1d00: invalid relocation 256 (). -error: .rela.debug_info: offset 0x2500: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x3600: invalid relocation 256 (). +error: .rela 0x600 of .debug_info: invalid relocation 2560 (). +error: .rela 0xc00 of .debug_info: invalid relocation 2560 (). +error: .rela 0x1100 of .debug_info: invalid relocation 2560 (). +error: .rela 0x1500 of .debug_info: invalid relocation 256 (). +error: .rela 0x1d00 of .debug_info: invalid relocation 256 (). +error: .rela 0x2500 of .debug_info: invalid relocation 2560 (). +error: .rela 0x3600 of .debug_info: invalid relocation 256 (). warning: .debug_info: CU 0: abbrev table offset seems to lack a relocation -warning: .debug_info: DIE 0xb (abbr. attribute 0): strp seems to lack a relocation -warning: .debug_info: DIE 0xb (abbr. attribute 0x4): strp seems to lack a relocation -warning: .debug_info: DIE 0xb (abbr. attribute 0xa): data4 seems to lack a relocation +warning: .debug_info: DIE 0xb, attr. producer: strp seems to lack a relocation +warning: .debug_info: DIE 0xb, attr. comp_dir: strp seems to lack a relocation +warning: .debug_info: DIE 0xb, attr. stmt_list: data4 seems to lack a relocation warning: .debug_info: DIE 0xb: DW_AT_low_pc value not below DW_AT_high_pc. error: .debug_line: table 0: header claims that it has a size of 542, but in fact it has a size of 30. -error: .debug_info: DIE 0xb (abbr. attribute 0xa): unresolved reference to .debug_line table 0x0. +error: .debug_info: DIE 0xb, attr. stmt_list: unresolved reference to .debug_line table 0x0. EOF testrun_compare ./dwarflint garbage-12 <. */ - -#include "where.h" - -#include -#include -#include -#include -#include - -extern bool show_refs (void); - -struct section_info -{ - const char *name; - const char *addr1f; - const char *addr2f; - const char *addr3f; -}; - -static struct section_info section_names[] = - { - [sec_info] = {".debug_info", "CU %"PRId64, "DIE %#"PRIx64, NULL}, - - [sec_abbrev] = {".debug_abbrev", "section %"PRId64, - "abbreviation %"PRId64, "abbr. attribute %#"PRIx64}, - - [sec_aranges] = {".debug_aranges", "table %"PRId64, - "arange %#"PRIx64, NULL}, - - [sec_pubnames] = {".debug_pubnames", "pubname table %"PRId64, - "pubname %#"PRIx64, NULL}, - - [sec_pubtypes] = {".debug_pubtypes", "pubtype table %"PRId64, - "pubtype %#"PRIx64, NULL}, - - [sec_str] = {".debug_str", "offset %#"PRIx64, NULL, NULL}, - - [sec_line] = {".debug_line", "table %"PRId64, "offset %#"PRIx64, NULL}, - - [sec_loc] = {".debug_loc", "loclist %#"PRIx64, "offset %#"PRIx64, NULL}, - - [sec_mac] = {".debug_mac", NULL, NULL, NULL}, - - [sec_ranges] = {".debug_ranges", "rangelist %#"PRIx64, - "offset %#"PRIx64, NULL}, - - [sec_locexpr] = {"location expression", "offset %#"PRIx64, NULL, NULL}, - - [sec_rel] = {".rel", "relocation %"PRId64, "offset %#"PRIx64, NULL}, - - [sec_rela] = {".rela", "relocation %"PRId64, "offset %#"PRIx64, NULL}, - }; - -const char * -where_fmt (const struct where *wh, char *ptr) -{ - if (wh == NULL) - return ""; - - static char buf[256]; - - static struct section_info special_formats[] = - { - [wf_cudie] = {".debug_info", "CU DIE %"PRId64, NULL, NULL} - }; - - assert (wh->section < sizeof (section_names) / sizeof (*section_names)); - struct section_info *inf - = (wh->formatting == wf_plain) - ? section_names + wh->section - : special_formats + wh->formatting; - - assert (inf->name); - - assert ((wh->addr1 != (uint64_t)-1) ? inf->addr1f != NULL : true); - assert ((wh->addr2 != (uint64_t)-1) ? inf->addr2f != NULL : true); - assert ((wh->addr3 != (uint64_t)-1) ? inf->addr3f != NULL : true); - - assert ((wh->addr3 != (uint64_t)-1) ? (wh->addr2 != (uint64_t)-1) : true); - assert ((wh->addr2 != (uint64_t)-1) ? (wh->addr1 != (uint64_t)-1) : true); - - /* GCC insists on checking format parameters and emits a warning - when we don't use string literal. With -Werror this ends up - being hard error. So instead we walk around this warning by - using function pointer. */ - int (*x_asprintf)(char **strp, const char *fmt, ...) = asprintf; - -#define SETUP_ADDR(N) \ - char *addr##N##s; \ - bool free_s##N = false; \ - if (wh->addr##N == (uint64_t)-1) \ - addr##N##s = NULL; \ - else if (x_asprintf (&addr##N##s, inf->addr##N##f, wh->addr##N) >= 0) \ - free_s##N = true; \ - else \ - addr##N##s = "(fmt error)" - - SETUP_ADDR (1); - SETUP_ADDR (2); - SETUP_ADDR (3); -#undef SETUP_ADDR - - char *orig = ptr; - bool is_reloc = wh->section == sec_rel || wh->section == sec_rela; - if (ptr == NULL) - { - ptr = stpcpy (buf, inf->name); - if (is_reloc) - { - struct where const *ref = wh->ref; - assert (ref != NULL); - if (ref->section == sec_locexpr) - { - ref = ref->next; - assert (ref != NULL); - assert (ref->section != sec_locexpr); - } - ptr = stpcpy (ptr, section_names[ref->section].name); - } - - if (addr1s != NULL) - ptr = stpcpy (ptr, ": "); - } - - if (addr3s != NULL) - ptr = stpcpy (ptr, addr3s); - else if (addr2s != NULL) - ptr = stpcpy (ptr, addr2s); - else if (addr1s != NULL) - ptr = stpcpy (ptr, addr1s); - - if (free_s1) - free (addr1s); - if (free_s2) - free (addr2s); - if (free_s3) - free (addr3s); - - if (wh->ref != NULL && !is_reloc) - { - ptr = stpcpy (ptr, " ("); - ptr = (char *)where_fmt (wh->ref, ptr); - *ptr++ = ')'; - *ptr = 0; - } - - if (orig == NULL) - return buf; - else - return ptr; -} - -void -where_fmt_chain (const struct where *wh, const char *severity) -{ - if (wh != NULL && show_refs ()) - for (struct where const *it = wh->next; it != NULL; it = it->next) - printf ("%s: %s: caused by this reference.\n", - severity, where_fmt (it, NULL)); -} - -void -where_reset_1 (struct where *wh, uint64_t addr) -{ - wh->addr1 = addr; - wh->addr2 = wh->addr3 = (uint64_t)-1; -} - -void -where_reset_2 (struct where *wh, uint64_t addr) -{ - wh->addr2 = addr; - wh->addr3 = (uint64_t)-1; -} - -void -where_reset_3 (struct where *wh, uint64_t addr) -{ - wh->addr3 = addr; -} diff --git a/dwarflint/where.h b/dwarflint/where.h deleted file mode 100644 index fb1dd47a5..000000000 --- a/dwarflint/where.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Pedantic checking of DWARF files - Copyright (C) 2009,2010,2011 Red Hat, Inc. - This file is part of Red Hat elfutils. - - Red Hat elfutils is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by the - Free Software Foundation; version 2 of the License. - - Red Hat elfutils is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License along - with Red Hat elfutils; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. - - Red Hat elfutils is an included package of the Open Invention Network. - An included package of the Open Invention Network is a package for which - Open Invention Network licensees cross-license their patents. No patent - license is granted, either expressly or impliedly, by designation as an - included package. Should you wish to participate in the Open Invention - Network licensing program, please visit www.openinventionnetwork.com - . */ - -#ifndef DWARFLINT_WHERE_H -#define DWARFLINT_WHERE_H - -#include "section_id.hh" - -#include -#include - -#ifdef __cplusplus -#include -extern "C" -{ -#endif - - enum where_formatting - { - wf_plain = 0, /* Default formatting for given section. */ - wf_cudie, - }; - - struct where - { - enum section_id section; - enum where_formatting formatting; - uint64_t addr1; // E.g. a CU offset. - uint64_t addr2; // E.g. a DIE address. - uint64_t addr3; // E.g. an attribute. - struct where const *ref; // Related reference, e.g. an abbrev - // related to given DIE. - struct where const *next; // For forming "caused-by" chains. - }; - - extern const char *where_fmt (const struct where *wh, char *ptr); - extern void where_fmt_chain (const struct where *wh, const char *severity); - extern void where_reset_1 (struct where *wh, uint64_t addr); - extern void where_reset_2 (struct where *wh, uint64_t addr); - extern void where_reset_3 (struct where *wh, uint64_t addr); - -#ifdef __cplusplus -} - -#include - -inline where -WHERE (section_id sec, where const *next = NULL) -{ - where ret = {sec, wf_plain, - (uint64_t)-1, - (uint64_t)-1, - (uint64_t)-1, - NULL, next}; - return ret; -} - - -inline std::ostream & -operator << (std::ostream &os, where const &wh) -{ - os << where_fmt (&wh, NULL); - return os; -} - -#endif - -#endif//DWARFLINT_WHERE_H