mirror of
https://github.com/bitdefender/bddisasm.git
synced 2024-11-25 00:48:09 +00:00
179 lines
4.9 KiB
Python
179 lines
4.9 KiB
Python
#
|
|
# Copyright (c) 2020 Bitdefender
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import os
|
|
import sys
|
|
import glob
|
|
import shutil
|
|
from zipfile import ZipFile
|
|
from pathlib import Path
|
|
|
|
TEMP_PATH = "!temp"
|
|
|
|
# A test file-name contains some indicators as to how the emulation should be done:
|
|
# - If '_16' is present in the name, emulation will be done on 16 bit
|
|
# - If '_32' is present in the name, emulation will be done on 32 bit
|
|
# - If '_64' is present in the name, emulation will be done on 64 bit
|
|
# - If '_r0' is present in the name, emulation will be done as kernel code
|
|
# A test case consists of minimum two files:
|
|
# - An '.test' file, containing the binary code to be emulated
|
|
# - An '.result' file, containing the emulation output
|
|
# A test is considered passed if the output produced during emulation is identical to the
|
|
# output containted in the '.result' file.
|
|
|
|
#
|
|
# test_dir
|
|
#
|
|
# Runs the tests inside the provided directory.
|
|
# Returns a tuplecontaining the total number of tests run and the number of failed tests.
|
|
#
|
|
def test_dir(dir, arch='x86'):
|
|
total_tests = 0
|
|
failed_tests = 0
|
|
|
|
for f in glob.glob('%s\\*.test' % dir):
|
|
base, _ = os.path.splitext(f)
|
|
|
|
tst_file = f
|
|
res_file = base + '.result'
|
|
tmp_file = base + '.temp'
|
|
|
|
if 0 < tst_file.find('_16'):
|
|
mod = '-b16'
|
|
elif 0 < tst_file.find('_32'):
|
|
mod = '-b32'
|
|
else:
|
|
mod = '-b64'
|
|
|
|
if 0 < tst_file.find('_r0'):
|
|
mod += ' -k'
|
|
|
|
print(' * Running test case %s...' % tst_file)
|
|
os.system('disasm shemu %s -f %s >%s' % (mod, tst_file, tmp_file))
|
|
try:
|
|
res = open(res_file).read()
|
|
except:
|
|
print(' ! No result file provided for test %s!' % tst_file)
|
|
|
|
try:
|
|
tmp = open(tmp_file).read()
|
|
except:
|
|
print(' ! No result produced by test %s!' % tst_file)
|
|
|
|
total_tests += 1
|
|
if res != tmp:
|
|
print(' **** FAILED! ****')
|
|
failed_tests += 1
|
|
else:
|
|
print(' * Passed.')
|
|
|
|
# Cleanup.
|
|
os.remove(tmp_file)
|
|
os.remove(tst_file + "_decoded.bin")
|
|
|
|
return (total_tests, failed_tests)
|
|
|
|
#
|
|
# regenerate
|
|
#
|
|
def regenerate(dir, arch='x86'):
|
|
for f in glob.glob('%s\\*.test' % dir):
|
|
base, _ = os.path.splitext(f)
|
|
|
|
tst_file = f
|
|
res_file = base + '.result'
|
|
|
|
if 0 < f.find('_16'):
|
|
mod = '-b16'
|
|
elif 0 < f.find('_32'):
|
|
mod = '-b32'
|
|
else:
|
|
mod = '-b64'
|
|
|
|
if 0 < f.find('_r0'):
|
|
mod += ' -k'
|
|
|
|
print(' * Regenerating test case %s...' % tst_file)
|
|
os.system('disasm -exi shemu %s -f %s >%s' % (mod, tst_file, res_file))
|
|
|
|
# Cleanup.
|
|
os.remove(tst_file + "_decoded.bin")
|
|
|
|
#
|
|
# parse_dir_rec
|
|
#
|
|
def parse_dir_rec(dir, arch, handler):
|
|
for f in glob.glob(dir + "\\*"):
|
|
path, name = os.path.split(f)
|
|
if name in ['.', '..']:
|
|
continue
|
|
if os.path.isdir(f):
|
|
parse_dir_rec(f, arch, handler)
|
|
handler(f, arch)
|
|
|
|
|
|
#
|
|
# test_archive
|
|
#
|
|
def test_archive(filename, arch='x86'):
|
|
cleanup_files = []
|
|
|
|
# Run the x86 test.
|
|
print("Extracting test archive...")
|
|
with ZipFile(filename) as zf:
|
|
cleanup_files = zf.namelist()
|
|
zf.extractall(path=TEMP_PATH)
|
|
zf.close()
|
|
|
|
print("Running tests...")
|
|
total_tests, failed_tests = 0, 0
|
|
for dn in glob.glob(os.path.join(TEMP_PATH, "*")):
|
|
if not os.path.isdir(dn):
|
|
continue
|
|
print('Testing %s...' % dn)
|
|
cnt_tests, cnt_failed = test_dir(dn, arch)
|
|
|
|
total_tests += cnt_tests
|
|
failed_tests += cnt_failed
|
|
|
|
print("========================================================================")
|
|
print("Summary:")
|
|
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
|
|
print("========================================================================")
|
|
print()
|
|
|
|
shutil.rmtree(TEMP_PATH)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# No arguments provided, auto-run all tests.
|
|
if len(sys.argv) == 1:
|
|
print("Running x86 tests...")
|
|
test_archive("x86\\bdshemu_test_x86.zip")
|
|
|
|
sys.exit(0)
|
|
|
|
opt_dir = ""
|
|
opt_regen = False
|
|
opt_arch = 'x86'
|
|
|
|
for arg in sys.argv[1:]:
|
|
if os.path.isdir(arg):
|
|
print("Will test directory", arg)
|
|
opt_dir = arg
|
|
if arg == "regenerate":
|
|
print("Will regenerate tests...")
|
|
opt_regen = True
|
|
|
|
print("Identified architecture: ", opt_arch)
|
|
|
|
# Single directory test.
|
|
if not opt_dir:
|
|
print("A directory containing tests must be supplied!")
|
|
sys.exit(-1)
|
|
|
|
if opt_regen:
|
|
parse_dir_rec(opt_dir, opt_arch, regenerate)
|
|
else:
|
|
parse_dir_rec(opt_dir, opt_arch, test_dir) |