xref: /aosp_15_r20/external/mesa3d/bin/symbols-check.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*61046927SAndroid Build Coastguard Worker
3*61046927SAndroid Build Coastguard Workerimport argparse
4*61046927SAndroid Build Coastguard Workerimport os
5*61046927SAndroid Build Coastguard Workerimport platform
6*61046927SAndroid Build Coastguard Workerimport subprocess
7*61046927SAndroid Build Coastguard Worker
8*61046927SAndroid Build Coastguard Worker# This list contains symbols that _might_ be exported for some platforms
9*61046927SAndroid Build Coastguard WorkerPLATFORM_SYMBOLS = [
10*61046927SAndroid Build Coastguard Worker    '_GLOBAL_OFFSET_TABLE_',
11*61046927SAndroid Build Coastguard Worker    '__bss_end__',
12*61046927SAndroid Build Coastguard Worker    '__bss_start__',
13*61046927SAndroid Build Coastguard Worker    '__bss_start',
14*61046927SAndroid Build Coastguard Worker    '__cxa_guard_abort',
15*61046927SAndroid Build Coastguard Worker    '__cxa_guard_acquire',
16*61046927SAndroid Build Coastguard Worker    '__cxa_guard_release',
17*61046927SAndroid Build Coastguard Worker    '__cxa_allocate_dependent_exception',
18*61046927SAndroid Build Coastguard Worker    '__cxa_allocate_exception',
19*61046927SAndroid Build Coastguard Worker    '__cxa_begin_catch',
20*61046927SAndroid Build Coastguard Worker    '__cxa_call_unexpected',
21*61046927SAndroid Build Coastguard Worker    '__cxa_current_exception_type',
22*61046927SAndroid Build Coastguard Worker    '__cxa_current_primary_exception',
23*61046927SAndroid Build Coastguard Worker    '__cxa_decrement_exception_refcount',
24*61046927SAndroid Build Coastguard Worker    '__cxa_deleted_virtual',
25*61046927SAndroid Build Coastguard Worker    '__cxa_demangle',
26*61046927SAndroid Build Coastguard Worker    '__cxa_end_catch',
27*61046927SAndroid Build Coastguard Worker    '__cxa_free_dependent_exception',
28*61046927SAndroid Build Coastguard Worker    '__cxa_free_exception',
29*61046927SAndroid Build Coastguard Worker    '__cxa_get_exception_ptr',
30*61046927SAndroid Build Coastguard Worker    '__cxa_get_globals',
31*61046927SAndroid Build Coastguard Worker    '__cxa_get_globals_fast',
32*61046927SAndroid Build Coastguard Worker    '__cxa_increment_exception_refcount',
33*61046927SAndroid Build Coastguard Worker    '__cxa_new_handler',
34*61046927SAndroid Build Coastguard Worker    '__cxa_pure_virtual',
35*61046927SAndroid Build Coastguard Worker    '__cxa_rethrow',
36*61046927SAndroid Build Coastguard Worker    '__cxa_rethrow_primary_exception',
37*61046927SAndroid Build Coastguard Worker    '__cxa_terminate_handler',
38*61046927SAndroid Build Coastguard Worker    '__cxa_throw',
39*61046927SAndroid Build Coastguard Worker    '__cxa_uncaught_exception',
40*61046927SAndroid Build Coastguard Worker    '__cxa_uncaught_exceptions',
41*61046927SAndroid Build Coastguard Worker    '__cxa_unexpected_handler',
42*61046927SAndroid Build Coastguard Worker    '__dynamic_cast',
43*61046927SAndroid Build Coastguard Worker    '__emutls_get_address',
44*61046927SAndroid Build Coastguard Worker    '__gxx_personality_v0',
45*61046927SAndroid Build Coastguard Worker    '__end__',
46*61046927SAndroid Build Coastguard Worker    '__odr_asan._glapi_Context',
47*61046927SAndroid Build Coastguard Worker    '__odr_asan._glapi_Dispatch',
48*61046927SAndroid Build Coastguard Worker    '_bss_end__',
49*61046927SAndroid Build Coastguard Worker    '_edata',
50*61046927SAndroid Build Coastguard Worker    '_end',
51*61046927SAndroid Build Coastguard Worker    '_fini',
52*61046927SAndroid Build Coastguard Worker    '_init',
53*61046927SAndroid Build Coastguard Worker    '_fbss',
54*61046927SAndroid Build Coastguard Worker    '_fdata',
55*61046927SAndroid Build Coastguard Worker    '_ftext',
56*61046927SAndroid Build Coastguard Worker]
57*61046927SAndroid Build Coastguard Worker
58*61046927SAndroid Build Coastguard Workerdef get_symbols_nm(nm, lib):
59*61046927SAndroid Build Coastguard Worker    '''
60*61046927SAndroid Build Coastguard Worker    List all the (non platform-specific) symbols exported by the library
61*61046927SAndroid Build Coastguard Worker    using `nm`
62*61046927SAndroid Build Coastguard Worker    '''
63*61046927SAndroid Build Coastguard Worker    symbols = []
64*61046927SAndroid Build Coastguard Worker    platform_name = platform.system()
65*61046927SAndroid Build Coastguard Worker    output = subprocess.check_output([nm, '-gP', lib],
66*61046927SAndroid Build Coastguard Worker                                     stderr=open(os.devnull, 'w')).decode("ascii")
67*61046927SAndroid Build Coastguard Worker    for line in output.splitlines():
68*61046927SAndroid Build Coastguard Worker        fields = line.split()
69*61046927SAndroid Build Coastguard Worker        if len(fields) == 2 or fields[1] == 'U':
70*61046927SAndroid Build Coastguard Worker            continue
71*61046927SAndroid Build Coastguard Worker        symbol_name = fields[0]
72*61046927SAndroid Build Coastguard Worker        if platform_name == 'Linux' or platform_name == 'GNU' or platform_name.startswith('GNU/'):
73*61046927SAndroid Build Coastguard Worker            if symbol_name in PLATFORM_SYMBOLS:
74*61046927SAndroid Build Coastguard Worker                continue
75*61046927SAndroid Build Coastguard Worker        elif platform_name == 'Darwin':
76*61046927SAndroid Build Coastguard Worker            assert symbol_name[0] == '_'
77*61046927SAndroid Build Coastguard Worker            symbol_name = symbol_name[1:]
78*61046927SAndroid Build Coastguard Worker        symbols.append(symbol_name)
79*61046927SAndroid Build Coastguard Worker    return symbols
80*61046927SAndroid Build Coastguard Worker
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Workerdef get_symbols_dumpbin(dumpbin, lib):
83*61046927SAndroid Build Coastguard Worker    '''
84*61046927SAndroid Build Coastguard Worker    List all the (non platform-specific) symbols exported by the library
85*61046927SAndroid Build Coastguard Worker    using `dumpbin`
86*61046927SAndroid Build Coastguard Worker    '''
87*61046927SAndroid Build Coastguard Worker    symbols = []
88*61046927SAndroid Build Coastguard Worker    output = subprocess.check_output([dumpbin, '/exports', lib],
89*61046927SAndroid Build Coastguard Worker                                     stderr=open(os.devnull, 'w')).decode("ascii")
90*61046927SAndroid Build Coastguard Worker    for line in output.splitlines():
91*61046927SAndroid Build Coastguard Worker        fields = line.split()
92*61046927SAndroid Build Coastguard Worker        # The lines with the symbols are made of at least 4 columns; see details below
93*61046927SAndroid Build Coastguard Worker        if len(fields) < 4:
94*61046927SAndroid Build Coastguard Worker            continue
95*61046927SAndroid Build Coastguard Worker        try:
96*61046927SAndroid Build Coastguard Worker            # Making sure the first 3 columns are a dec counter, a hex counter
97*61046927SAndroid Build Coastguard Worker            # and a hex address
98*61046927SAndroid Build Coastguard Worker            _ = int(fields[0], 10)
99*61046927SAndroid Build Coastguard Worker            _ = int(fields[1], 16)
100*61046927SAndroid Build Coastguard Worker            _ = int(fields[2], 16)
101*61046927SAndroid Build Coastguard Worker        except ValueError:
102*61046927SAndroid Build Coastguard Worker            continue
103*61046927SAndroid Build Coastguard Worker        symbol_name = fields[3]
104*61046927SAndroid Build Coastguard Worker        # De-mangle symbols
105*61046927SAndroid Build Coastguard Worker        if symbol_name[0] == '_' and '@' in symbol_name:
106*61046927SAndroid Build Coastguard Worker            symbol_name = symbol_name[1:].split('@')[0]
107*61046927SAndroid Build Coastguard Worker        symbols.append(symbol_name)
108*61046927SAndroid Build Coastguard Worker    return symbols
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Workerdef main():
112*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
113*61046927SAndroid Build Coastguard Worker    parser.add_argument('--symbols-file',
114*61046927SAndroid Build Coastguard Worker                        action='store',
115*61046927SAndroid Build Coastguard Worker                        required=True,
116*61046927SAndroid Build Coastguard Worker                        help='path to file containing symbols')
117*61046927SAndroid Build Coastguard Worker    parser.add_argument('--lib',
118*61046927SAndroid Build Coastguard Worker                        action='store',
119*61046927SAndroid Build Coastguard Worker                        required=True,
120*61046927SAndroid Build Coastguard Worker                        help='path to library')
121*61046927SAndroid Build Coastguard Worker    parser.add_argument('--nm',
122*61046927SAndroid Build Coastguard Worker                        action='store',
123*61046927SAndroid Build Coastguard Worker                        help='path to binary (or name in $PATH)')
124*61046927SAndroid Build Coastguard Worker    parser.add_argument('--dumpbin',
125*61046927SAndroid Build Coastguard Worker                        action='store',
126*61046927SAndroid Build Coastguard Worker                        help='path to binary (or name in $PATH)')
127*61046927SAndroid Build Coastguard Worker    parser.add_argument('--ignore-symbol',
128*61046927SAndroid Build Coastguard Worker                        action='append',
129*61046927SAndroid Build Coastguard Worker                        help='do not process this symbol')
130*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker    try:
133*61046927SAndroid Build Coastguard Worker        if platform.system() == 'Windows':
134*61046927SAndroid Build Coastguard Worker            if not args.dumpbin:
135*61046927SAndroid Build Coastguard Worker                parser.error('--dumpbin is mandatory')
136*61046927SAndroid Build Coastguard Worker            lib_symbols = get_symbols_dumpbin(args.dumpbin, args.lib)
137*61046927SAndroid Build Coastguard Worker        else:
138*61046927SAndroid Build Coastguard Worker            if not args.nm:
139*61046927SAndroid Build Coastguard Worker                parser.error('--nm is mandatory')
140*61046927SAndroid Build Coastguard Worker            lib_symbols = get_symbols_nm(args.nm, args.lib)
141*61046927SAndroid Build Coastguard Worker    except:
142*61046927SAndroid Build Coastguard Worker        # We can't run this test, but we haven't technically failed it either
143*61046927SAndroid Build Coastguard Worker        # Return the GNU "skip" error code
144*61046927SAndroid Build Coastguard Worker        exit(77)
145*61046927SAndroid Build Coastguard Worker    mandatory_symbols = []
146*61046927SAndroid Build Coastguard Worker    optional_symbols = []
147*61046927SAndroid Build Coastguard Worker    with open(args.symbols_file) as symbols_file:
148*61046927SAndroid Build Coastguard Worker        qualifier_optional = '(optional)'
149*61046927SAndroid Build Coastguard Worker        for line in symbols_file.readlines():
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker            # Strip comments
152*61046927SAndroid Build Coastguard Worker            line = line.split('#')[0]
153*61046927SAndroid Build Coastguard Worker            line = line.strip()
154*61046927SAndroid Build Coastguard Worker            if not line:
155*61046927SAndroid Build Coastguard Worker                continue
156*61046927SAndroid Build Coastguard Worker
157*61046927SAndroid Build Coastguard Worker            # Line format:
158*61046927SAndroid Build Coastguard Worker            # [qualifier] symbol
159*61046927SAndroid Build Coastguard Worker            qualifier = None
160*61046927SAndroid Build Coastguard Worker            symbol = None
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker            fields = line.split()
163*61046927SAndroid Build Coastguard Worker            if len(fields) == 1:
164*61046927SAndroid Build Coastguard Worker                symbol = fields[0]
165*61046927SAndroid Build Coastguard Worker            elif len(fields) == 2:
166*61046927SAndroid Build Coastguard Worker                qualifier = fields[0]
167*61046927SAndroid Build Coastguard Worker                symbol = fields[1]
168*61046927SAndroid Build Coastguard Worker            else:
169*61046927SAndroid Build Coastguard Worker                print(args.symbols_file + ': invalid format: ' + line)
170*61046927SAndroid Build Coastguard Worker                exit(1)
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker            # The only supported qualifier is 'optional', which means the
173*61046927SAndroid Build Coastguard Worker            # symbol doesn't have to be exported by the library
174*61046927SAndroid Build Coastguard Worker            if qualifier and not qualifier == qualifier_optional:
175*61046927SAndroid Build Coastguard Worker                print(args.symbols_file + ': invalid qualifier: ' + qualifier)
176*61046927SAndroid Build Coastguard Worker                exit(1)
177*61046927SAndroid Build Coastguard Worker
178*61046927SAndroid Build Coastguard Worker            if qualifier == qualifier_optional:
179*61046927SAndroid Build Coastguard Worker                optional_symbols.append(symbol)
180*61046927SAndroid Build Coastguard Worker            else:
181*61046927SAndroid Build Coastguard Worker                mandatory_symbols.append(symbol)
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker    unknown_symbols = []
184*61046927SAndroid Build Coastguard Worker    for symbol in lib_symbols:
185*61046927SAndroid Build Coastguard Worker        if symbol in mandatory_symbols:
186*61046927SAndroid Build Coastguard Worker            continue
187*61046927SAndroid Build Coastguard Worker        if symbol in optional_symbols:
188*61046927SAndroid Build Coastguard Worker            continue
189*61046927SAndroid Build Coastguard Worker        if args.ignore_symbol and symbol in args.ignore_symbol:
190*61046927SAndroid Build Coastguard Worker            continue
191*61046927SAndroid Build Coastguard Worker        if symbol[:2] == '_Z':
192*61046927SAndroid Build Coastguard Worker            # As ajax found out, the compiler intentionally exports symbols
193*61046927SAndroid Build Coastguard Worker            # that we explicitly asked it not to export, and we can't do
194*61046927SAndroid Build Coastguard Worker            # anything about it:
195*61046927SAndroid Build Coastguard Worker            # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36022#c4
196*61046927SAndroid Build Coastguard Worker            continue
197*61046927SAndroid Build Coastguard Worker        unknown_symbols.append(symbol)
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker    missing_symbols = [
200*61046927SAndroid Build Coastguard Worker        sym for sym in mandatory_symbols if sym not in lib_symbols
201*61046927SAndroid Build Coastguard Worker    ]
202*61046927SAndroid Build Coastguard Worker
203*61046927SAndroid Build Coastguard Worker    for symbol in unknown_symbols:
204*61046927SAndroid Build Coastguard Worker        print(args.lib + ': unknown symbol exported: ' + symbol)
205*61046927SAndroid Build Coastguard Worker
206*61046927SAndroid Build Coastguard Worker    for symbol in missing_symbols:
207*61046927SAndroid Build Coastguard Worker        print(args.lib + ': missing symbol: ' + symbol)
208*61046927SAndroid Build Coastguard Worker
209*61046927SAndroid Build Coastguard Worker    if unknown_symbols or missing_symbols:
210*61046927SAndroid Build Coastguard Worker        exit(1)
211*61046927SAndroid Build Coastguard Worker    exit(0)
212*61046927SAndroid Build Coastguard Worker
213*61046927SAndroid Build Coastguard Worker
214*61046927SAndroid Build Coastguard Workerif __name__ == '__main__':
215*61046927SAndroid Build Coastguard Worker    main()
216