OSDN Git Service

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