summaryrefslogtreecommitdiffstats
path: root/clang/utils/check_cfc/obj_diff.py
blob: 6f932b3172daa8ec83fb5327584f4c48154170dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env python2.7

from __future__ import print_function

import argparse
import difflib
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 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)

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")
OpenPOWER on IntegriCloud