| #!/usr/bin/env python | 
 |  | 
 | from __future__ import absolute_import, division, print_function | 
 |  | 
 | import argparse | 
 | import difflib | 
 | import filecmp | 
 | import os | 
 | import subprocess | 
 | import sys | 
 |  | 
 | disassembler = "objdump" | 
 |  | 
 |  | 
 | def keep_line(line): | 
 |     """Returns true for lines that should be compared in the disassembly | 
 |     output.""" | 
 |     return "file format" not in line | 
 |  | 
 |  | 
 | def disassemble(objfile): | 
 |     """Disassemble object to a file.""" | 
 |     p = subprocess.Popen( | 
 |         [disassembler, "-d", objfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE | 
 |     ) | 
 |     (out, err) = p.communicate() | 
 |     if p.returncode or err: | 
 |         print("Disassemble failed: {}".format(objfile)) | 
 |         sys.exit(1) | 
 |     return [line for line in out.split(os.linesep) if keep_line(line)] | 
 |  | 
 |  | 
 | def dump_debug(objfile): | 
 |     """Dump all of the debug info from a file.""" | 
 |     p = subprocess.Popen( | 
 |         [disassembler, "-WliaprmfsoRt", objfile], | 
 |         stdout=subprocess.PIPE, | 
 |         stderr=subprocess.PIPE, | 
 |     ) | 
 |     (out, err) = p.communicate() | 
 |     if p.returncode or err: | 
 |         print("Dump debug failed: {}".format(objfile)) | 
 |         sys.exit(1) | 
 |     return [line for line in out.split(os.linesep) if keep_line(line)] | 
 |  | 
 |  | 
 | def first_diff(a, b, fromfile, tofile): | 
 |     """Returns the first few lines of a difference, if there is one.  Python | 
 |     diff can be very slow with large objects and the most interesting changes | 
 |     are the first ones. Truncate data before sending to difflib.  Returns None | 
 |     is there is no difference.""" | 
 |  | 
 |     # Find first diff | 
 |     first_diff_idx = None | 
 |     for idx, val in enumerate(a): | 
 |         if val != b[idx]: | 
 |             first_diff_idx = idx | 
 |             break | 
 |  | 
 |     if first_diff_idx == None: | 
 |         # No difference | 
 |         return None | 
 |  | 
 |     # Diff to first line of diff plus some lines | 
 |     context = 3 | 
 |     diff = difflib.unified_diff( | 
 |         a[: first_diff_idx + context], b[: first_diff_idx + context], fromfile, tofile | 
 |     ) | 
 |     difference = "\n".join(diff) | 
 |     if first_diff_idx + context < len(a): | 
 |         difference += "\n*** Diff truncated ***" | 
 |     return difference | 
 |  | 
 |  | 
 | def compare_object_files(objfilea, objfileb): | 
 |     """Compare disassembly of two different files. | 
 |     Allowing unavoidable differences, such as filenames. | 
 |     Return the first difference if the disassembly differs, or None. | 
 |     """ | 
 |     disa = disassemble(objfilea) | 
 |     disb = disassemble(objfileb) | 
 |     return first_diff(disa, disb, objfilea, objfileb) | 
 |  | 
 |  | 
 | def compare_debug_info(objfilea, objfileb): | 
 |     """Compare debug info of two different files. | 
 |     Allowing unavoidable differences, such as filenames. | 
 |     Return the first difference if the debug info differs, or None. | 
 |     If there are differences in the code, there will almost certainly be differences in the debug info too. | 
 |     """ | 
 |     dbga = dump_debug(objfilea) | 
 |     dbgb = dump_debug(objfileb) | 
 |     return first_diff(dbga, dbgb, objfilea, objfileb) | 
 |  | 
 |  | 
 | def compare_exact(objfilea, objfileb): | 
 |     """Byte for byte comparison between object files. | 
 |     Returns True if equal, False otherwise. | 
 |     """ | 
 |     return filecmp.cmp(objfilea, objfileb) | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     parser = argparse.ArgumentParser() | 
 |     parser.add_argument("objfilea", nargs=1) | 
 |     parser.add_argument("objfileb", nargs=1) | 
 |     parser.add_argument("-v", "--verbose", action="store_true") | 
 |     args = parser.parse_args() | 
 |     diff = compare_object_files(args.objfilea[0], args.objfileb[0]) | 
 |     if diff: | 
 |         print("Difference detected") | 
 |         if args.verbose: | 
 |             print(diff) | 
 |         sys.exit(1) | 
 |     else: | 
 |         print("The same") |