mirror of
https://github.com/kinnay/Wii-U-Firmware-Emulator.git
synced 2025-04-02 10:41:41 -04:00
666 lines
19 KiB
Python
666 lines
19 KiB
Python
|
|
import pyemu
|
|
import log
|
|
import time
|
|
import struct
|
|
|
|
|
|
class BreakpointHandler:
|
|
def __init__(self, interpreter):
|
|
self.interpreter = interpreter
|
|
self.callbacks = {}
|
|
self.callbacks_write = {}
|
|
self.callbacks_read = {}
|
|
|
|
def add(self, addr, callback):
|
|
self.interpreter.add_breakpoint(addr)
|
|
if addr not in self.callbacks:
|
|
self.callbacks[addr] = []
|
|
self.callbacks[addr].append(callback)
|
|
|
|
def remove(self, addr, callback):
|
|
self.interpreter.remove_breakpoint(addr)
|
|
self.callbacks[addr].remove(callback)
|
|
|
|
def watch(self, write, addr, callback):
|
|
self.interpreter.add_watchpoint(write, addr)
|
|
|
|
callbacks = self.callbacks_write if write else self.callbacks_read
|
|
if addr not in callbacks:
|
|
callbacks[addr] = []
|
|
callbacks[addr].append(callback)
|
|
|
|
def unwatch(self, write, addr, callback):
|
|
self.interpreter.remove_watchpoint(write, addr)
|
|
callbacks = self.callbacks_write if write else self.callbacks_read
|
|
callbacks[addr].remove(callback)
|
|
|
|
def handle(self, addr):
|
|
for callback in self.callbacks[addr]:
|
|
callback(addr)
|
|
|
|
def handle_watch(self, addr, write):
|
|
callbacks = self.callbacks_write if write else self.callbacks_read
|
|
for callback in callbacks[addr]:
|
|
callback(addr, write)
|
|
|
|
|
|
class MemoryReader:
|
|
def __init__(self, physmem, virtmem, mirror):
|
|
self.physmem = physmem
|
|
self.virtmem = virtmem
|
|
self.mirror = mirror
|
|
|
|
def read(self, addr, len, trans=True):
|
|
if trans:
|
|
addr = self.virtmem.translate(addr)
|
|
if self.mirror and addr >= 0xFFE00000:
|
|
addr = addr - 0xFFE00000 + 0x08000000
|
|
return self.physmem.read(addr, len)
|
|
|
|
def string(self, addr, trans=True):
|
|
data = b""
|
|
char = self.read(addr, 1, trans)
|
|
while char != b"\0":
|
|
data += char
|
|
addr += 1
|
|
char = self.read(addr, 1, trans)
|
|
return data.decode("ascii")
|
|
|
|
def u32(self, addr, trans=True):
|
|
return struct.unpack(">I", self.read(addr, 4, trans))[0]
|
|
|
|
|
|
class MemoryWriter:
|
|
def __init__(self, physmem, virtmem, mirror):
|
|
self.physmem = physmem
|
|
self.virtmem = virtmem
|
|
self.mirror = mirror
|
|
|
|
def write(self, addr, data, trans=True):
|
|
if trans:
|
|
addr = self.virtmem.translate(addr, trans)
|
|
if self.mirror and addr >= 0xFFE00000:
|
|
addr = addr - 0xFFE00000 + 0x08000000
|
|
self.physmem.write(addr, data)
|
|
|
|
|
|
class ArgParser:
|
|
|
|
#States
|
|
NEXT = 0
|
|
SIMPLE = 1
|
|
STRING = 2
|
|
ESCAPE = 3
|
|
|
|
def __init__(self):
|
|
self.args = []
|
|
self.argtext = ""
|
|
self.strchar = None #" or '
|
|
|
|
def parse(self, data):
|
|
self.state = self.NEXT
|
|
for char in data:
|
|
self.process(char)
|
|
if self.argtext:
|
|
self.args.append(self.argtext)
|
|
self.argtext = ""
|
|
|
|
def process(self, char):
|
|
if self.state == self.NEXT:
|
|
if char != " ":
|
|
if char in ['"', "'"]:
|
|
self.state = self.STRING
|
|
self.argtext = ""
|
|
self.strchar = char
|
|
else:
|
|
self.state = self.SIMPLE
|
|
self.argtext = char
|
|
|
|
elif self.state == self.SIMPLE:
|
|
if char == " ":
|
|
self.state = self.NEXT
|
|
self.args.append(self.argtext)
|
|
self.argtext = ""
|
|
else:
|
|
self.argtext += char
|
|
|
|
elif self.state == self.STRING:
|
|
if char == self.strchar:
|
|
self.state = self.NEXT
|
|
self.args.append(self.argtext)
|
|
self.argtext = ""
|
|
elif char == "\\":
|
|
self.state = self.ESCAPE
|
|
else:
|
|
self.argtext += char
|
|
|
|
elif self.state == self.ESCAPE:
|
|
if char in ['"', "'", "\\"]:
|
|
self.argtext += char
|
|
else:
|
|
self.argtext += "\\" + char
|
|
self.state = self.STRING
|
|
|
|
|
|
class Command:
|
|
def __init__(self, min_args, max_args, func, usage):
|
|
self.min_args = min_args
|
|
self.max_args = max_args
|
|
self.func = func
|
|
self.usage = usage
|
|
|
|
def call(self, args):
|
|
if len(args) < self.min_args:
|
|
self.print_usage()
|
|
else:
|
|
if len(args) > self.max_args and self.max_args != 0:
|
|
args = args[:self.max_args - 1] + [" ".join(args[self.max_args - 1:])]
|
|
self.func(*args)
|
|
|
|
def print_usage(self):
|
|
print("Usage: %s" %self.usage)
|
|
|
|
|
|
printables = "\0\n\t\"\\ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
|
"1234567890!@#$%^&*()-_=+[]{}|;:'/?.,<>`~"
|
|
def is_printable(data):
|
|
return all(chr(char) in printables for char in data)
|
|
|
|
|
|
class ARMDebugger:
|
|
def __init__(self, emulator):
|
|
self.core = emulator.core
|
|
|
|
self.commands = {
|
|
"state": Command(0, 0, self.state, "state")
|
|
}
|
|
|
|
def name(self): return "ARM"
|
|
def pc(self): return self.core.reg(pyemu.ARMCore.PC)
|
|
def lr(self): return self.core.reg(pyemu.ARMCore.LR)
|
|
|
|
def get_context(self):
|
|
core = self.core
|
|
vars = {"R%i" %i: core.reg(i) for i in range(16)}
|
|
vars.update({
|
|
"SP": vars["R13"],
|
|
"LR": vars["R14"],
|
|
"PC": vars["R15"]
|
|
})
|
|
return vars
|
|
|
|
def eval(self, source):
|
|
return eval(source, self.get_context())
|
|
|
|
def state(self):
|
|
core = self.core
|
|
print("R0 = %08X R1 = %08X R2 = %08X R3 = %08X R4 = %08X" %(core.reg(0), core.reg(1), core.reg(2), core.reg(3), core.reg(4)))
|
|
print("R5 = %08X R6 = %08X R7 = %08X R8 = %08X R9 = %08X" %(core.reg(5), core.reg(6), core.reg(7), core.reg(8), core.reg(9)))
|
|
print("R10= %08X R11= %08X R12= %08X" %(core.reg(10), core.reg(11), core.reg(12)))
|
|
print("SP = %08X LR = %08X PC = %08X" %(core.reg(13), core.reg(14), core.reg(15)))
|
|
|
|
|
|
class Module:
|
|
def __init__(self, reader, module):
|
|
info = reader.u32(module + 0x28)
|
|
self.path = reader.string(reader.u32(info))
|
|
self.name = self.path.split("\\")[-1]
|
|
self.text = reader.u32(info + 4)
|
|
self.textsize = reader.u32(info + 0xC)
|
|
self.data = reader.u32(info + 0x10)
|
|
self.datasize = reader.u32(info + 0x18)
|
|
self.next = reader.u32(module + 0x54)
|
|
|
|
def __repr__(self):
|
|
return "<module %s>" %self.name
|
|
|
|
|
|
class PPCDebugger:
|
|
def __init__(self, emulator, core_id):
|
|
self.emulator = emulator
|
|
self.mmu = emulator.virtmem
|
|
self.core = emulator.core
|
|
self.core_id = core_id
|
|
|
|
self.commands = {
|
|
"state": Command(0, 1, self.state, "state (all)"),
|
|
"getspr": Command(1, 1, self.getspr, "getspr <spr>"),
|
|
"setspr": Command(2, 2, self.setspr, "setspr <spr> <value>"),
|
|
"setpc": Command(1, 1, self.setpc, "setpc <value>"),
|
|
"modules": Command(0, 0, self.modules, "modules"),
|
|
"module": Command(1, 1, self.module, "module <name>"),
|
|
"threads": Command(0, 0, self.threads, "threads"),
|
|
"thread": Command(1, 1, self.thread, "thread <addr>"),
|
|
"find": Command(1, 1, self.find, "find <addr>"),
|
|
"trace": Command(0, 0, self.trace, "trace"),
|
|
"memmap": Command(0, 0, self.memmap, "memmap")
|
|
}
|
|
|
|
def name(self): return "PPC%i" %self.core_id
|
|
def pc(self): return self.core.pc()
|
|
def lr(self): return self.core.spr(pyemu.PPCCore.LR)
|
|
|
|
def get_context(self):
|
|
core = self.core
|
|
vars = {"r%i" %i: core.reg(i) for i in range(32)}
|
|
vars.update({
|
|
"sp": vars["r1"],
|
|
"pc": core.pc(),
|
|
"lr": core.spr(pyemu.PPCCore.LR),
|
|
"ctr": core.spr(pyemu.PPCCore.CTR),
|
|
"module": self.get_module_by_name
|
|
})
|
|
return vars
|
|
|
|
def eval(self, source):
|
|
return eval(source, self.get_context())
|
|
|
|
def state(self, mode="basic"):
|
|
core = self.core
|
|
mmu = self.mmu
|
|
|
|
print("r0 = %08X r1 = %08X r2 = %08X r3 = %08X r4 = %08X" %(core.reg(0), core.reg(1), core.reg(2), core.reg(3), core.reg(4)))
|
|
print("r5 = %08X r6 = %08X r7 = %08X r8 = %08X r9 = %08X" %(core.reg(5), core.reg(6), core.reg(7), core.reg(8), core.reg(9)))
|
|
print("r10 = %08X r11 = %08X r12 = %08X r13 = %08X r14 = %08X" %(core.reg(10), core.reg(11), core.reg(12), core.reg(13), core.reg(14)))
|
|
print("r15 = %08X r16 = %08X r17 = %08X r18 = %08X r19 = %08X" %(core.reg(15), core.reg(16), core.reg(17), core.reg(18), core.reg(19)))
|
|
print("r20 = %08X r21 = %08X r22 = %08X r23 = %08X r24 = %08X" %(core.reg(20), core.reg(21), core.reg(22), core.reg(23), core.reg(24)))
|
|
print("r25 = %08X r26 = %08X r27 = %08X r28 = %08X r29 = %08X" %(core.reg(25), core.reg(26), core.reg(27), core.reg(28), core.reg(29)))
|
|
print("r30 = %08X r31 = %08X pc = %08X lr = %08X ctr = %08X" %(core.reg(30), core.reg(31), core.pc(), core.spr(core.LR), core.spr(core.CTR)))
|
|
print("cr = %08X dec = %08X srr0= %08X srr1= %08X" %(core.cr(), core.spr(22), core.spr(26), core.spr(27)))
|
|
|
|
if mode == "all":
|
|
print()
|
|
print("sr0 = %08X sr1 = %08X sr2 = %08X sr3 = %08X" %(mmu.get_sr(0), mmu.get_sr(1), mmu.get_sr(2), mmu.get_sr(3)))
|
|
print("sr4 = %08X sr5 = %08X sr6 = %08X sr7 = %08X" %(mmu.get_sr(4), mmu.get_sr(5), mmu.get_sr(6), mmu.get_sr(7)))
|
|
print("sr8 = %08X sr9 = %08X sr10 = %08X sr11 = %08X" %(mmu.get_sr(8), mmu.get_sr(9), mmu.get_sr(10), mmu.get_sr(11)))
|
|
print("sr12 = %08X sr13 = %08X sr14 = %08X sr15 = %08X" %(mmu.get_sr(12), mmu.get_sr(13), mmu.get_sr(14), mmu.get_sr(15)))
|
|
|
|
def getspr(self, spr):
|
|
value = self.core.spr(int(spr))
|
|
print("%08X (%i)" %(value, value))
|
|
|
|
def setspr(self, spr, value):
|
|
self.core.setspr(int(spr), self.eval(value))
|
|
|
|
def setpc(self, value):
|
|
self.core.setpc(self.eval(value))
|
|
|
|
def get_modules(self):
|
|
reader = self.emulator.mem_reader
|
|
|
|
#Memory might not be mapped yet
|
|
try: addr = reader.u32(0x10081018)
|
|
except: return []
|
|
|
|
modules = []
|
|
while addr:
|
|
module = Module(reader, addr)
|
|
modules.append(module)
|
|
addr = module.next
|
|
return modules
|
|
|
|
def get_module_by_name(self, name):
|
|
for module in self.get_modules():
|
|
if name in module.path:
|
|
return module
|
|
|
|
def get_module_by_addr(self, addr):
|
|
for module in self.get_modules():
|
|
if module.text <= addr < module.text + module.textsize or \
|
|
module.data <= addr < module.data + module.datasize:
|
|
return module
|
|
|
|
def format_module_addr(self, addr):
|
|
module = self.get_module_by_addr(addr)
|
|
if module:
|
|
if module.text <= addr < module.text + module.textsize:
|
|
return "%08X: %s:text+0x%X" %(addr, module.name, addr - module.text)
|
|
return "%08X: %s:data+0x%X" %(addr, module.name, addr - module.data)
|
|
return "%08X" %addr
|
|
|
|
def print_stack_trace(self, sp, tabs=0):
|
|
tabs = "\t" * tabs
|
|
reader = self.emulator.mem_reader
|
|
while sp:
|
|
lr = reader.u32(sp + 4)
|
|
if not lr: return
|
|
|
|
print("%s%s" %(tabs, self.format_module_addr(lr)))
|
|
sp = reader.u32(sp)
|
|
|
|
def modules(self):
|
|
for module in sorted(self.get_modules(), key=lambda m: m.text):
|
|
print("%08X: %s" %(module.text, module.path))
|
|
|
|
def module(self, name):
|
|
for module in filter(lambda m: name in m.path, self.get_modules()):
|
|
print("%s:" %module.path)
|
|
print("\t.text: %08X - %08X" %(module.text, module.text + module.textsize))
|
|
print("\t.data: %08X - %08X" %(module.data, module.data + module.datasize))
|
|
|
|
def threads(self):
|
|
reader = self.emulator.mem_reader
|
|
thread = reader.u32(0x100567F8)
|
|
while thread:
|
|
nameptr = reader.u32(thread + 0x5C0)
|
|
if nameptr:
|
|
name = reader.string(nameptr)
|
|
else:
|
|
module = self.get_module_by_addr(thread)
|
|
if module:
|
|
name = "<no name:%s>" %module.name
|
|
else:
|
|
name = "<no name>"
|
|
|
|
cores = [
|
|
"invalid", "core 0", "core 1", "core 0/1",
|
|
"core 2", "core 0/2", "core 1/2", "all cores"
|
|
][reader.u32(thread + 0x304) & 7]
|
|
|
|
print("%08X: [%s] %s" %(thread, cores, name))
|
|
thread = reader.u32(thread + 0x38C)
|
|
|
|
def thread(self, thread):
|
|
thread = self.eval(thread)
|
|
reader = self.emulator.mem_reader
|
|
print("Name:", reader.string(reader.u32(thread + 0x5C0)))
|
|
print("Entry point: %s" %self.format_module_addr(reader.u32(thread + 0x39C)))
|
|
print("Stack trace:")
|
|
self.print_stack_trace(reader.u32(thread + 0xC), 1)
|
|
|
|
def find(self, addr):
|
|
print(self.format_module_addr(self.eval(addr)))
|
|
|
|
def trace(self):
|
|
#Stack frame might be set up only partially
|
|
lr = self.core.spr(self.core.LR)
|
|
for addr in [self.core.pc(), lr]:
|
|
print(self.format_module_addr(addr))
|
|
|
|
reader = self.emulator.mem_reader
|
|
sp = reader.u32(self.core.reg(1))
|
|
if sp and reader.u32(sp + 4) == lr:
|
|
sp = reader.u32(sp)
|
|
self.print_stack_trace(sp)
|
|
|
|
def print_bat(self, name, batu, batl):
|
|
if batu & 3:
|
|
validity = {
|
|
1: "user mode only",
|
|
2: "supervisor only",
|
|
3: "user/supervisor"
|
|
}[batu & 3]
|
|
|
|
access = [
|
|
"no access", "read only", "read/write", "read only"
|
|
][batl & 3]
|
|
|
|
size = 0x20000
|
|
sizemask = (batu >> 2) & 0x7FF
|
|
while sizemask & 1:
|
|
size *= 2
|
|
sizemask >>= 1
|
|
|
|
vaddr = batu & 0xFFFE0000
|
|
paddr = batl & 0xFFFE0000
|
|
print("\t%s: %08X-%08X => %08X-%08X (%s, %s)" %(
|
|
name, vaddr, vaddr + size, paddr, paddr + size, access, validity
|
|
))
|
|
|
|
else:
|
|
print("\t%s: disabled" %name)
|
|
|
|
#Prints the virtual memory map of a PowerPC core
|
|
def memmap(self):
|
|
reader = self.emulator.mem_reader
|
|
mmu = self.emulator.virtmem
|
|
|
|
print("DBAT:")
|
|
for i in range(8):
|
|
dbatu = mmu.get_dbatu(i)
|
|
dbatl = mmu.get_dbatl(i)
|
|
self.print_bat("dbat%i" %i, dbatu, dbatl)
|
|
|
|
print("\nIBAT:")
|
|
for i in range(8):
|
|
ibatu = mmu.get_ibatu(i)
|
|
ibatl = mmu.get_ibatl(i)
|
|
self.print_bat("ibat%i" %i, ibatu, ibatl)
|
|
|
|
sdr1 = mmu.get_sdr1()
|
|
pagetbl = sdr1 & 0xFFFF0000
|
|
pagemask = sdr1 & 0x1FF
|
|
hashmask = (pagemask << 10) | 0x3FF
|
|
|
|
print("\nPage table (%08X):" %pagetbl)
|
|
|
|
pagemap = []
|
|
current = None
|
|
for segment in range(16):
|
|
sr = mmu.get_sr(segment)
|
|
if sr >> 31: #Direct-store
|
|
if current: pagemap.append(current)
|
|
current = None
|
|
|
|
else:
|
|
ks = (sr >> 30) & 1
|
|
kp = (sr >> 29) & 1
|
|
nx = (sr >> 28) & 1
|
|
vsid = sr & 0xFFFFFF
|
|
|
|
pageidx = 0
|
|
for addr in range(segment * 0x10000000, (segment + 1) * 0x10000000, 0x20000):
|
|
hash = ((vsid & 0x7FFFF) ^ pageidx) & hashmask
|
|
api = pageidx >> 5
|
|
|
|
pteaddr = pagetbl | (hash << 6)
|
|
ptes = struct.unpack_from(">8Q", reader.read(pteaddr, 64, False))
|
|
for pte in ptes:
|
|
if not pte >> 63: continue
|
|
if (pte >> 38) & 1: continue
|
|
if (pte >> 39) & 0xFFFFFF != vsid: continue
|
|
if (pte >> 32) & 0x3F != api: continue
|
|
|
|
pp = pte & 3
|
|
phys = pte & 0xFFFFF000
|
|
|
|
if current and current[2:] == [ks, kp, nx, pp, phys - current[1]]:
|
|
current[1] += 0x20000
|
|
else:
|
|
if current: pagemap.append(current)
|
|
current = [addr, 0x20000, ks, kp, nx, pp, phys]
|
|
break
|
|
|
|
else:
|
|
if current: pagemap.append(current)
|
|
current = None
|
|
|
|
pageidx += 1
|
|
|
|
if current: pagemap.append(current)
|
|
|
|
if pagemap:
|
|
for start, size, ks, kp, nx, pp, phys in pagemap:
|
|
access_prot = [
|
|
["read/write", "read/write", "read/write", "read only"],
|
|
["no access", "read only", "read/write", "read only"]
|
|
]
|
|
user_access = "user: %s" %access_prot[kp][pp]
|
|
kernel_access = "supervisor: %s" %access_prot[ks][pp]
|
|
no_execute = "no execute" if nx else "executable"
|
|
print("\t%08X-%08X => %08X-%08X (%s, %s, %s)" %(
|
|
start, start + size, phys, phys + size, user_access, kernel_access, no_execute
|
|
))
|
|
else:
|
|
print("\tno pages mapped")
|
|
|
|
|
|
class DebugShell:
|
|
def __init__(self, scheduler):
|
|
self.scheduler = scheduler
|
|
self.current_override = None
|
|
self.input_interrupt = False
|
|
|
|
self.commands = {
|
|
"help": Command(0, 1, self.help, "help (<command>)"),
|
|
"select": Command(1, 1, self.select, "select <index>"),
|
|
"break": Command(2, 2, self.breakp, "break add/del <address>"),
|
|
"watch": Command(3, 3, self.watch, "watch add/del read/write <address>"),
|
|
"read": Command(3, 3, self.read, "read phys/virt <address> <length>"),
|
|
"dump": Command(4, 4, self.dump, "dump phys/virt <address> <length> <filename>"),
|
|
"translate": Command(1, 2, self.translate, "translate <address> (type)"),
|
|
"getreg": Command(1, 1, self.getreg, "getreg <reg>"),
|
|
"setreg": Command(2, 2, self.setreg, "setreg <reg> <value>"),
|
|
"step": Command(0, 0, self.step, "step"),
|
|
"eval": Command(1, 1, self.evalcmd, "eval <expr>")
|
|
}
|
|
|
|
def current(self):
|
|
if self.current_override:
|
|
return self.current_override
|
|
return self.scheduler.current()
|
|
|
|
def handle_breakpoint(self, addr):
|
|
self.current_override = None
|
|
name = self.current().debugger.name()
|
|
print("%s: Breakpoint hit at %08X\n" %(name, addr))
|
|
self.show(True)
|
|
|
|
def handle_watchpoint(self, addr, write):
|
|
self.current_override = None
|
|
debugger = self.current().debugger
|
|
type = "write" if write else "read"
|
|
print("%s: Watchpoint %08X (%s) hit at %08X\n" %(debugger.name(), addr, type, debugger.pc()))
|
|
self.show(True)
|
|
|
|
def show(self, is_break):
|
|
#Catching KeyboardInterrupts is quite messy
|
|
while True:
|
|
debugger = self.current().debugger
|
|
|
|
try:
|
|
try: inp = input("%s:%08X> " %(debugger.name(), debugger.pc()))
|
|
except EOFError: #Apparently this is a Windows problem
|
|
time.sleep(2) #Wait for keyboard interrupt
|
|
self.input_interrupt = True
|
|
raise
|
|
except KeyboardInterrupt:
|
|
self.input_interrupt = True
|
|
raise #Exit
|
|
|
|
try:
|
|
parser = ArgParser()
|
|
parser.parse(inp)
|
|
if parser.args:
|
|
cmd, args = parser.args[0], parser.args[1:]
|
|
if cmd == "run":
|
|
if not is_break:
|
|
self.scheduler.run()
|
|
return
|
|
else:
|
|
self.execute_command(cmd, args)
|
|
|
|
except KeyboardInterrupt as e:
|
|
#Exit if Ctrl+C is pressed during input()
|
|
if self.input_interrupt: raise
|
|
|
|
#But show the debugger if Ctrl+C is pressed while the interpreter is running
|
|
print("Keyboard interrupt")
|
|
|
|
except Exception as e:
|
|
print("%s: %s" %(e.__class__.__name__, e))
|
|
|
|
def get_command(self, cmd):
|
|
for plugin in [self, self.current().debugger]:
|
|
if cmd in plugin.commands:
|
|
return plugin.commands[cmd]
|
|
print("Unknown command")
|
|
|
|
def execute_command(self, cmd, args):
|
|
command = self.get_command(cmd)
|
|
if command:
|
|
command.call(args)
|
|
|
|
def eval(self, source):
|
|
return self.current().debugger.eval(source)
|
|
|
|
def help(self, cmd=None):
|
|
debugger = self.current().debugger
|
|
|
|
if cmd:
|
|
command = self.get_command(cmd)
|
|
if command:
|
|
command.print_usage()
|
|
|
|
else:
|
|
print()
|
|
for plugin in [self, debugger]:
|
|
print("%s:" %plugin.__class__.__name__)
|
|
for cmd in sorted(plugin.commands.keys()):
|
|
print("\t%s" %cmd)
|
|
print()
|
|
|
|
def select(self, index):
|
|
self.current_override = self.scheduler.emulators[int(index)]
|
|
|
|
def breakp(self, op, address):
|
|
func = {
|
|
"add": self.current().breakpoints.add,
|
|
"del": self.current().breakpoints.remove
|
|
}[op]
|
|
func(self.eval(address), self.handle_breakpoint)
|
|
|
|
def watch(self, op, type, address):
|
|
func = {
|
|
"add": self.current().breakpoints.watch,
|
|
"del": self.current().breakpoints.unwatch
|
|
}[op]
|
|
|
|
write = {
|
|
"read": False,
|
|
"write": True
|
|
}[type]
|
|
|
|
func(write, self.eval(address), self.handle_watchpoint)
|
|
|
|
def read(self, type, address, length):
|
|
reader = self.current().mem_reader
|
|
address = self.eval(address)
|
|
length = self.eval(length)
|
|
|
|
data = reader.read(address, length, type == "virt")
|
|
|
|
print(data.hex())
|
|
if is_printable(data):
|
|
print(data.decode("ascii"))
|
|
|
|
def dump(self, type, address, length, filename):
|
|
reader = self.current().mem_reader
|
|
address = self.eval(address)
|
|
length = self.eval(length)
|
|
|
|
data = reader.read(address, length, type == "virt")
|
|
with open(filename, "wb") as f:
|
|
f.write(data)
|
|
|
|
def translate(self, address, type=pyemu.IVirtualMemory.DATA_READ):
|
|
addr = self.current().virtmem.translate(self.eval(address), type)
|
|
print("0x%08X" %addr)
|
|
|
|
def getreg(self, reg):
|
|
value = self.current().core.reg(int(reg))
|
|
print("0x%08X (%i)" %(value, value))
|
|
|
|
def setreg(self, reg, value):
|
|
self.current().core.setreg(int(reg), self.eval(value))
|
|
|
|
def step(self):
|
|
self.current().interpreter.step()
|
|
|
|
def evalcmd(self, source):
|
|
result = self.eval(source)
|
|
if type(result) == int:
|
|
print("%08X (%i)" %(result, result))
|
|
else:
|
|
print(result)
|