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 \
}
check_debug_abbrev::abbrev_map
- load_debug_abbrev (dwarflint &lint,
+ load_debug_abbrev (checkstack &stack,
+ dwarflint &lint,
struct sec §,
elf_file &file)
{
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)
{
}
}
-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))
{
}
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;
#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)
{
// 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;
}
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;
}
}
-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 ()))
}
}
-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 ();
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
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);
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,
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);
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)
}
}
-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,
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,
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
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
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));
}
};
: 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,
: 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;
}
}
-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
{
: 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
{
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
{
--- /dev/null
+/*
+ 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;
+}
/*
- 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
{
{
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;
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)
{
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);
}
};
--- /dev/null
+struct check_base;
+struct checkdescriptor;
}
}
-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);
}
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;
+}
#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
{
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 ()
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
}
}
-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))
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 ();
};
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)
#include <sys/types.h>
#include <iostream>
+#include <sstream>
#include "low.h"
#include "options.h"
#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[] =
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 }
};
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)),
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;
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"));
}
}
-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 ();
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)
{
: 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 ();
};
public:
sec §
elf_file &file;
- section_base (dwarflint &lint, section_id secid);
+ section_base (checkstack &stack,
+ dwarflint &lint, section_id secid);
relocation_data *reldata () const
{
, 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)
{}
};