#!/usr/bin/env python3
"""Annotate ghidra/decomp.c: resolve absolute VAs (0x180........) to IL2CPP symbol names
(methods.tsv) and string literals (strings.tsv). Ghidra image base = 0x180000000.

methods.tsv : <rva-decimal>\t<symbol>        (rva = scriptAddress - 0x1000)
strings.tsv : <scriptAddress-decimal>\t<str> (raw ScriptString.Address)

Usage:
  venv/bin/python reverse/resolve_decomp.py            # writes ghidra/decomp.annotated.c
  venv/bin/python reverse/resolve_decomp.py <substr>   # print only funcs whose name matches substr
"""
import re, sys, os
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
G = os.path.join(ROOT, "ghidra")
BASE = 0x180000000

def load_methods():
    m = {}
    for l in open(os.path.join(G, "methods.tsv")):
        if "\t" in l:
            rva, name = l.rstrip("\n").split("\t", 1)
            m[int(rva)] = name
    return m

def load_strings():
    s = {}
    p = os.path.join(G, "strings.tsv")
    if os.path.exists(p):
        for l in open(p):
            if "\t" in l:
                a, v = l.rstrip("\n").split("\t", 1)
                s[int(a)] = v
    return s

def main():
    methods = load_methods()
    strings = load_strings()
    src = open(os.path.join(G, "decomp.c"), encoding="utf-8", errors="replace").read()
    hexre = re.compile(r"0x(1[0-9a-fA-F]{8,9})")

    def repl(m):
        va = int(m.group(1), 16)
        rva = va - BASE
        if rva in methods:
            return "%s/*%s*/" % (m.group(0), methods[rva])
        # string literal: try raw rva, rva+0x1000 (scriptAddress), and the table conventions
        for cand in (rva, rva + 0x1000, va, va - BASE + 0x1000):
            if cand in strings:
                return '%s/*"%s"*/' % (m.group(0), strings[cand][:60])
        return m.group(0)

    out = hexre.sub(repl, src)
    outp = os.path.join(G, "decomp.annotated.c")
    open(outp, "w", encoding="utf-8").write(out)
    nres = out.count("/*")
    print("wrote %s (%d annotations)" % (outp, nres))

    if len(sys.argv) > 1:
        sub = sys.argv[1]
        blocks = re.split(r"(?=// ==== )", out)
        for b in blocks:
            if sub.lower() in b[:200].lower():
                print(b)

if __name__ == "__main__":
    main()
