// 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);
}
#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>
+/* 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;
+}
{
typedef std::map <void const *, class check_base *> check_map;
check_map _m_checks;
+ char const *_m_fname;
int _m_fd;
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 ();
-/* 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.
#include <libintl.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <fcntl.h>
-#include <error.h>
#include <iostream>
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);