update getfunction.py

This commit is contained in:
SwareJonge 2023-03-27 14:05:46 +02:00
parent 86ebaaeac3
commit a5dd12f676
2 changed files with 98 additions and 23 deletions

View File

@ -41,14 +41,77 @@ class Binary(Enum):
# ppcdis source output
SourceDesc = Union[str, Tuple[str, int, int]]
def get_containing_slice(addr: int) -> Tuple[Binary, SourceDesc]:
"""Finds the binary containing an address and its source file
Source file is empty string if not decompiled"""
dol_raw = get_cmd_stdout(f"{SLICES} {DOL_YML} {DOL_SLICES} -p {DOL_SRCDIR}/ --containing {addr:x}")
dol_raw = get_cmd_stdout(
f"{SLICES} {DOL_YML} {DOL_SLICES} -p {DOL_SRCDIR}/ --containing {addr:x}")
containing = json.loads(dol_raw)
return (Binary.DOL, containing)
def lookup_sym(sym: str, dol: bool = False, rel: bool = False, source_name: str = None) -> int:
"""Takes a symbol as a name or address and returns the address"""
# Get binary
if dol:
binary_name = DOL_YML
else:
binary_name = None
# Determine type
try:
return int(sym, 16)
except ValueError:
return get_address(sym, binary_name, source_name)
def lookup_sym_full(sym: str, dol: bool = False, rel: bool = False, source_name: str = None
) -> int:
"""Takes a symbol as a name or address and returns both the name and address"""
# Get binary
if dol:
binary_name = DOL_YML
else:
binary_name = None
# Determine type
try:
return int(sym, 16), get_name(sym)
except ValueError:
return get_address(sym, binary_name, source_name), sym
def get_address(name: str, binary: bool = None, source_name: bool = None) -> int:
"""Finds the address of a symbol"""
args = [name]
if binary is not None:
args.append(f"-b {binary}")
if source_name is not None:
args.append(f"-n {source_name}")
raw = get_cmd_stdout(
f"{SYMBOLSCRIPT} {SYMBOLS} --get-addr {' '.join(args)}")
return json.loads(raw)
def get_name(addr: int, binary: bool = None, source_name: bool = None) -> int:
"""Finds the name of a symbol"""
args = [addr]
if binary is not None:
args.append(f"-b {binary}")
if source_name is not None:
args.append(f"-n {source_name}")
raw = get_cmd_stdout(
f"{SYMBOLSCRIPT} {SYMBOLS} --get-name {' '.join(args)}")
return json.loads(raw)
def find_headers(dirname: str, base=None) -> List[str]:
"""Returns a list of all headers in a folder recursively"""
@ -138,6 +201,7 @@ ELF2DOL = f"{PYTHON} {PPCDIS}/elf2dol.py"
FORCEACTIVEGEN = f"{PYTHON} {PPCDIS}/forceactivegen.py"
SLICES = f"{PYTHON} {PPCDIS}/slices.py"
PROGRESS = f"{PYTHON} {PPCDIS}/progress.py"
SYMBOLSCRIPT = f"{PYTHON} {PPCDIS}/symbols.py"
# Codewarrior
SDK_CW = os.path.join(TOOLS, "1.2.5")

View File

@ -4,47 +4,58 @@ Disassembles a single function
from argparse import ArgumentParser
from os import system, unlink
import os.path
from tempfile import NamedTemporaryFile
import common as c
def get_function(binary: c.Binary, srcflag: str, addr: int) -> str:
# Get flags for binary
if binary == c.Binary.DOL:
binary = c.DOL_YML
binflags = ""
anlflags = f"{c.DOL_LABELS} {c.DOL_RELOCS}"
else:
binary = c.REL_YML
binflags = c.PPCDIS_REL_FLAGS
anlflags = f"{c.REL_LABELS} {c.REL_RELOCS}"
def get_function(binary: c.Binary, source: c.SourceDesc, addr: int, extra: bool, inline=False) -> str:
# Get context
ctx = c.DOL_CTX if binary == c.Binary.DOL else c.REL_CTX
assert os.path.exists(ctx.labels), "Error: analysis has not ran!"
# Disassemble function
with NamedTemporaryFile(suffix=".c", delete=False) as tmp:
extraflag = "-e" if extra else ""
srcflag = f"-n {source}" if isinstance(source, str) else ""
inlineflag = "-i" if inline else ""
with NamedTemporaryFile(suffix=".s", delete=False) as tmp:
try:
tmp.close()
ret = system(
f"{c.DISASSEMBLER} {binary} {anlflags} {tmp.name} -f {addr:x} "
f"-m {c.SYMBOLS} {binflags} {srcflag} -q"
f"{c.DISASSEMBLER} {ctx.binary} {ctx.labels} {ctx.relocs} {tmp.name} -f {addr:x} "
f"-m {c.SYMBOLS} {srcflag} -q {extraflag} {inlineflag}"
)
assert ret == 0, f"Disassembly error code {ret}"
with open(tmp.name) as f:
asm = f.read()
finally:
unlink(tmp.name)
return asm
if __name__=="__main__":
if __name__ == "__main__":
parser = ArgumentParser()
hex_int = lambda s: int(s, 16)
parser.add_argument("addr", type=hex_int)
parser.add_argument("sym", type=str, help="Symbol name or address")
parser.add_argument("-e", "--extra", action="store_true",
help="Include referenced jumptables")
parser.add_argument("-d", "--dol", action="store_true",
help="Prioritise dol-local symbols")
parser.add_argument("-r", "--rel", action="store_true",
help="Prioritise rel-local symbols")
parser.add_argument("-n", "--source-name", type=str,
help="Prioritise source-local symbols")
parser.add_argument("-i", "--inline", action="store_true",
help="Output as inline assembly")
args = parser.parse_args()
# Find address
assert not (args.dol and args.rel), "--dol and --rel are incompatible"
addr = c.lookup_sym(args.sym, args.dol, args.rel, args.source_name)
assert addr is not None, f"Symbol {args.sym} not found"
# Find containing binary
binary, source = c.get_containing_slice(args.addr)
binary, source = c.get_containing_slice(addr)
# Get source file name flag
srcflag = f"-n {source}" if isinstance(source, str) else ""
print(get_function(binary, srcflag, args.addr))
print(get_function(binary, source, addr, args.extra, args.inline))