Files
st/tools/vtable_sym.py
Yanis 90203403dd Decompile overlay 24 (Part 1) (#65)
* GameModeAdventure_001 OK

* GameModeAdventure_024 17%

* GameModeAdventure_024 73%

* GameModeAdventure_024 99%

* jp region differences

* rename GameModeAdventure_024 and GameModeAdventure + UnkStruct_ov000_020d8660_024 OK

* UnkActorSystem1OK

* UnkActorSystem2 OK

* delink more of ov024 & UnkStruct_027e0998_024 OK

* improve instance stuff & UnkStruct_027e0cf8_024 OK

* AdventureModeManager_160_024 OK & GameModeStartUp OK

* fix regressions

* fix regressions 2

* AdventureModeManager_170 OK

* AdventureModeManager_174_Base OK

* AdventureModeManager_174 OK

* mark GameModeAdventure_024 as complete

* AdventureModeManager_178 OK

* AdventureModeManager_180 OK

* AdventureModeManager_184_024 OK

* AdventureModeManager_18C_024 OK & AdventureModeManager_190_024 OK

* AdventureModeManager_15C_20_00 61%

* AdventureModeManager_15C_20_00 OK

* jp version differences

* delink what's left in the overlay

* fix regressions

* AdventureModeManager_1B8_Base_024 98%

* AdventureModeManager_1B8 48% and link AdventureModeManager_024

* AdventureModeManager_1B8_Base and AdventureModeManager_1B8 OK

* oops

* mark statics as local
2026-05-18 21:14:27 +02:00

135 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
# made by Aetias
import argparse
from pathlib import Path
import re
def main():
parser = argparse.ArgumentParser(description='Define vtable symbols and update relocations')
parser.add_argument('old_name', help='The old name of the vtable symbol')
parser.add_argument('new_name', help='The new name of the vtable symbol')
parser.add_argument('--dry', action='store_true', help='Print the changes without writing to files')
parser.add_argument("-v", "--version", help='version', default="eur")
args = parser.parse_args()
old_name: str = args.old_name
new_name: str = args.new_name
dry_run: bool = args.dry
file_write_buffer: list[tuple[Path, list[str]]] = []
manual_changes: list[str] = []
current_path = Path(__file__).parent
root_path = current_path.parent
base_config_path = root_path / "config" / args.version
for config_path in base_config_path.iterdir():
if config_path.is_file():
continue
old_address = None
new_address = None
dest_module = None
for symbol_file in config_path.glob("**/symbols.txt"):
with symbol_file.open("r") as f:
lines = f.readlines()
for row, line in enumerate(lines):
if not line.startswith(old_name):
continue
print(f"Updating symbol {old_name} in {symbol_file}:{row + 1}")
address = get_attr_value(line, "addr")
if address is None:
print(f"Error: Could not find symbol address at {symbol_file}:{row + 1}")
exit(1)
address = int(address, 16)
old_address = address
new_address = address - 8
line = line.replace(old_name, new_name, 1)
line = set_attr_value(line, "addr", f"0x{new_address:08x}")
print(f"-> {line}")
lines[row] = line
if old_address is None or new_address is None:
# Try next symbols.txt file
continue
file_name = str(symbol_file.relative_to(config_path))
if file_name.endswith("dtcm/symbols.txt"):
dest_module = ("dtcm", 0)
elif file_name.endswith("itcm/symbols.txt"):
dest_module = ("itcm", 0)
elif file_name.endswith("arm9/symbols.txt"):
dest_module = ("main", 0)
else:
overlay_id = re.search(r"ov(\d+)/symbols.txt", file_name)
if overlay_id is None:
print(f"Error: Could not determine module for {symbol_file}")
exit(1)
dest_module = ("overlay", int(overlay_id.group(1)))
file_write_buffer.append((symbol_file, lines))
break
if old_address is None or new_address is None or dest_module is None:
print(f"Error: Could not find symbol {old_name} in any symbols.txt file in {config_path}")
exit(1)
for relocs_file in config_path.glob("**/relocs.txt"):
with relocs_file.open("r") as f:
lines = f.readlines()
any_change = False
for row, line in enumerate(lines):
to_addr = get_attr_value(line, "to")
if to_addr is None:
continue
to_addr = int(to_addr, 16)
if to_addr != old_address:
continue
reloc_module = get_attr_value(line, "module")
if reloc_module is None:
continue
if dest_module[0] == "overlay" and reloc_module.startswith("overlays"):
print(f"Warning: Found ambiguous relocation for {old_name} in {relocs_file}, it will require manual review.")
manual_changes.append(f"{relocs_file}:{row + 1}")
if not reloc_module.startswith(dest_module[0]):
continue
print(f"Updating relocation for {old_name} in {relocs_file}:{row + 1}")
line = set_attr_value(line, "to", f"0x{new_address:08x}")
line = set_attr_value(line, "add", "0x8")
print(f"-> {line}")
lines[row] = line
any_change = True
if any_change:
file_write_buffer.append((relocs_file, lines))
if not dry_run:
for symbol_file, lines in file_write_buffer:
with symbol_file.open("w") as f:
f.writelines(lines)
print(f"Changes written to {len(file_write_buffer)} files:")
else:
print(f"Dry run complete. {len(file_write_buffer)} files would be updated:")
for symbol_file, _ in file_write_buffer:
print(f"- {symbol_file}")
def get_attr_value(line: str, attr: str) -> str | None:
match = re.search(rf"{attr}:(\S+)", line)
if match is None:
return None
return match.group(1)
def set_attr_value(line: str, attr: str, value: str) -> str:
pattern = rf"{attr}:\S+"
if not re.search(pattern, line):
line = line.strip() + f" {attr}:{value}\n"
return line
return re.sub(rf"{attr}:\S+", f"{attr}:{value}", line, count=1)
if __name__ == "__main__":
main()