blob: 11fe9fd4c4917e20b91adbe64242b4ea3ea04f1c [file] [log] [blame]
/* 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 <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <clocale>
#include <libintl.h>
#include <ostream>
#include <iomanip>
#include <tr1/unordered_map>
#include <functional>
#include <algorithm>
#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<dwarf::debug_info_entry::identity_type,
int> refs_map;
template<typename attrs_type,
void (*act) (const typename attrs_type::value_type &, refs_map &)
>
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<int, iterator> &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<int, iterator> sorted;
for (iterator i = attrs.begin (); i != attrs.end (); ++i)
sorted[(*i).first] = i;
for_each (sorted.begin (), sorted.end (),
attr_walker<attrs_type, act> (r));
}
}
};
template<typename attrs_type>
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<typename attrs_type>
static void
print_attrs (const attrs_type &attrs, refs_map &refs)
{
attr_walker<attrs_type, print_attr<attrs_type> >::walk (attrs, refs);
}
template<typename attrs_type>
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<typename attrs_type>
static void
prewalk_attrs (const attrs_type &attrs, refs_map &refs)
{
attr_walker<attrs_type, prewalk_attr<attrs_type> >::walk (attrs, refs);
}
template<typename file>
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<file> (*i, refs);
prewalk_attrs (die.attributes (), refs);
}
static int nth;
static std::map<int, int> nth_ref;
template<typename file>
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<file> (*i, indent + 1, limit, refs);
cout << prefix << "</" << tag << ">\n";
}
else
cout << "/>\n";
}
static inline void
dump_nth (pair<int, int> p)
{
cout << dec << p.first << ": ref" << p.second << "\n";
}
template<typename file>
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<const typename file::debug_info_entry &> (cu);
if (!print_offset && !elide_refs)
prewalk_die<file> (die, refs);
print_die<file> (die, 1, limit, refs);
}
template<typename file>
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<file> (*i, limit, refs_shared_file ? common_refs : file_refs);
else
{
refs_map refs;
print_cu<file> (*i, limit, refs);
}
if (dump_refs)
for_each (nth_ref.begin (), nth_ref.end (), dump_nth);
}
template<typename file>
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);