Home | History | Annotate | Download | only in check_cfc
      1 #!/usr/bin/env python2.7
      2 
      3 from __future__ import print_function
      4 
      5 import argparse
      6 import difflib
      7 import filecmp
      8 import os
      9 import subprocess
     10 import sys
     11 
     12 disassembler = 'objdump'
     13 
     14 def keep_line(line):
     15     """Returns true for lines that should be compared in the disassembly
     16     output."""
     17     return "file format" not in line
     18 
     19 def disassemble(objfile):
     20     """Disassemble object to a file."""
     21     p = subprocess.Popen([disassembler, '-d', objfile],
     22                          stdout=subprocess.PIPE,
     23                          stderr=subprocess.PIPE)
     24     (out, err) = p.communicate()
     25     if p.returncode or err:
     26         print("Disassemble failed: {}".format(objfile))
     27         sys.exit(1)
     28     return filter(keep_line, out.split(os.linesep))
     29 
     30 def dump_debug(objfile):
     31     """Dump all of the debug info from a file."""
     32     p = subprocess.Popen([disassembler, '-WliaprmfsoRt', objfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     33     (out, err) = p.communicate()
     34     if p.returncode or err:
     35         print("Dump debug failed: {}".format(objfile))
     36         sys.exit(1)
     37     return filter(keep_line, out.split(os.linesep))
     38 
     39 def first_diff(a, b, fromfile, tofile):
     40     """Returns the first few lines of a difference, if there is one.  Python
     41     diff can be very slow with large objects and the most interesting changes
     42     are the first ones. Truncate data before sending to difflib.  Returns None
     43     is there is no difference."""
     44 
     45     # Find first diff
     46     first_diff_idx = None
     47     for idx, val in enumerate(a):
     48         if val != b[idx]:
     49             first_diff_idx = idx
     50             break
     51 
     52     if first_diff_idx == None:
     53         # No difference
     54         return None
     55 
     56     # Diff to first line of diff plus some lines
     57     context = 3
     58     diff = difflib.unified_diff(a[:first_diff_idx+context],
     59                                 b[:first_diff_idx+context],
     60                                 fromfile,
     61                                 tofile)
     62     difference = "\n".join(diff)
     63     if first_diff_idx + context < len(a):
     64         difference += "\n*** Diff truncated ***"
     65     return difference
     66 
     67 def compare_object_files(objfilea, objfileb):
     68     """Compare disassembly of two different files.
     69        Allowing unavoidable differences, such as filenames.
     70        Return the first difference if the disassembly differs, or None.
     71     """
     72     disa = disassemble(objfilea)
     73     disb = disassemble(objfileb)
     74     return first_diff(disa, disb, objfilea, objfileb)
     75 
     76 def compare_debug_info(objfilea, objfileb):
     77     """Compare debug info of two different files.
     78        Allowing unavoidable differences, such as filenames.
     79        Return the first difference if the debug info differs, or None.
     80        If there are differences in the code, there will almost certainly be differences in the debug info too.
     81     """
     82     dbga = dump_debug(objfilea)
     83     dbgb = dump_debug(objfileb)
     84     return first_diff(dbga, dbgb, objfilea, objfileb)
     85 
     86 def compare_exact(objfilea, objfileb):
     87     """Byte for byte comparison between object files.
     88        Returns True if equal, False otherwise.
     89     """
     90     return filecmp.cmp(objfilea, objfileb)
     91 
     92 if __name__ == '__main__':
     93     parser = argparse.ArgumentParser()
     94     parser.add_argument('objfilea', nargs=1)
     95     parser.add_argument('objfileb', nargs=1)
     96     parser.add_argument('-v', '--verbose', action='store_true')
     97     args = parser.parse_args()
     98     diff = compare_object_files(args.objfilea[0], args.objfileb[0])
     99     if diff:
    100         print("Difference detected")
    101         if args.verbose:
    102             print(diff)
    103         sys.exit(1)
    104     else:
    105         print("The same")
    106