]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Make locstats an independent tool
authorPetr Machata <pmachata@redhat.com>
Tue, 5 Apr 2011 18:00:42 +0000 (20:00 +0200)
committerPetr Machata <pmachata@redhat.com>
Tue, 5 Apr 2011 18:00:42 +0000 (20:00 +0200)
dwarflint/Makefile.am
dwarflint/dwarflint.cc
dwarflint/files.cc [new file with mode: 0644]
dwarflint/files.hh [new file with mode: 0644]
dwarflint/highlevel_check.cc
dwarflint/locstats.cc
dwarflint/main.cc
dwarflint/option.cc
dwarflint/option.hh

index d7def5dbff476a80f3fa664c91941a2f408135ca..6bc9113e2045128417120bc7cc8bf4dc744b7709 100644 (file)
@@ -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)
 
index d2c22b0de0abf282874855acb33f165853d91ad0..2f30415f0edcfb8c2cd875067ae316af173758ee 100644 (file)
@@ -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
    Network licensing program, please visit www.openinventionnetwork.com
    <http://www.openinventionnetwork.com>.  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include "dwarflint.hh"
 #include "messages.hh"
 #include "checks.hh"
 #include "check_registrar.hh"
+#include "files.hh"
 
 #include <fcntl.h>
 #include <cstring>
 #include <cerrno>
 #include <stdexcept>
-#include <sstream>
 
 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 (file)
index 0000000..2e0c30e
--- /dev/null
@@ -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
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "files.hh"
+#include "messages.hh"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sstream>
+#include <cstring>
+#include <cerrno>
+#include <stdexcept>
+
+namespace
+{
+  inline bool failed (void *ptr) { return ptr == NULL; }
+  inline bool failed (int i) { return i < 0; }
+
+  template <class T>
+  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 (file)
index 0000000..9ce0c9e
--- /dev/null
@@ -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
+   <http://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_ */
index 13f7d1dd5f1e5c19e585b6c71c8c2305ad06c853..9751174233b73ac39ab04c52732cac7108537eb3 100644 (file)
@@ -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
    <http://www.openinventionnetwork.com>.  */
 
 #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 <class T>
-  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<lowlevel_checks> (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 ()
index 7ef2423e5be3bec09e29fe97e776100125d1c991..614563eb4f480f550fb417c320b9cfbf0587c475 100644 (file)
    Network licensing program, please visit www.openinventionnetwork.com
    <http://www.openinventionnetwork.com>.  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include "highlevel_check.hh"
 #include "all-dies-it.hh"
 #include "option.hh"
-#include "messages.hh"
 #include "pri.hh"
+#include "files.hh"
+
+#include <libintl.h>
 
 #include <sstream>
 #include <bitset>
 
 using elfutils::dwarf;
 
-namespace
-{
-
-#define DIE_OPTSTRING                                  \
+#define DIE_OPTSTRING                          \
   "}[,...]"
 
-  string_option opt_ignore
+global_opt<string_option> 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<string_option> opt_dump
   ("Dump certain DIEs.  For classes, see option 'ignore'.",
-   "class[,...]", "locstats:dump");
+   "class[,...]", "dump");
 
-  string_option opt_tabulation_rule
+global_opt<string_option> 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<locstats>
-  {
-  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<locstats> 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<tabrule>
+struct tabrules_t
+  : public std::vector<tabrule>
+{
+  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<char **> (&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<char **> (&ptr), 10);
 
-             step = std::strtol (ptr, const_cast<char **> (&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<char **> (&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<dt__count>
+class die_type_matcher
+  : public std::bitset<dt__count>
+{
+  class invalid {};
+  std::pair<die_type_e, bool>
+  parse (std::string &desc)
   {
-    class invalid {};
-    std::pair<die_type_e, bool>
-    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<die_type_e, bool> 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<die_type_e, bool> 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<dwarf::debug_info_entry> 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<dwarf::debug_info_entry> 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<locstats> (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<dt__count> interested = ignore | dump;
   bool interested_mutability
     = interested.test (dt_mutable) || interested.test (dt_immutable);
 
-
   for (all_dies_iterator<dwarf> it = all_dies_iterator<dwarf> (dw);
        it != all_dies_iterator<dwarf> (); ++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);
+}
index f11849d80185e102c81b810b09f2e91e321ae6c1..e3ba7c6d43d4222a6f3a63bc706dfb7cad8f054b 100644 (file)
@@ -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);
index d87d22fde66a47c6acf68a736b6f50cdc02cabd0..9ddb191b515040cdb50f8ef0d6d3fd87b504880a 100644 (file)
@@ -35,6 +35,8 @@
 #include <cstring>
 #include <iostream>
 
+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<options const *>::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<options *> (*it);
       return 0;
     }
index 7afe10ca7c3371963343beba3bd2a62ec92e1935..e4c1c735c1ee7d4d6fa1ce2b4d78bae594874b63 100644 (file)
@@ -70,13 +70,15 @@ class argppp
   std::vector<options const *> _m_children_inputs;
   argp _m_argp;
   bool _m_inited;
-  argppp (options const &global,
-         std::vector<checkdescriptor const *> 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<checkdescriptor const *> checkdescriptors);
+
   void parse (int argc, char **argv, unsigned flags, int *remaining);
   void help (FILE *stream, unsigned flags, char *name);
 };