summaryrefslogtreecommitdiff
path: root/suite
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2018-06-06 20:44:47 -0400
committerRyan Snyder <ryan@vector35.com>2018-07-10 18:11:09 -0400
commit5d4015659d20cfee839ccccdcfb96094ac8e610a (patch)
tree8ccf2888610ce6fa604ae25ccbf5a4083c3a3459 /suite
parent3ead1e28774663514992adea4ad2c38b0416e66d (diff)
Various Python 3 support changes
Diffstat (limited to 'suite')
m---------suite/binaries0
-rwxr-xr-xsuite/generator.py107
-rw-r--r--suite/testcommon.py282
-rw-r--r--suite/unit.py309
4 files changed, 352 insertions, 346 deletions
diff --git a/suite/binaries b/suite/binaries
-Subproject 7d5d207de812ccd7c4648331b00fa936ef0a82c
+Subproject ab6b18161a5b9ccd3588c88233f150fb6c7e2ce
diff --git a/suite/generator.py b/suite/generator.py
index b812b1b5..3302d118 100755
--- a/suite/generator.py
+++ b/suite/generator.py
@@ -10,24 +10,77 @@ import time
unit_test_template = """#!/usr/bin/env python
# This is an auto generated unit test file do not edit directly
import os
+import sys
import unittest
import pickle
import zipfile
import testcommon
-import binaryninja
import api_test
import difflib
+from collections import Counter
+global verbose
+verbose = False
class TestBinaryNinjaAPI(unittest.TestCase):
+ # Returns a tuple of:
+ # bool : Two lists are equal
+ # string : The string diff
+ # Args:
+ # list
+ # list : (compare list one vs list two)
+ # string : anything additional wanted to be printed before the string diff
+ # bool : the ordering of the items in the two lists must be the same
+ def report(self, oracle, test, firstText='', strictOrdering = False):
+ stringDiff = ""
+
+ equality = False
+ if not strictOrdering:
+ equality = (Counter(oracle) == Counter(test))
+ else:
+ equality = (oracle == test)
+
+ if equality:
+ return (True, '')
+ elif not strictOrdering:
+ try:
+ for elem in oracle:
+ test.remove(elem)
+ oracle.remove(elem) # If it's not in the test, it won't get here!
+ except ValueError:
+ pass
+
+ differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
+ skipped_lines = 0
+ for delta in differ.compare(oracle, test):
+ if delta[0] == ' ':
+ skipped_lines += 1
+ continue
+ if skipped_lines > 0:
+ stringDiff += "<---" + str(skipped_lines) + ' same lines--->\\n'
+ skipped_lines = 0
+ delta = delta.replace(\'\\n\', '')
+ stringDiff += delta + \'\\n\'
+
+ stringDiffList = stringDiff.split(\'\\n\')
+
+ if len(stringDiffList) > 10:
+ if not verbose:
+ stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10])
+ stringDiff += \'\\n\\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###"
+ elif not verbose:
+ stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList)
+ stringDiff = \'\\n\\n\' + firstText + stringDiff
+ return (equality, stringDiff)
+
@classmethod
def setUpClass(self):
self.builder = testcommon.TestBuilder("{3}")
try:
- #Python 2 does not have the encodings option
- self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rUb"), errors="ignore")
+ # Python 2 does not have the encodings option
+ self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rb"), encoding='charmap')
except TypeError:
- self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rU"))
+ self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "r"))
self.verifybuilder = testcommon.VerifyBuilder("{3}")
def run_binary_test(self, testfile):
@@ -38,10 +91,10 @@ class TestBinaryNinjaAPI(unittest.TestCase):
self.assertTrue(os.path.exists(testname + ".pkl"), "Test pickle doesn't exist")
try:
- #Python 2 does not have the encodings option
- binary_oracle = pickle.load(open(testname + ".pkl", "rUb"), errors="ignore")
+ # Python 2 does not have the encodings option
+ binary_oracle = pickle.load(open(testname + ".pkl", "rb"), encoding='charmap')
except TypeError:
- binary_oracle = pickle.load(open(testname + ".pkl", "rU"))
+ binary_oracle = pickle.load(open(testname + ".pkl", "r"))
test_builder = testcommon.BinaryViewTestBuilder(testname, "{3}")
for method in test_builder.methods():
@@ -52,22 +105,16 @@ class TestBinaryNinjaAPI(unittest.TestCase):
result = getattr(test_builder, method).__doc__
result += ":\\n"
- d = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in d.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\\n'
- skipped_lines = 0
- delta = delta.replace('\\n', '')
- result += delta + '\\n'
- self.assertTrue(False, result)
+ report = self.report(oracle, test, result)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
os.unlink(testname)
{1}{2}
if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ if sys.argv[1] == '-v' or sys.argv[1] == '-V' or sys.argv[1] == '--verbose':
+ verbose = True
+
test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinjaAPI))
runner = unittest.TextTestRunner(verbosity=2)
@@ -83,20 +130,8 @@ test_string = """
def {0}(self):
oracle = self.oracle_test_data['{0}']
test = self.builder.{0}()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\\n'
- skipped_lines = 0
- delta = delta.replace('\\n', '')
- result += delta + '\\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
"""
verify_string = """
@@ -108,7 +143,7 @@ verify_string = """
class OracleTestFile:
def __init__(self, filename):
self.f = open(filename + ".pkl", "wb")
- self.pkl = pickle.Pickler(self.f)
+ self.pkl = pickle.Pickler(self.f, protocol=2)
self.filename = filename
self.oracle_test_data = {}
@@ -131,7 +166,7 @@ class UnitTestFile:
self.binary_tests = ""
def close(self):
- self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, self.test_store).encode('utf-8'))
+ self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, self.test_store).encode('charmap'))
self.f.close()
def add_verify(self, test_name):
@@ -146,8 +181,6 @@ class UnitTestFile:
quiet = False
-
-
def myprint(stuff):
if not quiet:
print(stuff)
diff --git a/suite/testcommon.py b/suite/testcommon.py
index 1bbc0d47..ef85c053 100644
--- a/suite/testcommon.py
+++ b/suite/testcommon.py
@@ -1,14 +1,54 @@
import tempfile
import pickle
import os
+import sys
import zipfile
import inspect
import binaryninja as binja
from binaryninja.binaryview import BinaryViewType, BinaryView
from binaryninja.filemetadata import FileMetadata
import subprocess
-import traceback
-import types
+import re
+
+
+# Dear people from the future: If you're adding tests or debuging an
+# issue where python2 and python3 are producing different output
+# for the same function and it's a issue of `longs`, run the output
+# through this function. If it's a unicode/bytes issue, fix it in
+# api/python/
+def fixOutput(outputList):
+ # Apply regular expression to detect python2 longs
+ splitList = []
+ for elem in outputList:
+ if isinstance(elem, str):
+ splitList.append(re.split(r"((?<=[\[ ])0x[\da-f]+L|[\d]+L)", elem))
+ else:
+ splitList.append(elem)
+
+ # Resolve application of regular expression
+ result = []
+ for elem in splitList:
+ if isinstance(elem, list):
+ newElem = []
+ for item in elem:
+ if len(item) > 1 and item[-1] == 'L':
+ newElem.append(item[:-1])
+ else:
+ newElem.append(item)
+ result.append(''.join(newElem))
+ else:
+ result.append(elem)
+ return result
+
+
+# Alright so this one is here for Binja functions that output <in set([blah, blah, blah])>
+def fixSet(string):
+ # Apply regular expression
+ splitList = (re.split(r"((?<=<in set\(\[).*(?=\]\)>))", string))
+ if len(splitList) > 1:
+ return splitList[0] + ', '.join(sorted(splitList[1].split(', '))) + splitList[2]
+ else:
+ return string
def get_file_list(test_store):
@@ -16,13 +56,12 @@ def get_file_list(test_store):
for root, dir, files in os.walk(test_store):
for file in files:
all_files.append(os.path.join(root, file))
-
return all_files
def remove_low_confidence(type_string):
low_confidence_types = ["int32_t", "void"]
for lct in low_confidence_types:
- type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties
+ type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties
return type_string
class Builder(object):
@@ -66,15 +105,24 @@ class BinaryViewTestBuilder(Builder):
def test_function_starts(self):
"""Function starts list doesnt match"""
- return ["Function start: " + hex(x.start) for x in self.bv.functions]
+ result = []
+ for x in self.bv.functions:
+ result.append("Function start: " + hex(x.start))
+ return fixOutput(result)
def test_function_symbol_names(self):
"""Function.symbol.name list doesnt match"""
- return ["Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address) for x in self.bv.functions]
+ result = []
+ for x in self.bv.functions:
+ result.append("Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address))
+ return fixOutput(result)
def test_function_can_return(self):
"""Function.can_return list doesnt match"""
- return ["function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return)) for x in self.bv.functions]
+ result = []
+ for x in self.bv.functions:
+ result.append("function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return)))
+ return fixOutput(result)
def test_function_basic_blocks(self):
"""Function basic_block list doesnt match (start, end, has_undetermined_outgoing_edges)"""
@@ -85,32 +133,31 @@ class BinaryViewTestBuilder(Builder):
for anno in func.get_block_annotations(bb.start):
bblist.append("basic block {} function annotation: ".format(str(bb)) + str(anno))
bblist.append("basic block {} test get self: ".format(str(bb)) + str(func.get_basic_block_at(bb.start)))
- return bblist
+ return fixOutput(bblist)
def test_function_low_il_basic_blocks(self):
- """"Function low_il_basic_block list doesnt match"""
+ """Function low_il_basic_block list doesnt match"""
ilbblist = []
for func in self.bv.functions:
for bb in func.low_level_il.basic_blocks:
ilbblist.append("LLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing edges: ' + str(len(bb.outgoing_edges)))
- return ilbblist
+ return fixOutput(ilbblist)
def test_function_med_il_basic_blocks(self):
- """"Function med_il_basic_block list doesn't match"""
+ """Function med_il_basic_block list doesn't match"""
ilbblist = []
for func in self.bv.functions:
for bb in func.medium_level_il.basic_blocks:
ilbblist.append("MLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing_edges: ' + str(len(bb.outgoing_edges)))
- return ilbblist
+ return fixOutput(ilbblist)
def test_symbols(self):
- """"Symbols list doesn't match"""
+ """Symbols list doesn't match"""
return ["Symbol: " + str(i) for i in sorted(self.bv.symbols)]
def test_strings(self):
"""Strings list doesn't match"""
- return ["String: " + x.value + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings]
-
+ return fixOutput(["String: " + str(x.value) + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings])
def test_low_il_instructions(self):
"""LLIL instructions produced different output"""
@@ -126,9 +173,7 @@ class BinaryViewTestBuilder(Builder):
retinfo.append("Postfix operands: " + str(ins.postfix_operands))
retinfo.append("SSA form: " + str(ins.ssa_form))
retinfo.append("Non-SSA form: " + str(ins.non_ssa_form))
-
- return retinfo
-
+ return fixOutput(retinfo)
def test_low_il_ssa(self):
"""LLIL ssa produced different output"""
@@ -151,9 +196,7 @@ class BinaryViewTestBuilder(Builder):
retinfo.append("SSA instruction index: " + str(func.get_ssa_instruction_index(tempind)))
retinfo.append("MLIL instruction index: " + str(func.get_medium_level_il_instruction_index(ins.instr_index)))
retinfo.append("Mapped MLIL instruction index: " + str(func.get_mapped_medium_level_il_instruction_index(ins.instr_index)))
-
- return retinfo
-
+ return fixOutput(retinfo)
def test_med_il_instructions(self):
"""MLIL instructions produced different output"""
@@ -165,18 +208,33 @@ class BinaryViewTestBuilder(Builder):
retinfo.append("LLIL: " + str(ins.low_level_il))
retinfo.append("Value: " + str(ins.value))
retinfo.append("Possible values: " + str(ins.possible_values))
- retinfo.append("Branch dependence: " + str(ins.branch_dependence))
- retinfo.append("Prefix operands: " + str(sorted([str(i) for i in ins.prefix_operands])))
- retinfo.append("Postfix operands: " + str(sorted([str(i) for i in ins.postfix_operands])))
- retinfo.append("SSA form: " + str(ins.ssa_form))
- retinfo.append("Non-SSA form" + str(ins.non_ssa_form))
-
- return retinfo
+ retinfo.append("Branch dependence: " + str(sorted(ins.branch_dependence.items())))
+ prefixList = []
+ for i in ins.prefix_operands:
+ if isinstance(i, float) and 'e' in str(i):
+ prefixList.append(str(round(i, 21)))
+ elif isinstance(i, float):
+ prefixList.append(str(round(i, 11)))
+ else:
+ prefixList.append(str(i))
+ retinfo.append("Prefix operands: " + str(sorted(prefixList)))
+ postfixList = []
+ for i in ins.prefix_operands:
+ if isinstance(i, float) and 'e' in str(i):
+ postfixList.append(str(round(i, 21)))
+ elif isinstance(i, float):
+ postfixList.append(str(round(i, 11)))
+ else:
+ postfixList.append(str(i))
+ retinfo.append("Postfix operands: " + str(sorted(postfixList)))
+ retinfo.append("SSA form: " + str(ins.ssa_form))
+ retinfo.append("Non-SSA form" + str(ins.non_ssa_form))
+ return fixOutput(retinfo)
def test_med_il_vars(self):
- """"Function med_il_vars doesn't match"""
+ """Function med_il_vars doesn't match"""
varlist = []
for func in self.bv.functions:
func = func.medium_level_il
@@ -184,14 +242,13 @@ class BinaryViewTestBuilder(Builder):
for instruction in bb:
instruction = instruction.ssa_form
for var in (instruction.vars_read + instruction.vars_written):
- #varlist.append((func.get_var_uses(var), func.get_var_definitions(var)))
if hasattr(var, "var"):
varlist.append("SSA var definition: " + str(func.get_ssa_var_definition(var)))
varlist.append("SSA var uses: " + str(func.get_ssa_var_uses(var)))
varlist.append("SSA var value: " + str(func.get_ssa_var_value(var)))
- varlist.append("SSA var possible values: " + str(instruction.get_ssa_var_possible_values(var)))
+ varlist.append("SSA var possible values: " + fixSet(str(instruction.get_ssa_var_possible_values(var))))
varlist.append("SSA var version: " + str(instruction.get_ssa_var_version))
- return varlist
+ return fixOutput(varlist)
def test_function_stack(self):
"""Function stack produced different output"""
@@ -211,32 +268,26 @@ class BinaryViewTestBuilder(Builder):
funcinfo.append("Sample stack var: " + str(func.get_stack_var_at_frame_offset(0, 0)))
func.delete_user_stack_var(0)
func.delete_auto_stack_var(0)
-
return funcinfo
def test_function_llil(self):
"""Function LLIL produced different output"""
retinfo = []
-
for func in self.bv.functions:
for llilbb in func.llil_basic_blocks:
retinfo.append("LLIL basic block: " + str(llilbb))
for llilins in func.llil_instructions:
retinfo.append("LLIL instruction: " + str(llilins))
-
for mlilbb in func.mlil_basic_blocks:
retinfo.append("MLIL basic block: " + str(mlilbb))
for mlilins in func.mlil_instructions:
retinfo.append("MLIL instruction: " + str(mlilins))
-
for ins in func.instructions:
- retinfo.append("Instructiin: {}: ".format(hex(ins[1])) + ''.join([str(i) for i in ins[0]]))
-
- return retinfo
-
+ retinfo.append("Instruction: {}: ".format(hex(ins[1])) + ''.join([str(i) for i in ins[0]]))
+ return fixOutput(retinfo)
def test_functions_attributes(self):
- """"Function attributes don't match"""
+ """Function attributes don't match"""
funcinfo = []
for func in self.bv.functions:
func.comment = "testcomment " + func.name
@@ -284,9 +335,7 @@ class BinaryViewTestBuilder(Builder):
token = str(token)
token = remove_low_confidence(token)
funcinfo.append("Function {} type token: ".format(func.name) + str(token))
-
-
- return funcinfo
+ return fixOutput(funcinfo)
def test_BinaryView(self):
"""BinaryView produced different results"""
@@ -309,11 +358,12 @@ class BinaryViewTestBuilder(Builder):
retinfo.append("BV entry point: " + hex(self.bv.entry_point))
retinfo.append("BV start: " + hex(self.bv.start))
retinfo.append("BV length: " + hex(len(self.bv)))
- return retinfo
+
+ return fixOutput(retinfo)
class TestBuilder(Builder):
- """ The TestBuilder is for tests that need to be checked against
+ """ The TestBuilder is for tests that need to be checked againsttest_BinaryView
stored oracle data that isn't from a binary. These test are
generated on your local machine then run again on the build
machine to verify correctness.
@@ -335,23 +385,81 @@ class TestBuilder(Builder):
"""unexpected assemble result"""
result = []
# success cases
- result.append("x86 assembly: " + str(binja.Architecture["x86"].assemble("xor eax, eax")))
- result.append("x86_64 assembly: " + str(binja.Architecture["x86_64"].assemble("xor rax, rax")))
- result.append("mips32 assembly: " + str(binja.Architecture["mips32"].assemble("move $ra, $zero")))
- result.append("mipsel32 assembly: " + str(binja.Architecture["mipsel32"].assemble("move $ra, $zero")))
- result.append("armv7 assembly: " + str(binja.Architecture["armv7"].assemble("str r2, [sp, #-0x4]!")))
- result.append("aarch64 assembly: " + str(binja.Architecture["aarch64"].assemble("mov x0, x0")))
- result.append("thumb2 assembly: " + str(binja.Architecture["thumb2"].assemble("ldr r4, [r4]")))
- result.append("thumb2eb assembly: " + str(binja.Architecture["thumb2eb"].assemble("ldr r4, [r4]")))
+
+ strResult = binja.Architecture["x86"].assemble("xor eax, eax")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("x86 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("x86 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["x86_64"].assemble("xor rax, rax")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("x86_64 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("x86_64 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["mips32"].assemble("move $ra, $zero")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("mips32 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("mips32 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["mipsel32"].assemble("move $ra, $zero")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("mipsel32 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("mipsel32 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["armv7"].assemble("str r2, [sp, #-0x4]!")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("armv7 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("armv7 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["aarch64"].assemble("mov x0, x0")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("aarch64 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("aarch64 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["thumb2"].assemble("ldr r4, [r4]")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("thumb2 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("thumb2 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["thumb2eb"].assemble("ldr r4, [r4]")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("thumb2eb assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("thumb2eb assembly: " + repr(str(strResult)))
+
# fail cases
- result.append("x86 assembly: " + str(binja.Architecture["x86"].assemble("thisisnotaninstruction")))
- result.append("x86_64 assembly: " + str(binja.Architecture["x86_64"].assemble("thisisnotaninstruction")))
- result.append("mips32 assembly: " + str(binja.Architecture["mips32"].assemble("thisisnotaninstruction")))
- result.append("mipsel32 assembly: " + str(binja.Architecture["mipsel32"].assemble("thisisnotaninstruction")))
- result.append("armv7 assembly: " + str(binja.Architecture["armv7"].assemble("thisisnotaninstruction")))
- result.append("aarch64 assembly: " + str(binja.Architecture["aarch64"].assemble("thisisnotaninstruction")))
- result.append("thumb2 assembly: " + str(binja.Architecture["thumb2"].assemble("thisisnotaninstruction")))
- result.append("thumb2eb assembly: " + str(binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction")))
+ try:
+ strResult = binja.Architecture["x86"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86'")
+ try:
+ strResult = binja.Architecture["x86_64"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86_64'")
+ try:
+ strResult = binja.Architecture["mips32"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mips32'")
+ try:
+ strResult = binja.Architecture["mipsel32"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mipsel32'")
+ try:
+ strResult = binja.Architecture["armv7"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'armv7'")
+ try:
+ strResult = binja.Architecture["aarch64"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'aarch64'")
+ try:
+ strResult = binja.Architecture["thumb2"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2'")
+ try:
+ strResult = binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2eb'")
return result
def test_Architecture(self):
@@ -385,8 +493,6 @@ class TestBuilder(Builder):
retinfo.append("Instruction: " + str(ins))
return retinfo
-
-
def test_Function(self):
"""Function produced different result"""
inttype = binja.Type.int(4)
@@ -433,7 +539,6 @@ class TestBuilder(Builder):
def test_Types(self):
"""Types produced different result"""
-
file_name = os.path.join(self.test_store, "helloworld")
bv = binja.BinaryViewType.get_view_of_file(file_name)
preprocessed = binja.preprocess_source("""
@@ -445,7 +550,7 @@ class TestBuilder(Builder):
long long bar1 = 2;
#endif
""")
- source = '\n'.join([i.decode("utf-8") for i in preprocessed[0].split('\n') if not b"#line" in i and len(i) > 0])
+ source = '\n'.join([i.decode('utf-8') for i in preprocessed[0].split(b'\n') if not b'#line' in i and len(i) > 0])
typelist = bv.platform.parse_types_from_source(source)
inttype = binja.Type.int(4)
@@ -464,12 +569,11 @@ class TestBuilder(Builder):
def test_Plugin_bin_info(self):
"""print_syscalls plugin produced different result"""
-
file_name = os.path.join(self.test_store, "helloworld")
self.unpackage_file(file_name)
result = subprocess.Popen(["python", os.path.join(self.examples_dir, "bin_info.py"), file_name], stdout=subprocess.PIPE).communicate()[0]
# normalize line endings and path sep
- return [result.replace(b"\\", b"/").replace(b"\r\n", b"\n")]
+ return [result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap")]
def test_linear_disassembly(self):
"""linear_disassembly produced different result"""
@@ -486,7 +590,6 @@ class TestBuilder(Builder):
def test_partial_register_dataflow(self):
"""partial_register_dataflow produced different results"""
-
file_name = os.path.join(self.test_store, "partial_register_dataflow")
self.unpackage_file(file_name)
result = []
@@ -505,7 +608,6 @@ class TestBuilder(Builder):
del bv
finally:
os.unlink(file_name)
-
return result
@@ -524,20 +626,13 @@ class TestBuilder(Builder):
retinfo.append("LLIL second stack element: " + str(ins.get_stack_contents_after(0,1)))
retinfo.append("LLIL possible first stack element: " + str(ins.get_possible_stack_contents(0,1)))
retinfo.append("LLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0,1)))
-
-
for flag in flag_list:
retinfo.append("LLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag)))
retinfo.append("LLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag)))
-
retinfo.append("LLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag)))
retinfo.append("LLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values_after(flag)))
-
- os.unlink(file_name)
-
os.unlink(file_name)
-
- return retinfo
+ return fixOutput(retinfo)
def test_med_il_stack(self):
"""MLIL stack produced different output"""
@@ -555,25 +650,21 @@ class TestBuilder(Builder):
retinfo.append("MLIL second stack element: " + str(ins.get_stack_contents_after(0, 1)))
retinfo.append("MLIL possible first stack element: " + str(ins.get_possible_stack_contents(0, 1)))
retinfo.append("MLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0, 1)))
-
+
for reg in reg_list:
retinfo.append("MLIL reg {} var at {}: ".format(reg, hex(ins.address)) + str(ins.get_var_for_reg(reg)))
retinfo.append("MLIL reg {} value at {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value(reg)))
retinfo.append("MLIL reg {} value after {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value_after(reg)))
- retinfo.append("MLIL reg {} possible value at {}: ".format(reg, hex(ins.address)) + str(ins.get_possible_reg_values(reg)))
- retinfo.append("MLIL reg {} possible value after {}: ".format(reg, hex(ins.address)) + str(ins.get_possible_reg_values_after(reg)))
-
+ retinfo.append("MLIL reg {} possible value at {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values(reg))))
+ retinfo.append("MLIL reg {} possible value after {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values_after(reg))))
for flag in flag_list:
retinfo.append("MLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag)))
retinfo.append("MLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag)))
- retinfo.append("MLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag)))
- retinfo.append("MLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag)))
-
+ retinfo.append("MLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag))))
+ retinfo.append("MLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag))))
os.unlink(file_name)
-
- return retinfo
-
+ return fixOutput(retinfo)
def test_events(self):
"""Event failure"""
@@ -582,11 +673,9 @@ class TestBuilder(Builder):
bv = binja.BinaryViewType['ELF'].open(file_name)
results = []
-
def simple_complete(self):
results.append("analysis complete")
-
evt = binja.AnalysisCompletionEvent(bv, simple_complete)
class NotifyTest(binja.BinaryDataNotification):
@@ -643,7 +732,13 @@ class TestBuilder(Builder):
def string_found(self, view, string_type, offset, length):
def string_found_complete(self):
- results.append("string found: offset {0} length {1}".format(hex(offset), hex(length)))
+ offset = hex(offset)
+ length = hex(length)
+ if offset[-1] == 'L':
+ offset = offset[:-1]
+ if length[-1] == 'L':
+ length = length[:-1]
+ results.append("string found: offset {0} length {1}".format(offset, length))
evt = binja.AnalysisCompletionEvent(bv, string_found_complete)
def string_removed(self, view, string_type, offset, length):
@@ -666,7 +761,6 @@ class TestBuilder(Builder):
bv.register_notification(test)
sacrificial_addr = 0x84fc
-
type, name = bv.parse_type_string("int foo")
type_id = type.generate_auto_type_id("source", name)
bv.define_type(type_id, name, type)
@@ -684,10 +778,10 @@ class TestBuilder(Builder):
bv.remove(sacrificial_addr, 4)
bv.update_analysis_and_wait()
-
+
bv.unregister_notification(test)
- return sorted(results)
+ return fixOutput(sorted(results))
def unpackage(self, fileName):
testname = None
diff --git a/suite/unit.py b/suite/unit.py
index 9a59b13f..fe2c4b8c 100644
--- a/suite/unit.py
+++ b/suite/unit.py
@@ -1,24 +1,77 @@
#!/usr/bin/env python
# This is an auto generated unit test file do not edit directly
import os
+import sys
import unittest
import pickle
import zipfile
import testcommon
-import binaryninja
import api_test
import difflib
+from collections import Counter
+global verbose
+verbose = False
class TestBinaryNinjaAPI(unittest.TestCase):
+ # Returns a tuple of:
+ # bool : Two lists are equal
+ # string : The string diff
+ # Args:
+ # list
+ # list : (compare list one vs list two)
+ # string : anything additional wanted to be printed before the string diff
+ # bool : the ordering of the items in the two lists must be the same
+ def report(self, oracle, test, firstText='', strictOrdering = False):
+ stringDiff = ""
+
+ equality = False
+ if not strictOrdering:
+ equality = (Counter(oracle) == Counter(test))
+ else:
+ equality = (oracle == test)
+
+ if equality:
+ return (True, '')
+ elif not strictOrdering:
+ try:
+ for elem in oracle:
+ test.remove(elem)
+ oracle.remove(elem) # If it's not in the test, it won't get here!
+ except ValueError:
+ pass
+
+ differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
+ skipped_lines = 0
+ for delta in differ.compare(oracle, test):
+ if delta[0] == ' ':
+ skipped_lines += 1
+ continue
+ if skipped_lines > 0:
+ stringDiff += "<---" + str(skipped_lines) + ' same lines--->\n'
+ skipped_lines = 0
+ delta = delta.replace('\n', '')
+ stringDiff += delta + '\n'
+
+ stringDiffList = stringDiff.split('\n')
+
+ if len(stringDiffList) > 10:
+ if not verbose:
+ stringDiff = '\n'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10])
+ stringDiff += '\n\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###"
+ elif not verbose:
+ stringDiff = '\n'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList)
+ stringDiff = '\n\n' + firstText + stringDiff
+ return (equality, stringDiff)
+
@classmethod
def setUpClass(self):
self.builder = testcommon.TestBuilder("suite/binaries/test_corpus")
try:
- #Python 2 does not have the encodings option
- self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rUb"), errors="ignore")
+ # Python 2 does not have the encodings option
+ self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rb"), encoding='charmap')
except TypeError:
- self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rU"))
+ self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "r"))
self.verifybuilder = testcommon.VerifyBuilder("suite/binaries/test_corpus")
def run_binary_test(self, testfile):
@@ -29,10 +82,10 @@ class TestBinaryNinjaAPI(unittest.TestCase):
self.assertTrue(os.path.exists(testname + ".pkl"), "Test pickle doesn't exist")
try:
- #Python 2 does not have the encodings option
- binary_oracle = pickle.load(open(testname + ".pkl", "rUb"), errors="ignore")
+ # Python 2 does not have the encodings option
+ binary_oracle = pickle.load(open(testname + ".pkl", "rb"), encoding='charmap')
except TypeError:
- binary_oracle = pickle.load(open(testname + ".pkl", "rU"))
+ binary_oracle = pickle.load(open(testname + ".pkl", "r"))
test_builder = testcommon.BinaryViewTestBuilder(testname, "suite/binaries/test_corpus")
for method in test_builder.methods():
@@ -43,271 +96,93 @@ class TestBinaryNinjaAPI(unittest.TestCase):
result = getattr(test_builder, method).__doc__
result += ":\n"
- d = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in d.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
- self.assertTrue(False, result)
+ report = self.report(oracle, test, result)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
os.unlink(testname)
def test_Architecture(self):
oracle = self.oracle_test_data['test_Architecture']
test = self.builder.test_Architecture()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Architecture_list(self):
oracle = self.oracle_test_data['test_Architecture_list']
test = self.builder.test_Architecture_list()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Assemble(self):
oracle = self.oracle_test_data['test_Assemble']
test = self.builder.test_Assemble()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_BinaryViewType_list(self):
oracle = self.oracle_test_data['test_BinaryViewType_list']
test = self.builder.test_BinaryViewType_list()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Enumeration(self):
oracle = self.oracle_test_data['test_Enumeration']
test = self.builder.test_Enumeration()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Function(self):
oracle = self.oracle_test_data['test_Function']
test = self.builder.test_Function()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Plugin_bin_info(self):
oracle = self.oracle_test_data['test_Plugin_bin_info']
test = self.builder.test_Plugin_bin_info()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Struct(self):
oracle = self.oracle_test_data['test_Struct']
test = self.builder.test_Struct()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_Types(self):
oracle = self.oracle_test_data['test_Types']
test = self.builder.test_Types()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_events(self):
oracle = self.oracle_test_data['test_events']
test = self.builder.test_events()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_linear_disassembly(self):
oracle = self.oracle_test_data['test_linear_disassembly']
test = self.builder.test_linear_disassembly()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_low_il_stack(self):
oracle = self.oracle_test_data['test_low_il_stack']
test = self.builder.test_low_il_stack()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_med_il_stack(self):
oracle = self.oracle_test_data['test_med_il_stack']
test = self.builder.test_med_il_stack()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_partial_register_dataflow(self):
oracle = self.oracle_test_data['test_partial_register_dataflow']
test = self.builder.test_partial_register_dataflow()
- result = ""
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(test, oracle):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- result += "<---" + str(skipped_lines) + ' same lines--->\n'
- skipped_lines = 0
- delta = delta.replace('\n', '')
- result += delta + '\n'
-
- self.assertTrue(oracle == test, result)
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
def test_verify_BNDB_round_trip(self):
self.assertTrue(self.verifybuilder.test_verify_BNDB_round_trip(), self.test_verify_BNDB_round_trip.__doc__)
@@ -386,6 +261,10 @@ class TestBinaryNinjaAPI(unittest.TestCase):
if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ if sys.argv[1] == '-v' or sys.argv[1] == '-V' or sys.argv[1] == '--verbose':
+ verbose = True
+
test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinjaAPI))
runner = unittest.TextTestRunner(verbosity=2)