1#!/usr/bin/env python 2#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===# 3# 4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5# See https://llvm.org/LICENSE.txt for license information. 6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7# 8#===------------------------------------------------------------------------===# 9# 10# Generates the list of functions that should be exported from sanitizer 11# runtimes. The output format is recognized by --dynamic-list linker option. 12# Usage: 13# gen_dynamic_list.py libclang_rt.*san*.a [ files ... ] 14# 15#===------------------------------------------------------------------------===# 16from __future__ import print_function 17import argparse 18import os 19import re 20import subprocess 21import sys 22import platform 23 24new_delete = set([ 25 '_Znam', '_ZnamRKSt9nothrow_t', # operator new[](unsigned long) 26 '_Znwm', '_ZnwmRKSt9nothrow_t', # operator new(unsigned long) 27 '_Znaj', '_ZnajRKSt9nothrow_t', # operator new[](unsigned int) 28 '_Znwj', '_ZnwjRKSt9nothrow_t', # operator new(unsigned int) 29 # operator new(unsigned long, std::align_val_t) 30 '_ZnwmSt11align_val_t', '_ZnwmSt11align_val_tRKSt9nothrow_t', 31 # operator new(unsigned int, std::align_val_t) 32 '_ZnwjSt11align_val_t', '_ZnwjSt11align_val_tRKSt9nothrow_t', 33 # operator new[](unsigned long, std::align_val_t) 34 '_ZnamSt11align_val_t', '_ZnamSt11align_val_tRKSt9nothrow_t', 35 # operator new[](unsigned int, std::align_val_t) 36 '_ZnajSt11align_val_t', '_ZnajSt11align_val_tRKSt9nothrow_t', 37 '_ZdaPv', '_ZdaPvRKSt9nothrow_t', # operator delete[](void *) 38 '_ZdlPv', '_ZdlPvRKSt9nothrow_t', # operator delete(void *) 39 '_ZdaPvm', # operator delete[](void*, unsigned long) 40 '_ZdlPvm', # operator delete(void*, unsigned long) 41 '_ZdaPvj', # operator delete[](void*, unsigned int) 42 '_ZdlPvj', # operator delete(void*, unsigned int) 43 # operator delete(void*, std::align_val_t) 44 '_ZdlPvSt11align_val_t', '_ZdlPvSt11align_val_tRKSt9nothrow_t', 45 # operator delete[](void*, std::align_val_t) 46 '_ZdaPvSt11align_val_t', '_ZdaPvSt11align_val_tRKSt9nothrow_t', 47 # operator delete(void*, unsigned long, std::align_val_t) 48 '_ZdlPvmSt11align_val_t', 49 # operator delete[](void*, unsigned long, std::align_val_t) 50 '_ZdaPvmSt11align_val_t', 51 # operator delete(void*, unsigned int, std::align_val_t) 52 '_ZdlPvjSt11align_val_t', 53 # operator delete[](void*, unsigned int, std::align_val_t) 54 '_ZdaPvjSt11align_val_t', 55 ]) 56 57versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np', 58 'pthread_cond_broadcast', 59 'pthread_cond_destroy', 'pthread_cond_init', 60 'pthread_cond_signal', 'pthread_cond_timedwait', 61 'pthread_cond_wait', 'realpath', 62 'sched_getaffinity']) 63 64def get_global_functions(nm_executable, library): 65 functions = [] 66 nm = os.environ.get('NM', nm_executable) 67 nm_proc = subprocess.Popen([nm, library], stdout=subprocess.PIPE, 68 stderr=subprocess.PIPE) 69 nm_out = nm_proc.communicate()[0].decode().split('\n') 70 if nm_proc.returncode != 0: 71 raise subprocess.CalledProcessError(nm_proc.returncode, nm) 72 func_symbols = ['T', 'W'] 73 # On PowerPC, nm prints function descriptors from .data section. 74 if platform.uname()[4] in ["powerpc", "ppc64"]: 75 func_symbols += ['D'] 76 for line in nm_out: 77 cols = line.split(' ') 78 if len(cols) == 3 and cols[1] in func_symbols : 79 functions.append(cols[2]) 80 return functions 81 82def main(argv): 83 parser = argparse.ArgumentParser() 84 parser.add_argument('--version-list', action='store_true') 85 parser.add_argument('--extra', default=[], action='append') 86 parser.add_argument('libraries', default=[], nargs='+') 87 parser.add_argument('--nm-executable', required=True) 88 parser.add_argument('-o', '--output', required=True) 89 args = parser.parse_args() 90 91 result = [] 92 93 all_functions = [] 94 for library in args.libraries: 95 all_functions.extend(get_global_functions(args.nm_executable, library)) 96 function_set = set(all_functions) 97 for func in all_functions: 98 # Export new/delete operators. 99 if func in new_delete: 100 result.append(func) 101 continue 102 # Export interceptors. 103 match = re.match('__interceptor_(.*)', func) 104 if match: 105 result.append(func) 106 # We have to avoid exporting the interceptors for versioned library 107 # functions due to gold internal error. 108 orig_name = match.group(1) 109 if orig_name in function_set and (args.version_list or orig_name not in versioned_functions): 110 result.append(orig_name) 111 continue 112 # Export sanitizer interface functions. 113 if re.match('__sanitizer_(.*)', func): 114 result.append(func) 115 116 # Additional exported functions from files. 117 for fname in args.extra: 118 f = open(fname, 'r') 119 for line in f: 120 result.append(line.rstrip()) 121 # Print the resulting list in the format recognized by ld. 122 with open(args.output, 'w') as f: 123 print('{', file=f) 124 if args.version_list: 125 print('global:', file=f) 126 result.sort() 127 for sym in result: 128 print(u' %s;' % sym, file=f) 129 if args.version_list: 130 print('local:', file=f) 131 print(' *;', file=f) 132 print('};', file=f) 133 134if __name__ == '__main__': 135 main(sys.argv) 136