summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <[email protected]>2011-03-28 16:10:26 +0200
committerPetr Machata <[email protected]>2011-03-28 16:10:26 +0200
commit6eecad70d2ae747aa04cca78ea2334ed3fb7986d (patch)
treed517de3b332a0c3c0b397abd5e06149e80455f44
parent1bfd2cbcc0591061089dcf88b2f4024d1fc06377 (diff)
parent0c1f888bcaedeb4b4eed550294a93ea09d386b6f (diff)
Merge branch 'pmachata/dwarflint' into dwarf
-rw-r--r--dwarflint/Makefile.am4
-rw-r--r--dwarflint/all-dies-it.hh4
-rw-r--r--dwarflint/check_die_tree.cc89
-rw-r--r--dwarflint/check_die_tree.hh111
-rw-r--r--dwarflint/check_die_tree.ii1
-rw-r--r--dwarflint/check_duplicate_DW_tag_variable.cc25
-rw-r--r--dwarflint/check_registrar.cc101
-rw-r--r--dwarflint/check_registrar.hh (renamed from dwarflint/checks.cc)63
-rw-r--r--dwarflint/check_registrar.ii2
-rw-r--r--dwarflint/checkdescriptor.cc11
-rw-r--r--dwarflint/checkdescriptor.hh3
-rw-r--r--dwarflint/checks.hh106
-rw-r--r--dwarflint/checks.ii1
-rw-r--r--dwarflint/dwarflint.cc241
-rw-r--r--dwarflint/dwarflint.hh108
-rw-r--r--dwarflint/dwarflint.ii1
-rw-r--r--dwarflint/highlevel_check.hh6
-rw-r--r--dwarflint/main.cc3
-rw-r--r--dwarflint/option.cc8
19 files changed, 620 insertions, 268 deletions
diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am
index 2247d0e9..b4164ddf 100644
--- a/dwarflint/Makefile.am
+++ b/dwarflint/Makefile.am
@@ -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 \
diff --git a/dwarflint/all-dies-it.hh b/dwarflint/all-dies-it.hh
index 7bcc36f2..7af7316f 100644
--- a/dwarflint/all-dies-it.hh
+++ b/dwarflint/all-dies-it.hh
@@ -23,6 +23,10 @@
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
index 00000000..e37fb893
--- /dev/null
+++ b/dwarflint/check_die_tree.cc
@@ -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
index 00000000..cd0a14ed
--- /dev/null
+++ b/dwarflint/check_die_tree.hh
@@ -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
index 00000000..95b98e68
--- /dev/null
+++ b/dwarflint/check_die_tree.ii
@@ -0,0 +1 @@
+class check_die_tree;
diff --git a/dwarflint/check_duplicate_DW_tag_variable.cc b/dwarflint/check_duplicate_DW_tag_variable.cc
index 80f96632..cd6f4abf 100644
--- a/dwarflint/check_duplicate_DW_tag_variable.cc
+++ b/dwarflint/check_duplicate_DW_tag_variable.cc
@@ -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
@@ -23,8 +23,7 @@
Network licensing program, please visit www.openinventionnetwork.com
<http://www.openinventionnetwork.com>. */
-#include "highlevel_check.hh"
-#include "all-dies-it.hh"
+#include "check_die_tree.hh"
#include "pri.hh"
#include "messages.hh"
#include <map>
@@ -34,7 +33,7 @@ using elfutils::dwarf;
namespace
{
class check_duplicate_DW_tag_variable
- : public highlevel_check<check_duplicate_DW_tag_variable>
+ : public die_check
{
struct varinfo
{
@@ -65,18 +64,10 @@ namespace
return &cd;
}
- check_duplicate_DW_tag_variable (checkstack &stack, dwarflint &lint);
- };
-
- reg<check_duplicate_DW_tag_variable> reg_duplicate_DW_tag_variable;
-}
+ check_duplicate_DW_tag_variable (checkstack &, dwarflint &) {}
-check_duplicate_DW_tag_variable
-::check_duplicate_DW_tag_variable (checkstack &stack, dwarflint &lint)
- : highlevel_check<check_duplicate_DW_tag_variable> (stack, lint)
-{
- for (all_dies_iterator<dwarf> it = all_dies_iterator<dwarf> (dw);
- it != all_dies_iterator<dwarf> (); ++it)
+ virtual void
+ die (all_dies_iterator<dwarf> const &it)
{
dwarf::debug_info_entry::children_type const &children
= it->children ();
@@ -91,7 +82,7 @@ check_duplicate_DW_tag_variable
{
dwarf::debug_info_entry::attributes_type const &
attrs = jt->attributes ();
- dwarf::debug_info_entry::attributes_type::const_iterator
+ dwarf::debug_info_entry::attributes_type::const_iterator
at, et = attrs.end ();
if ((at = attrs.find (DW_AT_name)) == et)
continue;
@@ -136,4 +127,6 @@ check_duplicate_DW_tag_variable
}
}
}
+ };
+ reg_die_check<check_duplicate_DW_tag_variable> reg;
}
diff --git a/dwarflint/check_registrar.cc b/dwarflint/check_registrar.cc
new file mode 100644
index 00000000..35198482
--- /dev/null
+++ b/dwarflint/check_registrar.cc
@@ -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;
+ }
+}
diff --git a/dwarflint/checks.cc b/dwarflint/check_registrar.hh
index 4561f8c8..7f3064ea 100644
--- a/dwarflint/checks.cc
+++ b/dwarflint/check_registrar.hh
@@ -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
@@ -23,32 +23,49 @@
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
index 00000000..6e84c911
--- /dev/null
+++ b/dwarflint/check_registrar.ii
@@ -0,0 +1,2 @@
+//-*-c++-*-
+struct check_registrar;
diff --git a/dwarflint/checkdescriptor.cc b/dwarflint/checkdescriptor.cc
index a5cecc6d..a74d69c0 100644
--- a/dwarflint/checkdescriptor.cc
+++ b/dwarflint/checkdescriptor.cc
@@ -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)
{
diff --git a/dwarflint/checkdescriptor.hh b/dwarflint/checkdescriptor.hh
index c36eb067..2127d5f5 100644
--- a/dwarflint/checkdescriptor.hh
+++ b/dwarflint/checkdescriptor.hh
@@ -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)
diff --git a/dwarflint/checks.hh b/dwarflint/checks.hh
index a29f83cb..08b15295 100644
--- a/dwarflint/checks.hh
+++ b/dwarflint/checks.hh
@@ -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)
diff --git a/dwarflint/checks.ii b/dwarflint/checks.ii
index b9ca68df..2d405382 100644
--- a/dwarflint/checks.ii
+++ b/dwarflint/checks.ii
@@ -1 +1,2 @@
struct check_base;
+class die_check;
diff --git a/dwarflint/dwarflint.cc b/dwarflint/dwarflint.cc
index f00c1c17..d2c22b0d 100644
--- a/dwarflint/dwarflint.cc
+++ b/dwarflint/dwarflint.cc
@@ -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
}
diff --git a/dwarflint/dwarflint.hh b/dwarflint/dwarflint.hh
index 51e65f53..6ee64943 100644
--- a/dwarflint/dwarflint.hh
+++ b/dwarflint/dwarflint.hh
@@ -1,5 +1,5 @@
/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010 Red Hat, Inc.
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -35,12 +35,48 @@
#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
diff --git a/dwarflint/dwarflint.ii b/dwarflint/dwarflint.ii
index e574a5ff..9769d6bd 100644
--- a/dwarflint/dwarflint.ii
+++ b/dwarflint/dwarflint.ii
@@ -1,2 +1,3 @@
class checkstack;
class dwarflint;
+class main_check_registrar;
diff --git a/dwarflint/highlevel_check.hh b/dwarflint/highlevel_check.hh
index d4d61d91..3db9f5c7 100644
--- a/dwarflint/highlevel_check.hh
+++ b/dwarflint/highlevel_check.hh
@@ -1,5 +1,5 @@
/* Pedantic checking of DWARF files.
- Copyright (C) 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -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;
}
diff --git a/dwarflint/main.cc b/dwarflint/main.cc
index eb0252e0..f11849d8 100644
--- a/dwarflint/main.cc
+++ b/dwarflint/main.cc
@@ -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;
diff --git a/dwarflint/option.cc b/dwarflint/option.cc
index 99277270..420493ee 100644
--- a/dwarflint/option.cc
+++ b/dwarflint/option.cc
@@ -1,5 +1,5 @@
/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010 Red Hat, Inc.
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -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 ())