123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- #!/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")
|