]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Load high-level DWARF context through libdwfl
authorPetr Machata <pmachata@redhat.com>
Sun, 29 Nov 2009 21:24:33 +0000 (22:24 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:14 +0000 (14:55 +0200)
src/dwarflint/check_highlevel.cc
src/dwarflint/checks-high.hh
src/dwarflint/dwarflint.cc
src/dwarflint/dwarflint.hh
src/dwarflint/main.cc

index 68309d477a944685ef8e13b8db9c8b2592be386f..d7b256d1b746c21cde7e13d8de29681888498626 100644 (file)
   // failure.  We need to catch it and convert to check_base::failed.
 
 #include "checks-high.hh" // xxx rename
-#include "../libdwfl/libdwfl.h"
 
-Dwarf *
-dwarf_handle_loader::get_dwarf_handle (int fd)
+namespace
 {
-  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
-  /*
-    static const Dwfl_Callbacks callbacks =
+  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
     {
-    .section_address = dwfl_offline_section_address,
-    .find_debuginfo = find_no_debuginfo
-    };
-    Dwfl *dwfl = dwfl_begin (&callbacks);
-    if (unlikely (dwfl == NULL))
-      throw check_base::failed ();
-    */
-  return dwarf_begin_elf (elf, DWARF_C_READ, NULL);
+      // 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 ();
+      }
+  }
+}
+
+open_highlevel_dwarf::open_highlevel_dwarf (dwarflint &lint)
+  : _m_dwfl (open_dwfl ())
+  , _m_dw (open_dwarf (_m_dwfl, lint.fname (), lint.fd ()))
+  , dw (open_hl_dwarf (_m_dw))
+{
+}
+
+open_highlevel_dwarf::~open_highlevel_dwarf ()
+{
+  dwarf_end (_m_dw);
+  dwfl_end (_m_dwfl);
 }
index 5361e5e8a569ad3a84dc5afc99776acb1eb5c639..1d5582506119ec249c7305e95946ad58a19d6775 100644 (file)
 #include "checks-low.hh"
 #include "config.h"
 #include "c++/dwarf"
+#include "../libdwfl/libdwfl.h"
 
-struct dwarf_handle_loader
+class open_highlevel_dwarf
+  : public check<open_highlevel_dwarf>
 {
-  Dwarf *get_dwarf_handle (int fd);
+  Dwfl *const _m_dwfl;
+  Dwarf *const _m_dw;
+public:
+  elfutils::dwarf const dw;
+  explicit open_highlevel_dwarf (dwarflint &lint);
+  ~open_highlevel_dwarf ();
 };
 
 template<class T>
 class highlevel_check
   : public check<highlevel_check<T> >
-  , private dwarf_handle_loader
 {
-  ::Dwarf *_m_handle;
-
+  open_highlevel_dwarf *_m_loader;
 public:
-  elfutils::dwarf dw;
+  elfutils::dwarf const &dw;
 
-  // xxx this will throw an exception on <c++/dwarf> or <libdw.h>
-  // failure.  We need to catch it and convert to check_base::failed.
   explicit highlevel_check (dwarflint &lint)
-    : _m_handle (get_dwarf_handle (lint.fd ()))
-    , dw (_m_handle)
+    : _m_loader (lint.check (_m_loader))
+    , dw (_m_loader->dw)
   {
     if (!do_high_level)
       throw check_base::unscheduled ();
   }
-
-  ~highlevel_check ()
-  {
-    dwarf_end (_m_handle);
-  }
 };
 
 template <class T>
index 27f51f18151294862213b20cd9b827e334a50200..50a2fa528b587cd28a0c2109557e5b2044007f56 100644 (file)
@@ -1,7 +1,65 @@
+/* Dwarflint check scheduler.
+   Copyright (C) 2008,2009 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 "dwarflint.hh"
+#include "messages.h"
+#include <fcntl.h>
+#include <cstring>
+#include <cerrno>
+#include <stdexcept>
+#include <sstream>
+
+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;
+  }
+}
 
-dwarflint::dwarflint (int a_fd)
-  : _m_fd (a_fd)
+dwarflint::dwarflint (char const *a_fname)
+  : _m_fname (a_fname)
+  , _m_fd (get_fd (_m_fname))
 {
   check_registrar::inst ()->enroll (*this);
 }
+
+dwarflint::~dwarflint ()
+{
+  if (close (_m_fd) < 0)
+    // Not that we can do anything about it...
+    wr_error () << "Couldn't close the file " << _m_fname << ": "
+               << strerror (errno) << "." << std::endl;
+}
index 6d256a7e8473fa1c59ac64ad2c2bcd9ecaff7462..20944f64123a5fd0fec12d3e59fc434d6af05c40 100644 (file)
@@ -10,6 +10,7 @@ class dwarflint
 {
   typedef std::map <void const *, class check_base *> check_map;
   check_map _m_checks;
+  char const *_m_fname;
   int _m_fd;
 
 public:
@@ -43,8 +44,10 @@ public:
     std::vector <item *> _m_items;
   };
 
-  explicit dwarflint (int fd);
+  explicit dwarflint (char const *fname);
+  ~dwarflint ();
   int fd () { return _m_fd; }
+  char const *fname () { return _m_fname; }
 
   template <class T> T *check ();
 
index f544635a944a057f29d1fc8e299ff3b621a4d414..9801d2929c966608248cad33cd2d2d74162e4f29 100644 (file)
@@ -1,4 +1,4 @@
-/* Pedantic checking of DWARF files.  Low-level checks.
+/* Main entry point for dwarflint, a pedantic checker for DWARF files.
    Copyright (C) 2008,2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
@@ -30,8 +30,6 @@
 #include <libintl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <fcntl.h>
-#include <error.h>
 
 #include <iostream>
 
@@ -209,24 +207,23 @@ main (int argc, char *argv[])
   bool only_one = remaining + 1 == argc;
   do
     {
-      /* Open the file.  */
-      int fd = open (argv[remaining], O_RDONLY);
-      if (fd == -1)
+      try
        {
-         error (0, errno, gettext ("cannot open input file"));
+         char const *fname = argv[remaining];
+         /* Create an `Elf' descriptor.  */
+         unsigned int prev_error_count = error_count;
+         if (!only_one)
+           std::cout << std::endl << fname << ":" << std::endl;
+         dwarflint lint (fname);
+
+         if (prev_error_count == error_count && !be_quiet)
+           puts (gettext ("No errors"));
+       }
+      catch (std::runtime_error &e)
+       {
+         wr_error () << e.what () << std::endl;
          continue;
        }
-
-      /* Create an `Elf' descriptor.  */
-      unsigned int prev_error_count = error_count;
-      if (!only_one)
-       std::cout << std::endl << argv[remaining] << ":" << std::endl;
-      dwarflint lint (fd);
-
-      if (prev_error_count == error_count && !be_quiet)
-       puts (gettext ("No errors"));
-
-      close (fd);
     }
   while (++remaining < argc);