/* Pseudo-XMLish printing for elfutils::dwarf* tests. Copyright (C) 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 . */ #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);