From d61ae83df13ba7ca7fa0bcec04dd1561565f79fe Mon Sep 17 00:00:00 2001 From: Darin Date: Sun, 20 Sep 2020 08:16:00 -0700 Subject: [PATCH] Added ability to provide ichaindis a symbol (#385) * Added ability to provide ichaindis a symbol and gave it ability to look up actor var names * Minor fixes * Fixed bug with output of script * Refactored the ROM lookup for ichaindis * Switched ichaindis to use filemap for ROM address lookup * Removed unused import and constant * Minor improvements to ichaindis * Updated help text * ichaindis will now only calculate Actor vars if needed * Changed no-names switch to names switch --- tools/ichaindis.py | 61 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/tools/ichaindis.py b/tools/ichaindis.py index 896dd87f01..017b1ba0d8 100755 --- a/tools/ichaindis.py +++ b/tools/ichaindis.py @@ -4,6 +4,8 @@ import os import sys import struct import argparse +import re +from overlayhelpers.filemap import FileResult, GetFromVRam, GetFromRom ICHAIN_MACROS = [ 'ICHAIN_U8', @@ -19,11 +21,55 @@ ICHAIN_MACROS = [ 'ICHAIN_VEC3S', ] +Z64_ACTOR_PATH = "../include/z64actor.h" + +def get_rom_address(offset): + + if offset.startswith("D_"): + offset = offset[2:] + + offset = int(offset, 16) + + if offset >= 0x80000000: + result = GetFromVRam(offset) + offset = result.vrom.start + result.offset + + return hex(offset) + +def get_actor_var_names(): + in_actor = False + actor_vars = {} + with open(os.path.dirname(os.path.realpath(__file__)) + "/" + Z64_ACTOR_PATH) as actor_h: + for line in actor_h: + if in_actor: + if "}" in line: + # Reached the end of the actor struct so break out + break + + # Parse out the memory address (from the comment) and the variable name + regex = r'.*\/\* (.*) \*\/\s+(struct)?\s*.+\s+(.+);.*' + actor_var_info = re.match(regex, line) + + if actor_var_info: + # Strip off the 0x0* part and store it + new_var_index = re.sub('0x0*', '', actor_var_info[1]) + actor_vars[new_var_index] = actor_var_info[3] + + elif "typedef struct Actor {" in line: + # Found the Actor struct + in_actor = True + return actor_vars + def main(): parser = argparse.ArgumentParser(description='Decompiles an InitChain') parser.add_argument('filename', help='ROM file path') - parser.add_argument('offset', help='ROM offset to an InitChain') + parser.add_argument('offset', help='ROM offset or symbol of an InitChain') + parser.add_argument('--names', action="store_true", help='Retrieve variable names from the actor struct') args = parser.parse_args() + + # Get the ROM address, if the offset is already a ROM address it will just be returned. + args.offset = get_rom_address(args.offset) + romOff = int(args.offset, 16) try: @@ -34,6 +80,10 @@ def main(): sys.exit(1) print ('static InitChainEntry sInitChain[] = {') + + if args.names: + actor_variable_names = get_actor_var_names() + while True: entry = struct.unpack('>I', romData[romOff:romOff+4])[0] romOff += 4 @@ -43,7 +93,14 @@ def main(): offset = ((entry) >> 16) & 0x7FF value = (entry) & 0xFFFF - print(' {0}(unk_{1:X}, {2}, {3}),'.format(ICHAIN_MACROS[t], offset, value, ('ICHAIN_CONTINUE' if cont == 1 else 'ICHAIN_STOP'))) + var_name = '{0:X}'.format(offset) + + if args.names and var_name in actor_variable_names: + var_name = actor_variable_names[var_name] + else: + var_name = "unk_" + var_name + + print(' {0}({1}, {2}, {3}),'.format(ICHAIN_MACROS[t], var_name, value, ('ICHAIN_CONTINUE' if cont == 1 else 'ICHAIN_STOP'))) if cont == 0: break print ('};')