106 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/usr/bin/env python2.7
 | |
| 
 | |
| from __future__ import 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 filter(keep_line, out.split(os.linesep))
 | |
| 
 | |
| 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 filter(keep_line, out.split(os.linesep))
 | |
| 
 | |
| 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")
 |