]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Add check_die_tree pass for generic per-DIE checks
authorPetr Machata <pmachata@redhat.com>
Thu, 24 Mar 2011 16:44:12 +0000 (17:44 +0100)
committerPetr Machata <pmachata@redhat.com>
Mon, 28 Mar 2011 14:03:00 +0000 (16:03 +0200)
- add reg_die_check for registering per-DIE check passes
- turn check_registrar into a template to allow reuse among reg<> and
  reg_die_check<>
- the per-DIE checking magic is in check_die_tree.hh
- hide most of checks.hh into dwarflint.cc.  That has little to do
  with per-DIE checks as such, but was a necessary cleanup

18 files changed:
dwarflint/Makefile.am
dwarflint/all-dies-it.hh
dwarflint/check_die_tree.cc [new file with mode: 0644]
dwarflint/check_die_tree.hh [new file with mode: 0644]
dwarflint/check_die_tree.ii [new file with mode: 0644]
dwarflint/check_registrar.cc [new file with mode: 0644]
dwarflint/check_registrar.hh [moved from dwarflint/checks.cc with 50% similarity]
dwarflint/check_registrar.ii [new file with mode: 0644]
dwarflint/checkdescriptor.cc
dwarflint/checkdescriptor.hh
dwarflint/checks.hh
dwarflint/checks.ii
dwarflint/dwarflint.cc
dwarflint/dwarflint.hh
dwarflint/dwarflint.ii
dwarflint/highlevel_check.hh
dwarflint/main.cc
dwarflint/option.cc

index 2247d0e94659e894ec4ee0eba6fcec8629bf101e..b4164ddf0ad1483378c7f440db99a634b90e4fce 100644 (file)
@@ -41,10 +41,11 @@ noinst_PROGRAMS = tests/test-coverage tests/test-wrap tests/test-all-dies-it
 dwarflint_SOURCES = \
        addr-record.cc addr-record.hh \
        all-dies-it.hh \
+       check_registrar.cc check_registrar.hh check_registrar.ii \
        checkdescriptor.cc checkdescriptor.hh checkdescriptor.ii \
        checked_read.cc checked_read.hh \
        checkrule.cc checkrule.hh \
-       checks.cc checks.hh checks.ii \
+       checks.hh checks.ii \
        coverage.cc coverage.hh \
        cu_coverage.cc cu_coverage.hh cu_coverage.ii \
        dwarf_2.cc dwarf_2.hh \
@@ -76,6 +77,7 @@ dwarflint_SOURCES = \
        check_debug_line.cc check_debug_line.hh check_debug_line.ii \
        check_debug_loc_range.cc check_debug_loc_range.hh check_debug_loc_range.ii \
        check_debug_pub.cc check_debug_pub.hh \
+       check_die_tree.cc check_die_tree.hh check_die_tree.ii \
        check_duplicate_DW_tag_variable.cc \
        check_dups_abstract_origin.cc \
        check_expected_trees.cc \
index 7bcc36f2bf486c9ca41f536ce4b635c4e01c7b9e..7af7316febf88a840d84473be27bf616d42bfd82 100644 (file)
    Network licensing program, please visit www.openinventionnetwork.com
    <http://www.openinventionnetwork.com>.  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <vector>
 #include <stdexcept>
 
diff --git a/dwarflint/check_die_tree.cc b/dwarflint/check_die_tree.cc
new file mode 100644 (file)
index 0000000..e37fb89
--- /dev/null
@@ -0,0 +1,89 @@
+/* Pedantic checking of DWARF files
+   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
+   <http://www.openinventionnetwork.com>.  */
+
+#include "messages.hh"
+#include "highlevel_check.hh"
+#include "check_die_tree.hh"
+
+using namespace elfutils;
+
+namespace
+{
+  reg<check_die_tree> reg;
+}
+
+class die_check_context
+  : protected std::vector<die_check *>
+{
+  typedef std::vector<die_check *> _super_t;
+
+public:
+  die_check_context (checkdescriptor const *cd, dwarflint &lint,
+                    die_check_registrar const &registrar)
+  {
+    // For per-DIE runs, we are only interested in limited context:
+    // the main iteration check, and the per-DIE check.  This should
+    // be enough to decide whether to run the per-DIE check or not.
+    // We cannot use the original stack as a criterion, because the
+    // original check that tricked us into running is here, and the
+    // logic in should_check would then assume that we need to run
+    // everything.
+    checkstack stack;
+    stack.push_back (cd);
+
+    for (die_check_registrar::const_iterator it = registrar.begin ();
+        it != registrar.end (); ++it)
+      {
+       stack.push_back ((*it)->descriptor ());
+       popper p (stack);
+       if (lint.rules ().should_check (stack))
+         push_back ((*it)->create (stack, lint));
+      }
+  }
+
+  void
+  die (all_dies_iterator<dwarf> const &a_d_it)
+  {
+    for (iterator it = begin (); it != end (); ++it)
+      (*it)->die (a_d_it);
+  }
+
+  ~die_check_context ()
+  {
+    for (iterator it = begin (); it != end (); ++it)
+      delete *it;
+  }
+};
+
+check_die_tree::check_die_tree (checkstack &stack, dwarflint &lint)
+  : highlevel_check<check_die_tree> (stack, lint)
+{
+  //std::cout << "check_die_tree" << std::endl;
+  die_check_context ctx (descriptor (), lint, *dwarflint::die_registrar ());
+
+  for (all_dies_iterator<dwarf> it = all_dies_iterator<dwarf> (dw);
+       it != all_dies_iterator<dwarf> (); ++it)
+    ctx.die (it);
+}
diff --git a/dwarflint/check_die_tree.hh b/dwarflint/check_die_tree.hh
new file mode 100644 (file)
index 0000000..cd0a14e
--- /dev/null
@@ -0,0 +1,111 @@
+/* Pedantic checking of DWARF files
+   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
+   <http://www.openinventionnetwork.com>.  */
+
+#ifndef _CHECK_DIE_TREE_H_
+#define _CHECK_DIE_TREE_H_
+
+#include "all-dies-it.hh"
+#include "highlevel_check.hh"
+#include "check_die_tree.ii"
+
+#include <c++/dwarf>
+
+/// Top-level check that iterates over all DIEs in a file and
+/// dispatches per-DIE checks on each one.  Per-DIE checks are written
+/// as subclasses of die_check (see below) and registered using
+/// reg_die_check (see further below).
+class check_die_tree
+  : public highlevel_check<check_die_tree>
+{
+public:
+  static checkdescriptor const *descriptor ()
+  {
+    static checkdescriptor cd
+      (checkdescriptor::create ("check_die_tree")
+       .inherit<highlevel_check<check_die_tree> > ()
+       .hidden ()
+       .description ("A pass over the DIE tree that dispatches to various per-DIE checks.\n"));
+    return &cd;
+  }
+
+  check_die_tree (checkstack &stack, dwarflint &lint);
+};
+
+class die_check
+{
+public:
+  virtual ~die_check () {}
+  virtual void die (all_dies_iterator<elfutils::dwarf> const &it) = 0;
+};
+
+template <class T>
+struct reg_die_check
+  : public die_check_item
+{
+  reg_die_check ()
+  {
+    dwarflint::die_registrar ()->push_back (this);
+  }
+
+  virtual die_check *create (checkstack &stack, dwarflint &lint)
+  {
+    return new T (stack, lint);
+  }
+
+  virtual checkdescriptor const *descriptor () const
+  {
+    return T::descriptor ();
+  }
+
+private:
+  /// The top-level scheduler needs to see per-DIE checks as real
+  /// checks, which they are not.  So the per-DIE registrar creates
+  /// this check stub that's here only to trick the check_die_tree to
+  /// run.  check_die_tree then does the per-DIE check scheduling
+  /// itself, down in die_check_context.
+  class check_stub
+    : public highlevel_check<check_stub>
+  {
+    check_die_tree *_m_die_tree_check;
+  public:
+    static checkdescriptor const *descriptor ()
+    {
+      static checkdescriptor cd
+       (checkdescriptor::create (*T::descriptor ())
+        .prereq<typeof (*_m_die_tree_check)> ()
+        .inherit<highlevel_check<check_stub> > ());
+      return &cd;
+    }
+
+    check_stub (checkstack &stack, dwarflint &lint)
+      : highlevel_check<check_stub> (stack, lint)
+      , _m_die_tree_check (lint.check (stack, _m_die_tree_check))
+    {}
+  };
+
+  ::reg<check_stub> _m_reg_stub;
+};
+
+#endif /* _CHECK_DIE_TREE_H_ */
diff --git a/dwarflint/check_die_tree.ii b/dwarflint/check_die_tree.ii
new file mode 100644 (file)
index 0000000..95b98e6
--- /dev/null
@@ -0,0 +1 @@
+class check_die_tree;
diff --git a/dwarflint/check_registrar.cc b/dwarflint/check_registrar.cc
new file mode 100644 (file)
index 0000000..3519848
--- /dev/null
@@ -0,0 +1,101 @@
+/* Pedantic checking of DWARF files
+   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
+   <http://www.openinventionnetwork.com>.  */
+
+#include "check_registrar.hh"
+#include "checkdescriptor.hh"
+#include "dwarflint.hh"
+#include "main.hh"
+#include "wrap.hh"
+
+void
+check_registrar_aux::add_deps (std::set<checkdescriptor const *> &to,
+                               checkdescriptor const *cd)
+{
+  for (std::set<checkdescriptor const *>::const_iterator it
+        = cd->prereq ().begin (); it != cd->prereq ().end (); ++it)
+    include (to, *it);
+}
+
+void
+check_registrar_aux::include (std::set<checkdescriptor const *> &to,
+                              checkdescriptor const *cd)
+{
+  if (cd->hidden ())
+    add_deps (to, cd);
+  else
+    to.insert (cd);
+}
+
+bool
+check_registrar_aux::be_verbose ()
+{
+  // We can hopefully assume that the option doesn't change during
+  // execution, so we can simply cache it this was.
+  static bool be_verbose = opt_list_checks.value () == "full";
+  return be_verbose;
+}
+
+void
+check_registrar_aux::list_one_check (checkdescriptor const &cd)
+{
+  const size_t columns = 70;
+
+  if (be_verbose ())
+    std::cout << "=== " << cd.name () << " ===";
+  else
+    std::cout << cd.name ();
+
+  checkgroups const &groups = cd.groups ();
+  if (!groups.empty ())
+    {
+      if (be_verbose ())
+       std::cout << std::endl << "groups: ";
+      else
+       std::cout << ' ';
+      std::cout << groups;
+    }
+  std::cout << std::endl;
+
+  if (be_verbose ())
+    {
+      prereqs const &prereq = cd.prereq ();
+      if (!prereq.empty ())
+       std::cout << "prerequisites: " << prereq << std::endl;
+
+      char const *desc = cd.description ();
+      if (desc != NULL)
+       std::cout << wrap_str (desc, columns).join ();
+
+      options const &opts = cd.opts ();
+      if (!opts.empty ())
+       {
+         std::cout << "recognized options:" << std::endl;
+         argp a = opts.build_argp ();
+         argp_help (&a, stdout, ARGP_HELP_LONG, NULL);
+       }
+
+      std::cout << std::endl;
+    }
+}
similarity index 50%
rename from dwarflint/checks.cc
rename to dwarflint/check_registrar.hh
index 4561f8c8765f580bef3d5b7be334c812fb9b16e2..7f3064ea01dce2ee996be549bbf43e85e3f708a4 100644 (file)
@@ -1,5 +1,5 @@
-/*
-   Copyright (C) 2010 Red Hat, Inc.
+/* Pedantic checking of DWARF files
+   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
    Network licensing program, please visit www.openinventionnetwork.com
    <http://www.openinventionnetwork.com>.  */
 
-#include "checks.hh"
-#include "option.hh"
+#ifndef _CHECK_REGISTRAR_H_
+#define _CHECK_REGISTRAR_H_
 
-static global_opt<void_option> show_progress
-  ("Print out checks as they are performed, their context and result.",
-   "show-progress");
+#include "dwarflint.ii"
+#include "checkdescriptor.ii"
 
-reporter::reporter (checkstack const &s, checkdescriptor const &a_cd)
-  : stack (s)
-  , cd (a_cd)
+#include <vector>
+#include <set>
+#include <iostream>
+
+namespace check_registrar_aux
 {
-  (*this) ("...", true);
+  bool be_verbose ();
+  void list_one_check (checkdescriptor const &cd);
+
+  void include (std::set<checkdescriptor const *> &to,
+               checkdescriptor const *cd);
+  void add_deps (std::set<checkdescriptor const *> &to,
+                checkdescriptor const *cd);
 }
 
-void
-reporter::operator () (char const *what, bool ext)
+template <class Item>
+class check_registrar_T
+  : protected std::vector<Item *>
 {
-  if (!show_progress)
-    return;
+  typedef std::vector<Item *> _super_t;
+public:
 
-  if (false)
-    for (size_t i = 0; i < stack.size (); ++i)
-      std::cout << ' ';
+  using _super_t::push_back;
+  using _super_t::const_iterator;
+  using _super_t::begin;
+  using _super_t::end;
 
-  std::cout << cd.name () << ' ' << what;
-  if (ext)
-    std::cout << ' ' << cd.groups () << ' ' << stack;
-  std::cout << std::endl;
-}
+  typedef std::vector<checkdescriptor const *> checkdescriptors_t;
+
+  checkdescriptors_t
+  get_descriptors () const
+  {
+    std::set<checkdescriptor const *> descriptors;
+    for (typename _super_t::const_iterator it = begin (); it != end (); ++it)
+      check_registrar_aux::include (descriptors, (*it)->descriptor ());
+    return checkdescriptors_t (descriptors.begin (), descriptors.end ());
+  }
+};
+
+#endif /* _CHECK_REGISTRAR_H_ */
diff --git a/dwarflint/check_registrar.ii b/dwarflint/check_registrar.ii
new file mode 100644 (file)
index 0000000..6e84c91
--- /dev/null
@@ -0,0 +1,2 @@
+//-*-c++-*-
+struct check_registrar;
index a5cecc6dd8ca8a561c11400f501ee93150af35db..a74d69c01926fba158533572be84c11af18b52e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 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
@@ -62,6 +62,15 @@ checkdescriptor::create::create (char const *name)
   , _m_hidden (false)
 {}
 
+checkdescriptor::create::create (checkdescriptor const &base)
+  : _m_groups (base.groups ())
+  , _m_prereq (base.prereq ())
+  , _m_name (base.name ())
+  , _m_description (base.description ())
+  , _m_hidden (base.hidden ())
+  , _m_opts (base.opts ())
+{}
+
 checkdescriptor::create &
 checkdescriptor::create::groups (char const *a_groups)
 {
index c36eb06749907ec6748619b7c6aa9b30121b9213..2127d5f54d42417ce708f7654121695c54a3d8b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 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
@@ -59,6 +59,7 @@ struct checkdescriptor
 
   public:
     create (char const *name = NULL);
+    create (checkdescriptor const &base); ///< For construction of overrides.
     create &groups (char const *name);
 
     create &description (char const *d)
index a29f83cbc7e227495f47b9b7abbd1312973ed77c..08b1529591636a2890679d820195a7f38c226c4b 100644 (file)
@@ -30,6 +30,8 @@
 #include "dwarflint.hh"
 #include "checkdescriptor.hh"
 #include "messages.hh"
+#include "check_registrar.hh"
+
 #include <string>
 #include <cassert>
 
@@ -53,97 +55,24 @@ private:
   }
 };
 
-struct reporter
+class popper
 {
-  checkstack const &stack;
-  checkdescriptor const &cd;
-
-  reporter (checkstack const &s, checkdescriptor const &a_cd);
-  void operator () (char const *what, bool ext = false);
-};
+  checkstack &_m_guard_stack;
 
-template <class T>
-T *
-dwarflint::check (checkstack &stack)
-{
-  void const *key = T::key ();
-  T *c = static_cast <T *> (find_check (key));
+public:
+  popper (checkstack &guard_stack)
+    : _m_guard_stack (guard_stack)
+  {}
 
-  if (c == NULL)
-    {
-      checkdescriptor const &cd = *T::descriptor ();
-
-      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");
-
-#define FAIL                                   \
-      /* Put the anchor in the table.  */      \
-       _m_checks[key] = NULL;                  \
-       report ("FAIL")
-
-      reporter report (stack, cd);
-      try
-       {
-         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 (check_base::failed &e)
-       {
-         // We can assume that the check emitted error message.
-         FAIL;
-         throw;
-       }
-      catch (std::exception &e)
-       {
-         wr_error () << "A check failed: " << (cd.name () ?: "(nil)") << ": "
-                     << e.what () << std::endl;
-         FAIL;
-         throw check_base::failed ();
-       }
-      catch (...)
-       {
-         wr_error () << "A check failed: " << (cd.name () ?: "(nil)") << "."
-                     << std::endl;
-         FAIL;
-         throw check_base::failed ();
-       }
-
-#undef FAIL
-
-      report ("done");
-
-      // On success, put the actual check object there instead of the
-      // marker.
-      _m_checks[key] = c;
-    }
-  return c;
-}
+  ~popper ()
+  {
+    _m_guard_stack.pop_back ();
+  }
+};
 
 template <class T>
 inline T *
-dwarflint::toplev_check (checkstack &stack,
-                        __attribute__ ((unused)) T *tag)
+dwarflint::toplev_check (checkstack &stack, T *)
 {
   try
     {
@@ -157,11 +86,10 @@ dwarflint::toplev_check (checkstack &stack,
 
 template <class T>
 struct reg
-  : public dwarflint::check_registrar::item
+  : public main_check_item
 {
-  reg ()
-  {
-    dwarflint::check_registrar::inst ()->add (this);
+  reg () {
+    dwarflint::main_registrar ()->push_back (this);
   }
 
   virtual void run (checkstack &stack, dwarflint &lint)
index b9ca68df792e38289be5da9070c494f2e4becf33..2d405382e9a374a6b4365d01f768f8c8076f05fc 100644 (file)
@@ -1 +1,2 @@
 struct check_base;
+class die_check;
index f00c1c175461ed3b0e230dc68b719bd0376188b5..d2c22b0de0abf282874855acb33f165853d91ad0 100644 (file)
@@ -1,4 +1,4 @@
-/* Dwarflint check scheduler.
+/* Pedantic checking of DWARF files
    Copyright (C) 2008,2009,2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
@@ -26,8 +26,7 @@
 #include "dwarflint.hh"
 #include "messages.hh"
 #include "checks.hh"
-#include "main.hh"
-#include "wrap.hh"
+#include "check_registrar.hh"
 
 #include <fcntl.h>
 #include <cstring>
@@ -68,12 +67,22 @@ namespace
   }
 }
 
-dwarflint::dwarflint (char const *a_fname, checkrules const &rules)
+void
+main_check_registrar::run (dwarflint &lint)
+{
+  for (const_iterator it = begin (); it != end (); ++it)
+    {
+      checkstack stack;
+      (*it)->run (stack, lint);
+    }
+}
+
+dwarflint::dwarflint (char const *a_fname, checkrules const &a_rules)
   : _m_fname (a_fname)
   , _m_fd (get_fd (_m_fname))
-  , _m_rules (rules)
+  , _m_rules (a_rules)
 {
-  check_registrar::inst ()->enroll (*this);
+  main_registrar ()->run (*this);
 }
 
 dwarflint::~dwarflint ()
@@ -87,123 +96,167 @@ dwarflint::~dwarflint ()
     delete it->second;
 }
 
-void
-dwarflint::check_registrar::enroll (dwarflint &lint)
+void *const dwarflint::marker = (void *)-1;
+
+void *
+dwarflint::find_check (void const *key)
 {
-  for (std::vector <item *>::iterator it = _m_items.begin ();
-       it != _m_items.end (); ++it)
+  check_map::const_iterator it = _m_checks.find (key);
+
+  if (it != _m_checks.end ())
     {
-      checkstack stack;
-      (*it)->run (stack, lint);
+      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;
 }
 
-namespace
+main_check_registrar *
+dwarflint::main_registrar ()
 {
-  template <class T> void include (T &to, checkdescriptor const *cd);
+  static main_check_registrar inst;
+  return &inst;
+}
 
-  template <class T>
-  void add_deps (T &to, checkdescriptor const *cd)
-  {
-    for (typename T::const_iterator it = cd->prereq ().begin ();
-        it != cd->prereq ().end (); ++it)
-      include (to, *it);
-  }
+die_check_registrar *
+dwarflint::die_registrar ()
+{
+  static die_check_registrar inst;
+  return &inst;
+}
 
+namespace
+{
   template <class T>
-  void include (T &to, checkdescriptor const *cd)
+  void
+  list_part_checks (T const &descriptors)
   {
-    if (cd->hidden ())
-      add_deps (to, cd);
-    else
-      to.insert (cd);
+    for (typename T::const_iterator it = descriptors.begin ();
+        it != descriptors.end (); ++it)
+      check_registrar_aux::list_one_check (**it);
   }
 }
 
-dwarflint::check_registrar::checkdescriptors_t
-dwarflint::check_registrar::get_descriptors () const
-{
-  std::set<checkdescriptor const *> descriptors;
-  for (std::vector <item *>::const_iterator it = _m_items.begin ();
-       it != _m_items.end (); ++it)
-    include (descriptors, (*it)->descriptor ());
-  return checkdescriptors_t (descriptors.begin (), descriptors.end ());
-}
-
 void
-dwarflint::check_registrar::list_checks () const
+dwarflint::list_checks ()
 {
-  bool be_verbose = opt_list_checks.value () == "full";
-  checkdescriptors_t descriptors = get_descriptors ();
-  const size_t columns = 70;
+  list_part_checks (dwarflint::main_registrar ()->get_descriptors ());
 
-  for (checkdescriptors_t::const_iterator it = descriptors.begin ();
-       it != descriptors.end (); ++it)
-    {
-      checkdescriptor const &cd = **it;
-      if (be_verbose)
-       std::cout << "=== " << cd.name () << " ===";
-      else
-       std::cout << cd.name ();
-
-      checkgroups const &groups = cd.groups ();
-      if (!groups.empty ())
-       {
-         if (be_verbose)
-           std::cout << std::endl << "groups: ";
-         else
-           std::cout << ' ';
-         std::cout << groups;
-       }
-      std::cout << std::endl;
-
-      if (be_verbose)
-       {
-         prereqs const &prereq = cd.prereq ();
-         if (!prereq.empty ())
-           std::cout << "prerequisites: " << prereq << std::endl;
-
-         char const *desc = cd.description ();
-         if (desc != NULL)
-           std::cout << wrap_str (desc, columns).join ();
-
-         options const &opts = cd.opts ();
-         if (!opts.empty ())
-           {
-             std::cout << "recognized options:" << std::endl;
-             argp a = opts.build_argp ();
-             argp_help (&a, stdout, ARGP_HELP_LONG, NULL);
-           }
-
-         std::cout << std::endl;
-       }
-    }
-  if (!be_verbose)
+  if (!check_registrar_aux::be_verbose ())
     std::cout
       << "Use --list-checks=full to get more detailed description."
       << std::endl;
 }
 
-void *const dwarflint::marker = (void *)-1;
+static global_opt<void_option> show_progress
+  ("Print out checks as they are performed, their context and result.",
+   "show-progress");
+
+namespace
+{
+  struct reporter
+  {
+    checkstack const &stack;
+    checkdescriptor const &cd;
+
+    reporter (checkstack const &s, checkdescriptor const &a_cd);
+    void operator () (char const *what, bool ext = false);
+  };
+
+  reporter::reporter (checkstack const &s, checkdescriptor const &a_cd)
+    : stack (s)
+    , cd (a_cd)
+  {
+    (*this) ("...", true);
+  }
+
+  void
+  reporter::operator () (char const *what, bool ext)
+  {
+    if (!show_progress)
+      return;
+
+    if (false)
+      for (size_t i = 0; i < stack.size (); ++i)
+       std::cout << ' ';
+
+    std::cout << cd.name () << ' ' << what;
+    if (ext)
+      std::cout << ' ' << cd.groups () << ' ' << stack;
+    std::cout << std::endl;
+  }
+}
 
 void *
-dwarflint::find_check (void const *key)
+dwarflint::dispatch_check (checkstack &stack,
+                          checkdescriptor const &cd,
+                          void const *key,
+                          check_base *(* create) (checkstack &, dwarflint &))
 {
-  check_map::const_iterator it = _m_checks.find (key);
+  // Put a marker there indicating that we are trying to satisfy
+  // that dependency.
+  bool inserted
+    = _m_checks.insert (std::make_pair (key, (check_base *)marker)).second;
+  assert (inserted || !"duplicate key");
 
-  if (it != _m_checks.end ())
+#define FAIL                                   \
+  /* Put the anchor in the table.  */          \
+    _m_checks[key] = NULL;                     \
+    report ("FAIL")
+
+  reporter report (stack, cd);
+  try
     {
-      void *c = it->second;
+      stack.push_back (&cd);
+      popper p (stack);
 
-      // We already tried to do the check, but failed.
-      if (c == NULL)
-       throw check_base::failed ();
-      else
-       // Recursive dependency!
-       assert (c != marker);
+      if (!_m_rules.should_check (stack))
+       throw check_base::unscheduled ();
 
+      // Now do the check.
+      check_base *c = create (stack, *this);
+
+      // On success, put the actual check object there instead of the
+      // marker.
+      _m_checks[key] = c;
+      report ("done");
       return c;
     }
+  catch (check_base::unscheduled &e)
+    {
+      report ("skipped");
+      _m_checks.erase (key);
+      throw;
+    }
+  catch (check_base::failed &e)
+    {
+      // We can assume that the check emitted error message.
+      FAIL;
+      throw;
+    }
+  catch (std::exception &e)
+    {
+      wr_error () << "A check failed: " << (cd.name () ?: "(nil)") << ": "
+                 << e.what () << std::endl;
+      FAIL;
+      throw check_base::failed ();
+    }
+  catch (...)
+    {
+      wr_error () << "A check failed: " << (cd.name () ?: "(nil)") << "."
+                 << std::endl;
+      FAIL;
+      throw check_base::failed ();
+    }
 
-  return NULL;
+#undef FAIL
 }
index 51e65f539862fcc37e77d0ced7085d82faa0cca1..6ee64943d413be3291a623e1f2524487fca85c98 100644 (file)
@@ -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
 #include "checks.ii"
 #include "checkdescriptor.ii"
 #include "checkrule.hh"
+#include "check_registrar.hh"
+#include "dwarflint.ii"
+
+// Classes for full-blown check passes.
+struct main_check_item
+{
+  virtual checkdescriptor const *descriptor () const = 0;
+  virtual ~main_check_item () {}
+  virtual void run (checkstack &stack, dwarflint &lint) = 0;
+};
+
+class main_check_registrar
+  : public check_registrar_T<main_check_item>
+{
+public:
+  friend class dwarflint;
+  void run (dwarflint &lint);
+};
+
+// Classes for simplified single-die passes.
+struct die_check_item
+{
+  virtual checkdescriptor const *descriptor () const = 0;
+  virtual ~die_check_item () {}
+  virtual die_check *create (checkstack &stack, dwarflint &lint) = 0;
+};
+
+class die_check_registrar
+  : public check_registrar_T<die_check_item>
+{
+public:
+  friend class dwarflint;
+  void run (checkstack &stack, dwarflint &lint);
+};
+
 
 class checkstack
   : public std::vector <checkdescriptor const *>
 {};
 std::ostream &operator << (std::ostream &o, checkstack const &stack);
 
+
 class dwarflint
 {
   typedef std::map <void const *, class check_base *> check_map;
@@ -57,56 +93,47 @@ class dwarflint
   // was detected.
   void *find_check (void const *key);
 
-public:
-  struct check_registrar
+  template <class T>
+  static check_base *
+  create_check_object (checkstack &stack, dwarflint &lint)
   {
-    struct item
-    {
-      virtual void run (checkstack &stack, dwarflint &lint) = 0;
-      virtual checkdescriptor const *descriptor () const = 0;
-    };
-
-    static check_registrar *inst ()
-    {
-      static check_registrar inst;
-      return &inst;
-    }
-
-    void add (item *i)
-    {
-      _m_items.push_back (i);
-    }
-
-    void list_checks () const;
-
-    typedef std::vector<checkdescriptor const *> checkdescriptors_t;
-    checkdescriptors_t get_descriptors () const;
-
-  private:
-    friend class dwarflint;
-    void enroll (dwarflint &lint);
+    return new T (stack, lint);
+  }
 
-    std::vector <item *> _m_items;
-  };
+  void *dispatch_check (checkstack &stack,
+                       checkdescriptor const &cd,
+                       void const *key,
+                       check_base *(* create) (checkstack &, dwarflint &));
 
+public:
   dwarflint (char const *fname, checkrules const &rules);
   ~dwarflint ();
   int fd () { return _m_fd; }
   char const *fname () { return _m_fname; }
 
-  template <class T> T *check (checkstack &stack);
+  template <class T>
+  T *
+  check (checkstack &stack)
+  {
+    void const *key = T::key ();
+    T *c = static_cast <T *> (find_check (key));
+    checkdescriptor const &cd = *T::descriptor ();
+
+    if (c == NULL)
+      c = (T *)dispatch_check (stack, cd, key, &create_check_object<T>);
+
+    return c;
+  }
 
   template <class T>
   T *
-  check (checkstack &stack,
-        __attribute__ ((unused)) T *fake)
+  check (checkstack &stack, T *)
   {
     return check<T> (stack);
   }
 
   template <class T>
-  T *toplev_check (checkstack &stack,
-                  __attribute__ ((unused)) T *fake = NULL);
+  T *toplev_check (checkstack &stack, T *fake = NULL);
 
   template <class T>
   T *
@@ -118,6 +145,17 @@ public:
     else
       return NULL;
   }
+
+  checkrules const &
+  rules () const
+  {
+    return _m_rules;
+  }
+
+  static main_check_registrar *main_registrar ();
+  static die_check_registrar *die_registrar ();
+
+  static void list_checks ();
 };
 
 #endif//DWARFLINT_HH
index e574a5ffa02eb91fe28f083d70354803b9fb44d0..9769d6bd90936a9c3a30cac93a2fbbc96f6618c2 100644 (file)
@@ -1,2 +1,3 @@
 class checkstack;
 class dwarflint;
+class main_check_registrar;
index d4d61d916a56da07aa06b15936cac5176289a7bd..3db9f5c76d35c3d4c91aedb94bc57459a242e86f 100644 (file)
@@ -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
@@ -40,7 +40,9 @@ class open_highlevel_dwarf
   Dwfl *const _m_dwfl;
 public:
   static checkdescriptor const *descriptor () {
-    static checkdescriptor cd ("open_highlevel_dwarf");
+    static checkdescriptor cd
+      (checkdescriptor::create ("open_highlevel_dwarf")
+       .hidden ());
     return &cd;
   }
 
index eb0252e0aa665581a96fb74d38768503da87ed40..f11849d80185e102c81b810b09f2e91e321ae6c1 100644 (file)
@@ -159,7 +159,7 @@ main (int argc, char *argv[])
 
   if (opt_list_checks.seen ())
     {
-      dwarflint::check_registrar::inst ()->list_checks ();
+      dwarflint::list_checks ();
       std::exit (0);
     }
   else if (remaining == argc)
@@ -210,7 +210,6 @@ main (int argc, char *argv[])
       try
        {
          char const *fname = argv[remaining];
-         /* Create an `Elf' descriptor.  */
          unsigned int prev_error_count = error_count;
          if (!only_one)
            std::cout << std::endl << fname << ":" << std::endl;
index 99277270e94bfffacfb6c2d0a299919980887f24..420493eeea085b5cee10995ab83895fbaa13926a 100644 (file)
@@ -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
@@ -30,6 +30,7 @@
 #include "option.hh"
 #include "dwarflint.hh"
 #include "checkdescriptor.hh"
+#include "check_registrar.hh"
 #include <cassert>
 #include <cstring>
 #include <iostream>
@@ -91,8 +92,7 @@ argppp &
 argppp::inst ()
 {
   static argppp my
-    (global_opts,
-     dwarflint::check_registrar::inst ()->get_descriptors ());
+    (global_opts, dwarflint::main_registrar ()->get_descriptors ());
   return my;
 }
 
@@ -102,7 +102,7 @@ argppp::argppp (options const &global,
 {
   argp main = global.build_argp (true);
 
-  typedef dwarflint::check_registrar::checkdescriptors_t checkdescriptors_t;
+  typedef main_check_registrar::checkdescriptors_t checkdescriptors_t;
   for (checkdescriptors_t::const_iterator it = checkdescriptors.begin ();
        it != checkdescriptors.end (); ++it)
     if (!(*it)->opts ().empty ())