From: Petr Machata Date: Sun, 29 Nov 2009 21:24:33 +0000 (+0100) Subject: dwarflint: Load high-level DWARF context through libdwfl X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f9ca15b4833887e0d9f95c4169425d388939992c;p=thirdparty%2Felfutils.git dwarflint: Load high-level DWARF context through libdwfl --- diff --git a/src/dwarflint/check_highlevel.cc b/src/dwarflint/check_highlevel.cc index 68309d477..d7b256d1b 100644 --- a/src/dwarflint/check_highlevel.cc +++ b/src/dwarflint/check_highlevel.cc @@ -27,21 +27,118 @@ // 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 + 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); } diff --git a/src/dwarflint/checks-high.hh b/src/dwarflint/checks-high.hh index 5361e5e8a..1d5582506 100644 --- a/src/dwarflint/checks-high.hh +++ b/src/dwarflint/checks-high.hh @@ -33,36 +33,34 @@ #include "checks-low.hh" #include "config.h" #include "c++/dwarf" +#include "../libdwfl/libdwfl.h" -struct dwarf_handle_loader +class open_highlevel_dwarf + : public check { - 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 highlevel_check : public check > - , 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 or - // 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 diff --git a/src/dwarflint/dwarflint.cc b/src/dwarflint/dwarflint.cc index 27f51f181..50a2fa528 100644 --- a/src/dwarflint/dwarflint.cc +++ b/src/dwarflint/dwarflint.cc @@ -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 + . */ + #include "dwarflint.hh" +#include "messages.h" +#include +#include +#include +#include +#include + +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; +} diff --git a/src/dwarflint/dwarflint.hh b/src/dwarflint/dwarflint.hh index 6d256a7e8..20944f641 100644 --- a/src/dwarflint/dwarflint.hh +++ b/src/dwarflint/dwarflint.hh @@ -10,6 +10,7 @@ class dwarflint { typedef std::map check_map; check_map _m_checks; + char const *_m_fname; int _m_fd; public: @@ -43,8 +44,10 @@ public: std::vector _m_items; }; - explicit dwarflint (int fd); + explicit dwarflint (char const *fname); + ~dwarflint (); int fd () { return _m_fd; } + char const *fname () { return _m_fname; } template T *check (); diff --git a/src/dwarflint/main.cc b/src/dwarflint/main.cc index f544635a9..9801d2929 100644 --- a/src/dwarflint/main.cc +++ b/src/dwarflint/main.cc @@ -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 #include #include -#include -#include #include @@ -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);