diff options
Diffstat (limited to 'utils/abtest')
-rwxr-xr-x | utils/abtest/abtest.py | 234 | ||||
-rwxr-xr-x | utils/abtest/mark_aarch64fns.py | 65 | ||||
-rwxr-xr-x | utils/abtest/mark_armfns.py | 54 |
3 files changed, 0 insertions, 353 deletions
diff --git a/utils/abtest/abtest.py b/utils/abtest/abtest.py deleted file mode 100755 index ad6a3e0ea8d2..000000000000 --- a/utils/abtest/abtest.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python -# -# Given a previous good compile narrow down miscompiles. -# Expects two directories named "before" and "after" each containing a set of -# assembly or object files where the "after" version is assumed to be broken. -# You also have to provide a script called "link_test". It is called with a list -# of files which should be linked together and result tested. "link_test" should -# returns with exitcode 0 if the linking and testing succeeded. -# -# abtest.py operates by taking all files from the "before" directory and -# in each step replacing one of them with a file from the "bad" directory. -# -# Additionally you can perform the same steps with a single .s file. In this -# mode functions are identified by "# -- Begin FunctionName" and -# "# -- End FunctionName" markers. The abtest.py then takes all functions from -# the file in the "before" directory and replaces one function with the -# corresponding function from the "bad" file in each step. -# -# Example usage to identify miscompiled files: -# 1. Create a link_test script, make it executable. Simple Example: -# clang "$@" -o /tmp/test && /tmp/test || echo "PROBLEM" -# 2. Run the script to figure out which files are miscompiled: -# > ./abtest.py -# somefile.s: ok -# someotherfile.s: skipped: same content -# anotherfile.s: failed: './link_test' exitcode != 0 -# ... -# Example usage to identify miscompiled functions inside a file: -# 3. First you have to mark begin and end of the functions. -# The script comes with some examples called mark_xxx.py. -# Unfortunately this is very specific to your environment and it is likely -# that you have to write a custom version for your environment. -# > for i in before/*.s after/*.s; do mark_xxx.py $i; done -# 4. Run the tests on a single file (assuming before/file.s and -# after/file.s exist) -# > ./abtest.py file.s -# funcname1 [0/XX]: ok -# funcname2 [1/XX]: ok -# funcname3 [2/XX]: skipped: same content -# funcname4 [3/XX]: failed: './link_test' exitcode != 0 -# ... -from fnmatch import filter -from sys import stderr -import argparse -import filecmp -import os -import subprocess -import sys - -LINKTEST="./link_test" -ESCAPE="\033[%sm" -BOLD=ESCAPE % "1" -RED=ESCAPE % "31" -NORMAL=ESCAPE % "0" -FAILED=RED+"failed"+NORMAL - -def find(dir, file_filter=None): - files = [walkdir[0]+"/"+file for walkdir in os.walk(dir) for file in walkdir[2]] - if file_filter != None: - files = filter(files, file_filter) - return files - -def error(message): - stderr.write("Error: %s\n" % (message,)) - -def warn(message): - stderr.write("Warning: %s\n" % (message,)) - -def extract_functions(file): - functions = [] - in_function = None - for line in open(file): - if line.startswith("# -- Begin "): - if in_function != None: - warn("Missing end of function %s" % (in_function,)) - funcname = line[12:-1] - in_function = funcname - text = line - elif line.startswith("# -- End "): - function_name = line[10:-1] - if in_function != function_name: - warn("End %s does not match begin %s" % (function_name, in_function)) - else: - text += line - functions.append( (in_function, text) ) - in_function = None - elif in_function != None: - text += line - return functions - -def replace_function(file, function, replacement, dest): - out = open(dest, "w") - skip = False - found = False - in_function = None - for line in open(file): - if line.startswith("# -- Begin "): - if in_function != None: - warn("Missing end of function %s" % (in_function,)) - funcname = line[12:-1] - in_function = funcname - if in_function == function: - out.write(replacement) - skip = True - elif line.startswith("# -- End "): - function_name = line[10:-1] - if in_function != function_name: - warn("End %s does not match begin %s" % (function_name, in_function)) - in_function = None - if skip: - skip = False - continue - if not skip: - out.write(line) - -def announce_test(name): - stderr.write("%s%s%s: " % (BOLD, name, NORMAL)) - stderr.flush() - -def announce_result(result, info): - stderr.write(result) - if info != "": - stderr.write(": %s" % info) - stderr.write("\n") - stderr.flush() - -def testrun(files): - linkline="%s %s" % (LINKTEST, " ".join(files),) - res = subprocess.call(linkline, shell=True) - if res != 0: - announce_result(FAILED, "'%s' exitcode != 0" % LINKTEST) - return False - else: - announce_result("ok", "") - return True - -def check_files(): - """Check files mode""" - for i in range(0, len(NO_PREFIX)): - f = NO_PREFIX[i] - b=baddir+"/"+f - if b not in BAD_FILES: - warn("There is no corresponding file to '%s' in %s" \ - % (gooddir+"/"+f, baddir)) - continue - - announce_test(f + " [%s/%s]" % (i+1, len(NO_PREFIX))) - - # combine files (everything from good except f) - testfiles=[] - skip=False - for c in NO_PREFIX: - badfile = baddir+"/"+c - goodfile = gooddir+"/"+c - if c == f: - testfiles.append(badfile) - if filecmp.cmp(goodfile, badfile): - announce_result("skipped", "same content") - skip = True - break - else: - testfiles.append(goodfile) - if skip: - continue - testrun(testfiles) - -def check_functions_in_file(base, goodfile, badfile): - functions = extract_functions(goodfile) - if len(functions) == 0: - warn("Couldn't find any function in %s, missing annotations?" % (goodfile,)) - return - badfunctions = dict(extract_functions(badfile)) - if len(functions) == 0: - warn("Couldn't find any function in %s, missing annotations?" % (badfile,)) - return - - COMBINED="/tmp/combined.s" - i = 0 - for (func,func_text) in functions: - announce_test(func + " [%s/%s]" % (i+1, len(functions))) - i+=1 - if func not in badfunctions: - warn("Function '%s' missing from bad file" % func) - continue - if badfunctions[func] == func_text: - announce_result("skipped", "same content") - continue - replace_function(goodfile, func, badfunctions[func], COMBINED) - testfiles=[] - for c in NO_PREFIX: - if c == base: - testfiles.append(COMBINED) - continue - testfiles.append(gooddir + "/" + c) - - testrun(testfiles) - -parser = argparse.ArgumentParser() -parser.add_argument('--a', dest='dir_a', default='before') -parser.add_argument('--b', dest='dir_b', default='after') -parser.add_argument('--insane', help='Skip sanity check', action='store_true') -parser.add_argument('file', metavar='file', nargs='?') -config = parser.parse_args() - -gooddir=config.dir_a -baddir=config.dir_b - -BAD_FILES=find(baddir, "*") -GOOD_FILES=find(gooddir, "*") -NO_PREFIX=sorted([x[len(gooddir)+1:] for x in GOOD_FILES]) - -# "Checking whether build environment is sane ..." -if not config.insane: - announce_test("sanity check") - if not os.access(LINKTEST, os.X_OK): - error("Expect '%s' to be present and executable" % (LINKTEST,)) - exit(1) - - res = testrun(GOOD_FILES) - if not res: - # "build environment is grinning and holding a spatula. Guess not." - linkline="%s %s" % (LINKTEST, " ".join(GOOD_FILES),) - stderr.write("\n%s\n\n" % linkline) - stderr.write("Returned with exitcode != 0\n") - sys.exit(1) - -if config.file is not None: - # File exchange mode - goodfile = gooddir+"/"+config.file - badfile = baddir+"/"+config.file - check_functions_in_file(config.file, goodfile, badfile) -else: - # Function exchange mode - check_files() diff --git a/utils/abtest/mark_aarch64fns.py b/utils/abtest/mark_aarch64fns.py deleted file mode 100755 index 652014792849..000000000000 --- a/utils/abtest/mark_aarch64fns.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -# Mark functions in an arm assembly file. This is done by surrounding the -# function with "# -- Begin Name" and "# -- End Name" -# (This script is designed for aarch64 ios assembly syntax) -import sys -import re - -inp = open(sys.argv[1], "r").readlines() - -# First pass -linenum = 0 -INVALID=-100 -last_align = INVALID -last_code = INVALID -last_globl = INVALID -last_globl_name = None -begin = INVALID -in_text_section = False -begins = dict() -for line in inp: - linenum += 1 - if re.search(r'.section\s+__TEXT,__text,regular,pure_instructions', line): - in_text_section = True - continue - elif ".section" in line: - in_text_section = False - continue - - if not in_text_section: - continue - - if ".align" in line: - last_align = linenum - gl = re.search(r'.globl\s+(\w+)', line) - if gl: - last_globl_name = gl.group(1) - last_globl = linenum - m = re.search(r'^(\w+):', line) - if m and begin == INVALID: - labelname = m.group(1) - if last_globl+2 == linenum and last_globl_name == labelname: - begin = last_globl - funcname = labelname - if line == "\n" and begin != INVALID: - end = linenum - triple = (funcname, begin, end) - begins[begin] = triple - begin = INVALID - -# Second pass: Mark -out = open(sys.argv[1], "w") -in_func = None -linenum = 0 -for line in inp: - linenum += 1 - if in_func is not None and linenum == end: - out.write("# -- End %s\n" % in_func) - in_func = None - - triple = begins.get(linenum) - if triple is not None: - in_func, begin, end = triple - out.write("# -- Begin %s\n" % in_func) - out.write(line) diff --git a/utils/abtest/mark_armfns.py b/utils/abtest/mark_armfns.py deleted file mode 100755 index 0edf42e8a83c..000000000000 --- a/utils/abtest/mark_armfns.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -# Mark functions in an arm assembly file. This is done by surrounding the -# function with "# -- Begin Name" and "# -- End Name" -# (This script is designed for arm ios assembly syntax) -import sys -import re - -inp = open(sys.argv[1], "r").readlines() - -# First pass -linenum = 0 -INVALID=-100 -last_align = INVALID -last_code = INVALID -last_globl = INVALID -begin = INVALID -begins = dict() -for line in inp: - linenum += 1 - if ".align" in line: - last_align = linenum - if ".code" in line: - last_code = linenum - if ".globl" in line: - last_globl = linenum - m = re.search(r'.thumb_func\s+(\w+)', line) - if m: - funcname = m.group(1) - if last_code == last_align+1 and (linenum - last_code) < 4: - begin = last_align - if last_globl+1 == last_align: - begin = last_globl - if line == "\n" and begin != INVALID: - end = linenum - triple = (funcname, begin, end) - begins[begin] = triple - begin = INVALID - -# Second pass: Mark -out = open(sys.argv[1], "w") -in_func = None -linenum = 0 -for line in inp: - linenum += 1 - if in_func is not None and linenum == end: - out.write("# -- End %s\n" % in_func) - in_func = None - - triple = begins.get(linenum) - if triple is not None: - in_func, begin, end = triple - out.write("# -- Begin %s\n" % in_func) - out.write(line) |