From: Roland McGrath Date: Wed, 30 Sep 2009 23:33:11 +0000 (-0700) Subject: dwarfcmp: Support four-argument usage to compare specific entries. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db5d1f5f98c0a5bab3eddf753a1839854569bd29;p=thirdparty%2Felfutils.git dwarfcmp: Support four-argument usage to compare specific entries. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 1800a2950..0259370d9 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,8 @@ 2009-09-30 Roland McGrath + * c++/dwarf_tracker (dwarf_path_finder::walk::jump): New method. + (dwarf_ref_tracker::walk::jump): New method. + * c++/dwarf (dwarf::debug_info_entry): Make constructor from file and offset public. (dwarf::debug_info_entry::compile_unit): New method. diff --git a/libdw/c++/dwarf_tracker b/libdw/c++/dwarf_tracker index 06618e36b..37055b935 100644 --- a/libdw/c++/dwarf_tracker +++ b/libdw/c++/dwarf_tracker @@ -161,17 +161,29 @@ namespace elfutils 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 @@ -199,10 +211,38 @@ namespace elfutils } }; + 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 found = _m_seen->insert (std::make_pair (id, bad_die_path ())); if (found.second @@ -462,6 +502,14 @@ namespace elfutils 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 diff --git a/src/ChangeLog b/src/ChangeLog index 217143cbd..9d5a50a5e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2009-09-30 Roland McGrath + + * dwarfcmp.cc: Support four-argument usage to compare specific entries. + 2009-09-15 Roland McGrath * dwarfcmp.cc (talker, noisy_cmp): Describe context mismatch details diff --git a/src/dwarfcmp.cc b/src/dwarfcmp.cc index 37cbb6c6a..aba8c86b7 100644 --- a/src/dwarfcmp.cc +++ b/src/dwarfcmp.cc @@ -40,7 +40,7 @@ #include #include -#include +#include #include "../libdw/libdwP.h" // XXX #include "c++/dwarf" @@ -80,10 +80,12 @@ static const struct argp_option options[] = /* 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); @@ -196,7 +198,8 @@ struct talker : public dwarf_ref_tracker 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 () @@ -376,6 +379,24 @@ struct talker : public dwarf_ref_tracker } }; +template +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 struct cmp : public dwarf_comparator @@ -390,7 +411,24 @@ struct cmp template struct quiet_cmp : public cmp > -{}; +{ + typedef dwarf_ref_tracker 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 static inline bool @@ -399,12 +437,25 @@ quiet_compare (const dwarf1 &a, const dwarf2 &b) return quiet_cmp () (a, b); } +template +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 () (file1, file2, a, b); +} + // To be noisy, the talker wraps the standard tracker with verbosity hooks. template struct noisy_cmp : public cmp > { - inline bool operator () (const dwarf1 &a, const dwarf2 &b) + typedef talker my_tracker; + + template + inline bool compare (const item1 &a, const item2 &b) { if (equals (a, b) && this->_m_tracker.result_) { @@ -414,6 +465,21 @@ struct noisy_cmp 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 @@ -425,6 +491,18 @@ noisy_compare (const dwarf1 &a, const dwarf2 &b, bool print_all) : noisy_cmp () (a, b)); } +template +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 () (file1, file2, a, b) + : noisy_cmp () (file1, file2, a, b)); +} + #ifdef TEST @@ -514,6 +592,31 @@ static inline void do_writer_test (dwarf &, dwarf &, bool) {} #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[]) { @@ -531,17 +634,18 @@ 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); @@ -563,13 +667,29 @@ main (int argc, char *argv[]) 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);