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