/* Pedantic checking of DWARF files Copyright (C) 2011 Red Hat, Inc. This file is part of elfutils. This file 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; either version 3 of the License, or (at your option) any later version. 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 this program. If not, see . */ #include "messages.hh" #include "highlevel_check.hh" #include "check_die_tree.hh" using namespace elfutils; namespace { class die_check_registrar : public check_registrar_T { public: friend class dwarflint; void run (checkstack &stack, dwarflint &lint); static die_check_registrar * inst () { static die_check_registrar inst; return &inst; } }; } void check_die_tree::register_check (die_check_item *check) { die_check_registrar::inst ()->push_back (check); } class die_check_context : protected std::vector { typedef std::vector _super_t; checkdescriptor const *_m_cd; public: die_check_context (highlevel_check_i *check, checkdescriptor const *cd, dwarflint &lint, die_check_registrar const ®istrar) : _m_cd (cd) { // For per-DIE runs, we are only interested in limited context: // the main iteration check, and the per-DIE check. This should // be enough to decide whether to run the per-DIE check or not. // We cannot use the original stack as a criterion, because the // original check that tricked us into running is here, and the // logic in should_check would then assume that we need to run // everything. checkstack stack; stack.push_back (cd); for (die_check_registrar::const_iterator it = registrar.begin (); it != registrar.end (); ++it) { stack.push_back ((*it)->descriptor ()); popper p (stack); if (lint.rules ().should_check (stack)) push_back ((*it)->create (check, stack, lint)); } } void error (all_dies_iterator const &a_d_it, char const *reason = NULL) { std::string r; if (reason) { r += ": "; r += reason; } wr_error (die_locus (*a_d_it)) << "A check failed: " << (_m_cd->name () ?: "(nil)") << r << std::endl; } void die (all_dies_iterator const &a_d_it) { for (iterator it = begin (); it != end (); ++it) again: try { (*it)->die (a_d_it); } catch (check_base::unscheduled &e) { // Turn the check off. size_t pos = it - begin (); delete *it; erase (it); it = begin () + pos; if (it == end ()) break; goto again; } catch (check_base::failed &e) { // The check was supposed to emit an error message. } catch (std::exception &e) { error (a_d_it, e.what ()); } catch (...) { error (a_d_it); } } ~die_check_context () { for (iterator it = begin (); it != end (); ++it) delete *it; } }; check_die_tree::check_die_tree (checkstack &stack, dwarflint &lint) : highlevel_check (stack, lint) { die_check_context ctx (this, descriptor (), lint, *die_check_registrar::inst ()); for (all_dies_iterator it = all_dies_iterator (dw); it != all_dies_iterator (); ++it) ctx.die (it); }