Skip to content

Commit

Permalink
Create decomp.py as an abstraction over m2c (#1090)
Browse files Browse the repository at this point in the history
usage: decomp.py [-h] [--no-context] [--no-copy] [--no-print] [--colorize]
                 function ...

Decomp a function using m2c

positional arguments:
  function      a function to be processed
  m2c_args      additional arguments to be passed to m2c

options:
  -h, --help    show this help message and exit
  --no-context  do not generate ctx.c
  --no-copy     do not copy the output to the clipboard
  --no-print    do not print the output
  --colorize    colorize the output (requires pygments)
  • Loading branch information
ribbanya authored Jan 21, 2024
1 parent f3cd8c0 commit 5a614b8
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ orig/*/sys/*
/*.txt

# Python
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# .DS_Store
.DS_Store
Expand Down
8 changes: 8 additions & 0 deletions config/GALE01/symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ memcpy = .init:0x800031F4; // type:function size:0x50 scope:global
TRK_memcpy = .init:0x80003244; // type:function size:0x24 scope:global
TRK_memset = .init:0x80003268; // type:function size:0x30 scope:global
gTRKInterruptVectorTable = .init:0x80003298; // type:label scope:global
fn_800051CC = .init:0x800051CC; // type:function size:0x20
gTRKInterruptVectorTableEnd = .init:0x800051CC; // type:label scope:global
__check_pad3 = .init:0x800051EC; // type:function size:0x40 scope:global
__start = .init:0x8000522C; // type:function size:0x114 scope:global
Expand Down Expand Up @@ -18713,10 +18714,14 @@ ClearArena = .text:0x80342EBC; // type:function size:0x10C scope:global
OSInit = .text:0x80342FC8; // type:function size:0x344 scope:global
OSExceptionInit = .text:0x8034330C; // type:function size:0x280 scope:global
__OSDBIntegrator = .text:0x8034358C; // type:function size:0x24 scope:local
__OSDBINTSTART = .text:0x8034358C; // type:label scope:global
__OSDBINTEND = .text:0x803435B0; // type:label scope:global
fn_803435B0 = .text:0x803435B0; // type:function size:0x4
__OSSetExceptionHandler = .text:0x803435B4; // type:function size:0x1C scope:global
__OSDBJUMPEND = .text:0x803435B4; // type:label scope:global
__OSGetExceptionHandler = .text:0x803435D0; // type:function size:0x14 scope:global
OSExceptionVector = .text:0x803435E4; // type:function size:0x9C scope:local
__OSEVStart = .text:0x803435E4; // type:label scope:global
__DBVECTOR = .text:0x8034363C; // type:label scope:global data:4byte
__OSEVSetNumber = .text:0x8034364C; // type:label scope:global data:4byte
__OSEVEnd = .text:0x8034367C; // type:label scope:global
Expand Down Expand Up @@ -18881,6 +18886,7 @@ GetTypeCallback = .text:0x8034A5E8; // type:function size:0x298 scope:local
SIGetType = .text:0x8034A880; // type:function size:0x1C4 scope:global
SIGetTypeAsync = .text:0x8034AA44; // type:function size:0x13C scope:global
__OSSystemCallVector = .text:0x8034AB80; // type:function size:0x20 scope:global
__OSSystemCallVectorStart = .text:0x8034AB80; // type:label scope:global
__OSSystemCallVectorEnd = .text:0x8034AB9C; // type:label scope:global
__OSInitSystemCall = .text:0x8034ABA0; // type:function size:0x64 scope:global
__OSThreadInit = .text:0x8034AC04; // type:function size:0x128 scope:global
Expand Down Expand Up @@ -20235,7 +20241,9 @@ fn_803B61B4 = .text:0x803B61B4; // type:function size:0x66C
fn_803B6820 = .text:0x803B6820; // type:function size:0x3C4
hsd_803B6BE4 = .text:0x803B6BE4; // type:function size:0x64C scope:global
_ctors = .ctors:0x803B7240; // type:label scope:global data:4byte
__init_cpp_exceptions_reference = .ctors:0x803B7240; // type:object size:0x4 scope:global
_dtors = .dtors:0x803B7260; // type:label scope:global data:4byte
__destroy_global_chain_reference = .dtors:0x803B7260; // type:object size:0x4 scope:global
__fini_cpp_exceptions_reference = .dtors:0x803B7264; // type:object size:0x4 scope:global
lb_803B7280 = .rodata:0x803B7280; // type:object size:0x28 scope:global data:4byte
lb_803B72A8 = .rodata:0x803B72A8; // type:object size:0xC scope:global data:4byte
Expand Down
146 changes: 146 additions & 0 deletions tools/decomp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env python3

import argparse
import subprocess
import sys
from pathlib import Path
from sys import stderr
from typing import Optional, cast

from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection

root = Path(__file__).parent.parent
dtk_root = root / "build/GALE01"
obj_root = dtk_root / "obj"
asm_root = dtk_root / "asm"
m2c_script = root / "tools/m2c/m2c.py"
ctx_file = root / "build/ctx.c"
m2ctx_script = root / "tools/m2ctx/m2ctx.py"


def has_function(obj_path: Path, function_name: str) -> bool:
with open(obj_path, "rb") as f:
elf_file = ELFFile(f)
symbol_table = elf_file.get_section_by_name(".symtab")

if isinstance(symbol_table, SymbolTableSection):
for symbol in symbol_table.iter_symbols():
if (
symbol["st_info"]["type"] == "STT_FUNC"
and symbol.name == function_name
):
return True
return False


def find_obj(root: Path, function_name: str) -> Optional[Path]:
for p in root.rglob("*.o"):
if has_function(p, function_name):
return p.relative_to(root)
return None


def resolve_path(p: Path) -> str:
return str(p.resolve())


def run_cmd(cmd: list[str]) -> str:
result = subprocess.run(cmd, capture_output=True)
if result.returncode != 0:
print(" ".join(cmd))
print(result.stderr.decode(), file=sys.stderr)
sys.exit(1)
else:
return result.stdout.decode()


def gen_ctx():
run_cmd(
[
"python",
resolve_path(m2ctx_script),
"--quiet",
"--preprocessor",
]
)


def main():
parser = argparse.ArgumentParser(description="Decomp a function using m2c")
parser.add_argument(
"function",
type=str,
help="a function to be processed",
)
parser.add_argument(
dest="m2c_args",
nargs=argparse.REMAINDER,
help="additional arguments to be passed to m2c",
)
parser.add_argument(
"--no-context",
action="store_false",
dest="ctx",
help=f"do not generate {ctx_file.name}",
)
parser.add_argument(
"--no-copy",
action="store_false",
dest="copy",
help=f"do not copy the output to the clipboard",
)
parser.add_argument(
"--no-print",
action="store_false",
dest="print",
help=f"do not print the output",
)
parser.add_argument(
"--colorize",
action="store_true",
dest="color",
help=f"colorize the output (requires pygments)",
)

args = parser.parse_args()

if (obj_file := find_obj(obj_root, args.function)) is not None:
asm_file = asm_root / cast(Path, obj_file).with_suffix(".s")

m2c_cmd: list[str] = [
"python",
resolve_path(m2c_script),
*args.m2c_args,
"--target",
"ppc-mwcc-c",
"--context",
resolve_path(ctx_file),
"--function",
args.function,
resolve_path(asm_file),
]

if args.ctx:
gen_ctx()

output = run_cmd(m2c_cmd)
if args.copy:
import pyperclip

pyperclip.copy(output)
if args.print:
if args.color:
from pygments import highlight
from pygments.formatters import TerminalFormatter
from pygments.lexers import CLexer

output = highlight(output, CLexer(), TerminalFormatter())
print(output, file=sys.stdout)
else:
print(f"Could not find {args.function}", file=stderr)
sys.exit(1)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion tools/m2ctx/m2ctx.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def main():
"-f",
"--format",
action="store_true",
help="colorize the output (requires clang-format)",
help="format the output (requires clang-format)",
)
parser.add_argument(
"-p",
Expand Down

0 comments on commit 5a614b8

Please sign in to comment.