#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Usage: unnamed.py [-h] [-r rootdir] [-l count] pokecrystal.sym Parse the symfile to find unnamed symbols. """ import sys import argparse import subprocess import struct import enum import signal class symtype(enum.Enum): LOCAL = 0 IMPORT = 1 EXPORT = 2 def unpack_from(fmt, file): size = struct.calcsize(fmt) return struct.unpack(fmt, file.read(size)) def read_string(file): buf = bytearray() while True: b = file.read(1) if b is None or b == b'\0': return buf.decode() buf += b # Fix broken pipe when using `head` signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser(description='Parse the symfile to find unnamed symbols') parser.add_argument('symfile', type=argparse.FileType('r'), help='the list of symbols') parser.add_argument('-r', '--rootdir', type=str, help='scan the output files to obtain a list of files with unnamed symbols (note: will rebuild objects as necessary)') parser.add_argument('-l', '--list', type=int, default=0, help="output this many of each file's unnamed symbols (note: requires -r)") args = parser.parse_args() # Get list of object files objects = None if args.rootdir: for line in subprocess.Popen(['make', '-C', args.rootdir, '-s', '-p', 'DEBUG=1'], stdout=subprocess.PIPE).stdout.read().decode().split('\n'): if line.startswith('pokecrystal_obj :='): objects = line[len('pokecrystal_obj :='):].strip().split() break else: print('Error: Object files not found!', file=sys.stderr) sys.exit(1) # Scan all unnamed symbols from the symfile symbols_total = 0 symbols = set() for line in args.symfile: line = line.split(';')[0].strip() split = line.split(' ') if len(split) < 2: continue symbols_total += 1 symbol = ' '.join(split[1:]).strip() if symbol[-3:].lower() == split[0][-3:].lower(): symbols.add(symbol) # If no object files were provided, just print what we know and exit unnamed_percent = 100 * (symbols_total - len(symbols)) / symbols_total print(f'Unnamed pokecrystal symbols: {len(symbols)} ({unnamed_percent:.2f}% complete)') if not objects: for sym in symbols: print(sym) sys.exit() # Count the amount of symbols in each file file_symbols = {} for objfile in objects: with open(objfile, 'rb') as file: obj_ver = None magic = unpack_from('4s', file)[0] if magic == b'RGB6': obj_ver = 6 elif magic == b'RGB9': obj_ver = 10 + unpack_from('