#!/usr/bin/env pythonfrom __future__ import print_functionimport timeimport sysimport readlineimport argparseimport numexprimport tracebackfrom scarelib import * parser = argparse.ArgumentParser(description="")parser.add_argument('-a', dest='arch', help='Target architecture')parser.add_argument('-c', dest='cpu', help='Target cpu')parser.add_argument('-f', dest='inFile', help='File to read')parser.add_argument('--base', type=lambda x: parseInt(x), dest='baseaddr', help='Base Address (default: 0x400000)')parser.add_argument('--stack', type=lambda x: parseInt(x), dest='stackaddr', help='Stack Address (default: 0x401000)')parser.add_argument('--memsize', dest='memsize', help='Emulator Memory Size (default: 0x800000 [8MB])') ## CommandscmdQuit = ["/exit", "/x", "/quit", "/q"]cmdHelp = ["/", "/help", "/?", "/h"]cmdConf = ["/config", "/c"]cmdPList= ["/list", "/l"] def parseInt(x): return int(numexpr.evaluate(x).item()) # parseCmd# Commands must start with / to be parsed# If 0 is returned, the main command loop will not try to assemble the input# If 1 is returned, then the main command loop should try to assemble the input# If 2 is returned, the main command loop should not append the current command and just assemble and run# If 3 is returned, reinitialize the scaremudef parseCmd(cmd, smu): shouldAssemble = 1 if len(cmd) > 0: if cmd[0] == "/": shouldAssemble = 0 cmdList = cmd.split() cmdListLen = len(cmdList) if cmdList[0] in cmdQuit: sys.exit() if cmdList[0] in cmdHelp: print(helpfile) if cmdList[0] in cmdConf: if cmdListLen == 3 or cmdListLen == 4: try: cfgOptName = cmdList[1] cfgOptVal = cmdList[2] cfgOptExtra = cmdList[3] if cmdListLen == 4 else "" if cfgOptName in sConfig.keys(): third = ("/"+cfgOptExtra) if cfgOptExtra != "" else "" print(f"{cfgOptName}->{cfgOptVal}{third}") # TODO: Keep better track of config option types if cfgOptName == "emu/arch": okArch = cfgOptVal in archez.keys() if okArch: arch = archez[cfgOptVal] if cfgOptExtra in arch["cpus"].keys(): sConfig[cfgOptName] = cfgOptVal sConfig["emu/cpu"] = cfgOptExtra else: print(f"Invalid cpu! Supported cpus: {arch["cpus"].keys()}") else: print(f"Invalid arch! Supported arches: {archez.keys()}") else: sConfig[cfgOptName] = parseInt(cfgOptVal) else: print("Invalid config opt name!") except Exception as e: print(f"Error in /config:") print(traceback.format_exc()) elif cmdListLen == 2: try: cfgOptName = cmdList[1] if cfgOptName in sConfig.keys(): print(f"{cfgOptName} = {sConfig[cfgOptName]}") except Exception as e: print(f"Error in /config:") print(traceback.format_exc()) else: configPrint(sConfig) if cmdList[0] == "/info": if smu: smu.info() else: print("No emulator running!") if cmdList[0] == "/regs": if smu: smu.printRegs() else: print("No emulator running!") if cmdList[0] == "/back": backAmount = parseInt(cmdList[1]) if backAmount <= len(smu.asm_code): smu.asm_code = smu.asm_code[:-backAmount] print(f"Moved back {backAmount} lines to line {len(smu.asm_code)}") shouldAssemble = 2 # Reassemble and run else: print(f"Too far back! You're currently on line {len(smu.asm_code)}") if cmdList[0] == "/load": if cmdListLen > 1: smu.asm_code = loadAsm(cmdList[1], lambda c: parseCmd(c, smu)) currentAddr = sConfig["emu/baseaddr"] else: print("Please specify a filename!") if cmdList[0] == "/save": if cmdListLen > 1: saveAsm(smu.asm_code, cmdList[1]) else: print("Please specify a filename!") if cmdList[0] == "/run": shouldAssemble = 2 # Reassemble and run if cmdList[0] == "/reset": shouldAssemble = 3 # Reinitialize if cmdList[0] in cmdPList: printListing(smu, smu.asm_code, plan9=("plan9" in cmdList)) if cmdList[0] == "/read": if cmdListLen >= 3 and cmdListLen <= 4: try: memout = 0 baseAddr = 0 if cmdList[1][0] == "$": regTarget = cmdList[1].split("$")[1] regValue = smu.readReg(regTarget) if regValue is not None: memout = smu.mu_ctx.mem_read(regValue, parseInt(cmdList[2])) baseAddr = regValue else: baseAddr = parseInt(cmdList[1]) memout = smu.mu_ctx.mem_read(baseAddr, parseInt(cmdList[2])) if memout: if cmdListLen > 3: with open(cmdList[3], "wb") as f: f.truncate() f.write(memout) else: dHex(memout, baseAddr) else: print("Usage: /read {0xaddress|$register} size") except Exception as e: print(e) print("Usage: /read {0xaddress|$register} size") else: print("Usage: /read {0xaddress|$register} size") if cmdList[0] == "/write": if cmdListLen == 3: try: if cmdList[2][0] == '.': with open(cmdList[2], "rb") as f: data = f.read(-1) print(f"{cmdList[2]}: {len(data)} bytes") else: data = bytes.fromhex(cmdList[2]) if cmdList[1][0] == "$": regTarget = cmdList[1].split("$")[1] regValue = smu.readReg(regTarget) if regValue is not None: smu.mu_ctx.mem_write(regValue, data) else: memout = smu.mu_ctx.mem_write(parseInt(cmdList[1]), data) except Exception as e: print(e) print("Usage: /write {0xaddress|$register} hexdata") else: print("Usage: /write {0xaddress|$register} hexdata") if cmdList[0] == "/set": if cmdListLen == 3: try: regTarget = cmdList[1] value = parseInt(cmdList[2]) smu.writeReg(regTarget, value) except Exception as e: print(e) print("Usage: /set register value") else: print("Usage: /set register value") if cmdList[0] == "/get": if cmdListLen >= 2: try: for regTarget in cmdList[1:]: value = smu.readReg(regTarget) print(f"{cRegN} {regTarget}: {value:032x}") except Exception as e: print(e) print("Usage: /get register [register... ]") else: print("Usage: /get register [register... ]") if cmdList[0] == "/dis": try: if cmdListLen == 3: if cmdList[1][0:2] == "0x": instructions4dis = smu.dis(parseInt(cmdList[1]), parseInt(cmdList[2])) printListing(smu, instructions4dis) elif cmdList[1][0] == "$": regTarget = cmdList[1].split("$")[1] regValue = smu.readReg(regTarget) if regValue is not None: instructions4dis = smu.dis(regValue, parseInt(cmdList[2])) printListing(smu, instructions4dis) else: print("Usage: /dis {0xaddress|$register} size") else: print("Usage: /dis {0xaddress|$register} size") except Exception as e: print(e) print("Usage: /dis {0xaddress|$register} size") if cmdList[0] == "/export": try: if cmdListLen == 3: fArch = smu.arch_name if cmdList[1] == "bin": mcLen = len(smu.machine_code) if mcLen > 0: print(f"Exporting {mcLen} bytes of code as raw binary") exportBin(smu.machine_code, "bin", fArch, cmdList[2]) else: print("No machine code to export!") elif cmdList[1] == "elf64": mcLen = len(smu.machine_code) if mcLen > 0: print(f"Exporting {mcLen} bytes of code as ELF64") exportBin(smu.machine_code, "elf64", fArch, cmdList[2]) else: print("No machine code to export!") else: print("Invalid binary type!") else: print("Usage: /export type filename") except Exception as e: print(f"Export Error: {e}") else: shouldAssemble = 0 # Don't do anything if there's no input return shouldAssemble if __name__ == '__main__': args = parser.parse_args() print("Type / for help\n") inFile = args.inFile if args.inFile else "" currentArch = args.arch.lower() if args.arch else "NoArch" currentCpu = args.cpu.lower() if args.cpu else "" if args.stackaddr: sConfig["emu/stackaddr"] = args.stackaddr if args.baseaddr: sConfig["emu/baseaddr"] = args.baseaddr if args.memsize: sConfig["emu/memsize"] = args.memsize if currentArch == "NoArch": print(f"Please select an architecture! Use `/c emu/arch ARCH`.\nSupported arches: {archez.keys()}") smu = False currentAddr = sConfig["emu/baseaddr"] else: sConfig["emu/arch"] = currentArch sConfig["emu/cpu"] = currentCpu smu = scaremu(currentArch, currentCpu) currentAddr = sConfig["emu/baseaddr"] if inFile: smu.asm_code = loadAsm(inFile, lambda c: parseCmd(c, smu)) printSplash() while True: try: cmd = input(f"[{cArchP}{currentArch}]{cIP}{currentAddr:02x}{cEnd}> ") try: shouldAsm = parseCmd(cmd, smu) except: continue if (((smu == False) and (sConfig["emu/arch"] != "NoArch")) or sConfig["emu/arch"] != currentArch or shouldAsm == 3): currentArch = sConfig["emu/arch"] currentCpu = sConfig["emu/cpu"] currentAddr = sConfig["emu/baseaddr"] smu = scaremu(currentArch, currentCpu) if smu != False and shouldAsm: if shouldAsm == 1: smu.asm_code.append(cmd) if len(smu.asm_code) > 0: asmStatus = smu.asm(smu.asm_code) if asmStatus == 0: currentAddr, runStatus = smu.run() if runStatus == 0: smu.printRegs() else: print("run() returned a non-zero value") else: smu.asm_code.pop() # Gets rid of the last line of assembly else: currentAddr = sConfig["emu/baseaddr"] except EOFError: break
#!/usr/bin/env python
from __future__ import print_function
import time
import sys
import readline
import argparse
import numexpr
import traceback
from scarelib import *
parser = argparse.ArgumentParser(description="")
parser.add_argument('-a', dest='arch', help='Target architecture')
parser.add_argument('-c', dest='cpu', help='Target cpu')
parser.add_argument('-f', dest='inFile', help='File to read')
parser.add_argument('--base', type=lambda x: parseInt(x), dest='baseaddr', help='Base Address (default: 0x400000)')
parser.add_argument('--stack', type=lambda x: parseInt(x), dest='stackaddr', help='Stack Address (default: 0x401000)')
parser.add_argument('--memsize', dest='memsize', help='Emulator Memory Size (default: 0x800000 [8MB])')
## Commands
cmdQuit = ["/exit", "/x", "/quit", "/q"]
cmdHelp = ["/", "/help", "/?", "/h"]
cmdConf = ["/config", "/c"]
cmdPList= ["/list", "/l"]
def parseInt(x):
return int(numexpr.evaluate(x).item())
# parseCmd
# Commands must start with / to be parsed
# If 0 is returned, the main command loop will not try to assemble the input
# If 1 is returned, then the main command loop should try to assemble the input
# If 2 is returned, the main command loop should not append the current command and just assemble and run
# If 3 is returned, reinitialize the scaremu
def parseCmd(cmd, smu):
shouldAssemble = 1
if len(cmd) > 0:
if cmd[0] == "/":
shouldAssemble = 0
cmdList = cmd.split()
cmdListLen = len(cmdList)
if cmdList[0] in cmdQuit:
sys.exit()
if cmdList[0] in cmdHelp:
print(helpfile)
if cmdList[0] in cmdConf:
if cmdListLen == 3 or cmdListLen == 4:
try:
cfgOptName = cmdList[1]
cfgOptVal = cmdList[2]
cfgOptExtra = cmdList[3] if cmdListLen == 4 else ""
if cfgOptName in sConfig.keys():
third = ("/"+cfgOptExtra) if cfgOptExtra != "" else ""
print(f"{cfgOptName}->{cfgOptVal}{third}")
# TODO: Keep better track of config option types
if cfgOptName == "emu/arch":
okArch = cfgOptVal in archez.keys()
if okArch:
arch = archez[cfgOptVal]
if cfgOptExtra in arch["cpus"].keys():
sConfig[cfgOptName] = cfgOptVal
sConfig["emu/cpu"] = cfgOptExtra
else:
print(f"Invalid cpu! Supported cpus: {arch["cpus"].keys()}")
else:
print(f"Invalid arch! Supported arches: {archez.keys()}")
else:
sConfig[cfgOptName] = parseInt(cfgOptVal)
else:
print("Invalid config opt name!")
except Exception as e:
print(f"Error in /config:")
print(traceback.format_exc())
elif cmdListLen == 2:
try:
cfgOptName = cmdList[1]
if cfgOptName in sConfig.keys():
print(f"{cfgOptName} = {sConfig[cfgOptName]}")
except Exception as e:
print(f"Error in /config:")
print(traceback.format_exc())
else:
configPrint(sConfig)
if cmdList[0] == "/info":
if smu:
smu.info()
else:
print("No emulator running!")
if cmdList[0] == "/regs":
if smu:
smu.printRegs()
else:
print("No emulator running!")
if cmdList[0] == "/back":
backAmount = parseInt(cmdList[1])
if backAmount <= len(smu.asm_code):
smu.asm_code = smu.asm_code[:-backAmount]
print(f"Moved back {backAmount} lines to line {len(smu.asm_code)}")
shouldAssemble = 2 # Reassemble and run
else:
print(f"Too far back! You're currently on line {len(smu.asm_code)}")
if cmdList[0] == "/load":
if cmdListLen > 1:
smu.asm_code = loadAsm(cmdList[1], lambda c: parseCmd(c, smu))
currentAddr = sConfig["emu/baseaddr"]
else:
print("Please specify a filename!")
if cmdList[0] == "/save":
if cmdListLen > 1:
saveAsm(smu.asm_code, cmdList[1])
else:
print("Please specify a filename!")
if cmdList[0] == "/run":
shouldAssemble = 2 # Reassemble and run
if cmdList[0] == "/reset":
shouldAssemble = 3 # Reinitialize
if cmdList[0] in cmdPList:
printListing(smu, smu.asm_code, plan9=("plan9" in cmdList))
if cmdList[0] == "/read":
if cmdListLen >= 3 and cmdListLen <= 4:
try:
memout = 0
baseAddr = 0
if cmdList[1][0] == "$":
regTarget = cmdList[1].split("$")[1]
regValue = smu.readReg(regTarget)
if regValue is not None:
memout = smu.mu_ctx.mem_read(regValue, parseInt(cmdList[2]))
baseAddr = regValue
else:
baseAddr = parseInt(cmdList[1])
memout = smu.mu_ctx.mem_read(baseAddr, parseInt(cmdList[2]))
if memout:
if cmdListLen > 3:
with open(cmdList[3], "wb") as f:
f.truncate()
f.write(memout)
else:
dHex(memout, baseAddr)
else:
print("Usage: /read {0xaddress|$register} size")
except Exception as e:
print(e)
print("Usage: /read {0xaddress|$register} size")
else:
print("Usage: /read {0xaddress|$register} size")
if cmdList[0] == "/write":
if cmdListLen == 3:
try:
if cmdList[2][0] == '.':
with open(cmdList[2], "rb") as f:
data = f.read(-1)
print(f"{cmdList[2]}: {len(data)} bytes")
else:
data = bytes.fromhex(cmdList[2])
if cmdList[1][0] == "$":
regTarget = cmdList[1].split("$")[1]
regValue = smu.readReg(regTarget)
if regValue is not None:
smu.mu_ctx.mem_write(regValue, data)
else:
memout = smu.mu_ctx.mem_write(parseInt(cmdList[1]), data)
except Exception as e:
print(e)
print("Usage: /write {0xaddress|$register} hexdata")
else:
print("Usage: /write {0xaddress|$register} hexdata")
if cmdList[0] == "/set":
if cmdListLen == 3:
try:
regTarget = cmdList[1]
value = parseInt(cmdList[2])
smu.writeReg(regTarget, value)
except Exception as e:
print(e)
print("Usage: /set register value")
else:
print("Usage: /set register value")
if cmdList[0] == "/get":
if cmdListLen >= 2:
try:
for regTarget in cmdList[1:]:
value = smu.readReg(regTarget)
print(f"{cRegN} {regTarget}: {value:032x}")
except Exception as e:
print(e)
print("Usage: /get register [register... ]")
else:
print("Usage: /get register [register... ]")
if cmdList[0] == "/dis":
try:
if cmdListLen == 3:
if cmdList[1][0:2] == "0x":
instructions4dis = smu.dis(parseInt(cmdList[1]), parseInt(cmdList[2]))
printListing(smu, instructions4dis)
elif cmdList[1][0] == "$":
regTarget = cmdList[1].split("$")[1]
regValue = smu.readReg(regTarget)
if regValue is not None:
instructions4dis = smu.dis(regValue, parseInt(cmdList[2]))
printListing(smu, instructions4dis)
else:
print("Usage: /dis {0xaddress|$register} size")
else:
print("Usage: /dis {0xaddress|$register} size")
except Exception as e:
print(e)
print("Usage: /dis {0xaddress|$register} size")
if cmdList[0] == "/export":
try:
if cmdListLen == 3:
fArch = smu.arch_name
if cmdList[1] == "bin":
mcLen = len(smu.machine_code)
if mcLen > 0:
print(f"Exporting {mcLen} bytes of code as raw binary")
exportBin(smu.machine_code, "bin", fArch, cmdList[2])
else:
print("No machine code to export!")
elif cmdList[1] == "elf64":
mcLen = len(smu.machine_code)
if mcLen > 0:
print(f"Exporting {mcLen} bytes of code as ELF64")
exportBin(smu.machine_code, "elf64", fArch, cmdList[2])
else:
print("No machine code to export!")
else:
print("Invalid binary type!")
else:
print("Usage: /export type filename")
except Exception as e:
print(f"Export Error: {e}")
else:
shouldAssemble = 0 # Don't do anything if there's no input
return shouldAssemble
if __name__ == '__main__':
args = parser.parse_args()
print("Type / for help\n")
inFile = args.inFile if args.inFile else ""
currentArch = args.arch.lower() if args.arch else "NoArch"
currentCpu = args.cpu.lower() if args.cpu else ""
if args.stackaddr:
sConfig["emu/stackaddr"] = args.stackaddr
if args.baseaddr:
sConfig["emu/baseaddr"] = args.baseaddr
if args.memsize:
sConfig["emu/memsize"] = args.memsize
if currentArch == "NoArch":
print(f"Please select an architecture! Use `/c emu/arch ARCH`.\nSupported arches: {archez.keys()}")
smu = False
currentAddr = sConfig["emu/baseaddr"]
else:
sConfig["emu/arch"] = currentArch
sConfig["emu/cpu"] = currentCpu
smu = scaremu(currentArch, currentCpu)
currentAddr = sConfig["emu/baseaddr"]
if inFile:
smu.asm_code = loadAsm(inFile, lambda c: parseCmd(c, smu))
printSplash()
while True:
try:
cmd = input(f"[{cArchP}{currentArch}]{cIP}{currentAddr:02x}{cEnd}> ")
try:
shouldAsm = parseCmd(cmd, smu)
except:
continue
if (((smu == False) and (sConfig["emu/arch"] != "NoArch")) or
sConfig["emu/arch"] != currentArch or
shouldAsm == 3):
currentArch = sConfig["emu/arch"]
currentCpu = sConfig["emu/cpu"]
currentAddr = sConfig["emu/baseaddr"]
smu = scaremu(currentArch, currentCpu)
if smu != False and shouldAsm:
if shouldAsm == 1:
smu.asm_code.append(cmd)
if len(smu.asm_code) > 0:
asmStatus = smu.asm(smu.asm_code)
if asmStatus == 0:
currentAddr, runStatus = smu.run()
if runStatus == 0:
smu.printRegs()
else:
print("run() returned a non-zero value")
else:
smu.asm_code.pop() # Gets rid of the last line of assembly
else:
currentAddr = sConfig["emu/baseaddr"]
except EOFError:
break