diff options
| author | LagoLunatic <LagoLunatic@users.noreply.github.com> | 2026-07-13 13:20:35 -0400 |
|---|---|---|
| committer | LagoLunatic <LagoLunatic@users.noreply.github.com> | 2026-07-13 13:20:35 -0400 |
| commit | 3cb9b3bdb49c76e71c06ab2cd873ed5130864afb (patch) | |
| tree | fe1867bc5d14726cc73166ec54d93e502ee790e2 | |
| parent | 6f09bf28ce1a2f1cdea62b931cbbdb40e7f821ec (diff) | |
debug_map_diff.py: Several improvements
Auto-detect if the TU is in main.dol or a REL. Detect this separately for the target and the base, in order to support TUs like d_a_npc_tt which are in main.dol for the debug build, but a REL for release builds. And disable linkage comparison when comparing a REL TU to a main.dol TU as the official main.dol maps do not include linkage information, but the REL maps do.
| -rwxr-xr-x | tools/utilities/debug_map_diff.py | 81 |
1 files changed, 53 insertions, 28 deletions
diff --git a/tools/utilities/debug_map_diff.py b/tools/utilities/debug_map_diff.py index bec1e986..12d29331 100755 --- a/tools/utilities/debug_map_diff.py +++ b/tools/utilities/debug_map_diff.py @@ -4,6 +4,10 @@ # Checks for missing inline usages, fake inline usages, and inlines being the wrong size. # NOTE: You must mark the TU as "Matching" in configure.py, even if it doesn't match! Otherwise this script won't work properly. +# To use this script, pass the name of the TU as the only argument. Examples: +# ./tools/utilities/debug_map_diff.py d_a_andsw0 +# ./tools/utilities/debug_map_diff.py d_a_npc_fa1 + from pathlib import Path import re import subprocess @@ -11,28 +15,46 @@ import argparse from collections import defaultdict arg_parse = argparse.ArgumentParser() -arg_parse.add_argument("object_name", help="Name of the object to compare, e.g. d_a_bridge for a REL, or main/d_a_npc_fa1 for a main.dol object") +arg_parse.add_argument("object_name", help="Name of the object to compare, e.g. d_a_bridge or d_a_npc_fa1") args = arg_parse.parse_args() object_name: str = args.object_name +assert "/" not in object_name and "." not in object_name, "The object name should not contain slashes or dots" debug_maps_root_path = Path("orig/D44J01/files/maps") decomp_root_path = Path(".") -is_rel: bool -if object_name.startswith("main/"): - is_rel = False - object_name = object_name.split("/", 1)[1] - object_name = object_name.split(".", 1)[0] - target_map_path = debug_maps_root_path / "frameworkD.map" - base_map_path = decomp_root_path / "build/D44J01/framework.elf.MAP" -else: - is_rel = True - target_map_path = debug_maps_root_path / f"{object_name}D.map" - base_map_path = decomp_root_path / f"build/D44J01/{object_name}/{object_name}.plf.MAP" -assert "/" not in object_name and "." not in object_name - retcode = subprocess.call(["python", "configure.py", "--version", "D44J01", "--debug", "--map", "--non-matching"], cwd=decomp_root_path) assert retcode == 0, "Failed to configure" + +all_ninja_outputs = [] +for ninja_target in subprocess.check_output(["ninja", "-t", "targets", "all"]).decode("utf-8").splitlines(): + ninja_output, ninja_rule = ninja_target.split(":", 1) + all_ninja_outputs.append(ninja_output) + +target_map_path_dol = debug_maps_root_path / "frameworkD.map" +target_map_path_rel = debug_maps_root_path / f"{object_name}D.map" +if target_map_path_rel.exists(): + target_is_rel = True + target_map_path = target_map_path_rel +else: + assert target_map_path_dol.exists() + target_is_rel = False + target_map_path = target_map_path_dol +del target_map_path_dol +del target_map_path_rel + +base_map_path_dol = decomp_root_path / "build/D44J01/framework.elf.MAP" +base_map_path_rel = decomp_root_path / f"build/D44J01/{object_name}/{object_name}.plf.MAP" +if str(base_map_path_rel) in all_ninja_outputs: + base_is_rel = True + base_map_path = base_map_path_rel +else: + assert str(base_map_path_dol) in all_ninja_outputs + base_is_rel = False + base_map_path = base_map_path_dol +del base_map_path_dol +del base_map_path_rel + retcode = subprocess.call(["ninja", base_map_path.relative_to(decomp_root_path)], cwd=decomp_root_path) assert retcode == 0, "Ninja build call failed" @@ -61,7 +83,7 @@ def get_main_symbols(framework_map_contents: str, valid_obj_names = None): symbols[name] = Symbol(name, size) if len(symbols) == 0: - raise Exception("Failed to find object matching the given name") + raise Exception("Failed to find object matching the given name (check for typos)") return symbols def get_rel_symbols(rel_map_data: str): @@ -157,13 +179,15 @@ def is_debug_only_symbol(symbol_name: str): return True return False -if is_rel: +if target_is_rel: target_symbols = get_rel_symbols(target_map_path.read_text()) +else: + target_symbols = get_main_symbols(target_map_path.read_text(), valid_obj_names=[object_name]) + +if base_is_rel: base_symbols = get_rel_symbols(base_map_path.read_text()) else: - obj_names = [object_name] - target_symbols = get_main_symbols(target_map_path.read_text(), valid_obj_names=obj_names) - base_symbols = get_main_symbols(base_map_path.read_text(), valid_obj_names=obj_names) + base_symbols = get_main_symbols(base_map_path.read_text(), valid_obj_names=[object_name]) print(len(target_symbols), len(base_symbols)) @@ -219,15 +243,16 @@ for symbol_name, target_size, base_size, ratio in symbol_size_diffs: total_missing += 1 print(prefix + symbol_name, "0x%X" % target_size) -for symbol_name, target_symbol in target_symbols.items(): - if target_symbol.size == 0: - continue - if symbol_name not in base_symbols: - continue - base_symbol = base_symbols[symbol_name] - if target_symbol.linkage != base_symbol.linkage: - total_wrong_linkage += 1 - print(f"LINKAGE: {symbol_name} (should be {target_symbol.linkage}, is {base_symbol.linkage})") +if target_is_rel: + for symbol_name, target_symbol in target_symbols.items(): + if target_symbol.size == 0: + continue + if symbol_name not in base_symbols: + continue + base_symbol = base_symbols[symbol_name] + if target_symbol.linkage != base_symbol.linkage: + total_wrong_linkage += 1 + print(f"LINKAGE: {symbol_name} (should be {target_symbol.linkage}, is {base_symbol.linkage})") print("==================================================") print(f"Total right size: {total_right_size}") |
