From: Petr Machata Date: Tue, 5 Apr 2011 18:00:42 +0000 (+0200) Subject: dwarflint: Make locstats an independent tool X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=495e3fab443d696406920f0f63c070d1d4692792;p=thirdparty%2Felfutils.git dwarflint: Make locstats an independent tool --- diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am index d7def5dbf..6bc9113e2 100644 --- a/dwarflint/Makefile.am +++ b/dwarflint/Makefile.am @@ -35,7 +35,7 @@ AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw no_mudflap.os = -fmudflap -bin_PROGRAMS = dwarflint +bin_PROGRAMS = dwarflint locstats noinst_PROGRAMS = tests/test-coverage tests/test-wrap tests/test-all-dies-it dwarflint_SOURCES = \ @@ -58,6 +58,7 @@ dwarflint_SOURCES = \ dwarflint.cc dwarflint.hh dwarflint.ii \ elf_file.hh elf_file.ii \ expected-at.cc expected.hh \ + files.cc files.hh \ highlevel_check.cc highlevel_check.hh \ main.cc \ messages.cc messages.hh \ @@ -86,11 +87,17 @@ dwarflint_SOURCES = \ check_range_out_of_scope.cc \ check_self_referential_die.cc \ check_linkage_external_die.cc \ - locstats.cc \ lowlevel_checks.cc lowlevel_checks.hh \ \ ../src/dwarfstrings.c +locstats_SOURCES = \ + locstats.cc \ + files.cc files.hh \ + option.cc option.hh option.ii \ + pri.cc pri.hh \ + where.c where.h + tests_test_coverage_SOURCES = tests/test-coverage.cc coverage.cc pri.cc \ ../src/dwarfstrings.c @@ -177,6 +184,7 @@ libeu = ../lib/libeu.a libdwpp = ../libdw/libdwpp.a $(libdw) dwarflint_LDADD = $(libebl) $(libelf) $(libdwpp) $(libeu) $(libmudflap) -ldl +locstats_LDADD = $(libebl) $(libelf) $(libdwpp) $(libeu) $(libmudflap) -ldl tests_test_coverage_LDADD = $(libebl) $(libelf) $(libdwpp) $(libeu) $(libmudflap) -ldl tests_test_all_dies_it_LDADD = $(libdwpp) diff --git a/dwarflint/dwarflint.cc b/dwarflint/dwarflint.cc index d2c22b0de..2f30415f0 100644 --- a/dwarflint/dwarflint.cc +++ b/dwarflint/dwarflint.cc @@ -1,5 +1,5 @@ /* Pedantic checking of DWARF files - Copyright (C) 2008,2009,2010 Red Hat, Inc. + Copyright (C) 2008,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 @@ -23,16 +23,20 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "dwarflint.hh" #include "messages.hh" #include "checks.hh" #include "check_registrar.hh" +#include "files.hh" #include #include #include #include -#include std::ostream & operator << (std::ostream &o, checkstack const &stack) @@ -49,24 +53,6 @@ operator << (std::ostream &o, checkstack const &stack) return o; } -namespace -{ - int - get_fd (char const *fname) - { - /* Open the file. */ - int fd = open (fname, O_RDONLY); - if (fd == -1) - { - std::stringstream ss; - ss << "Cannot open input file: " << strerror (errno) << "."; - throw std::runtime_error (ss.str ()); - } - - return fd; - } -} - void main_check_registrar::run (dwarflint &lint) { @@ -79,7 +65,7 @@ main_check_registrar::run (dwarflint &lint) dwarflint::dwarflint (char const *a_fname, checkrules const &a_rules) : _m_fname (a_fname) - , _m_fd (get_fd (_m_fname)) + , _m_fd (files::open (_m_fname)) , _m_rules (a_rules) { main_registrar ()->run (*this); diff --git a/dwarflint/files.cc b/dwarflint/files.cc new file mode 100644 index 000000000..2e0c30ef1 --- /dev/null +++ b/dwarflint/files.cc @@ -0,0 +1,146 @@ +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include "files.hh" +#include "messages.hh" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + inline bool failed (void *ptr) { return ptr == NULL; } + inline bool failed (int i) { return i < 0; } + + template + inline T + throw_if_failed (T x, char const *msg, + char const *(*errmsgcb) (int) = NULL) + { + if (unlikely (failed (x))) + { + std::stringstream ss; + ss << msg; + if (errmsgcb != NULL) + ss << ": " << errmsgcb (-1); + throw std::runtime_error (ss.str ()); + } + return x; + } + + char const * + mystrerror (int i) + { + if (i == -1) + i = errno; + return strerror (i); + } +} + +int +files::open (char const *fname) +{ + int fd = ::open (fname, O_RDONLY); + if (fd == -1) + { + std::stringstream ss; + ss << "Cannot open input file: " << strerror (errno) << "."; + throw std::runtime_error (ss.str ()); + } + + return fd; +} + +Dwfl * +files::open_dwfl () +{ + static class my_callbacks + : public Dwfl_Callbacks + { + // Stub libdwfl callback, only the ELF handle already open is ever used. + static int + find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + const char *file_name __attribute__ ((unused)), + const char *debuglink_file __attribute__ ((unused)), + GElf_Word debuglink_crc __attribute__ ((unused)), + char **debuginfo_file_name __attribute__ ((unused))) + { + return -1; + } + + public: + my_callbacks () + { + section_address = dwfl_offline_section_address; + find_debuginfo = find_no_debuginfo; + } + } cbs; + + return throw_if_failed (dwfl_begin (&cbs), + "Couldn't initialize DWFL"); +} + +Dwarf * +files::open_dwarf (Dwfl *dwfl, char const *fname, int fd) +{ + dwfl_report_begin (dwfl); + + // Dup FD for dwfl to consume. + int dwfl_fd + = throw_if_failed (dup (fd), "Error: dup", mystrerror); + + Dwfl_Module *mod + = throw_if_failed (dwfl_report_offline (dwfl, fname, fname, dwfl_fd), + "Couldn't add DWFL module", dwfl_errmsg); + dwfl_report_end (dwfl, NULL, NULL); + Dwarf_Addr bias; + throw_if_failed (dwfl_module_getelf (mod, &bias), + "Couldn't open ELF.", dwfl_errmsg); + return throw_if_failed (dwfl_module_getdwarf (mod, &bias), + "Couldn't obtain DWARF descriptor", dwfl_errmsg); +} + +elfutils::dwarf +files::open_dwarf (Dwarf *dw) + try + { + return dw; + } + catch (...) + { + throw std::runtime_error + ("Couldn't initialize high-level DWARF descriptor"); + } diff --git a/dwarflint/files.hh b/dwarflint/files.hh new file mode 100644 index 000000000..9ce0c9ede --- /dev/null +++ b/dwarflint/files.hh @@ -0,0 +1,47 @@ +/* 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 + . */ + +#ifndef _DWARFLINT_FILES_H_ +#define _DWARFLINT_FILES_H_ + +#include "../libdwfl/libdwfl.h" +#include "../libdw/c++/dwarf" + +// The functions in this module do their own error handling, and throw +// std::runtime_error with descriptive error message on error. +namespace files +{ + int open (char const *fname); + + Dwfl *open_dwfl () + __attribute__ ((nonnull, malloc)); + + Dwarf *open_dwarf (Dwfl *dwfl, char const *fname, int fd) + __attribute__ ((nonnull, malloc)); + + elfutils::dwarf open_dwarf (Dwarf *dw); +} + +#endif /* _DWARFLINT_FILES_H_ */ diff --git a/dwarflint/highlevel_check.cc b/dwarflint/highlevel_check.cc index 13f7d1dd5..975117423 100644 --- a/dwarflint/highlevel_check.cc +++ b/dwarflint/highlevel_check.cc @@ -1,5 +1,5 @@ /* Initialization of high-level check context - 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 @@ -24,116 +24,14 @@ . */ #include "highlevel_check.hh" -#include "messages.hh" - -#include "sections.hh" #include "lowlevel_checks.hh" - -namespace -{ - inline bool failed (void *ptr) { return ptr == NULL; } - inline bool failed (int i) { return i < 0; } - - template - inline T - throw_if_failed (T x, char const *msg, - char const *(*errmsgcb) (int) = NULL) - { - if (unlikely (failed (x))) - { - std::stringstream ss; - ss << msg; - if (errmsgcb != NULL) - ss << ": " << errmsgcb (-1); - ss << '.'; - wr_error () << ss.str () << std::endl; - throw check_base::failed (); - } - return x; - } - - Dwfl *open_dwfl () __attribute__ ((nonnull, malloc)); - Dwarf *open_dwarf (Dwfl *dwfl, int fd) __attribute__ ((nonnull, malloc)); - - Dwfl * - open_dwfl () - { - static class my_callbacks - : public Dwfl_Callbacks - { - // Stub libdwfl callback, only the ELF handle already open is ever used. - static int - find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)), - void **userdata __attribute__ ((unused)), - const char *modname __attribute__ ((unused)), - Dwarf_Addr base __attribute__ ((unused)), - const char *file_name __attribute__ ((unused)), - const char *debuglink_file __attribute__ ((unused)), - GElf_Word debuglink_crc __attribute__ ((unused)), - char **debuginfo_file_name __attribute__ ((unused))) - { - return -1; - } - - public: - my_callbacks () - { - section_address = dwfl_offline_section_address; - find_debuginfo = find_no_debuginfo; - } - } cbs; - - return throw_if_failed (dwfl_begin (&cbs), - "Couldn't initialize DWFL"); - } - - char const * - mystrerror (int i) - { - if (i == -1) - i = errno; - return strerror (i); - } - - Dwarf * - open_dwarf (Dwfl *dwfl, char const *fname, int fd) - { - dwfl_report_begin (dwfl); - - // Dup FD for dwfl to consume. - int dwfl_fd - = throw_if_failed (dup (fd), "Error: dup", mystrerror); - - Dwfl_Module *mod - = throw_if_failed (dwfl_report_offline (dwfl, fname, fname, dwfl_fd), - "Couldn't add DWFL module", dwfl_errmsg); - dwfl_report_end (dwfl, NULL, NULL); - Dwarf_Addr bias; - throw_if_failed (dwfl_module_getelf (mod, &bias), - "Couldn't open ELF.", dwfl_errmsg); - return throw_if_failed (dwfl_module_getdwarf (mod, &bias), - "Couldn't obtain DWARF descriptor", dwfl_errmsg); - } - - elfutils::dwarf - open_hl_dwarf (Dwarf *dw) - try - { - return dw; - } - catch (...) - { - wr_error () - << "Couldn't initialize high-level DWARF descriptor." << std::endl; - throw check_base::failed (); - } -} +#include "files.hh" open_highlevel_dwarf::open_highlevel_dwarf (checkstack &stack, dwarflint &lint) : _m_dwfl ((lint.check (stack), - open_dwfl ())) - , c_dw (open_dwarf (_m_dwfl, lint.fname (), lint.fd ())) - , dw (open_hl_dwarf (c_dw)) + files::open_dwfl ())) + , c_dw (files::open_dwarf (_m_dwfl, lint.fname (), lint.fd ())) + , dw (files::open_dwarf (c_dw)) {} open_highlevel_dwarf::~open_highlevel_dwarf () diff --git a/dwarflint/locstats.cc b/dwarflint/locstats.cc index 7ef2423e5..614563eb4 100644 --- a/dwarflint/locstats.cc +++ b/dwarflint/locstats.cc @@ -23,64 +23,49 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "highlevel_check.hh" #include "all-dies-it.hh" #include "option.hh" -#include "messages.hh" #include "pri.hh" +#include "files.hh" + +#include #include #include using elfutils::dwarf; -namespace -{ - -#define DIE_OPTSTRING \ +#define DIE_OPTSTRING \ "}[,...]" - string_option opt_ignore +global_opt opt_ignore ("Skip certain DIEs. class may be one of single_addr, artificial, inlined, \ inlined_subroutine, no_coverage, mutable, or immutable.", - "class[,...]", "locstats:ignore"); + "class[,...]", "ignore"); - string_option opt_dump +global_opt opt_dump ("Dump certain DIEs. For classes, see option 'ignore'.", - "class[,...]", "locstats:dump"); + "class[,...]", "dump"); - string_option opt_tabulation_rule +global_opt opt_tabulation_rule ("Rule for sorting results into buckets. start is either integer 0..100, \ or special value 0.0 indicating cases with no coverage whatsoever \ (i.e. not those that happen to round to 0%).", - "start[:step][,...]", "locstats:tabulate"); - - class locstats - : public highlevel_check - { - public: - static checkdescriptor const *descriptor () { - static checkdescriptor cd - (checkdescriptor::create ("locstats") - .groups ("@nodefault") - .option (opt_ignore) - .option (opt_dump) - .option (opt_tabulation_rule) - .description ( -"Computes a location info coverage statistics. Goes through the whole " -"DIE graph, looking at each variable and formal parameter, and " -"determining scope coverage of its location information. In other " -"words for how big a part of scope we know, where the variable " -"\"lives\".\n" -" - https://fedorahosted.org/pipermail/elfutils-devel/2010-July/001498.html\n" -" - https://fedorahosted.org/pipermail/elfutils-devel/2010-September/001602.html\n")); - return &cd; - } - - locstats (checkstack &stack, dwarflint &lint); - }; + "start[:step][,...]", "tabulate"); - reg reg_locstats; +// where.c needs to know how to format certain wheres. The module +// doesn't know that we don't use these :) +extern "C" +bool +show_refs () +{ + return false; +} #define DIE_TYPES \ TYPE(single_addr) \ @@ -91,98 +76,98 @@ or special value 0.0 indicating cases with no coverage whatsoever \ TYPE(mutable) \ TYPE(immutable) - struct tabrule - { - int start; - int step; - tabrule (int a_start, int a_step) - : start (a_start), step (a_step) - {} - bool operator < (tabrule const &other) const { - return start < other.start; - } - }; +struct tabrule +{ + int start; + int step; + tabrule (int a_start, int a_step) + : start (a_start), step (a_step) + {} + bool operator < (tabrule const &other) const { + return start < other.start; + } +}; - // Sharp 0.0% coverage (i.e. not a single address byte is covered) - const int cov_00 = -1; +// Sharp 0.0% coverage (i.e. not a single address byte is covered) +const int cov_00 = -1; - struct tabrules_t - : public std::vector +struct tabrules_t + : public std::vector +{ + tabrules_t (std::string const &rule) { - tabrules_t (std::string const &rule) - { - std::stringstream ss; - ss << rule; + std::stringstream ss; + ss << rule; - std::string item; - while (std::getline (ss, item, ',')) - { - if (item.empty ()) - continue; - int start; - int step; - char const *ptr = item.c_str (); - - if (item.length () >= 3 - && std::strncmp (ptr, "0.0", 3) == 0) - { - start = cov_00; - ptr += 3; - } - else - start = std::strtol (ptr, const_cast (&ptr), 10); + std::string item; + while (std::getline (ss, item, ',')) + { + if (item.empty ()) + continue; + int start; + int step; + char const *ptr = item.c_str (); - if (*ptr == 0) - step = 0; - else - { - if (*ptr != ':') - { - step = 0; - goto garbage; - } - else - ptr++; + if (item.length () >= 3 + && std::strncmp (ptr, "0.0", 3) == 0) + { + start = cov_00; + ptr += 3; + } + else + start = std::strtol (ptr, const_cast (&ptr), 10); - step = std::strtol (ptr, const_cast (&ptr), 10); - if (*ptr != 0) - garbage: - std::cerr << "Ignoring garbage at the end of the rule item: '" - << ptr << '\'' << std::endl; - } + if (*ptr == 0) + step = 0; + else + { + if (*ptr != ':') + { + step = 0; + goto garbage; + } + else + ptr++; + + step = std::strtol (ptr, const_cast (&ptr), 10); + if (*ptr != 0) + garbage: + std::cerr << "Ignoring garbage at the end of the rule item: '" + << ptr << '\'' << std::endl; + } - push_back (tabrule (start, step)); - } + push_back (tabrule (start, step)); + } - push_back (tabrule (100, 0)); - std::sort (begin (), end ()); - } + push_back (tabrule (100, 0)); + std::sort (begin (), end ()); + } - void next () - { - if (at (0).step == 0) - erase (begin ()); - else - { - if (at (0).start == cov_00) - at (0).start = 0; - at (0).start += at (0).step; - if (size () > 1) - { - if (at (0).start > at (1).start) - erase (begin ()); - while (size () > 1 - && at (0).start == at (1).start) - erase (begin ()); - } - } - } + void next () + { + if (at (0).step == 0) + erase (begin ()); + else + { + if (at (0).start == cov_00) + at (0).start = 0; + at (0).start += at (0).step; + if (size () > 1) + { + if (at (0).start > at (1).start) + erase (begin ()); + while (size () > 1 + && at (0).start == at (1).start) + erase (begin ()); + } + } + } - bool match (int value) const - { - return at (0).start == value; - } - }; + bool match (int value) const + { + return at (0).start == value; + } +}; #define TYPE(T) dt_##T, enum die_type_e @@ -192,134 +177,133 @@ or special value 0.0 indicating cases with no coverage whatsoever \ }; #undef TYPE - class die_type_matcher - : public std::bitset +class die_type_matcher + : public std::bitset +{ + class invalid {}; + std::pair + parse (std::string &desc) { - class invalid {}; - std::pair - parse (std::string &desc) - { - bool val = true; - if (desc == "") - throw invalid (); + bool val = true; + if (desc == "") + throw invalid (); #define TYPE(T) \ - if (desc == #T) \ - return std::make_pair (dt_##T, val); - DIE_TYPES + if (desc == #T) \ + return std::make_pair (dt_##T, val); + DIE_TYPES #undef TYPE throw invalid (); - } - - public: - die_type_matcher (std::string const &rule) - { - std::stringstream ss; - ss << rule; - - std::string item; - while (std::getline (ss, item, ',')) - try - { - std::pair const &ig = parse (item); - set (ig.first, ig.second); - } - catch (invalid &i) - { - std::cerr << "Invalid die type: " << item << std::endl; - } - } - }; + } - class mutability_t +public: + die_type_matcher (std::string const &rule) { - bool _m_is_mutable; - bool _m_is_immutable; - - public: - mutability_t () - : _m_is_mutable (false) - , _m_is_immutable (false) - { - } - - void set (bool what) - { - if (what) - _m_is_mutable = true; - else - _m_is_immutable = true; - } + std::stringstream ss; + ss << rule; - void set_both () - { - set (true); - set (false); - } + std::string item; + while (std::getline (ss, item, ',')) + try + { + std::pair const &ig = parse (item); + set (ig.first, ig.second); + } + catch (invalid &i) + { + std::cerr << "Invalid die type: " << item << std::endl; + } + } +}; - void locexpr (Dwarf_Op *expr, size_t len) - { - // We scan the expression looking for DW_OP_{bit_,}piece - // operators which mark ends of sub-expressions to us. - bool m = false; - for (size_t i = 0; i < len; ++i) - switch (expr[i].atom) - { - case DW_OP_implicit_value: - case DW_OP_stack_value: - m = true; - break; - - case DW_OP_bit_piece: - case DW_OP_piece: - set (m); - m = false; - break; - }; - set (m); - } +class mutability_t +{ + bool _m_is_mutable; + bool _m_is_immutable; - bool is_mutable () const { return _m_is_mutable; } - bool is_immutable () const { return _m_is_immutable; } - }; +public: + mutability_t () + : _m_is_mutable (false) + , _m_is_immutable (false) + { + } - struct error - : public std::runtime_error + void set (bool what) { - explicit error (std::string const &what_arg) - : std::runtime_error (what_arg) - {} - }; - - // Look through the stack of parental dies and return the non-empty - // ranges instance closest to the stack top (i.e. die_stack.end ()). - dwarf::ranges - find_ranges (std::vector const &die_stack) + if (what) + _m_is_mutable = true; + else + _m_is_immutable = true; + } + + void set_both () { - for (auto it = die_stack.rbegin (); it != die_stack.rend (); ++it) - if (!it->ranges ().empty ()) - return it->ranges (); - throw error ("no ranges for this DIE"); + set (true); + set (false); } - bool - is_inlined (dwarf::debug_info_entry const &die) + void locexpr (Dwarf_Op *expr, size_t len) { - dwarf::debug_info_entry::attributes_type::const_iterator it - = die.attributes ().find (DW_AT_inline); - if (it != die.attributes ().end ()) - { - char const *name = (*it).second.dwarf_constant ().name (); - return std::strcmp (name, "declared_inlined") == 0 - || std::strcmp (name, "inlined") == 0; - } - return false; + // We scan the expression looking for DW_OP_{bit_,}piece + // operators which mark ends of sub-expressions to us. + bool m = false; + for (size_t i = 0; i < len; ++i) + switch (expr[i].atom) + { + case DW_OP_implicit_value: + case DW_OP_stack_value: + m = true; + break; + + case DW_OP_bit_piece: + case DW_OP_piece: + set (m); + m = false; + break; + }; + set (m); } + + bool is_mutable () const { return _m_is_mutable; } + bool is_immutable () const { return _m_is_immutable; } +}; + +struct error + : public std::runtime_error +{ + explicit error (std::string const &what_arg) + : std::runtime_error (what_arg) + {} +}; + +// Look through the stack of parental dies and return the non-empty +// ranges instance closest to the stack top (i.e. die_stack.end ()). +dwarf::ranges +find_ranges (std::vector const &die_stack) +{ + for (auto it = die_stack.rbegin (); it != die_stack.rend (); ++it) + if (!it->ranges ().empty ()) + return it->ranges (); + throw error ("no ranges for this DIE"); +} + +bool +is_inlined (dwarf::debug_info_entry const &die) +{ + dwarf::debug_info_entry::attributes_type::const_iterator it + = die.attributes ().find (DW_AT_inline); + if (it != die.attributes ().end ()) + { + char const *name = (*it).second.dwarf_constant ().name (); + return std::strcmp (name, "declared_inlined") == 0 + || std::strcmp (name, "inlined") == 0; + } + return false; } -locstats::locstats (checkstack &stack, dwarflint &lint) - : highlevel_check (stack, lint) +void +process(Dwarf *c_dw, dwarf const &dw) { // map percentage->occurrences. Percentage is cov_00..100, where // 0..100 is rounded-down integer division. @@ -328,15 +312,14 @@ locstats::locstats (checkstack &stack, dwarflint &lint) for (int i = 0; i <= 100; ++i) tally[i] = 0; - tabrules_t tabrules (/*opt_tabulation_rule.seen () - ? opt_tabulation_rule.value () :*/ "10:10"); - die_type_matcher ignore (/*opt_ignore.seen () ? opt_ignore.value () :*/ ""); - die_type_matcher dump (/*opt_dump.seen () ? opt_dump.value () :*/ ""); + tabrules_t tabrules (opt_tabulation_rule.seen () + ? opt_tabulation_rule.value () : "10:10"); + die_type_matcher ignore (opt_ignore.seen () ? opt_ignore.value () : ""); + die_type_matcher dump (opt_dump.seen () ? opt_dump.value () : ""); std::bitset interested = ignore | dump; bool interested_mutability = interested.test (dt_mutable) || interested.test (dt_immutable); - for (all_dies_iterator it = all_dies_iterator (dw); it != all_dies_iterator (); ++it) { @@ -413,7 +396,7 @@ locstats::locstats (checkstack &stack, dwarflint &lint) // Unfortunately the location expression is not yet wrapped // in c++, so we need to revert back to C code. Dwarf_Die die_c_mem, - *die_c = dwarf_offdie (this->c_dw, die.offset (), &die_c_mem); + *die_c = dwarf_offdie (c_dw, die.offset (), &die_c_mem); assert (die_c != NULL); Dwarf_Attribute locattr_mem, @@ -533,7 +516,8 @@ locstats::locstats (checkstack &stack, dwarflint &lint) struct where where = WHERE (sec_info, NULL); where_reset_1 (&where, it.cu ().offset ()); where_reset_2 (&where, die.offset ()); - wr_error (where) << e.what () << '.' << std::endl; + std::cerr << "error: " << where << ": " + << e.what () << '.' << std::endl; continue; } } @@ -594,6 +578,12 @@ locstats::locstats (checkstack &stack, dwarflint &lint) unsigned long cumulative = 0; unsigned long last = 0; int last_pct = cov_00; + if (total == 0) + { + std::cout << "No coverage recorded." << std::endl; + return; + } + std::cout << "cov%\tsamples\tcumul" << std::endl; for (int i = cov_00; i <= 100; ++i) { @@ -625,3 +615,54 @@ locstats::locstats (checkstack &stack, dwarflint &lint) } } } + +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 ()); + int remaining; + argp.parse (argc, argv, 0, &remaining); + + 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); + } + + bool only_one = remaining + 1 == argc; + do + { + try + { + char const *fname = argv[remaining]; + if (!only_one) + std::cout << std::endl << fname << ":" << std::endl; + + int fd = files::open (fname); + Dwfl *dwfl = files::open_dwfl (); + Dwarf *c_dw = files::open_dwarf (dwfl, fname, fd); + dwarf dw = files::open_dwarf (c_dw); + + process (c_dw, dw); + + close (fd); + dwfl_end (dwfl); + } + catch (std::runtime_error &e) + { + std::cerr << "error: " + << e.what () << '.' << std::endl; + continue; + } + } + while (++remaining < argc); +} diff --git a/dwarflint/main.cc b/dwarflint/main.cc index f11849d80..e3ba7c6d4 100644 --- a/dwarflint/main.cc +++ b/dwarflint/main.cc @@ -1,5 +1,5 @@ /* Main entry point for dwarflint, a pedantic checker for DWARF files. - Copyright (C) 2008,2009,2010 Red Hat, Inc. + Copyright (C) 2008,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 @@ -152,7 +152,8 @@ main (int argc, char *argv[]) textdomain (PACKAGE_TARNAME); /* Parse and process arguments. */ - argppp &argp = argppp::inst (); + argppp argp (global_opts (), + dwarflint::main_registrar ()->get_descriptors ()); int remaining; argp.parse (argc, argv, 0, &remaining); diff --git a/dwarflint/option.cc b/dwarflint/option.cc index d87d22fde..9ddb191b5 100644 --- a/dwarflint/option.cc +++ b/dwarflint/option.cc @@ -35,6 +35,8 @@ #include #include +argppp *argppp::instance = NULL; + option_i * options::find_opt (int key) const { @@ -88,12 +90,16 @@ Pedantic checking of DWARF stored in ELF files.", return a; } -argppp & -argppp::inst () +argppp::argppp (options const &global) + : _m_inited (false) { - static argppp my - (global_opts (), dwarflint::main_registrar ()->get_descriptors ()); - return my; + argp main = global.build_argp (true); + main.parser = &parse_opt; + _m_argp = main; + + // Only one instance is allowed per program. + assert (instance == NULL); + instance = this; } argppp::argppp (options const &global, @@ -135,18 +141,23 @@ argppp::argppp (options const &global, main.parser = &parse_opt; _m_argp = main; + + // Only one instance is allowed per program. + assert (instance == NULL); + instance = this; } error_t argppp::parse_opt (int key, char *arg, argp_state *state) { - if (key == ARGP_KEY_INIT && !inst ()._m_inited) + assert (instance != NULL); + if (key == ARGP_KEY_INIT && !instance->_m_inited) { - inst ()._m_inited = true; + instance->_m_inited = true; unsigned i = 0; for (std::vector::const_iterator it - = inst ()._m_children_inputs.begin (); - it != inst ()._m_children_inputs.end (); ++it) + = instance->_m_children_inputs.begin (); + it != instance->_m_children_inputs.end (); ++it) state->child_inputs[i++] = const_cast (*it); return 0; } diff --git a/dwarflint/option.hh b/dwarflint/option.hh index 7afe10ca7..e4c1c735c 100644 --- a/dwarflint/option.hh +++ b/dwarflint/option.hh @@ -70,13 +70,15 @@ class argppp std::vector _m_children_inputs; argp _m_argp; bool _m_inited; - argppp (options const &global, - std::vector checkdescriptors); static error_t parse_opt (int key, char *arg, argp_state *state); + static argppp *instance; public: - static argppp &inst (); + argppp (options const &global); + argppp (options const &global, + std::vector checkdescriptors); + void parse (int argc, char **argv, unsigned flags, int *remaining); void help (FILE *stream, unsigned flags, char *name); };