summaryrefslogtreecommitdiff
path: root/tools/unnamed.py
blob: f99a38d8813ddeb5046031e5b5df43b02d79bf2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3

from sys import stderr, exit
from subprocess import Popen, PIPE
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)")
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 Popen(["make", "-C", args.rootdir, "-s", "-p", "DEBUG=1"],
            stdout=PIPE).stdout.read().decode().split("\n"):
        if line.startswith("pokered_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_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
print("Unnamed pokered symbols: %d (%.2f%% complete)" % (len(symbols),
        (symbols_total - len(symbols)) / symbols_total * 100))
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")
    obj_ver = None

    magic = unpack_file("4s", f)[0]
    if magic == b'RGB6':
        obj_ver = 6
    elif magic == b'RGB9':
        obj_ver = 10 + unpack_file("<I", f)[0]

    if obj_ver not in [6, 10, 11, 12, 13, 15, 16]:
        print("Error: File '%s' is of an unknown format." % objfile, file=stderr)
        exit(1)

    num_symbols = unpack_file("<I", f)[0]
    unpack_file("<I", f) # skip num sections

    if obj_ver in [16]:
        node_filenames = []
        num_nodes = unpack_file("<I", f)[0]
        for x in range(num_nodes):
            unpack_file("<II", f) # parent id, parent line no
            node_type = unpack_file("<B", f)[0]
            if node_type:
                node_filenames.append(read_string(f))
            else:
                node_filenames.append("rept")
                depth = unpack_file("<I", f)[0]
                for i in range(depth):
                    unpack_file("<I", f) # rept iterations
        node_filenames.reverse()

    for x in range(num_symbols):
        sym_name = read_string(f)
        sym_type = symtype(unpack_file("<B", f)[0] & 0x7f)
        if sym_type == symtype.IMPORT:
            continue
        if obj_ver in [16]:
            sym_fileno = unpack_file("<I", f)[0]
            sym_filename = node_filenames[sym_fileno]
        else:
            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] = []
        files[sym_filename].append(sym_name)

# Sort the files, the one with the most amount of symbols first
files = sorted(((f, files[f]) for f in files), key=lambda x: len(x[1]), reverse=True)
for f in files:
    filename, unnamed = f
    sym_list = ', '.join(unnamed[:args.list])
    print("%s: %d%s" % (filename, len(unnamed), ': ' + sym_list if sym_list else ''))