mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
Initial Commit
This commit is contained in:
1 parent
e9ea4cbb76
commit
369686c992
73 files changed
+8820
-4
No files matched your search
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/python3
|
||||
from enum import Flag
|
||||
import json
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import glob
|
||||
from threading import Thread
|
||||
import subprocess
|
||||
import time
|
||||
import multiprocessing
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
raise Exception("Python 3 or a more recent version is required.")
|
||||
|
||||
if (len(sys.argv) < 3):
|
||||
sys.exit("We need two arguments. Location of LockStepRunner and folder containing the tests")
|
||||
|
||||
# Remove our SHM regions if they still exist
|
||||
SHM_Files = glob.glob("/dev/shm/*_Lockstep")
|
||||
for file in SHM_Files:
|
||||
os.remove(file)
|
||||
|
||||
UnitTests = sorted(glob.glob(sys.argv[2] + "*"))
|
||||
UnitTestsSize = len(UnitTests)
|
||||
Threads = [None] * UnitTestsSize
|
||||
Results = [None] * UnitTestsSize
|
||||
ThreadResults = [[None] * 2] * UnitTestsSize
|
||||
MaxFileNameStringLen = 0
|
||||
|
||||
def Threaded_Runner(Args, ID, Client):
|
||||
Log = open("Log_" + str(ID) + "_" + str(Client), "w")
|
||||
Log.write("Args: %s\n" % " ".join(Args))
|
||||
Log.flush()
|
||||
Process = subprocess.Popen(Args, stdout=Log, stderr=Log)
|
||||
Process.wait()
|
||||
Log.flush()
|
||||
ThreadResults[ID][Client] = Process.returncode
|
||||
|
||||
def Threaded_Manager(Runner, ID, File):
|
||||
ServerArgs = ["catchsegv", Runner, "-c", "vm", "-n", "1", "-I", "R" + str(ID), File]
|
||||
ClientArgs = ["catchsegv", Runner, "-c", "vm", "-n", "1", "-I", "R" + str(ID), "-C"]
|
||||
|
||||
ServerThread = Thread(target = Threaded_Runner, args = (ServerArgs, ID, 0))
|
||||
ClientThread = Thread(target = Threaded_Runner, args = (ClientArgs, ID, 1))
|
||||
|
||||
ServerThread.start()
|
||||
ClientThread.start()
|
||||
|
||||
ClientThread.join()
|
||||
ServerThread.join()
|
||||
|
||||
# The server is the one we should listen to for results
|
||||
if (ThreadResults[ID][1] != 0 and ThreadResults[ID][0] == 0):
|
||||
# If the client died for some reason but server thought we were fine then take client data
|
||||
Results[ID] = ThreadResults[ID][1]
|
||||
else:
|
||||
# Else just take the server data
|
||||
Results[ID] = ThreadResults[ID][0]
|
||||
|
||||
DupLen = MaxFileNameStringLen - len(UnitTests[ID])
|
||||
|
||||
if (Results[ID] == 0):
|
||||
print("\t'%s'%s - PASSED ID: %d - 0" % (UnitTests[ID], " "*DupLen, ID))
|
||||
else:
|
||||
print("\t'%s'%s - FAILED ID: %d - %s" % (UnitTests[ID], " "*DupLen, ID, hex(Results[ID])))
|
||||
|
||||
RunnerSlot = 0
|
||||
MaxRunnerSlots = min(32, multiprocessing.cpu_count() / 2)
|
||||
RunnerSlots = [None] * MaxRunnerSlots
|
||||
for RunnerID in range(UnitTestsSize):
|
||||
File = UnitTests[RunnerID]
|
||||
print("'%s' Running Test" % File)
|
||||
MaxFileNameStringLen = max(MaxFileNameStringLen, len(File))
|
||||
Threads[RunnerID] = Thread(target = Threaded_Manager, args = (sys.argv[1], RunnerID, File))
|
||||
Threads[RunnerID].start()
|
||||
if (MaxRunnerSlots != 0):
|
||||
RunnerSlots[RunnerSlot] = Threads[RunnerID]
|
||||
RunnerSlot += 1
|
||||
if (RunnerSlot == MaxRunnerSlots):
|
||||
for i in range(MaxRunnerSlots):
|
||||
RunnerSlots[i].join()
|
||||
RunnerSlot = 0
|
||||
|
||||
for i in range(UnitTestsSize):
|
||||
Threads[i].join()
|
||||
|
||||
print("====== PASSED RESULTS ======")
|
||||
for i in range(UnitTestsSize):
|
||||
DupLen = MaxFileNameStringLen - len(UnitTests[i])
|
||||
if (Results[i] == 0):
|
||||
print("\t'%s'%s - PASSED ID: %d - 0" % (UnitTests[i], " "*DupLen, i))
|
||||
|
||||
print("====== FAILED RESULTS ======")
|
||||
for i in range(UnitTestsSize):
|
||||
DupLen = MaxFileNameStringLen - len(UnitTests[i])
|
||||
if (Results[i] != 0):
|
||||
print("\t'%s'%s - FAILED ID: %d - %s" % (UnitTests[i], " "*DupLen, i, hex(Results[i])))
|
||||
@@ -0,0 +1,229 @@
|
||||
from enum import Flag
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
|
||||
class Regs(Flag):
|
||||
REG_NONE = 0
|
||||
REG_RIP = (1 << 0)
|
||||
REG_RAX = (1 << 1)
|
||||
REG_RBX = (1 << 2)
|
||||
REG_RCX = (1 << 3)
|
||||
REG_RDX = (1 << 4)
|
||||
REG_RSI = (1 << 5)
|
||||
REG_RDI = (1 << 6)
|
||||
REG_RBP = (1 << 7)
|
||||
REG_RSP = (1 << 8)
|
||||
REG_R8 = (1 << 9)
|
||||
REG_R9 = (1 << 10)
|
||||
REG_R10 = (1 << 11)
|
||||
REG_R11 = (1 << 12)
|
||||
REG_R12 = (1 << 13)
|
||||
REG_R13 = (1 << 14)
|
||||
REG_R14 = (1 << 15)
|
||||
REG_R15 = (1 << 16)
|
||||
REG_XMM0 = (1 << 17)
|
||||
REG_XMM1 = (1 << 18)
|
||||
REG_XMM2 = (1 << 19)
|
||||
REG_XMM3 = (1 << 20)
|
||||
REG_XMM4 = (1 << 21)
|
||||
REG_XMM5 = (1 << 22)
|
||||
REG_XMM6 = (1 << 23)
|
||||
REG_XMM7 = (1 << 24)
|
||||
REG_XMM8 = (1 << 25)
|
||||
REG_XMM9 = (1 << 26)
|
||||
REG_XMM10 = (1 << 27)
|
||||
REG_XMM11 = (1 << 28)
|
||||
REG_XMM12 = (1 << 29)
|
||||
REG_XMM13 = (1 << 30)
|
||||
REG_XMM14 = (1 << 31)
|
||||
REG_XMM15 = (1 << 32)
|
||||
REG_GS = (1 << 33)
|
||||
REG_FS = (1 << 34)
|
||||
REG_FLAGS = (1 << 35)
|
||||
REG_ALL = (1 << 36) - 1
|
||||
REG_INVALID = (1 << 36)
|
||||
|
||||
class ABI(Flag) :
|
||||
ABI_SYSTEMV = 0
|
||||
ABI_WIN64 = 1
|
||||
ABI_NONE = 2
|
||||
|
||||
RegStringLookup = {
|
||||
"NONE": Regs.REG_NONE,
|
||||
"RAX": Regs.REG_RAX,
|
||||
"RIP": Regs.REG_RIP,
|
||||
"RBX": Regs.REG_RBX,
|
||||
"RCX": Regs.REG_RCX,
|
||||
"RDX": Regs.REG_RDX,
|
||||
"RSI": Regs.REG_RSI,
|
||||
"RDI": Regs.REG_RDI,
|
||||
"RBP": Regs.REG_RBP,
|
||||
"RSP": Regs.REG_RSP,
|
||||
"R8": Regs.REG_R8,
|
||||
"R9": Regs.REG_R9,
|
||||
"R10": Regs.REG_R10,
|
||||
"R11": Regs.REG_R11,
|
||||
"R12": Regs.REG_R12,
|
||||
"R13": Regs.REG_R13,
|
||||
"R14": Regs.REG_R14,
|
||||
"R15": Regs.REG_R15,
|
||||
"XMM0": Regs.REG_XMM0,
|
||||
"XMM1": Regs.REG_XMM1,
|
||||
"XMM2": Regs.REG_XMM2,
|
||||
"XMM3": Regs.REG_XMM3,
|
||||
"XMM4": Regs.REG_XMM4,
|
||||
"XMM5": Regs.REG_XMM5,
|
||||
"XMM6": Regs.REG_XMM6,
|
||||
"XMM7": Regs.REG_XMM7,
|
||||
"XMM8": Regs.REG_XMM8,
|
||||
"XMM9": Regs.REG_XMM9,
|
||||
"XMM10": Regs.REG_XMM10,
|
||||
"XMM11": Regs.REG_XMM11,
|
||||
"XMM12": Regs.REG_XMM12,
|
||||
"XMM13": Regs.REG_XMM13,
|
||||
"XMM14": Regs.REG_XMM14,
|
||||
"XMM15": Regs.REG_XMM15,
|
||||
"GS": Regs.REG_GS,
|
||||
"FS": Regs.REG_FS,
|
||||
"FLAGS": Regs.REG_FLAGS,
|
||||
"ALL": Regs.REG_ALL,
|
||||
}
|
||||
|
||||
ABIStringLookup = {
|
||||
"SYSTEMV": ABI.ABI_SYSTEMV,
|
||||
"WIN64": ABI.ABI_WIN64,
|
||||
"NONE": ABI.ABI_NONE,
|
||||
}
|
||||
|
||||
if (len(sys.argv) < 3):
|
||||
sys.exit()
|
||||
|
||||
output_file = sys.argv[2]
|
||||
asm_file = open(sys.argv[1], "r")
|
||||
asm_text = asm_file.read()
|
||||
asm_file.close()
|
||||
|
||||
# Default options
|
||||
OptionMatch = Regs.REG_INVALID
|
||||
OptionIgnore = Regs.REG_NONE
|
||||
OptionABI = ABI.ABI_SYSTEMV
|
||||
OptionStackSize = 4096
|
||||
OptionEntryPoint = 1
|
||||
OptionRegData = {}
|
||||
OptionMemoryRegions = {}
|
||||
|
||||
json_text = asm_text.split("%ifdef CONFIG")
|
||||
if (len(json_text) > 1):
|
||||
json_text = json_text[1].split("%endif")
|
||||
if (len(json_text) > 1):
|
||||
json_text = json_text[0].strip()
|
||||
|
||||
json_object = json.loads(json_text)
|
||||
json_object = {k.upper(): v for k, v in json_object.items()}
|
||||
|
||||
# Begin parsing the JSON
|
||||
if ("MATCH" in json_object):
|
||||
data = json_object["MATCH"]
|
||||
if (type(data) is str):
|
||||
data = [data]
|
||||
|
||||
for data_val in data:
|
||||
data_val = data_val.upper()
|
||||
if not (data_val in RegStringLookup):
|
||||
sys.exit("Invalid Match register option")
|
||||
if (OptionMatch == Regs.REG_INVALID):
|
||||
OptionMatch = Regs.REG_NONE
|
||||
RegOption = RegStringLookup[data_val]
|
||||
OptionMatch = OptionMatch | RegOption
|
||||
|
||||
if ("IGNORE" in json_object):
|
||||
data = json_object["IGNORE"]
|
||||
if (type(data) is str):
|
||||
data = [data]
|
||||
|
||||
for data_val in data:
|
||||
data_val = data_val.upper()
|
||||
if not (data_val in RegStringLookup):
|
||||
sys.exit("Invalid Ignore register option")
|
||||
if (OptionMatch == Regs.REG_INVALID):
|
||||
OptionMatch = Regs.REG_NONE
|
||||
RegOption = RegStringLookup[data_val]
|
||||
OptionIgnore = OptionIgnore | RegOption
|
||||
|
||||
if ("ABI" in json_object):
|
||||
data = json_object["ABI"]
|
||||
data = data.upper()
|
||||
if not (data in ABIStringLookup):
|
||||
sys.exit("Invalid ABI")
|
||||
OptionABI = ABIStringLookup[data]
|
||||
|
||||
if ("STACKSIZE" in json_object):
|
||||
data = json_object["STACKSIZE"]
|
||||
OptionStackSize = int(data, 0)
|
||||
|
||||
if ("ENTRYPOINT" in json_object):
|
||||
data = json_object["ENTRYPOINT"]
|
||||
data = int(data, 0)
|
||||
if (data == 0):
|
||||
sys.exit("Invalid entrypoint of 0")
|
||||
OptionEntryPoint = data
|
||||
|
||||
if ("MEMORYREGIONS" in json_object):
|
||||
data = json_object["MEMORYREGIONS"]
|
||||
if not (type(data) is dict):
|
||||
sys.exit("RegData value must be list of key:value pairs")
|
||||
for data_key, data_val in data.items():
|
||||
OptionMemoryRegions[int(data_key, 0)] = int(data_val, 0);
|
||||
|
||||
if ("REGDATA" in json_object):
|
||||
data = json_object["REGDATA"]
|
||||
if not (type(data) is dict):
|
||||
sys.exit("RegData value must be list of key:value pairs")
|
||||
for data_key, data_val in data.items():
|
||||
data_key = data_key.upper()
|
||||
if not (data_key in RegStringLookup):
|
||||
sys.exit("Invalid RegData register option")
|
||||
|
||||
data_key_index = RegStringLookup[data_key]
|
||||
data_key_values = []
|
||||
|
||||
# Create a list of values for this register as an integer
|
||||
if (type(data_val) is list):
|
||||
for data_key_value in data_val:
|
||||
data_key_values.append(int(data_key_value, 0))
|
||||
else:
|
||||
data_key_values.append(int(data_val, 0))
|
||||
OptionRegData[data_key_index] = data_key_values
|
||||
|
||||
# If Match option wasn't touched then set it to the default
|
||||
if (OptionMatch == Regs.REG_INVALID):
|
||||
OptionMatch = Regs.REG_NONE
|
||||
|
||||
config_file = open(output_file, "wb")
|
||||
config_file.write(struct.pack('Q', OptionMatch.value))
|
||||
config_file.write(struct.pack('Q', OptionIgnore.value))
|
||||
config_file.write(struct.pack('Q', OptionStackSize))
|
||||
config_file.write(struct.pack('Q', OptionEntryPoint))
|
||||
config_file.write(struct.pack('I', OptionABI.value))
|
||||
|
||||
# Number of memory regions
|
||||
config_file.write(struct.pack('I', len(OptionMemoryRegions)))
|
||||
|
||||
# Number of register values
|
||||
config_file.write(struct.pack('I', len(OptionRegData)))
|
||||
|
||||
# Print number of memory regions
|
||||
for reg_key, reg_val in OptionMemoryRegions.items():
|
||||
config_file.write(struct.pack('Q', reg_key))
|
||||
config_file.write(struct.pack('Q', reg_val))
|
||||
|
||||
# Print Register values
|
||||
for reg_key, reg_val in OptionRegData.items():
|
||||
config_file.write(struct.pack('I', len(reg_val)))
|
||||
config_file.write(struct.pack('Q', reg_key.value))
|
||||
for reg_vals in reg_val:
|
||||
config_file.write(struct.pack('Q', reg_vals))
|
||||
|
||||
config_file.close()
|
||||
|
||||
Reference in new issue
Block a user