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