1#!/usr/bin/env python 2#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===# 3# 4# The LLVM Compiler Infrastructure 5# 6# This file is distributed under the University of Illinois Open Source 7# License. See LICENSE.TXT for details. 8# 9#===------------------------------------------------------------------------===# 10# 11# Generates the list of functions that should be exported from sanitizer 12# runtimes. The output format is recognized by --dynamic-list linker option. 13# Usage: 14# gen_dynamic_list.py libclang_rt.*san*.a [ files ... ] 15# 16#===------------------------------------------------------------------------===# 17import argparse 18import os 19import re 20import subprocess 21import sys 22 23new_delete = set([ 24 '_Znam', '_ZnamRKSt9nothrow_t', # operator new[](unsigned long) 25 '_Znwm', '_ZnwmRKSt9nothrow_t', # operator new(unsigned long) 26 '_Znaj', '_ZnajRKSt9nothrow_t', # operator new[](unsigned int) 27 '_Znwj', '_ZnwjRKSt9nothrow_t', # operator new(unsigned int) 28 '_ZdaPv', '_ZdaPvRKSt9nothrow_t', # operator delete[](void *) 29 '_ZdlPv', '_ZdlPvRKSt9nothrow_t', # operator delete(void *) 30 '_ZdaPvm', # operator delete[](void*, unsigned long) 31 '_ZdlPvm', # operator delete(void*, unsigned long) 32 '_ZdaPvj', # operator delete[](void*, unsigned int) 33 '_ZdlPvj', # operator delete(void*, unsigned int) 34 ]) 35 36versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np', 37 'pthread_cond_broadcast', 38 'pthread_cond_destroy', 'pthread_cond_init', 39 'pthread_cond_signal', 'pthread_cond_timedwait', 40 'pthread_cond_wait', 'realpath', 41 'sched_getaffinity']) 42 43def get_global_functions(library): 44 functions = [] 45 nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE, 46 stderr=subprocess.PIPE) 47 nm_out = nm_proc.communicate()[0].decode().split('\n') 48 if nm_proc.returncode != 0: 49 raise subprocess.CalledProcessError(nm_proc.returncode, 'nm') 50 func_symbols = ['T', 'W'] 51 # On PowerPC, nm prints function descriptors from .data section. 52 if os.uname()[4] in ["powerpc", "ppc64"]: 53 func_symbols += ['D'] 54 for line in nm_out: 55 cols = line.split(' ') 56 if len(cols) == 3 and cols[1] in func_symbols : 57 functions.append(cols[2]) 58 return functions 59 60def main(argv): 61 parser = argparse.ArgumentParser() 62 parser.add_argument('--version-list', action='store_true') 63 parser.add_argument('--extra', default=[], action='append') 64 parser.add_argument('libraries', default=[], nargs='+') 65 args = parser.parse_args() 66 67 result = [] 68 69 all_functions = [] 70 for library in args.libraries: 71 all_functions.extend(get_global_functions(library)) 72 function_set = set(all_functions) 73 for func in all_functions: 74 # Export new/delete operators. 75 if func in new_delete: 76 result.append(func) 77 continue 78 # Export interceptors. 79 match = re.match('__interceptor_(.*)', func) 80 if match: 81 result.append(func) 82 # We have to avoid exporting the interceptors for versioned library 83 # functions due to gold internal error. 84 orig_name = match.group(1) 85 if orig_name in function_set and (args.version_list or orig_name not in versioned_functions): 86 result.append(orig_name) 87 continue 88 # Export sanitizer interface functions. 89 if re.match('__sanitizer_(.*)', func): 90 result.append(func) 91 92 # Additional exported functions from files. 93 for fname in args.extra: 94 f = open(fname, 'r') 95 for line in f: 96 result.append(line.rstrip()) 97 # Print the resulting list in the format recognized by ld. 98 print('{') 99 if args.version_list: 100 print('global:') 101 result.sort() 102 for f in result: 103 print(u' %s;' % f) 104 if args.version_list: 105 print('local:') 106 print(' *;') 107 print('};') 108 109if __name__ == '__main__': 110 main(sys.argv) 111