]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Each check now has a name and group membership
authorPetr Machata <pmachata@redhat.com>
Wed, 25 Aug 2010 17:16:25 +0000 (19:16 +0200)
committerPetr Machata <pmachata@redhat.com>
Wed, 25 Aug 2010 17:16:25 +0000 (19:16 +0200)
- 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.

25 files changed:
dwarflint/Makefile.am
dwarflint/check_debug_abbrev.cc
dwarflint/check_debug_abbrev.hh
dwarflint/check_debug_aranges.cc
dwarflint/check_debug_aranges.hh
dwarflint/check_debug_info.cc
dwarflint/check_debug_info.hh
dwarflint/check_debug_line.cc
dwarflint/check_debug_loc_range.cc
dwarflint/check_debug_loc_range.hh
dwarflint/check_debug_pub.cc
dwarflint/check_dups_abstract_origin.cc
dwarflint/check_expected_trees.cc
dwarflint/check_matching_ranges.cc
dwarflint/check_range_out_of_scope.cc
dwarflint/checks.cc [new file with mode: 0644]
dwarflint/checks.hh
dwarflint/checks.ii [new file with mode: 0644]
dwarflint/dwarflint.cc
dwarflint/dwarflint.hh
dwarflint/highlevel_check.cc
dwarflint/highlevel_check.hh
dwarflint/main.cc
dwarflint/sections.cc
dwarflint/sections.hh

index 9f4a6b8f9770042d7a916d53e7f2393795e7ed54..cfdd308a1a64529568adbf6f403c38985bc648f2 100644 (file)
@@ -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 \
index 49a6d1c0cad981acf6d660b66e75c7323c967009..c4cb2e1f071055387ae0aef8ad9377f7cac61b63 100644 (file)
@@ -95,7 +95,8 @@ namespace
   }
 
   check_debug_abbrev::abbrev_map
-  load_debug_abbrev (dwarflint &lint,
+  load_debug_abbrev (checkstack &stack,
+                    dwarflint &lint,
                     struct sec &sect,
                     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> ();
+    read_cu_headers *cu_headers = lint.toplev_check<read_cu_headers> (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))
 {
 }
 
index efa6320a0791b475399f41b2f2917286857d4e28..6739433b9968d26f40e4a92b63cd00a8c7189371 100644 (file)
@@ -32,11 +32,16 @@ class check_debug_abbrev
   section<sec_abbrev> *_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<check_debug_abbrev> reg_debug_abbrev;
index 41cd4ce73a511f2c01053943be2f9ab455b9ee6a..4ca69e630ac108116ef69d337c5b24aba1b9fb4b 100644 (file)
 #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> ();
+  check_debug_info *info = lint.toplev_check<check_debug_info> (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<check_debug_ranges> ();
+       lint.toplev_check<check_debug_ranges> (stack);
       if (!info->cu_cov.need_ranges)
        cov = &info->cu_cov.cov;
     }
index d2f6f8749373f3e095a3c437f627f07a6f8e31c9..ac14030e329d63583f33775bc1123cb386828eb7 100644 (file)
@@ -36,7 +36,12 @@ class check_debug_aranges
   section<sec_aranges> *_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<check_debug_aranges> reg_debug_aranges;
 
index 25f305aaf2e591b870c92e64b3fb185557ed5f03..f103f2bc903c106a19236d6cf865b6016a8eac11 100644 (file)
@@ -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 ();
index e82ac7776682e4264ff9d0c3b51578f22d26fc27..d9449e7eb018f73318a0ee4ec3bc89f8e24c9855 100644 (file)
@@ -39,8 +39,13 @@ class read_cu_headers
   section<sec_info> *_m_sec_info;
 
 public:
+  static checkdescriptor descriptor () {
+    static checkdescriptor cd ("read_cu_headers @low");
+    return cd;
+  }
+
   std::vector<cu_head> 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<cu> cus;
 
-  explicit check_debug_info (dwarflint &lint);
+  check_debug_info (checkstack &stack, dwarflint &lint);
   ~check_debug_info ();
 
   cu *find_cu (::Dwarf_Off offset);
index 8a4deceaa834619cd3e22be1f562ef9650b6ddb4..406e18eb5fa88a80bffb2d56c43e95492df11754 100644 (file)
@@ -56,7 +56,12 @@ namespace
     typedef std::vector<file_t> 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<check_debug_line> 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> ();
+  check_debug_info *cus = lint.toplev_check<check_debug_info> (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<cu>::iterator it = info->cus.begin ();
         it != info->cus.end (); ++it)
index 633e219a2ace566cd9afad32ed8496c61d47dfdc..1bdec89a1fbe5ca5d06f206df1677bb0477ef47e 100644 (file)
@@ -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,
index 31373288bf0ae96b3bc375511ecccdad8a25d560..1c6abd79d6e1c88592691dd040d61f3055c4dd03 100644 (file)
@@ -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
index cd2aec087709380931b7457c42645dcf1129e3e5..fdb893d6034d7737dd9b44b48635c529c2fa49b9 100644 (file)
@@ -33,17 +33,26 @@ namespace
   class check_debug_pub
     : public check<check_debug_pub<sec_id> >
   {
-    section<sec_id> *_m_sec;
+    typedef section<sec_id> 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_debug_info> ());
+      check_pub_structural (lint.toplev_check<check_debug_info> (stack));
     }
   };
 
index f85f574ee2f1195f95184fae67816ba35701fe25..88b584242f02fecb3fb00fcf073d68c34fec6c2c 100644 (file)
@@ -49,8 +49,13 @@ namespace
     : public highlevel_check<check_dups_abstract_origin>
   {
   public:
-    explicit check_dups_abstract_origin (dwarflint &lint)
-      : highlevel_check<check_dups_abstract_origin> (lint)
+    static checkdescriptor descriptor () {
+      static checkdescriptor cd ("check_dups_abstract_origin");
+      return cd;
+    }
+
+    explicit check_dups_abstract_origin (checkstack &stack, dwarflint &lint)
+      : highlevel_check<check_dups_abstract_origin> (stack, lint)
     {
       struct {
        void operator () (dwarf::debug_info_entry const &die,
index 74b8903ec9d54b48b3b53d8a8aabb11c4a2a1e1b..e3d69490abdbdab33740e9225acc3af7668b75ab 100644 (file)
@@ -17,7 +17,12 @@ namespace
     : public highlevel_check<check_expected_trees>
   {
   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<check_expected_trees> reg_check_expected_trees;
@@ -57,10 +62,10 @@ namespace
   }
 }
 
-check_expected_trees::check_expected_trees (dwarflint &lint)
-  : highlevel_check<check_expected_trees> (lint)
+check_expected_trees::check_expected_trees (checkstack &stack, dwarflint &lint)
+  : highlevel_check<check_expected_trees> (stack, lint)
 {
-  lint.check <check_debug_info> ();
+  lint.check <check_debug_info> (stack);
 
   try
     {
index ba380012326cb3d9ba26183b8a52e05aa916a08f..a0be41bde41e68fdfd8b0745a1160afaf42b0f22 100644 (file)
@@ -14,20 +14,26 @@ namespace
     : public highlevel_check<check_matching_ranges>
   {
   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<check_matching_ranges> reg_matching_ranges;
 }
 
-check_matching_ranges::check_matching_ranges (dwarflint &lint)
-  : highlevel_check<check_matching_ranges> (lint)
+check_matching_ranges::check_matching_ranges (checkstack &stack,
+                                             dwarflint &lint)
+  : highlevel_check<check_matching_ranges> (stack, lint)
 {
   if (be_tolerant || be_gnu)
     throw check_base::unscheduled ();
 
-  lint.check<check_debug_ranges> ();
-  lint.check<check_debug_aranges> ();
+  lint.check<check_debug_ranges> (stack);
+  lint.check<check_debug_aranges> (stack);
 
   try
     {
index f469ffa971a2427d81fad763437798dbfc547512..89e5796d6136282fe1ab9727996864b86d3d58d3 100644 (file)
@@ -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<check_range_out_of_scope> reg_range_out_of_scope;
 }
 
-check_range_out_of_scope::check_range_out_of_scope (dwarflint &lint)
-  : highlevel_check<check_range_out_of_scope> (lint)
+check_range_out_of_scope::check_range_out_of_scope (checkstack &stack, dwarflint &lint)
+  : highlevel_check<check_range_out_of_scope> (stack, lint)
 {
-  lint.check <check_debug_loc> ();
+  lint.check <check_debug_loc> (stack);
 
   try
     {
diff --git a/dwarflint/checks.cc b/dwarflint/checks.cc
new file mode 100644 (file)
index 0000000..dcc3b64
--- /dev/null
@@ -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
+   <http://www.openinventionnetwork.com>.  */
+
+#include "checks.hh"
+#include "options.h"
+#include <sstream>
+
+namespace
+{
+  std::vector<std::string>
+  split_groups (std::string const &str)
+  {
+    std::stringstream ss (str);
+    std::string item;
+    std::vector<std::string> 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<std::string>::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;
+}
index 2db2f05a7a748ead3f5a25ee95a83141b73fe922..8f9ea6d7df7228525115c53e1ed0d14d4674aa76 100644 (file)
@@ -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
 #ifndef DWARFLINT_CHECKS_HH
 #define DWARFLINT_CHECKS_HH
 
-#include <string>
-#include <cassert>
 #include "where.h"
 #include "dwarflint.hh"
+#include <string>
+#include <cassert>
+
+struct checkdescriptor
+{
+  std::vector<std::string> groups;
+  std::string const name;
+
+  checkdescriptor (std::string const &desc);
+};
 
 struct check_base
 {
@@ -44,51 +52,73 @@ class check
 {
 private:
   template <class X>
-  friend X *dwarflint::check ();
+  friend X *dwarflint::check (checkstack &stack);
   static void const *key ()
   {
     return reinterpret_cast <void const *> (&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 <class T>
 T *
-dwarflint::check ()
+dwarflint::check (checkstack &stack)
 {
   void const *key = T::key ();
-  check_map::iterator it = _m_checks.find (key);
+  T *c = static_cast <T *> (find_check (key));
 
-  T *c;
-  if (it != _m_checks.end ())
-    {
-      c = static_cast <T *> (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 <class T>
 inline T *
-dwarflint::toplev_check (__attribute__ ((unused)) T *tag)
+dwarflint::toplev_check (checkstack &stack,
+                        __attribute__ ((unused)) T *tag)
 {
   try
     {
-      return check<T> ();
+      return check<T> (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 <T> ();
+    lint.toplev_check <T> (stack);
   }
 };
 
diff --git a/dwarflint/checks.ii b/dwarflint/checks.ii
new file mode 100644 (file)
index 0000000..9db9722
--- /dev/null
@@ -0,0 +1,2 @@
+struct check_base;
+struct checkdescriptor;
index 3e23ec239253468cb8538fc689ee89fe40b77f87..83491ee67ce9186e705b2f96696e70650461194b 100644 (file)
@@ -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 <item *>::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<std::string>::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;
+}
index f5b5ba74e346a8074f6e4b038e5a33dec15d23ff..1cd3a4596912abe460281d26e043d14737985f34 100644 (file)
@@ -5,6 +5,35 @@
 #include <vector>
 #include <stdexcept>
 #include "../libelf/libelf.h"
+#include "checks.ii"
+
+class checkstack
+  : public std::vector <checkdescriptor const *>
+{
+};
+
+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<check_rule>
+{
+  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 <item *>::iterator it = _m_items.begin ();
-          it != _m_items.end (); ++it)
-       (*it)->run (lint);
-    }
+    void enroll (dwarflint &lint);
 
     std::vector <item *> _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 <class T> T *check ();
+  template <class T> T *check (checkstack &stack);
 
   template <class T>
   T *
-  check (__attribute__ ((unused)) T *fake)
+  check (checkstack &stack,
+        __attribute__ ((unused)) T *fake)
   {
-    return check<T> ();
+    return check<T> (stack);
   }
 
-  template <class T> T *toplev_check (T *tag = NULL);
+  template <class T> T *toplev_check (checkstack &stack,
+                                     T *tag = NULL);
 };
 
 #endif//DWARFLINT_HH
index 00dea32387f0e4b76a90cce8488159c94eaee8f6..ea8ce05d64b7eab8d394d4b83dca2f65299e7d2c 100644 (file)
@@ -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))
index 91ad2dd8509b4d237598a61f3e541088924be777..b2e4086d8b3c9a2b0d213749b0738f3d5e9ce5fa 100644 (file)
@@ -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)
index 721116f997a75d98765643797fe653018da02ac9..ccf35c5ed1472d925d16e564f2275fdcf74374ef 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 
 #include <iostream>
+#include <sstream>
 
 #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"));
index a4b51db71a7a7e5c003c628bc1320e1bc42eef58..641551cb05e65394f7054114a687fd1d8ac7f174 100644 (file)
@@ -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)
 {
index e12621c3a1ceca6a8e734c94e453fea71d071501..28b99b55841407b80f5bb88be5b99b23ebbf3a3c 100644 (file)
@@ -33,8 +33,13 @@ class load_sections
   : public check<load_sections>
 {
 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 &sect;
   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<section<sec_id> >
 {
 public:
-  explicit section (dwarflint &lint)
-    : section_base (lint, static_cast <enum section_id> (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)
   {}
 };