From 51068b71b016a52049bfc79e6e309c0f803c1582 Mon Sep 17 00:00:00 2001 From: Brendan Dougherty Date: Mon, 10 Jul 2023 12:27:06 -0500 Subject: [PATCH] reccmp: Add ability to compare template instantiations --- tools/reccmp/reccmp.py | 51 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index 226be15d..908baaf6 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -10,6 +10,7 @@ import os import sys import colorama +import html parser = argparse.ArgumentParser(allow_abbrev=False, description='Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.') @@ -42,7 +43,7 @@ verbose = int(args.verbose, 16) except ValueError: parser.error('invalid verbose argument') -html = args.html +html_path = args.html plain = args.no_color @@ -139,6 +140,7 @@ def get_file_in_script_dir(fn): class SymInfo: funcs = {} lines = {} + names = {} def __init__(self, pdb, file, wine_path_converter): call = [get_file_in_script_dir('cvdump.exe'), '-l', '-s'] @@ -182,6 +184,7 @@ def __init__(self, pdb, file, wine_path_converter): info.name = line[77:] + self.names[info.name] = info self.funcs[addr] = info elif current_section == 'LINES' and line.startswith(' ') and not line.startswith(' '): sourcepath = line.split()[0] @@ -237,6 +240,14 @@ def get_recompiled_address(self, filename, line): else: logger.error('Failed to find function symbol with filename and line: %s:%d', filename, line) + def get_recompiled_address_from_name(self, name): + logger.debug('Looking for %s', name) + + if name in self.names: + return self.names[name] + else: + logger.error('Failed to find function symbol with name: %s', name) + wine_path_converter = None if os.name != 'nt': wine_path_converter = WinePathConverter(source) @@ -347,14 +358,24 @@ def parse_asm(file, addr, size): else: continue - find_open_bracket = line - while '{' not in find_open_bracket: - find_open_bracket = srcfile.readline() - line_no += 1 + if line.endswith("TEMPLATE"): + line = srcfile.readline() + line_no += 1 + # Name comes after // comment + name = line[2:].strip() - recinfo = syminfo.get_recompiled_address(srcfilename, line_no) - if not recinfo: - continue + recinfo = syminfo.get_recompiled_address_from_name(name) + if not recinfo: + continue + else: + find_open_bracket = line + while '{' not in find_open_bracket: + find_open_bracket = srcfile.readline() + line_no += 1 + + recinfo = syminfo.get_recompiled_address(srcfilename, line_no) + if not recinfo: + continue if recinfo.size: origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size) @@ -414,14 +435,14 @@ def parse_asm(file, addr, size): print("\n%s is only %s similar to the original, diff above" % (recinfo.name, percenttext)) # If html, record the diffs to an HTML file - if html: + if html_path: escaped = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '<').replace('>', '>') - htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(ratio), escaped)) + htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), html.escape(recinfo.name), str(ratio), escaped)) except UnicodeDecodeError: break -def gen_html(html, data): +def gen_html(html_path, data): templatefile = open(get_file_in_script_dir('template.html'), 'r') if not templatefile: print('Failed to find HTML template file, can\'t generate HTML summary') @@ -432,9 +453,9 @@ def gen_html(html, data): templatedata = templatedata.replace('/* INSERT DATA HERE */', ','.join(data), 1) - htmlfile = open(html, 'w') + htmlfile = open(html_path, 'w') if not htmlfile: - print('Failed to write to HTML file %s' % html) + print('Failed to write to HTML file %s' % html_path) return htmlfile.write(templatedata) @@ -483,8 +504,8 @@ def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy): svgfile.write(templatedata) svgfile.close() -if html: - gen_html(html, htmlinsert) +if html_path: + gen_html(html_path, htmlinsert) if verbose: if not found_verbose_target: