61 lines
2.0 KiB
Python
61 lines
2.0 KiB
Python
#!/usr/bin/env python3.12
|
|
"""Symbolize mint hook DLL crash RVAs.
|
|
|
|
Usage:
|
|
python3.12 symbolize_hook.py <hook.dll> <rva> [rva ...]
|
|
|
|
RVAs are relative to the DLL's image base (e.g. from a wine/proton crash
|
|
line "X3DAudio1_7.dll + 0x521F15"). The script prints the containing symbol
|
|
for each RVA. Run it against a debug-symbol hook build (see README "Symbol
|
|
build"), NOT the stripped release artifact.
|
|
|
|
Optional env:
|
|
HOOK_IMAGE_BASE override base (default 0x180000000)
|
|
"""
|
|
import bisect, os, re, subprocess, sys
|
|
|
|
def main():
|
|
if len(sys.argv) < 3:
|
|
print(__doc__); sys.exit(1)
|
|
dll = sys.argv[1]
|
|
base = int(os.environ.get("HOOK_IMAGE_BASE", "0x180000000"), 16)
|
|
rv = [int(x, 16) for x in sys.argv[2:]]
|
|
|
|
sym_out = subprocess.run(
|
|
["x86_64-w64-mingw32-nm", "-n", "-C", dll],
|
|
capture_output=True, text=True)
|
|
syms = []
|
|
for line in sym_out.stdout.splitlines():
|
|
m = re.match(r"^([0-9a-f]+) [TtDdWw] (.+)$", line)
|
|
if m:
|
|
a = int(m.group(1), 16)
|
|
if a >= base:
|
|
syms.append((a, m.group(2).strip()))
|
|
if not syms:
|
|
print("no symbols found — is this a debug build? (see README)"); sys.exit(2)
|
|
addrs = [a for a, _ in syms]
|
|
syms.sort()
|
|
|
|
for r in rv:
|
|
va = base + r
|
|
i = bisect.bisect_right(addrs, va) - 1
|
|
if i < 0:
|
|
print(f"+{r:06x} NOT FOUND"); continue
|
|
fa, name = syms[i]
|
|
leaf = subprocess.run(
|
|
["x86_64-w64-mingw32-addr2line", "-Cfie", dll, hex(va)],
|
|
capture_output=True, text=True).stdout
|
|
leaf_frames = [l for l in leaf.splitlines() if "at " in l]
|
|
print(f"=== +{r:06x} (va {va:#x}) ===")
|
|
print(f" container: {name[:160]}{'…' if len(name) > 160 else ''}")
|
|
print(f" +{va - fa:#x} into symbol")
|
|
if leaf_frames:
|
|
print(f" leaf: {leaf_frames[0][:160]}")
|
|
# outermost non-inlined frame
|
|
if leaf_frames:
|
|
print(f" outer: {leaf_frames[-1][:160]}")
|
|
print()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|