From 06dbce2ff8bc1c012807e180e52cb861da907605 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 25 Aug 2010 19:16:25 +0200 Subject: [PATCH] Each check now has a name and group membership - whether a check is performed can now be configured via a command line argument --check - there's no explicit dependency resolution. While checks are really organized in a dependency graph, only the path from the check under investigation to its dependant is known at any given time. So with command line like --check=-X,+Y where Y depends on X, the scheduler may first reject X several times, just to perform it anyway when it later turns out that requested test Y depends on it. --- dwarflint/Makefile.am | 2 +- dwarflint/check_debug_abbrev.cc | 12 ++-- dwarflint/check_debug_abbrev.hh | 7 +- dwarflint/check_debug_aranges.cc | 8 +-- dwarflint/check_debug_aranges.hh | 7 +- dwarflint/check_debug_info.cc | 16 ++--- dwarflint/check_debug_info.hh | 14 +++- dwarflint/check_debug_line.cc | 15 ++-- dwarflint/check_debug_loc_range.cc | 12 ++-- dwarflint/check_debug_loc_range.hh | 14 +++- dwarflint/check_debug_pub.cc | 17 +++-- dwarflint/check_dups_abstract_origin.cc | 9 ++- dwarflint/check_expected_trees.cc | 13 ++-- dwarflint/check_matching_ranges.cc | 16 +++-- dwarflint/check_range_out_of_scope.cc | 13 ++-- dwarflint/checks.cc | 93 +++++++++++++++++++++++++ dwarflint/checks.hh | 89 +++++++++++++++-------- dwarflint/checks.ii | 2 + dwarflint/dwarflint.cc | 91 +++++++++++++++++++++++- dwarflint/dwarflint.hh | 59 ++++++++++++---- dwarflint/highlevel_check.cc | 4 +- dwarflint/highlevel_check.hh | 11 ++- dwarflint/main.cc | 66 +++++++++++++++++- dwarflint/sections.cc | 8 ++- dwarflint/sections.hh | 19 +++-- 25 files changed, 509 insertions(+), 108 deletions(-) create mode 100644 dwarflint/checks.cc create mode 100644 dwarflint/checks.ii diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am index 9f4a6b8f9..cfdd308a1 100644 --- a/dwarflint/Makefile.am +++ b/dwarflint/Makefile.am @@ -53,7 +53,7 @@ dwarflint_SOURCES = \ reloc.cc reloc.h \ tables.cc tables.hh tables.h \ all-dies-it.hh \ - checks.hh \ + checks.cc checks.hh checks.ii \ sections.cc sections.hh sections.ii \ highlevel_check.cc highlevel_check.hh \ check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev.ii \ diff --git a/dwarflint/check_debug_abbrev.cc b/dwarflint/check_debug_abbrev.cc index 49a6d1c0c..c4cb2e1f0 100644 --- a/dwarflint/check_debug_abbrev.cc +++ b/dwarflint/check_debug_abbrev.cc @@ -95,7 +95,8 @@ namespace } check_debug_abbrev::abbrev_map - load_debug_abbrev (dwarflint &lint, + load_debug_abbrev (checkstack &stack, + dwarflint &lint, struct sec §, elf_file &file) { @@ -109,7 +110,7 @@ namespace struct where where = WHERE (sec_abbrev, NULL); // Tolerate failure here. - read_cu_headers *cu_headers = lint.toplev_check (); + read_cu_headers *cu_headers = lint.toplev_check (stack); dwarf_version_h ver = NULL; if (cu_headers == NULL) { @@ -464,9 +465,10 @@ namespace } } -check_debug_abbrev::check_debug_abbrev (dwarflint &lint) - : _m_sec_abbr (lint.check (_m_sec_abbr)) - , abbrevs (load_debug_abbrev (lint, _m_sec_abbr->sect, _m_sec_abbr->file)) +check_debug_abbrev::check_debug_abbrev (checkstack &stack, dwarflint &lint) + : _m_sec_abbr (lint.check (stack, _m_sec_abbr)) + , abbrevs (load_debug_abbrev (stack, lint, + _m_sec_abbr->sect, _m_sec_abbr->file)) { } diff --git a/dwarflint/check_debug_abbrev.hh b/dwarflint/check_debug_abbrev.hh index efa6320a0..6739433b9 100644 --- a/dwarflint/check_debug_abbrev.hh +++ b/dwarflint/check_debug_abbrev.hh @@ -32,11 +32,16 @@ class check_debug_abbrev section *_m_sec_abbr; public: + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_abbrev @low"); + return cd; + } + // offset -> abbreviations typedef std::map< ::Dwarf_Off, abbrev_table> abbrev_map; abbrev_map const abbrevs; - explicit check_debug_abbrev (dwarflint &lint); + check_debug_abbrev (checkstack &stack, dwarflint &lint); ~check_debug_abbrev (); }; static reg reg_debug_abbrev; diff --git a/dwarflint/check_debug_aranges.cc b/dwarflint/check_debug_aranges.cc index 41cd4ce73..4ca69e630 100644 --- a/dwarflint/check_debug_aranges.cc +++ b/dwarflint/check_debug_aranges.cc @@ -33,10 +33,10 @@ #include "check_debug_info.hh" #include "check_debug_loc_range.hh" -check_debug_aranges::check_debug_aranges (dwarflint &lint) - : _m_sec_aranges (lint.check (_m_sec_aranges)) +check_debug_aranges::check_debug_aranges (checkstack &stack, dwarflint &lint) + : _m_sec_aranges (lint.check (stack, _m_sec_aranges)) { - check_debug_info *info = lint.toplev_check (); + check_debug_info *info = lint.toplev_check (stack); coverage *cov = NULL; if (info != NULL) { @@ -45,7 +45,7 @@ check_debug_aranges::check_debug_aranges (dwarflint &lint) // stored in check_ranges, and that should have been requested // explicitly. But for the time being... if (info->cu_cov.need_ranges) - lint.toplev_check (); + lint.toplev_check (stack); if (!info->cu_cov.need_ranges) cov = &info->cu_cov.cov; } diff --git a/dwarflint/check_debug_aranges.hh b/dwarflint/check_debug_aranges.hh index d2f6f8749..ac14030e3 100644 --- a/dwarflint/check_debug_aranges.hh +++ b/dwarflint/check_debug_aranges.hh @@ -36,7 +36,12 @@ class check_debug_aranges section *_m_sec_aranges; public: - explicit check_debug_aranges (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_aranges @low"); + return cd; + } + + check_debug_aranges (checkstack &stack, dwarflint &lint); }; static reg reg_debug_aranges; diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index 25f305aaf..f103f2bc9 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -974,8 +974,8 @@ namespace } } -read_cu_headers::read_cu_headers (dwarflint &lint) - : _m_sec_info (lint.check (_m_sec_info)) +read_cu_headers::read_cu_headers (checkstack &stack, dwarflint &lint) + : _m_sec_info (lint.check (stack, _m_sec_info)) , cu_headers (read_info_headers (&_m_sec_info->file, &_m_sec_info->sect, _m_sec_info->reldata ())) @@ -1162,13 +1162,13 @@ check_debug_info::check_info_structural () } } -check_debug_info::check_debug_info (dwarflint &lint) - : _m_sec_info (lint.check (_m_sec_info)) - , _m_sec_abbrev (lint.check (_m_sec_abbrev)) - , _m_sec_str (lint.check (_m_sec_str)) +check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) + : _m_sec_info (lint.check (stack, _m_sec_info)) + , _m_sec_abbrev (lint.check (stack, _m_sec_abbrev)) + , _m_sec_str (lint.check (stack, _m_sec_str)) , _m_file (_m_sec_info->file) - , _m_abbrevs (lint.check (_m_abbrevs)) - , _m_cu_headers (lint.check (_m_cu_headers)) + , _m_abbrevs (lint.check (stack, _m_abbrevs)) + , _m_cu_headers (lint.check (stack, _m_cu_headers)) { memset (&cu_cov, 0, sizeof (cu_cov)); check_info_structural (); diff --git a/dwarflint/check_debug_info.hh b/dwarflint/check_debug_info.hh index e82ac7776..d9449e7eb 100644 --- a/dwarflint/check_debug_info.hh +++ b/dwarflint/check_debug_info.hh @@ -39,8 +39,13 @@ class read_cu_headers section *_m_sec_info; public: + static checkdescriptor descriptor () { + static checkdescriptor cd ("read_cu_headers @low"); + return cd; + } + std::vector const cu_headers; - explicit read_cu_headers (dwarflint &lint); + read_cu_headers (checkstack &stack, dwarflint &lint); }; class check_debug_info @@ -66,13 +71,18 @@ class check_debug_info void check_info_structural (); public: + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_info"); + return cd; + } + // The check pass adds all low_pc/high_pc ranges loaded from DIE // tree into this following cu_cov structure. If it finds any // rangeptr-class attributes, it sets cu_cov.need_ranges to true. cu_coverage cu_cov; std::vector cus; - explicit check_debug_info (dwarflint &lint); + check_debug_info (checkstack &stack, dwarflint &lint); ~check_debug_info (); cu *find_cu (::Dwarf_Off offset); diff --git a/dwarflint/check_debug_line.cc b/dwarflint/check_debug_line.cc index 8a4deceaa..406e18eb5 100644 --- a/dwarflint/check_debug_line.cc +++ b/dwarflint/check_debug_line.cc @@ -56,7 +56,12 @@ namespace typedef std::vector files_t; public: - explicit check_debug_line (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_line @low"); + return cd; + } + + explicit check_debug_line (checkstack &stack, dwarflint &lint); /* Directory index. */ bool read_directory_index (include_directories_t &include_directories, @@ -111,10 +116,10 @@ namespace reg reg_debug_line; } -check_debug_line::check_debug_line (dwarflint &lint) - : _m_sec (lint.check (_m_sec)) +check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) + : _m_sec (lint.check (stack, _m_sec)) { - check_debug_info *cus = lint.toplev_check (); + check_debug_info *cus = lint.toplev_check (stack); addr_record line_tables; WIPE (line_tables); @@ -597,7 +602,7 @@ check_debug_line::check_debug_line (dwarflint &lint) throw check_base::failed (); check_debug_info *info = NULL; - info = lint.toplev_check (info); + info = lint.toplev_check (stack, info); if (info != NULL) for (std::vector::iterator it = info->cus.begin (); it != info->cus.end (); ++it) diff --git a/dwarflint/check_debug_loc_range.cc b/dwarflint/check_debug_loc_range.cc index 633e219a2..1bdec89a1 100644 --- a/dwarflint/check_debug_loc_range.cc +++ b/dwarflint/check_debug_loc_range.cc @@ -667,9 +667,9 @@ namespace } } -check_debug_ranges::check_debug_ranges (dwarflint &lint) - : _m_sec_ranges (lint.check (_m_sec_ranges)) - , _m_cus (lint.check (_m_cus)) +check_debug_ranges::check_debug_ranges (checkstack &stack, dwarflint &lint) + : _m_sec_ranges (lint.check (stack, _m_sec_ranges)) + , _m_cus (lint.check (stack, _m_cus)) { if (!::check_loc_or_range_structural (&_m_sec_ranges->file, &_m_sec_ranges->sect, @@ -678,9 +678,9 @@ check_debug_ranges::check_debug_ranges (dwarflint &lint) throw check_base::failed (); } -check_debug_loc::check_debug_loc (dwarflint &lint) - : _m_sec_loc (lint.check (_m_sec_loc)) - , _m_cus (lint.check (_m_cus)) +check_debug_loc::check_debug_loc (checkstack &stack, dwarflint &lint) + : _m_sec_loc (lint.check (stack, _m_sec_loc)) + , _m_cus (lint.check (stack, _m_cus)) { if (!::check_loc_or_range_structural (&_m_sec_loc->file, &_m_sec_loc->sect, diff --git a/dwarflint/check_debug_loc_range.hh b/dwarflint/check_debug_loc_range.hh index 31373288b..1c6abd79d 100644 --- a/dwarflint/check_debug_loc_range.hh +++ b/dwarflint/check_debug_loc_range.hh @@ -36,7 +36,12 @@ class check_debug_ranges check_debug_info *_m_cus; public: - explicit check_debug_ranges (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_ranges @low"); + return cd; + } + + check_debug_ranges (checkstack &stack, dwarflint &lint); }; class check_debug_loc @@ -46,7 +51,12 @@ class check_debug_loc check_debug_info *_m_cus; public: - explicit check_debug_loc (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_debug_loc @low"); + return cd; + } + + check_debug_loc (checkstack &stack, dwarflint &lint); }; struct hole_info diff --git a/dwarflint/check_debug_pub.cc b/dwarflint/check_debug_pub.cc index cd2aec087..fdb893d60 100644 --- a/dwarflint/check_debug_pub.cc +++ b/dwarflint/check_debug_pub.cc @@ -33,17 +33,26 @@ namespace class check_debug_pub : public check > { - section *_m_sec; + typedef section section_t; + section_t *_m_sec; elf_file const &_m_file; bool check_pub_structural (check_debug_info *cus); public: - explicit check_debug_pub (dwarflint &lint) - : _m_sec (lint.check (_m_sec)) + static checkdescriptor const &descriptor () { + static std::string name + = (std::string)"check_" + + section_t::descriptor ().name.substr (1); + static checkdescriptor cd (name.c_str ()); + return cd; + } + + check_debug_pub (checkstack &stack, dwarflint &lint) + : _m_sec (lint.check (stack, _m_sec)) , _m_file (_m_sec->file) { - check_pub_structural (lint.toplev_check ()); + check_pub_structural (lint.toplev_check (stack)); } }; diff --git a/dwarflint/check_dups_abstract_origin.cc b/dwarflint/check_dups_abstract_origin.cc index f85f574ee..88b584242 100644 --- a/dwarflint/check_dups_abstract_origin.cc +++ b/dwarflint/check_dups_abstract_origin.cc @@ -49,8 +49,13 @@ namespace : public highlevel_check { public: - explicit check_dups_abstract_origin (dwarflint &lint) - : highlevel_check (lint) + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_dups_abstract_origin"); + return cd; + } + + explicit check_dups_abstract_origin (checkstack &stack, dwarflint &lint) + : highlevel_check (stack, lint) { struct { void operator () (dwarf::debug_info_entry const &die, diff --git a/dwarflint/check_expected_trees.cc b/dwarflint/check_expected_trees.cc index 74b8903ec..e3d69490a 100644 --- a/dwarflint/check_expected_trees.cc +++ b/dwarflint/check_expected_trees.cc @@ -17,7 +17,12 @@ namespace : public highlevel_check { public: - explicit check_expected_trees (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_expected_trees"); + return cd; + } + + check_expected_trees (checkstack &stack, dwarflint &lint); }; reg reg_check_expected_trees; @@ -57,10 +62,10 @@ namespace } } -check_expected_trees::check_expected_trees (dwarflint &lint) - : highlevel_check (lint) +check_expected_trees::check_expected_trees (checkstack &stack, dwarflint &lint) + : highlevel_check (stack, lint) { - lint.check (); + lint.check (stack); try { diff --git a/dwarflint/check_matching_ranges.cc b/dwarflint/check_matching_ranges.cc index ba3800123..a0be41bde 100644 --- a/dwarflint/check_matching_ranges.cc +++ b/dwarflint/check_matching_ranges.cc @@ -14,20 +14,26 @@ namespace : public highlevel_check { public: - explicit check_matching_ranges (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_matching_ranges"); + return cd; + } + + check_matching_ranges (checkstack &stack, dwarflint &lint); }; reg reg_matching_ranges; } -check_matching_ranges::check_matching_ranges (dwarflint &lint) - : highlevel_check (lint) +check_matching_ranges::check_matching_ranges (checkstack &stack, + dwarflint &lint) + : highlevel_check (stack, lint) { if (be_tolerant || be_gnu) throw check_base::unscheduled (); - lint.check (); - lint.check (); + lint.check (stack); + lint.check (stack); try { diff --git a/dwarflint/check_range_out_of_scope.cc b/dwarflint/check_range_out_of_scope.cc index f469ffa97..89e5796d6 100644 --- a/dwarflint/check_range_out_of_scope.cc +++ b/dwarflint/check_range_out_of_scope.cc @@ -48,17 +48,22 @@ namespace where const &wh_parent); public: - explicit check_range_out_of_scope (dwarflint &lint); + static checkdescriptor descriptor () { + static checkdescriptor cd ("check_range_out_of_scope"); + return cd; + } + + check_range_out_of_scope (checkstack &stack, dwarflint &lint); }; // Register the check. reg reg_range_out_of_scope; } -check_range_out_of_scope::check_range_out_of_scope (dwarflint &lint) - : highlevel_check (lint) +check_range_out_of_scope::check_range_out_of_scope (checkstack &stack, dwarflint &lint) + : highlevel_check (stack, lint) { - lint.check (); + lint.check (stack); try { diff --git a/dwarflint/checks.cc b/dwarflint/checks.cc new file mode 100644 index 000000000..dcc3b64d9 --- /dev/null +++ b/dwarflint/checks.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2010 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 "checks.hh" +#include "options.h" +#include + +namespace +{ + std::vector + split_groups (std::string const &str) + { + std::stringstream ss (str); + std::string item; + std::vector ret; + + while (ss >> item) + ret.push_back (item); + + return ret; + } +} + +checkdescriptor::checkdescriptor (std::string const &desc) + : groups (::split_groups (desc)) + , name (groups[0]) +{ + groups.erase (groups.begin ()); +} + + +reporter::reporter (checkstack const &s, checkdescriptor const &a_cd) + : stack (s) + , cd (a_cd) +{ + //(*this) ("run", true); +} + +void +reporter::operator () (char const *what, bool ext) +{ + if (!be_verbose) + return; + + if (false) + for (size_t i = 0; i < stack.size (); ++i) + std::cout << ' '; + + std::cout << cd.name << ' ' << what; + if (ext) + { + std::cout << " ["; + for (std::vector::const_iterator it = cd.groups.begin (); + it != cd.groups.end (); ++it) + { + if (it != cd.groups.begin ()) + std::cout << ','; + std::cout << *it; + } + std::cout << "] {"; + for (checkstack::const_iterator it = stack.begin (); + it != stack.end (); ++it) + { + if (it != stack.begin ()) + std::cout << ','; + std::cout << (*it)->name; + } + std::cout << "}"; + } + std::cout << std::endl; +} diff --git a/dwarflint/checks.hh b/dwarflint/checks.hh index 2db2f05a7..8f9ea6d7d 100644 --- a/dwarflint/checks.hh +++ b/dwarflint/checks.hh @@ -1,5 +1,5 @@ /* - Copyright (C) 2009 Red Hat, Inc. + Copyright (C) 2009,2010 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,10 +26,18 @@ #ifndef DWARFLINT_CHECKS_HH #define DWARFLINT_CHECKS_HH -#include -#include #include "where.h" #include "dwarflint.hh" +#include +#include + +struct checkdescriptor +{ + std::vector groups; + std::string const name; + + checkdescriptor (std::string const &desc); +}; struct check_base { @@ -44,51 +52,73 @@ class check { private: template - friend X *dwarflint::check (); + friend X *dwarflint::check (checkstack &stack); static void const *key () { return reinterpret_cast (&key); } }; +struct reporter +{ + checkstack const &stack; + checkdescriptor const &cd; + + reporter (checkstack const &s, checkdescriptor const &a_cd); + void operator () (char const *what, bool ext = false); +}; + template T * -dwarflint::check () +dwarflint::check (checkstack &stack) { void const *key = T::key (); - check_map::iterator it = _m_checks.find (key); + T *c = static_cast (find_check (key)); - T *c; - if (it != _m_checks.end ()) - { - c = static_cast (it->second); - - // We already tried to do the check, but failed. - if (c == NULL) - throw check_base::failed (); - else - // Recursive dependency! - assert (c != (T *)-1); - } - else + if (c == NULL) { - // Put a marker there saying that we are trying to satisfy that - // dependency. - if (!_m_checks.insert (std::make_pair (key, (T *)-1)).second) - throw std::runtime_error ("duplicate key"); + checkdescriptor const &cd = T::descriptor (); - // Now do the check. + struct popper { + checkstack &guard_stack; + popper (checkstack &a_guard_stack) : guard_stack (a_guard_stack) {} + ~popper () { guard_stack.pop_back (); } + }; + + // Put a marker there indicating that we are trying to satisfy + // that dependency. + bool inserted + = _m_checks.insert (std::make_pair (key, (T *)marker)).second; + assert (inserted || !"duplicate key"); + + reporter report (stack, cd); try { - c = new T (*this); + stack.push_back (&cd); + popper p (stack); + + if (!_m_rules.should_check (stack)) + throw check_base::unscheduled (); + + // Now do the check. + c = new T (stack, *this); + } + catch (check_base::unscheduled &e) + { + report ("skipped"); + _m_checks.erase (key); + throw; } catch (...) { // Nope, we failed. Put the anchor there. _m_checks[key] = NULL; + report ("FAIL"); throw; } + report ("done"); + // On success, put the actual check object there instead of the // marker. _m_checks[key] = c; @@ -98,11 +128,12 @@ dwarflint::check () template inline T * -dwarflint::toplev_check (__attribute__ ((unused)) T *tag) +dwarflint::toplev_check (checkstack &stack, + __attribute__ ((unused)) T *tag) { try { - return check (); + return check (stack); } catch (check_base::failed const &f) { @@ -119,9 +150,9 @@ struct reg dwarflint::check_registrar::inst ()->add (this); } - virtual void run (dwarflint &lint) + virtual void run (checkstack &stack, dwarflint &lint) { - lint.toplev_check (); + lint.toplev_check (stack); } }; diff --git a/dwarflint/checks.ii b/dwarflint/checks.ii new file mode 100644 index 000000000..9db9722b4 --- /dev/null +++ b/dwarflint/checks.ii @@ -0,0 +1,2 @@ +struct check_base; +struct checkdescriptor; diff --git a/dwarflint/dwarflint.cc b/dwarflint/dwarflint.cc index 3e23ec239..83491ee67 100644 --- a/dwarflint/dwarflint.cc +++ b/dwarflint/dwarflint.cc @@ -51,9 +51,10 @@ namespace } } -dwarflint::dwarflint (char const *a_fname) +dwarflint::dwarflint (char const *a_fname, check_rules const &rules) : _m_fname (a_fname) , _m_fd (get_fd (_m_fname)) + , _m_rules (rules) { check_registrar::inst ()->enroll (*this); } @@ -68,3 +69,91 @@ dwarflint::~dwarflint () it != _m_checks.end (); ++it) delete it->second; } + +void +dwarflint::check_registrar::enroll (dwarflint &lint) +{ + for (std::vector ::iterator it = _m_items.begin (); + it != _m_items.end (); ++it) + { + checkstack stack; + (*it)->run (stack, lint); + } +} + +namespace +{ + bool + rule_matches (std::string const &name, + checkdescriptor const &d) + { + if (name == "@all") + return true; + if (name == "@none") + return false; + if (name == d.name) + return true; + for (std::vector::const_iterator it = d.groups.begin (); + it != d.groups.end (); ++it) + if (name == *it) + return true; + return false; + } +} + +bool +check_rules::should_check (checkstack const &stack) const +{ +#if 0 + std::cout << "---\nstack" << std::endl; + for (checkstack::const_iterator jt = stack.begin (); + jt != stack.end (); ++jt) + std::cout << (*jt)->name << std::flush << " "; + std::cout << std::endl; +#endif + + bool should = false; + for (const_iterator it = begin (); it != end (); ++it) + { + std::string const &rule_name = it->name; + bool nflag = it->action == check_rule::request; + if (nflag == should) + continue; + + for (checkstack::const_iterator jt = stack.begin (); + jt != stack.end (); ++jt) + if (rule_matches (rule_name, **jt)) + { + //std::cout << " rule: " << rule_name << " " << nflag << std::endl; + should = nflag; + break; + } + } + + return should; +} + + +void *const dwarflint::marker = (void *)-1; + +void * +dwarflint::find_check (void const *key) +{ + check_map::const_iterator it = _m_checks.find (key); + + if (it != _m_checks.end ()) + { + void *c = it->second; + + // We already tried to do the check, but failed. + if (c == NULL) + throw check_base::failed (); + else + // Recursive dependency! + assert (c != marker); + + return c; + } + + return NULL; +} diff --git a/dwarflint/dwarflint.hh b/dwarflint/dwarflint.hh index f5b5ba74e..1cd3a4596 100644 --- a/dwarflint/dwarflint.hh +++ b/dwarflint/dwarflint.hh @@ -5,6 +5,35 @@ #include #include #include "../libelf/libelf.h" +#include "checks.ii" + +class checkstack + : public std::vector +{ +}; + +struct check_rule +{ + enum action_t + { + forbid, + request, + }; + + std::string name; + action_t action; + + check_rule (std::string const &a_name, action_t an_action) + : name (a_name) + , action (an_action) + {} +}; +class check_rules + : public std::vector +{ + friend class dwarflint; + bool should_check (checkstack const &stack) const; +}; class dwarflint { @@ -12,13 +41,22 @@ class dwarflint check_map _m_checks; char const *_m_fname; int _m_fd; + check_rules const &_m_rules; + + static void *const marker; + + // Return a pointer to check, or NULL if the check hasn't been done + // yet. Throws check_base::failed if the check was requested + // earlier but failed, or aborts program via assertion if recursion + // was detected. + void *find_check (void const *key); public: struct check_registrar { struct item { - virtual void run (dwarflint &lint) = 0; + virtual void run (checkstack &stack, dwarflint &lint) = 0; }; static check_registrar *inst () @@ -34,31 +72,28 @@ public: private: friend class dwarflint; - void enroll (dwarflint &lint) - { - for (std::vector ::iterator it = _m_items.begin (); - it != _m_items.end (); ++it) - (*it)->run (lint); - } + void enroll (dwarflint &lint); std::vector _m_items; }; - explicit dwarflint (char const *fname); + dwarflint (char const *fname, check_rules const &rules); ~dwarflint (); int fd () { return _m_fd; } char const *fname () { return _m_fname; } - template T *check (); + template T *check (checkstack &stack); template T * - check (__attribute__ ((unused)) T *fake) + check (checkstack &stack, + __attribute__ ((unused)) T *fake) { - return check (); + return check (stack); } - template T *toplev_check (T *tag = NULL); + template T *toplev_check (checkstack &stack, + T *tag = NULL); }; #endif//DWARFLINT_HH diff --git a/dwarflint/highlevel_check.cc b/dwarflint/highlevel_check.cc index 00dea3238..ea8ce05d6 100644 --- a/dwarflint/highlevel_check.cc +++ b/dwarflint/highlevel_check.cc @@ -128,7 +128,9 @@ namespace } } -open_highlevel_dwarf::open_highlevel_dwarf (dwarflint &lint) +open_highlevel_dwarf::open_highlevel_dwarf (checkstack &stack + __attribute__ ((unused)), + dwarflint &lint) : _m_dwfl (open_dwfl ()) , _m_dw (open_dwarf (_m_dwfl, lint.fname (), lint.fd ())) , dw (open_hl_dwarf (_m_dw)) diff --git a/dwarflint/highlevel_check.hh b/dwarflint/highlevel_check.hh index 91ad2dd85..b2e4086d8 100644 --- a/dwarflint/highlevel_check.hh +++ b/dwarflint/highlevel_check.hh @@ -41,8 +41,13 @@ class open_highlevel_dwarf Dwfl *const _m_dwfl; Dwarf *const _m_dw; public: + static checkdescriptor descriptor () { + static checkdescriptor cd ("open_highlevel_dwarf"); + return cd; + } + elfutils::dwarf const dw; - explicit open_highlevel_dwarf (dwarflint &lint); + open_highlevel_dwarf (checkstack &stack, dwarflint &lint); ~open_highlevel_dwarf (); }; @@ -54,8 +59,8 @@ class highlevel_check public: elfutils::dwarf const &dw; - explicit highlevel_check (dwarflint &lint) - : _m_loader (lint.check (_m_loader)) + explicit highlevel_check (checkstack &stack, dwarflint &lint) + : _m_loader (lint.check (stack, _m_loader)) , dw (_m_loader->dw) { if (!do_high_level) diff --git a/dwarflint/main.cc b/dwarflint/main.cc index 721116f99..ccf35c5ed 100644 --- a/dwarflint/main.cc +++ b/dwarflint/main.cc @@ -32,6 +32,7 @@ #include #include +#include #include "low.h" #include "options.h" @@ -48,6 +49,7 @@ const char *argp_program_bug_address = PACKAGE_BUGREPORT; #define ARGP_ref 303 #define ARGP_nohl 304 #define ARGP_dump_off 305 +#define ARGP_check 306 /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = @@ -71,6 +73,8 @@ the DIE referring to the entry in consideration"), 0 }, N_("Be verbose"), 0 }, { "dump-offsets", ARGP_dump_off, NULL, 0, N_("Dump DIE offsets to stderr as the tree is iterated."), 0 }, + { "check", ARGP_check, "[+-][@]name,...", 0, + N_("Only run selected checks."), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; @@ -96,6 +100,15 @@ static struct argp argp = options, parse_opt, args_doc, doc, NULL, NULL, NULL }; +struct initial_check_rules + : public check_rules +{ + initial_check_rules () { + push_back (check_rule ("@all", check_rule::request)); + push_back (check_rule ("@nodefault", check_rule::forbid)); + } +} rules; + /* Handle program arguments. */ static error_t parse_opt (int key, char *arg __attribute__ ((unused)), @@ -127,6 +140,57 @@ parse_opt (int key, char *arg __attribute__ ((unused)), dump_die_offsets = true; break; + case ARGP_check: + { + static bool first = true; + std::stringstream ss (arg); + std::string item; + + while (std::getline (ss, item, ',')) + { + if (item.empty ()) + continue; + + enum { + forbid, + request, + replace + } act; + + // If the first rule has no operator, we assume the user + // wants to replace the implicit set of checks. + if (first) + { + act = replace; + first = false; + } + else + // Otherwise the rules are implicitly requesting, even + // without the '+' operator. + act = request; + + bool minus = item[0] == '-'; + bool plus = item[0] == '+'; + if (plus || minus) + item = item.substr (1); + if (plus) + act = request; + if (minus) + act = forbid; + + if (act == replace) + { + rules.clear (); + act = request; + } + + check_rule::action_t action + = act == request ? check_rule::request : check_rule::forbid; + rules.push_back (check_rule (item, action)); + } + } + break; + case 'i': tolerate_nodebug = true; break; @@ -213,7 +277,7 @@ main (int argc, char *argv[]) unsigned int prev_error_count = error_count; if (!only_one) std::cout << std::endl << fname << ":" << std::endl; - dwarflint lint (fname); + dwarflint lint (fname, rules); if (prev_error_count == error_count && !be_quiet) puts (gettext ("No errors")); diff --git a/dwarflint/sections.cc b/dwarflint/sections.cc index a4b51db71..641551cb0 100644 --- a/dwarflint/sections.cc +++ b/dwarflint/sections.cc @@ -390,7 +390,8 @@ namespace } } -load_sections::load_sections (dwarflint &lint) +load_sections::load_sections (checkstack &stack __attribute__ ((unused)), + dwarflint &lint) { if (!elf_file_init (&file, lint.fd ())) throw check_base::failed (); @@ -458,8 +459,9 @@ section_base::get_sec_or_throw (section_id secid) throw check_base::failed (); } -section_base::section_base (dwarflint &lint, section_id secid) - : sections (lint.check (sections)) +section_base::section_base (checkstack &stack, + dwarflint &lint, section_id secid) + : sections (lint.check (stack, sections)) , sect (get_sec_or_throw (secid)) , file (sections->file) { diff --git a/dwarflint/sections.hh b/dwarflint/sections.hh index e12621c3a..28b99b558 100644 --- a/dwarflint/sections.hh +++ b/dwarflint/sections.hh @@ -33,8 +33,13 @@ class load_sections : public check { public: + static checkdescriptor descriptor () { + static checkdescriptor cd ("load_sections"); + return cd; + } + elf_file file; - explicit load_sections (dwarflint &lint); + load_sections (checkstack &stack, dwarflint &lint); ~load_sections (); }; @@ -45,7 +50,8 @@ class section_base public: sec § elf_file &file; - section_base (dwarflint &lint, section_id secid); + section_base (checkstack &stack, + dwarflint &lint, section_id secid); relocation_data *reldata () const { @@ -59,8 +65,13 @@ class section , public check > { public: - explicit section (dwarflint &lint) - : section_base (lint, static_cast (sec_id)) + static checkdescriptor const &descriptor () { + static checkdescriptor cd(section_name[sec_id]); + return cd; + } + + explicit section (checkstack &stack, dwarflint &lint) + : section_base (stack, lint, sec_id) {} }; -- 2.47.3