diff options
author | Roland McGrath <roland@redhat.com> | 2009-01-04 05:11:23 -0800 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2009-01-04 05:11:23 -0800 |
commit | d3c0611ae6427a3035940a3899798980763012b1 (patch) | |
tree | 9cd417735486108a762f19cabfdc68f21ca61b87 /src/dwarfcmp.cc | |
parent | 9a8b9c756077a00b5015d46e596ddfcff8f5af9a (diff) | |
download | elfutils-d3c0611ae6427a3035940a3899798980763012b1.tar.gz |
unpolished first milestone for C++ and dwarfcmp
Diffstat (limited to 'src/dwarfcmp.cc')
-rw-r--r-- | src/dwarfcmp.cc | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/src/dwarfcmp.cc b/src/dwarfcmp.cc new file mode 100644 index 00000000..fcd1b20a --- /dev/null +++ b/src/dwarfcmp.cc @@ -0,0 +1,313 @@ +/* Compare semantic content of two DWARF files. + 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 + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <argp.h> +#include <assert.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <locale.h> +#include <libintl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "../libdw++/dwarf" + +using namespace elfutils; +using namespace std; + + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +/* Values for the parameters which have no short form. */ +#define OPT_XXX 0x100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Control options:"), 0 }, + { "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 }, + + { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Compare two DWARF files for semantic equality."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("FILE1 FILE2"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + +/* Nonzero if only exit status is wanted. */ +static bool quiet; + + +static Dwarf * +open_file (const char *fname, int *fdp) +{ + int fd = open (fname, O_RDONLY); + if (unlikely (fd == -1)) + error (EXIT_FAILURE, errno, gettext ("cannot open '%s'"), fname); + Dwarf *dw = dwarf_begin (fd, DWARF_C_READ); + if (dw == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create DWARF descriptor for '%s': %s"), + fname, dwarf_errmsg (-1)); + *fdp = fd; + return dw; +} + + +// XXX make translation-friendly +struct context +{ + const dwarf::debug_info_entry *a_; + const dwarf::debug_info_entry *b_; + const char *container_; + + context (const dwarf::debug_info_entry &a, const dwarf::debug_info_entry &b) + : a_ (&a), b_ (&b), container_ (NULL) {} + context () : a_ (NULL), b_ (NULL), container_ ("compilation units") {} + + ostream &location () const + { + if (a_ == NULL) + cout << "files differ: "; + else + cout << hex << a_->offset () << " vs " << b_->offset () << ": "; + return cout; + } + + void container (const char *msg) const + { + location () << msg << " " << container_ << endl; + } + + void missing () const + { + container ("missing"); + } + + void extra () const + { + container ("extra"); + } + + void tag () const + { + location () << "different tag" << endl; + } + + void attributes () const + { + location () << "different attributes" << endl; + } + + void values (int name) const + { + location () << "different values for attribute 0x" << name << endl; + } +}; + +template<typename container1, typename container2> +static int +describe_mismatch (const container1 &a, const container2 &b, const context &say) +{ + typename container1::const_iterator i = a.begin (); + typename container2::const_iterator j = b.begin (); + int result = 0; + while (i != a.end ()) + { + if (j == b.end ()) + { + say.missing (); // b lacks some of a. + result = 1; + break; + } + result = describe_mismatch (*i, *j, say); + assert ((result != 0) == (*i != *j)); + if (result != 0) + break; + ++i; + ++j; + } + if (result == 0 && j != b.end ()) + { + say.extra (); // a lacks some of b. + result = 1; + } + return result; +} + +template<> +int +describe_mismatch (const dwarf::debug_info_entry &a, + const dwarf::debug_info_entry &b, + const context &ctx) +{ + context here (a, b); + + int result = a.tag () != b.tag (); + if (result != 0) + here.tag (); + + if (result == 0) + { + here.container_ = "attributes"; + result = describe_mismatch (a.attributes (), b.attributes (), here); + assert ((result != 0) == (a.attributes () != b.attributes ())); + } + if (result == 0) + { + here.container_ = "children"; + result = describe_mismatch (a.children (), b.children (), here); + assert ((result != 0) == (a.children () != b.children ())); + } + return result; +} + +template<> +int +describe_mismatch (const dwarf::compile_unit &a, const dwarf::compile_unit &b, + const context &ctx) +{ + return describe_mismatch (static_cast<const dwarf::debug_info_entry &> (a), + static_cast<const dwarf::debug_info_entry &> (b), + ctx); +} + +template<> +int describe_mismatch (const dwarf::attribute &a, const dwarf::attribute &b, + const context &say) +{ + int result = a.first != b.first; + if (result != 0) + say.attributes (); + else + { + result = a.second != b.second; + if (result != 0) + say.values (a.first); + } + return result; +} + +int +main (int argc, char *argv[]) +{ + /* 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); + + /* Parse and process arguments. */ + int remaining; + (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* We expect exactly two non-option parameters. */ + if (unlikely (remaining + 2 != 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]; + int fd1; + Dwarf *dw1 = open_file (fname1, &fd1); + + const char *const fname2 = argv[remaining + 1]; + int fd2; + Dwarf *dw2 = open_file (fname2, &fd2); + + elfutils::dwarf file1 (dw1); + elfutils::dwarf file2 (dw2); + + int result = 0; + + if (quiet) + result = !(file1 == file2); + else + result = describe_mismatch (file1.compile_units (), file2.compile_units (), + context ()); + + return result; +} + + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) +{ + fprintf (stream, "dwarfcmp (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Red Hat, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2009"); +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case 'q': + quiet = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} |