diff options
Diffstat (limited to 'dwarflint/main.cc')
-rw-r--r-- | dwarflint/main.cc | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/dwarflint/main.cc b/dwarflint/main.cc new file mode 100644 index 00000000..dc4abda8 --- /dev/null +++ b/dwarflint/main.cc @@ -0,0 +1,224 @@ +/* Main entry point for dwarflint, a pedantic checker for DWARF files. + Copyright (C) 2008,2009,2010,2011 Red Hat, Inc. + This file is part of elfutils. + + This file 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; either version 3 of the License, or + (at your option) any later version. + + 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <libintl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <iostream> +#include <sstream> + +#include "dwarflint.hh" +#include "readctx.hh" +#include "checks.hh" +#include "option.hh" +#include "messages.hh" + +/* Messages that are accepted (and made into warning). */ +struct message_criteria warning_criteria; + +/* Accepted (warning) messages, that are turned into errors. */ +struct message_criteria error_criteria; + +struct check_option_t + : public global_opt<option_common> +{ + struct initial_checkrules + : public checkrules + { + initial_checkrules () + { + push_back (checkrule_internal ("@all", checkrule::request)); + push_back (checkrule_internal ("@nodefault", checkrule::forbid)); + } + } rules; + + check_option_t () + : global_opt<option_common> ("Only run selected checks.", + "[+-][@]name,...", "check", 0) + {} + + error_t parse_opt (char *arg, __attribute__ ((unused)) argp_state *state) + { + 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; + } + + checkrule::action_t action + = act == request ? checkrule::request : checkrule::forbid; + rules.push_back (checkrule (item, action)); + } + return 0; + } +} check_option; + +global_opt<void_option> + be_quiet ("Do not print anything if successful", + "quiet", 'q'); + +global_opt<string_option> + opt_list_checks ("List all the available checks.", + "full", "list-checks", 0, + OPTION_ARG_OPTIONAL); + +// xxx The following three should go away when we introduce the +// message filtering. Or should be preserved, but in a way that makes +// more sense, right now they are simply a misnomer. +global_opt<void_option> + ignore_bloat ("Ignore messages related to bloat.", "ignore-bloat"); +global_opt<void_option> + be_strict ("Be somewhat stricter.", "strict"); +global_opt<void_option> + be_tolerant ("Be somewhat more tolerant.", "tolerant"); + +int +main (int argc, char *argv[]) +{ + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Initialize the message catalog. */ + textdomain (PACKAGE_TARNAME); + + /* Parse and process arguments. */ + argppp argp (global_opts (), + dwarflint::main_registrar ()->get_descriptors ()); + + int remaining; + argp.parse (argc, argv, 0, &remaining); + + if (opt_list_checks.seen ()) + { + dwarflint::list_checks (); + std::exit (0); + } + else if (remaining == argc) + { + fputs (gettext ("Missing file name.\n"), stderr); + argp.help (stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + program_invocation_short_name); + std::exit (1); + } + + /* Initialize warning & error criteria. */ + warning_criteria |= message_term (mc_none, mc_none); + + error_criteria |= message_term (mc_impact_4, mc_none); + error_criteria |= message_term (mc_error, mc_none); + + /* Configure warning & error criteria according to configuration. */ + if (ignore_bloat) + warning_criteria &= message_term (mc_none, mc_acc_bloat); + + if (!be_strict) + { + warning_criteria &= message_term (mc_none, mc_strings); + warning_criteria.and_not (mc_line | mc_acc_bloat); + warning_criteria &= message_term (mc_none, mc_pubtypes); + } + + if (be_tolerant) + { + warning_criteria &= message_term (mc_none, mc_loc); + warning_criteria &= message_term (mc_none, mc_ranges); + } + + if (false) // for debugging + { + std::cout << "warning criteria: " << warning_criteria << std::endl; + std::cout << "error criteria: " << error_criteria << std::endl; + } + + /* Before we start tell the ELF library which version we are using. */ + elf_version (EV_CURRENT); + + /* Now process all the files given at the command line. */ + bool only_one = remaining + 1 == argc; + bool one_passed = false; + do + { + try + { + char const *fname = argv[remaining]; + if (!only_one) + std::cout << std::endl << fname << ":" << std::endl; + wr_reset_counters (); + dwarflint lint (fname, check_option.rules); + one_passed = true; + + if (error_count == 0 && !be_quiet) + puts (gettext ("No errors")); + } + catch (std::runtime_error &e) + { + wr_error () << e.what () << std::endl; + continue; + } + } + while (++remaining < argc); + + if (one_passed) + for (checkrules::const_iterator it = check_option.rules.begin (); + it != check_option.rules.end (); ++it) + if (!it->used ()) + std::cerr << "warning: the rule `" << it->name () + << "' never matched." << std::endl; + + return error_count != 0; +} |