struct walk
{
dwarf_path_finder *_m_tracker;
+ bool _m_jumped;
+
inline walk (dwarf_path_finder *w, const cu &root)
- : _m_tracker (w)
+ : _m_tracker (w), _m_jumped (false)
{
assert (_m_tracker->_m_path.empty ());
_m_tracker->_m_root = root;
}
+
inline ~walk ()
{
- assert (_m_tracker->_m_path.empty ());
+ if (_m_jumped)
+ _m_tracker->_m_path.clear ();
+ else
+ assert (_m_tracker->_m_path.empty ());
_m_tracker->_m_root = cu ();
}
+
+ inline void jump (const typename dw::debug_info_entry &there)
+ {
+ _m_jumped = true;
+ _m_tracker->prime_path_to (there);
+ }
};
/* A step object does pre-order work when constructed and post-order
}
};
+ void prime_path_to (const typename dw::debug_info_entry &here,
+ dwarf::debug_info_entry::identity_type id)
+ {
+ for (typename dw::debug_info_entry::children_type::const_iterator i
+ = here.children ().begin ();
+ i != here.children ().end ();
+ ++i)
+ {
+ step into (this, i);
+ if ((*i).identity () == id)
+ break;
+ prime_path_to (*i, id);
+ }
+ }
+
+ inline void prime_path_to (const typename dw::debug_info_entry &there)
+ {
+ assert (_m_path.empty ());
+ prime_path_to (*_m_root, there.identity ());
+ assert (_m_path.empty ());
+ _m_path = (*_m_seen)[there.identity ()];
+ }
+
// Random access to a DIE, find the path of the walk that gets there.
inline const die_path &path_to (const die &a)
{
- const dwarf::debug_info_entry::identity_type id = (*a).identity ();
+ return path_to (*a);
+ }
+
+ inline const die_path &path_to (const typename dw::debug_info_entry &a)
+ {
+ const dwarf::debug_info_entry::identity_type id = a.identity ();
std::pair<typename die_map::iterator, bool> found
= _m_seen->insert (std::make_pair (id, bad_die_path ()));
if (found.second
inline walk (dwarf_ref_tracker *w, const cu1 &a, const cu2 &b)
: _m_left (&w->_m_left, a), _m_right (&w->_m_right, b)
{}
+
+ // Wind forward to cache everything up through A and B.
+ inline void jump (const typename dwarf1::debug_info_entry &a,
+ const typename dwarf2::debug_info_entry &b)
+ {
+ _m_left.jump (a);
+ _m_right.jump (b);
+ }
};
struct step
#include <string.h>
#include <unistd.h>
-#include <cstdint>
+#include <cinttypes>
#include "../libdw/libdwP.h" // XXX
#include "c++/dwarf"
/* Short description of program. */
static const char doc[] = N_("\
-Compare two DWARF files for semantic equality.");
+Compare two DWARF files for semantic equality.\n\
+In the second form, compare only the given pair of entries.");
/* Strings for arguments in help texts. */
-static const char args_doc[] = N_("FILE1 FILE2");
+static const char args_doc[] = N_("FILE1 FILE2\n\
+FILE1 FILE2 OFFSET1 OFFSET2");
/* Prototype for option handler. */
static error_t parse_opt (int key, char *arg, struct argp_state *state);
if (!visiting_result_)
location () << dwarf::tags::name (a.tag ())
<< " vs "
- << dwarf::tags::name (b.tag ());
+ << dwarf::tags::name (b.tag ())
+ << endl;
}
inline bool keep_going ()
}
};
+template<class dw>
+static inline typename dw::compile_units::const_iterator
+find_cu (const dw &file, const typename dw::debug_info_entry &entry)
+{
+ dwarf::debug_info_entry::identity_type id = entry.compile_unit ().identity ();
+
+ for (typename dw::compile_units::const_iterator cu
+ = file.compile_units ().begin ();
+ cu != file.compile_units ().end ();
+ ++cu)
+ {
+ if ((*cu).identity () == id)
+ return cu;
+ }
+
+ throw std::logic_error ("cannot find compile_unit for debug_info_entry!");
+}
+
template<class dwarf1, class dwarf2, class tracker>
struct cmp
: public dwarf_comparator<dwarf1, dwarf2, false, tracker>
template<class dwarf1, class dwarf2>
struct quiet_cmp
: public cmp<dwarf1, dwarf2, dwarf_ref_tracker<dwarf1, dwarf2> >
-{};
+{
+ typedef dwarf_ref_tracker<dwarf1, dwarf2> my_tracker;
+
+ inline bool operator () (const dwarf1 &a, const dwarf2 &b)
+ {
+ return equals (a, b);
+ }
+
+ inline bool operator () (const dwarf1 &file1, const dwarf2 &file2,
+ const typename dwarf1::debug_info_entry &a,
+ const typename dwarf2::debug_info_entry &b)
+ {
+ typename my_tracker::walk in (&this->_m_tracker,
+ find_cu (file1, a), find_cu (file2, b));
+ in.jump (a, b);
+ return equals (a, b);
+ }
+};
template<class dwarf1, class dwarf2>
static inline bool
return quiet_cmp<dwarf1, dwarf2> () (a, b);
}
+template<class dwarf1, class dwarf2>
+static inline bool
+quiet_compare (const dwarf1 &file1, const dwarf2 &file2,
+ const typename dwarf1::debug_info_entry &a,
+ const typename dwarf2::debug_info_entry &b)
+
+{
+ return quiet_cmp<dwarf1, dwarf2> () (file1, file2, a, b);
+}
+
// To be noisy, the talker wraps the standard tracker with verbosity hooks.
template<class dwarf1, class dwarf2, bool print_all>
struct noisy_cmp
: public cmp<dwarf1, dwarf2, talker<dwarf1, dwarf2, print_all> >
{
- inline bool operator () (const dwarf1 &a, const dwarf2 &b)
+ typedef talker<dwarf1, dwarf2, print_all> my_tracker;
+
+ template<typename item1, typename item2>
+ inline bool compare (const item1 &a, const item2 &b)
{
if (equals (a, b) && this->_m_tracker.result_)
{
this->_m_tracker.print_bad_context ();
return false;
}
+
+ inline bool operator () (const dwarf1 &a, const dwarf2 &b)
+ {
+ return compare (a, b);
+ }
+
+ inline bool operator () (const dwarf1 &file1, const dwarf2 &file2,
+ const typename dwarf1::debug_info_entry &a,
+ const typename dwarf2::debug_info_entry &b)
+ {
+ typename my_tracker::walk in (&this->_m_tracker,
+ find_cu (file1, a), find_cu (file2, b));
+ in.jump (a, b);
+ return compare (a, b);
+ }
};
template<class dwarf1, class dwarf2>
: noisy_cmp<dwarf1, dwarf2, false> () (a, b));
}
+template<class dwarf1, class dwarf2>
+static inline bool
+noisy_compare (const dwarf1 &file1, const dwarf2 &file2,
+ const typename dwarf1::debug_info_entry &a,
+ const typename dwarf2::debug_info_entry &b,
+ bool print_all)
+{
+ return (print_all
+ ? noisy_cmp<dwarf1, dwarf2, true> () (file1, file2, a, b)
+ : noisy_cmp<dwarf1, dwarf2, false> () (file1, file2, a, b));
+}
+
#ifdef TEST
#endif // TEST
+static inline const dwarf::debug_info_entry
+parse_offset (const char *name, dwarf &file, const char *arg)
+{
+ char *end = NULL;
+ Dwarf_Off offset = strtoull (arg, &end, 16);
+ if (end == NULL || *end != '\0')
+ {
+ fputs (gettext ("Invalid offset parameter (use hex).\n"),
+ stderr);
+ argp_help (&argp, stderr, ARGP_HELP_SEE,
+ program_invocation_short_name);
+ exit (1);
+ }
+ try
+ {
+ return dwarf::debug_info_entry (file, offset);
+ }
+ catch (std::runtime_error x)
+ {
+ fprintf (stderr, gettext ("%s: offset %#" PRIx64 ": %s\n"),
+ name, offset, x.what ());
+ exit (1);
+ }
+}
+
int
main (int argc, char *argv[])
{
(void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
/* We expect exactly two non-option parameters. */
- if (unlikely (remaining + 2 != argc))
+ if (unlikely (remaining + 2 != argc)
+ && unlikely (remaining + 4 != argc))
{
fputs (gettext ("Invalid number of parameters.\n"), stderr);
argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
exit (1);
}
- const char *const fname1 = argv[remaining];
+ const char *const fname1 = argv[remaining++];
int fd1;
Dwarf *dw1 = open_file (fname1, &fd1);
- const char *const fname2 = argv[remaining + 1];
+ const char *const fname2 = argv[remaining++];
int fd2;
Dwarf *dw2 = open_file (fname2, &fd2);
dwarf file1 (dw1);
dwarf file2 (dw2);
- bool same = (quiet
- ? quiet_compare (file1, file2)
- : noisy_compare (file1, file2, verbose));
+ if (remaining < argc)
+ {
+ const dwarf::debug_info_entry a = parse_offset (fname1, file1,
+ argv[remaining++]);
+ const dwarf::debug_info_entry b = parse_offset (fname2, file2,
+ argv[remaining++]);
+
+ bool same = (quiet
+ ? quiet_compare (file1, file2, a, b)
+ : noisy_compare (file1, file2, a, b, verbose));
+
+ result = !same;
+ }
+ else
+ {
+ bool same = (quiet
+ ? quiet_compare (file1, file2)
+ : noisy_compare (file1, file2, verbose));
- do_writer_test (file1, file2, same);
+ do_writer_test (file1, file2, same);
- result = !same;
+ result = !same;
+ }
}
dwarf_end (dw1);