mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-17 05:40:48 +00:00

*** to conform to clang-format’s LLVM style. This kind of mass change has *** two obvious implications: Firstly, merging this particular commit into a downstream fork may be a huge effort. Alternatively, it may be worth merging all changes up to this commit, performing the same reformatting operation locally, and then discarding the merge for this particular commit. The commands used to accomplish this reformatting were as follows (with current working directory as the root of the repository): find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} + find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ; The version of clang-format used was 3.9.0, and autopep8 was 1.2.4. Secondly, “blame” style tools will generally point to this commit instead of a meaningful prior commit. There are alternatives available that will attempt to look through this change and find the appropriate prior commit. YMMV. llvm-svn: 280751
231 lines
6.3 KiB
Python
Executable File
231 lines
6.3 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
import argparse
|
|
import datetime
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Run an exhaustive test of the LLDB disassembler for a specific architecture.")
|
|
|
|
parser.add_argument(
|
|
'--arch',
|
|
required=True,
|
|
action='store',
|
|
help='The architecture whose disassembler is to be tested')
|
|
parser.add_argument(
|
|
'--bytes',
|
|
required=True,
|
|
action='store',
|
|
type=int,
|
|
help='The byte width of instructions for that architecture')
|
|
parser.add_argument(
|
|
'--random',
|
|
required=False,
|
|
action='store_true',
|
|
help='Enables non-sequential testing')
|
|
parser.add_argument(
|
|
'--start',
|
|
required=False,
|
|
action='store',
|
|
type=int,
|
|
help='The first instruction value to test')
|
|
parser.add_argument(
|
|
'--skip',
|
|
required=False,
|
|
action='store',
|
|
type=int,
|
|
help='The interval between instructions to test')
|
|
parser.add_argument(
|
|
'--log',
|
|
required=False,
|
|
action='store',
|
|
help='A log file to write the most recent instruction being tested')
|
|
parser.add_argument(
|
|
'--time',
|
|
required=False,
|
|
action='store_true',
|
|
help='Every 100,000 instructions, print an ETA to standard out')
|
|
parser.add_argument(
|
|
'--lldb',
|
|
required=False,
|
|
action='store',
|
|
help='The path to LLDB.framework, if LLDB should be overridden')
|
|
|
|
arguments = sys.argv[1:]
|
|
|
|
arg_ns = parser.parse_args(arguments)
|
|
|
|
|
|
def AddLLDBToSysPathOnMacOSX():
|
|
def GetLLDBFrameworkPath():
|
|
lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"])
|
|
re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path)
|
|
if re_result is None:
|
|
return None
|
|
xcode_contents_path = re_result.group(1)
|
|
return xcode_contents_path + "/SharedFrameworks/LLDB.framework"
|
|
|
|
lldb_framework_path = GetLLDBFrameworkPath()
|
|
|
|
if lldb_framework_path is None:
|
|
print "Couldn't find LLDB.framework"
|
|
sys.exit(-1)
|
|
|
|
sys.path.append(lldb_framework_path + "/Resources/Python")
|
|
|
|
if arg_ns.lldb is None:
|
|
AddLLDBToSysPathOnMacOSX()
|
|
else:
|
|
sys.path.append(arg_ns.lldb + "/Resources/Python")
|
|
|
|
import lldb
|
|
|
|
debugger = lldb.SBDebugger.Create()
|
|
|
|
if debugger.IsValid() == False:
|
|
print "Couldn't create an SBDebugger"
|
|
sys.exit(-1)
|
|
|
|
target = debugger.CreateTargetWithFileAndArch(None, arg_ns.arch)
|
|
|
|
if target.IsValid() == False:
|
|
print "Couldn't create an SBTarget for architecture " + arg_ns.arch
|
|
sys.exit(-1)
|
|
|
|
|
|
def ResetLogFile(log_file):
|
|
if log_file != sys.stdout:
|
|
log_file.seek(0)
|
|
|
|
|
|
def PrintByteArray(log_file, byte_array):
|
|
for byte in byte_array:
|
|
print >>log_file, hex(byte) + " ",
|
|
print >>log_file
|
|
|
|
|
|
class SequentialInstructionProvider:
|
|
|
|
def __init__(self, byte_width, log_file, start=0, skip=1):
|
|
self.m_byte_width = byte_width
|
|
self.m_log_file = log_file
|
|
self.m_start = start
|
|
self.m_skip = skip
|
|
self.m_value = start
|
|
self.m_last = (1 << (byte_width * 8)) - 1
|
|
|
|
def PrintCurrentState(self, ret):
|
|
ResetLogFile(self.m_log_file)
|
|
print >>self.m_log_file, self.m_value
|
|
PrintByteArray(self.m_log_file, ret)
|
|
|
|
def GetNextInstruction(self):
|
|
if self.m_value > self.m_last:
|
|
return None
|
|
ret = bytearray(self.m_byte_width)
|
|
for i in range(self.m_byte_width):
|
|
ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255
|
|
self.PrintCurrentState(ret)
|
|
self.m_value += self.m_skip
|
|
return ret
|
|
|
|
def GetNumInstructions(self):
|
|
return (self.m_last - self.m_start) / self.m_skip
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def next(self):
|
|
ret = self.GetNextInstruction()
|
|
if ret is None:
|
|
raise StopIteration
|
|
return ret
|
|
|
|
|
|
class RandomInstructionProvider:
|
|
|
|
def __init__(self, byte_width, log_file):
|
|
self.m_byte_width = byte_width
|
|
self.m_log_file = log_file
|
|
self.m_random_file = open("/dev/random", 'r')
|
|
|
|
def PrintCurrentState(self, ret):
|
|
ResetLogFile(self.m_log_file)
|
|
PrintByteArray(self.m_log_file, ret)
|
|
|
|
def GetNextInstruction(self):
|
|
ret = bytearray(self.m_byte_width)
|
|
for i in range(self.m_byte_width):
|
|
ret[i] = self.m_random_file.read(1)
|
|
self.PrintCurrentState(ret)
|
|
return ret
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def next(self):
|
|
ret = self.GetNextInstruction()
|
|
if ret is None:
|
|
raise StopIteration
|
|
return ret
|
|
|
|
log_file = None
|
|
|
|
|
|
def GetProviderWithArguments(args):
|
|
global log_file
|
|
if args.log is not None:
|
|
log_file = open(args.log, 'w')
|
|
else:
|
|
log_file = sys.stdout
|
|
instruction_provider = None
|
|
if args.random:
|
|
instruction_provider = RandomInstructionProvider(args.bytes, log_file)
|
|
else:
|
|
start = 0
|
|
skip = 1
|
|
if args.start is not None:
|
|
start = args.start
|
|
if args.skip is not None:
|
|
skip = args.skip
|
|
instruction_provider = SequentialInstructionProvider(
|
|
args.bytes, log_file, start, skip)
|
|
return instruction_provider
|
|
|
|
instruction_provider = GetProviderWithArguments(arg_ns)
|
|
|
|
fake_address = lldb.SBAddress()
|
|
|
|
actually_time = arg_ns.time and not arg_ns.random
|
|
|
|
if actually_time:
|
|
num_instructions_logged = 0
|
|
total_num_instructions = instruction_provider.GetNumInstructions()
|
|
start_time = time.time()
|
|
|
|
for inst_bytes in instruction_provider:
|
|
if actually_time:
|
|
if (num_instructions_logged != 0) and (
|
|
num_instructions_logged % 100000 == 0):
|
|
curr_time = time.time()
|
|
elapsed_time = curr_time - start_time
|
|
remaining_time = float(
|
|
total_num_instructions - num_instructions_logged) * (
|
|
float(elapsed_time) / float(num_instructions_logged))
|
|
print str(datetime.timedelta(seconds=remaining_time))
|
|
num_instructions_logged = num_instructions_logged + 1
|
|
inst_list = target.GetInstructions(fake_address, inst_bytes)
|
|
if not inst_list.IsValid():
|
|
print >>log_file, "Invalid instruction list"
|
|
continue
|
|
inst = inst_list.GetInstructionAtIndex(0)
|
|
if not inst.IsValid():
|
|
print >>log_file, "Invalid instruction"
|
|
continue
|
|
instr_output_stream = lldb.SBStream()
|
|
inst.GetDescription(instr_output_stream)
|
|
print >>log_file, instr_output_stream.GetData()
|