mirror of https://github.com/pret/pokecrystal.git
95 lines
2.7 KiB
Python
95 lines
2.7 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
from sys import stderr, exit
|
||
|
from subprocess import run
|
||
|
from struct import unpack, calcsize
|
||
|
from enum import Enum
|
||
|
|
||
|
class symtype(Enum):
|
||
|
LOCAL = 0
|
||
|
IMPORT = 1
|
||
|
EXPORT = 2
|
||
|
|
||
|
def unpack_file(fmt, file):
|
||
|
size = calcsize(fmt)
|
||
|
return 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()
|
||
|
else:
|
||
|
buf += b
|
||
|
|
||
|
|
||
|
# Fix broken pipe when using `head`
|
||
|
from signal import signal, SIGPIPE, SIG_DFL
|
||
|
signal(SIGPIPE,SIG_DFL)
|
||
|
|
||
|
import argparse
|
||
|
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)")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
# Get list of object files
|
||
|
objects = None
|
||
|
if args.rootdir:
|
||
|
for line in run(["make", "-C", args.rootdir, "-s", "-p"],
|
||
|
capture_output=True).stdout.decode().split("\n"):
|
||
|
if line.startswith("crystal_obj := "):
|
||
|
objects = line[15:].strip().split()
|
||
|
break
|
||
|
else:
|
||
|
print("Error: Object files not found!", file=stderr)
|
||
|
exit(1)
|
||
|
|
||
|
# Scan all unnamed symbols from the symfile
|
||
|
symbols = set()
|
||
|
for line in args.symfile:
|
||
|
line = line.split(";")[0].strip()
|
||
|
split = line.split(" ")
|
||
|
if len(split) < 2:
|
||
|
continue
|
||
|
|
||
|
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
|
||
|
print("Unnamed symbols: %d" % len(symbols))
|
||
|
if not objects:
|
||
|
for sym in symbols:
|
||
|
print(sym)
|
||
|
exit()
|
||
|
|
||
|
# Count the amount of symbols in each file
|
||
|
files = {}
|
||
|
for objfile in objects:
|
||
|
f = open(objfile, "rb")
|
||
|
if unpack_file("4s", f)[0] != b'RGB6':
|
||
|
print("Error: File '%s' is of an unknown format." % filename, file=stderr)
|
||
|
exit(1)
|
||
|
|
||
|
num_symbols = unpack_file("<II", f)[0]
|
||
|
for x in range(num_symbols):
|
||
|
sym_name = read_string(f)
|
||
|
sym_type = symtype(unpack_file("<B", f)[0])
|
||
|
if sym_type == symtype.IMPORT:
|
||
|
continue
|
||
|
sym_filename = read_string(f)
|
||
|
unpack_file("<III", f)
|
||
|
if sym_name not in symbols:
|
||
|
continue
|
||
|
|
||
|
if sym_filename not in files:
|
||
|
files[sym_filename] = 0
|
||
|
files[sym_filename] += 1
|
||
|
|
||
|
# Sort the files, the one with the most amount of symbols first
|
||
|
files = sorted([(fname, files[fname]) for fname in files], key=lambda x: x[1], reverse=True)
|
||
|
for f in files:
|
||
|
print("%s: %d" % (f[0], f[1]))
|