/* Pseudo-XMLish printing for elfutils::dwarf* tests. Copyright (C) 2009 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 #include #include #include #include #include #include #include #include #include #include "c++/dwarf_edit" #include "c++/dwarf_output" using namespace elfutils; using namespace std; static bool print_offset; static bool sort_attrs; static bool elide_refs; static bool dump_refs; static bool no_print; static bool output_stats; static bool refs_shared_cu; static bool refs_shared_file; static enum { copy_none, copy_edit, copy_output } make_copy; void print_die_main (int &argc, char **&argv, unsigned int &depth) { /* Set locale. */ (void) setlocale (LC_ALL, ""); /* Make sure the message catalog can be found. */ (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); /* Initialize the message catalog. */ (void) textdomain (PACKAGE_TARNAME); cout << hex << setiosflags (ios::showbase); if (argc > 1 && !strcmp (argv[1], "--offsets")) { print_offset = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--norefs")) { elide_refs = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--dump-refs")) { dump_refs = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--refs-shared-cu")) { refs_shared_cu = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--refs-shared-file")) { refs_shared_file = refs_shared_cu = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--sort-attrs")) { sort_attrs = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--edit")) { make_copy = copy_edit; --argc; ++argv; } else if (argc > 1 && !strcmp (argv[1], "--output")) { make_copy = copy_output; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--stats")) { output_stats = true; --argc; ++argv; } if (argc > 1 && !strcmp (argv[1], "--silent")) { no_print = true; --argc; ++argv; } depth = 0; if (argc > 1 && sscanf (argv[1], "--depth=%u", &depth) == 1) { --argc; ++argv; } } static int next_ref = 1; typedef tr1::unordered_map refs_map; template class attr_walker { private: refs_map &refs; inline attr_walker (refs_map &r) : refs (r) {} typedef typename attrs_type::const_iterator iterator; typedef typename iterator::value_type attr_type; public: inline void operator () (const pair &p) const { (*act) (*p.second, refs); } static inline void walk (const attrs_type &attrs, refs_map &r) { if (attrs_type::ordered () || !sort_attrs) for (iterator i = attrs.begin (); i != attrs.end (); ++i) (*act) (*i, r); else { map sorted; for (iterator i = attrs.begin (); i != attrs.end (); ++i) sorted[(*i).first] = i; for_each (sorted.begin (), sorted.end (), attr_walker (r)); } } }; template void print_attr (const typename attrs_type::value_type &attr, refs_map &refs) { if (!print_offset && attr.second.what_space () == dwarf::VS_reference) { if (elide_refs) cout << " " << dwarf::attributes::name (attr.first) << "=\"ref\""; else cout << " " << dwarf::attributes::name (attr.first) << "=\"#ref" << dec << refs[attr.second.reference ()->identity ()] << "\""; } else cout << " " << to_string (attr); } template static void print_attrs (const attrs_type &attrs, refs_map &refs) { attr_walker >::walk (attrs, refs); } template void prewalk_attr (const typename attrs_type::value_type &attr, refs_map &refs) { if (attr.second.what_space () == dwarf::VS_reference && refs.insert (make_pair (attr.second.reference ()->identity (), next_ref)).second) ++next_ref; } template static void prewalk_attrs (const attrs_type &attrs, refs_map &refs) { attr_walker >::walk (attrs, refs); } template static void prewalk_die (const typename file::debug_info_entry &die, refs_map &refs) { for (typename file::debug_info_entry::children_type::const_iterator i = die.children ().begin (); i != die.children ().end (); ++i) prewalk_die (*i, refs); prewalk_attrs (die.attributes (), refs); } static int nth; static std::map nth_ref; template static void print_die (const typename file::debug_info_entry &die, unsigned int indent, unsigned int limit, refs_map &refs) { string prefix (indent, ' '); const string tag = dwarf::tags::name (die.tag ()); ++nth; if (dump_refs) cout << dec << nth << ": "; cout << prefix << "<" << tag; if (print_offset) cout << " offset=[" << hex << die.offset () << "]"; else if (!elide_refs) { refs_map::const_iterator it = refs.find (die.identity ()); if (it != refs.end ()) { cout << " ref=\"ref" << dec << it->second << "\""; nth_ref[nth] = it->second; } } print_attrs (die.attributes (), refs); if (die.has_children ()) { if (limit != 0 && indent >= limit) { cout << ">...\n"; return; } cout << ">\n"; for (typename file::debug_info_entry::children_type::const_iterator i = die.children ().begin (); i != die.children ().end (); ++i) print_die (*i, indent + 1, limit, refs); cout << prefix << "\n"; } else cout << "/>\n"; } static inline void dump_nth (pair p) { cout << dec << p.first << ": ref" << p.second << "\n"; } template static void print_cu (const typename file::compile_unit &cu, const unsigned int limit, refs_map &refs) { const typename file::debug_info_entry &die = static_cast (cu); if (!print_offset && !elide_refs) prewalk_die (die, refs); print_die (die, 1, limit, refs); } template static void print_file (const file &dw, const unsigned int limit) { if (no_print) return; static refs_map common_refs; refs_map file_refs; for (typename file::compile_units_type::const_iterator i = dw.compile_units ().begin (); i != dw.compile_units ().end (); ++i) if (refs_shared_cu) print_cu (*i, limit, refs_shared_file ? common_refs : file_refs); else { refs_map refs; print_cu (*i, limit, refs); } if (dump_refs) for_each (nth_ref.begin (), nth_ref.end (), dump_nth); } template void print_file (const char *name, const file &dw, const unsigned int limit) { cout << name << ":\n"; switch (make_copy) { case copy_none: print_file (dw, limit); break; case copy_edit: print_file (dwarf_edit (dw), limit); break; case copy_output: { dwarf_output_collector c; // We'll just throw it away. dwarf_output out (dw, c); if (output_stats) c.stats (); print_file (out, limit); } break; default: abort (); } } // Explicit instantiations. template void print_file (const char *, const dwarf &, const unsigned int); template void print_file (const char *, const dwarf_edit &, const unsigned int); template void print_file (const char *, const dwarf_output &, const unsigned int);