tp/tools/utilities/weak_order_diff.py

127 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import re
from pathlib import Path
import subprocess
from argparse import ArgumentParser
def is_windows() -> bool:
return os.name == "nt"
EXE = ".exe" if is_windows() else ""
def get_symbols(o_path: Path, diff_data: bool):
readelf_path = f"build/binutils/powerpc-eabi-readelf{EXE}"
output = subprocess.check_output([readelf_path, "-Ws", o_path]).decode("ascii")
symbols = []
for line in output.split("\n")[3:]:
if line == "":
continue
words = line.split()
if len(words) == 7 and words[-1] == "UND":
continue
_, offset, size, sym_type, scope, vis, section_index, name = words
if diff_data:
# Only diff data.
if sym_type == "FUNC":
continue
if sym_type in ["FILE", "NOTYPE", "SECTION"]:
continue
if vis == "HIDDEN":
continue
if re.search(r"^@\d+$", name):
name = "@"
if re.search(r"^lbl_[0-9a-f]+_(?:data|bss)_[0-9a-f]+$", name):
continue
match = re.search(r"^(\S+\$)\d+$", name)
if match:
name = match.group(1)
else:
# Only diff functions.
if sym_type != "FUNC":
continue
if vis == "HIDDEN":
continue
symbols.append((sym_type, int(section_index), int(offset, 16), name))
symbols.sort()
symbol_names = [sym[-1] for sym in symbols]
return symbol_names
def print_symbols_with_unmatched_order_for_object(
relative_o_path: str, version: str, diff_data: bool
):
target_o = Path("build") / version / "obj" / relative_o_path
base_o = Path("build") / version / "src" / relative_o_path
if not target_o.exists():
rel_name = relative_o_path.split("/")[-1].split(".")[0]
target_o = Path("build") / version / rel_name / "obj" / relative_o_path
subprocess.check_output(["ninja", base_o])
target_symbols = get_symbols(target_o, diff_data)
base_symbols = get_symbols(base_o, diff_data)
target_symbols_set = set(target_symbols)
base_symbols = [sym for sym in base_symbols if sym in target_symbols_set]
base_idx = 0
matched_count = 0
unmatched_count = 0
for target_sym in target_symbols:
if base_idx == len(base_symbols):
base_sym = None
else:
base_sym = base_symbols[base_idx]
if target_sym == base_sym:
base_idx += 1
matched_count += 1
elif target_sym not in base_symbols:
print("MISSING SYMBOL:", target_sym)
else:
base_idx = base_symbols.index(target_sym)
base_idx += 1
unmatched_count += 1
print(target_sym)
print("====================================")
print("Number of order differences:", unmatched_count)
def main():
parser = ArgumentParser(
description="Print differences in weak function order for an object."
)
parser.add_argument(
"o_path",
type=str,
default="d/actor/d_a_alink.o",
nargs="?",
help="""relative path to the object file to diff (e.g. d/actor/d_a_alink.o).""",
)
parser.add_argument(
"-v",
"--version",
type=str,
default="GZ2E01",
help="version to build",
)
parser.add_argument(
"--data",
action="store_true",
help="""diffs data instead of functions.""",
)
args = parser.parse_args()
print_symbols_with_unmatched_order_for_object(args.o_path, args.version, args.data)
if __name__ == "__main__":
main()