brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 9d60259 Raw
117 lines · python
1#!/usr/bin/env python2 3from __future__ import absolute_import, division, print_function4 5import argparse6import difflib7import filecmp8import os9import subprocess10import sys11 12disassembler = "objdump"13 14 15def keep_line(line):16    """Returns true for lines that should be compared in the disassembly17    output."""18    return "file format" not in line19 20 21def disassemble(objfile):22    """Disassemble object to a file."""23    p = subprocess.Popen(24        [disassembler, "-d", objfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE25    )26    (out, err) = p.communicate()27    if p.returncode or err:28        print("Disassemble failed: {}".format(objfile))29        sys.exit(1)30    return [line for line in out.split(os.linesep) if keep_line(line)]31 32 33def dump_debug(objfile):34    """Dump all of the debug info from a file."""35    p = subprocess.Popen(36        [disassembler, "-WliaprmfsoRt", objfile],37        stdout=subprocess.PIPE,38        stderr=subprocess.PIPE,39    )40    (out, err) = p.communicate()41    if p.returncode or err:42        print("Dump debug failed: {}".format(objfile))43        sys.exit(1)44    return [line for line in out.split(os.linesep) if keep_line(line)]45 46 47def first_diff(a, b, fromfile, tofile):48    """Returns the first few lines of a difference, if there is one.  Python49    diff can be very slow with large objects and the most interesting changes50    are the first ones. Truncate data before sending to difflib.  Returns None51    is there is no difference."""52 53    # Find first diff54    first_diff_idx = None55    for idx, val in enumerate(a):56        if val != b[idx]:57            first_diff_idx = idx58            break59 60    if first_diff_idx is None:61        # No difference62        return None63 64    # Diff to first line of diff plus some lines65    context = 366    diff = difflib.unified_diff(67        a[: first_diff_idx + context], b[: first_diff_idx + context], fromfile, tofile68    )69    difference = "\n".join(diff)70    if first_diff_idx + context < len(a):71        difference += "\n*** Diff truncated ***"72    return difference73 74 75def compare_object_files(objfilea, objfileb):76    """Compare disassembly of two different files.77    Allowing unavoidable differences, such as filenames.78    Return the first difference if the disassembly differs, or None.79    """80    disa = disassemble(objfilea)81    disb = disassemble(objfileb)82    return first_diff(disa, disb, objfilea, objfileb)83 84 85def compare_debug_info(objfilea, objfileb):86    """Compare debug info of two different files.87    Allowing unavoidable differences, such as filenames.88    Return the first difference if the debug info differs, or None.89    If there are differences in the code, there will almost certainly be differences in the debug info too.90    """91    dbga = dump_debug(objfilea)92    dbgb = dump_debug(objfileb)93    return first_diff(dbga, dbgb, objfilea, objfileb)94 95 96def compare_exact(objfilea, objfileb):97    """Byte for byte comparison between object files.98    Returns True if equal, False otherwise.99    """100    return filecmp.cmp(objfilea, objfileb)101 102 103if __name__ == "__main__":104    parser = argparse.ArgumentParser()105    parser.add_argument("objfilea", nargs=1)106    parser.add_argument("objfileb", nargs=1)107    parser.add_argument("-v", "--verbose", action="store_true")108    args = parser.parse_args()109    diff = compare_object_files(args.objfilea[0], args.objfileb[0])110    if diff:111        print("Difference detected")112        if args.verbose:113            print(diff)114        sys.exit(1)115    else:116        print("The same")117