/* Copyright (C) 2009,2010,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 . */ #ifdef HAVE_CONFIG_H # include #endif #include "../libdw/c++/dwarf-knowledge.cc" #include "../libdw/c++/dwarf" #include "check_debug_info.hh" #include "highlevel_check.hh" #include "expected.hh" #include "messages.hh" using elfutils::dwarf; namespace { class check_expected_trees : public highlevel_check { public: static checkdescriptor const *descriptor () { static checkdescriptor cd (checkdescriptor::create ("check_expected_trees") .description ( "Checks whether all DIEs have the right attributes and the right children.\n" "Currently this is very much a work in progress.\n")); return &cd; } check_expected_trees (checkstack &stack, dwarflint &lint); }; reg reg_check_expected_trees; const expected_at_map expected_at; //static const expected_children_map expected_children; struct name_extractor { int operator () (dwarf::attribute const &at) { return at.first; } } extract_name; std::ostream & operator << (std::ostream &o, dwarf::value_space vs) { switch (vs) { case dwarf::VS_flag: return o << "flag"; case dwarf::VS_dwarf_constant: return o << "dwarf_constant"; case dwarf::VS_discr_list: return o << "discr_list"; case dwarf::VS_reference: return o << "reference"; case dwarf::VS_lineptr: return o << "lineptr"; case dwarf::VS_macptr: return o << "macptr"; case dwarf::VS_rangelistptr: return o << "rangelistptr"; case dwarf::VS_identifier: return o << "identifier"; case dwarf::VS_string: return o << "string"; case dwarf::VS_source_file: return o << "source_file"; case dwarf::VS_source_line: return o << "source_line"; case dwarf::VS_source_column: return o << "source_column"; case dwarf::VS_address: return o << "address"; case dwarf::VS_constant: return o << "constant"; case dwarf::VS_location: return o << "location"; }; abort (); } } check_expected_trees::check_expected_trees (checkstack &stack, dwarflint &lint) : highlevel_check (stack, lint) { lint.check (stack); try { struct { void operator () (dwarf::compile_unit const &cu, dwarf::debug_info_entry const &parent) { die_locus where (parent); int parent_tag = parent.tag (); // Set of attributes of this DIE. std::set attributes; std::transform (parent.attributes ().begin (), parent.attributes ().end (), std::inserter (attributes, attributes.end ()), extract_name); // Attributes that we expect at this DIE. expected_set::expectation_map const &expect = expected_at.map (parent_tag); // Check missing attributes. for (expected_set::expectation_map::const_iterator jt = expect.begin (); jt != expect.end (); ++jt) { std::set ::iterator kt = attributes.find (jt->first); char const *what = NULL; if (kt == attributes.end ()) switch (jt->second) { case opt_required: what = " lacks required attribute "; // FALL_THROUGH case opt_expected: if (what == NULL) what = " should contain attribute "; wr_message (where, mc_impact_2 | mc_info) << elfutils::dwarf::tags::name (parent_tag) << what << elfutils::dwarf::attributes::name (jt->first) << '.' << std::endl; break; case opt_optional: break; }; } // Check present attributes for expected-ness, and validate // value space. for (dwarf::debug_info_entry::attributes_type::const_iterator jt = parent.attributes ().begin (), jte = parent.attributes ().end (); jt != jte; ++jt) { unsigned name = extract_name (*jt); expected_set::expectation_map::const_iterator kt = expect.find (name); if (kt == expect.end ()) wr_message (where, mc_impact_3 | mc_info) << ": DIE \"" << dwarf::tags::name (parent_tag) << "\" has attribute \"" << dwarf::attributes::name (name) << "\", which is not expected." << std::endl; try { unsigned exp_vs = expected_value_space (name, parent_tag); dwarf::value_space vs = (*jt).second.what_space (); if ((exp_vs & (1U << vs)) == 0) wr_message (where, mc_impact_3 | mc_info) << ": in DIE \"" << dwarf::tags::name (parent_tag) << "\", attribute \"" << dwarf::attributes::name (name) << "\" has value of unexpected type \"" << vs << "\"." << std::endl; } // XXX more specific class when has it catch (...) { wr_message (where, mc_impact_4 | mc_info | mc_error) << ": in DIE \"" << dwarf::tags::name (parent_tag) << "\", couldn't obtain type of attribute \"" << dwarf::attributes::name (name) << "\"." << std::endl; } } // Check children recursively. dwarf::debug_info_entry::children_type const &children = parent.children (); for (dwarf::debug_info_entry::children_type::const_iterator jt = children.begin (); jt != children.end (); ++jt) (*this) (cu, *jt); } } recursively_validate; class dwarf::compile_units_type const &cus = dw.compile_units (); for (dwarf::compile_units_type::const_iterator it = cus.begin (); it != cus.end (); ++it) recursively_validate (*it, *it); } // XXX more specific class when has it catch (std::runtime_error &exc) { wr_error (section_locus (sec_info)) << "Exception while checking expected trees: " << exc.what () << std::endl; throw check_base::failed (); } }