xref: /aosp_15_r20/external/libdrm/symbols-check.py (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*7688df22SAndroid Build Coastguard Worker
3*7688df22SAndroid Build Coastguard Workerimport argparse
4*7688df22SAndroid Build Coastguard Workerimport os
5*7688df22SAndroid Build Coastguard Workerimport platform
6*7688df22SAndroid Build Coastguard Workerimport subprocess
7*7688df22SAndroid Build Coastguard Worker
8*7688df22SAndroid Build Coastguard Worker# This list contains symbols that _might_ be exported for some platforms
9*7688df22SAndroid Build Coastguard WorkerPLATFORM_SYMBOLS = [
10*7688df22SAndroid Build Coastguard Worker    '_GLOBAL_OFFSET_TABLE_',
11*7688df22SAndroid Build Coastguard Worker    '__bss_end__',
12*7688df22SAndroid Build Coastguard Worker    '__bss_start__',
13*7688df22SAndroid Build Coastguard Worker    '__bss_start',
14*7688df22SAndroid Build Coastguard Worker    '__end__',
15*7688df22SAndroid Build Coastguard Worker    '_bss_end__',
16*7688df22SAndroid Build Coastguard Worker    '_edata',
17*7688df22SAndroid Build Coastguard Worker    '_end',
18*7688df22SAndroid Build Coastguard Worker    '_fini',
19*7688df22SAndroid Build Coastguard Worker    '_init',
20*7688df22SAndroid Build Coastguard Worker    '_fbss',
21*7688df22SAndroid Build Coastguard Worker    '_fdata',
22*7688df22SAndroid Build Coastguard Worker    '_ftext',
23*7688df22SAndroid Build Coastguard Worker]
24*7688df22SAndroid Build Coastguard Worker
25*7688df22SAndroid Build Coastguard Worker
26*7688df22SAndroid Build Coastguard Workerdef get_symbols(nm, lib):
27*7688df22SAndroid Build Coastguard Worker    '''
28*7688df22SAndroid Build Coastguard Worker    List all the (non platform-specific) symbols exported by the library
29*7688df22SAndroid Build Coastguard Worker    '''
30*7688df22SAndroid Build Coastguard Worker    symbols = []
31*7688df22SAndroid Build Coastguard Worker    platform_name = platform.system()
32*7688df22SAndroid Build Coastguard Worker    output = subprocess.check_output([nm, '-gP', lib],
33*7688df22SAndroid Build Coastguard Worker                                     stderr=open(os.devnull, 'w')).decode("ascii")
34*7688df22SAndroid Build Coastguard Worker    for line in output.splitlines():
35*7688df22SAndroid Build Coastguard Worker        fields = line.split()
36*7688df22SAndroid Build Coastguard Worker        if len(fields) == 2 or fields[1] == 'U':
37*7688df22SAndroid Build Coastguard Worker            continue
38*7688df22SAndroid Build Coastguard Worker        symbol_name = fields[0]
39*7688df22SAndroid Build Coastguard Worker        if platform_name == 'Linux':
40*7688df22SAndroid Build Coastguard Worker            if symbol_name in PLATFORM_SYMBOLS:
41*7688df22SAndroid Build Coastguard Worker                continue
42*7688df22SAndroid Build Coastguard Worker        elif platform_name == 'Darwin':
43*7688df22SAndroid Build Coastguard Worker            assert symbol_name[0] == '_'
44*7688df22SAndroid Build Coastguard Worker            symbol_name = symbol_name[1:]
45*7688df22SAndroid Build Coastguard Worker        symbols.append(symbol_name)
46*7688df22SAndroid Build Coastguard Worker
47*7688df22SAndroid Build Coastguard Worker    return symbols
48*7688df22SAndroid Build Coastguard Worker
49*7688df22SAndroid Build Coastguard Worker
50*7688df22SAndroid Build Coastguard Workerdef main():
51*7688df22SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
52*7688df22SAndroid Build Coastguard Worker    parser.add_argument('--symbols-file',
53*7688df22SAndroid Build Coastguard Worker                        action='store',
54*7688df22SAndroid Build Coastguard Worker                        required=True,
55*7688df22SAndroid Build Coastguard Worker                        help='path to file containing symbols')
56*7688df22SAndroid Build Coastguard Worker    parser.add_argument('--lib',
57*7688df22SAndroid Build Coastguard Worker                        action='store',
58*7688df22SAndroid Build Coastguard Worker                        required=True,
59*7688df22SAndroid Build Coastguard Worker                        help='path to library')
60*7688df22SAndroid Build Coastguard Worker    parser.add_argument('--nm',
61*7688df22SAndroid Build Coastguard Worker                        action='store',
62*7688df22SAndroid Build Coastguard Worker                        required=True,
63*7688df22SAndroid Build Coastguard Worker                        help='path to binary (or name in $PATH)')
64*7688df22SAndroid Build Coastguard Worker    args = parser.parse_args()
65*7688df22SAndroid Build Coastguard Worker
66*7688df22SAndroid Build Coastguard Worker    try:
67*7688df22SAndroid Build Coastguard Worker        lib_symbols = get_symbols(args.nm, args.lib)
68*7688df22SAndroid Build Coastguard Worker    except:
69*7688df22SAndroid Build Coastguard Worker        # We can't run this test, but we haven't technically failed it either
70*7688df22SAndroid Build Coastguard Worker        # Return the GNU "skip" error code
71*7688df22SAndroid Build Coastguard Worker        exit(77)
72*7688df22SAndroid Build Coastguard Worker    mandatory_symbols = []
73*7688df22SAndroid Build Coastguard Worker    optional_symbols = []
74*7688df22SAndroid Build Coastguard Worker    with open(args.symbols_file) as symbols_file:
75*7688df22SAndroid Build Coastguard Worker        qualifier_optional = '(optional)'
76*7688df22SAndroid Build Coastguard Worker        for line in symbols_file.readlines():
77*7688df22SAndroid Build Coastguard Worker
78*7688df22SAndroid Build Coastguard Worker            # Strip comments
79*7688df22SAndroid Build Coastguard Worker            line = line.split('#')[0]
80*7688df22SAndroid Build Coastguard Worker            line = line.strip()
81*7688df22SAndroid Build Coastguard Worker            if not line:
82*7688df22SAndroid Build Coastguard Worker                continue
83*7688df22SAndroid Build Coastguard Worker
84*7688df22SAndroid Build Coastguard Worker            # Line format:
85*7688df22SAndroid Build Coastguard Worker            # [qualifier] symbol
86*7688df22SAndroid Build Coastguard Worker            qualifier = None
87*7688df22SAndroid Build Coastguard Worker            symbol = None
88*7688df22SAndroid Build Coastguard Worker
89*7688df22SAndroid Build Coastguard Worker            fields = line.split()
90*7688df22SAndroid Build Coastguard Worker            if len(fields) == 1:
91*7688df22SAndroid Build Coastguard Worker                symbol = fields[0]
92*7688df22SAndroid Build Coastguard Worker            elif len(fields) == 2:
93*7688df22SAndroid Build Coastguard Worker                qualifier = fields[0]
94*7688df22SAndroid Build Coastguard Worker                symbol = fields[1]
95*7688df22SAndroid Build Coastguard Worker            else:
96*7688df22SAndroid Build Coastguard Worker                print(args.symbols_file + ': invalid format: ' + line)
97*7688df22SAndroid Build Coastguard Worker                exit(1)
98*7688df22SAndroid Build Coastguard Worker
99*7688df22SAndroid Build Coastguard Worker            # The only supported qualifier is 'optional', which means the
100*7688df22SAndroid Build Coastguard Worker            # symbol doesn't have to be exported by the library
101*7688df22SAndroid Build Coastguard Worker            if qualifier and not qualifier == qualifier_optional:
102*7688df22SAndroid Build Coastguard Worker                print(args.symbols_file + ': invalid qualifier: ' + qualifier)
103*7688df22SAndroid Build Coastguard Worker                exit(1)
104*7688df22SAndroid Build Coastguard Worker
105*7688df22SAndroid Build Coastguard Worker            if qualifier == qualifier_optional:
106*7688df22SAndroid Build Coastguard Worker                optional_symbols.append(symbol)
107*7688df22SAndroid Build Coastguard Worker            else:
108*7688df22SAndroid Build Coastguard Worker                mandatory_symbols.append(symbol)
109*7688df22SAndroid Build Coastguard Worker
110*7688df22SAndroid Build Coastguard Worker    unknown_symbols = []
111*7688df22SAndroid Build Coastguard Worker    for symbol in lib_symbols:
112*7688df22SAndroid Build Coastguard Worker        if symbol in mandatory_symbols:
113*7688df22SAndroid Build Coastguard Worker            continue
114*7688df22SAndroid Build Coastguard Worker        if symbol in optional_symbols:
115*7688df22SAndroid Build Coastguard Worker            continue
116*7688df22SAndroid Build Coastguard Worker        unknown_symbols.append(symbol)
117*7688df22SAndroid Build Coastguard Worker
118*7688df22SAndroid Build Coastguard Worker    missing_symbols = [
119*7688df22SAndroid Build Coastguard Worker        sym for sym in mandatory_symbols if sym not in lib_symbols
120*7688df22SAndroid Build Coastguard Worker    ]
121*7688df22SAndroid Build Coastguard Worker
122*7688df22SAndroid Build Coastguard Worker    for symbol in unknown_symbols:
123*7688df22SAndroid Build Coastguard Worker        print(args.lib + ': unknown symbol exported: ' + symbol)
124*7688df22SAndroid Build Coastguard Worker
125*7688df22SAndroid Build Coastguard Worker    for symbol in missing_symbols:
126*7688df22SAndroid Build Coastguard Worker        print(args.lib + ': missing symbol: ' + symbol)
127*7688df22SAndroid Build Coastguard Worker
128*7688df22SAndroid Build Coastguard Worker    if unknown_symbols or missing_symbols:
129*7688df22SAndroid Build Coastguard Worker        exit(1)
130*7688df22SAndroid Build Coastguard Worker    exit(0)
131*7688df22SAndroid Build Coastguard Worker
132*7688df22SAndroid Build Coastguard Worker
133*7688df22SAndroid Build Coastguard Workerif __name__ == '__main__':
134*7688df22SAndroid Build Coastguard Worker    main()
135