| #!/usr/bin/env python |
| #===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===# |
| # |
| # The LLVM Compiler Infrastructure |
| # |
| # This file is distributed under the University of Illinois Open Source |
| # License. See LICENSE.TXT for details. |
| # |
| #===------------------------------------------------------------------------===# |
| # |
| # Generates the list of functions that should be exported from sanitizer |
| # runtimes. The output format is recognized by --dynamic-list linker option. |
| # Usage: |
| # gen_dynamic_list.py libclang_rt.*san*.a [ files ... ] |
| # |
| #===------------------------------------------------------------------------===# |
| import argparse |
| import os |
| import re |
| import subprocess |
| import sys |
| import platform |
| |
| new_delete = set([ |
| '_Znam', '_ZnamRKSt9nothrow_t', # operator new[](unsigned long) |
| '_Znwm', '_ZnwmRKSt9nothrow_t', # operator new(unsigned long) |
| '_Znaj', '_ZnajRKSt9nothrow_t', # operator new[](unsigned int) |
| '_Znwj', '_ZnwjRKSt9nothrow_t', # operator new(unsigned int) |
| # operator new(unsigned long, std::align_val_t) |
| '_ZnwmSt11align_val_t', '_ZnwmSt11align_val_tRKSt9nothrow_t', |
| # operator new(unsigned int, std::align_val_t) |
| '_ZnwjSt11align_val_t', '_ZnwjSt11align_val_tRKSt9nothrow_t', |
| # operator new[](unsigned long, std::align_val_t) |
| '_ZnamSt11align_val_t', '_ZnamSt11align_val_tRKSt9nothrow_t', |
| # operator new[](unsigned int, std::align_val_t) |
| '_ZnajSt11align_val_t', '_ZnajSt11align_val_tRKSt9nothrow_t', |
| '_ZdaPv', '_ZdaPvRKSt9nothrow_t', # operator delete[](void *) |
| '_ZdlPv', '_ZdlPvRKSt9nothrow_t', # operator delete(void *) |
| '_ZdaPvm', # operator delete[](void*, unsigned long) |
| '_ZdlPvm', # operator delete(void*, unsigned long) |
| '_ZdaPvj', # operator delete[](void*, unsigned int) |
| '_ZdlPvj', # operator delete(void*, unsigned int) |
| # operator delete(void*, std::align_val_t) |
| '_ZdlPvSt11align_val_t', '_ZdlPvSt11align_val_tRKSt9nothrow_t', |
| # operator delete[](void*, std::align_val_t) |
| '_ZdaPvSt11align_val_t', '_ZdaPvSt11align_val_tRKSt9nothrow_t', |
| # operator delete(void*, unsigned long, std::align_val_t) |
| '_ZdlPvmSt11align_val_t', |
| # operator delete[](void*, unsigned long, std::align_val_t) |
| '_ZdaPvmSt11align_val_t', |
| # operator delete(void*, unsigned int, std::align_val_t) |
| '_ZdlPvjSt11align_val_t', |
| # operator delete[](void*, unsigned int, std::align_val_t) |
| '_ZdaPvjSt11align_val_t', |
| ]) |
| |
| versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np', |
| 'pthread_cond_broadcast', |
| 'pthread_cond_destroy', 'pthread_cond_init', |
| 'pthread_cond_signal', 'pthread_cond_timedwait', |
| 'pthread_cond_wait', 'realpath', |
| 'sched_getaffinity']) |
| |
| def get_global_functions(library): |
| functions = [] |
| nm = os.environ.get('NM', 'nm') |
| nm_proc = subprocess.Popen([nm, library], stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE) |
| nm_out = nm_proc.communicate()[0].decode().split('\n') |
| if nm_proc.returncode != 0: |
| raise subprocess.CalledProcessError(nm_proc.returncode, nm) |
| func_symbols = ['T', 'W'] |
| # On PowerPC, nm prints function descriptors from .data section. |
| if platform.uname()[4] in ["powerpc", "ppc64"]: |
| func_symbols += ['D'] |
| for line in nm_out: |
| cols = line.split(' ') |
| if len(cols) == 3 and cols[1] in func_symbols : |
| functions.append(cols[2]) |
| return functions |
| |
| def main(argv): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--version-list', action='store_true') |
| parser.add_argument('--extra', default=[], action='append') |
| parser.add_argument('libraries', default=[], nargs='+') |
| args = parser.parse_args() |
| |
| result = [] |
| |
| all_functions = [] |
| for library in args.libraries: |
| all_functions.extend(get_global_functions(library)) |
| function_set = set(all_functions) |
| for func in all_functions: |
| # Export new/delete operators. |
| if func in new_delete: |
| result.append(func) |
| continue |
| # Export interceptors. |
| match = re.match('__interceptor_(.*)', func) |
| if match: |
| result.append(func) |
| # We have to avoid exporting the interceptors for versioned library |
| # functions due to gold internal error. |
| orig_name = match.group(1) |
| if orig_name in function_set and (args.version_list or orig_name not in versioned_functions): |
| result.append(orig_name) |
| continue |
| # Export sanitizer interface functions. |
| if re.match('__sanitizer_(.*)', func): |
| result.append(func) |
| |
| # Additional exported functions from files. |
| for fname in args.extra: |
| f = open(fname, 'r') |
| for line in f: |
| result.append(line.rstrip()) |
| # Print the resulting list in the format recognized by ld. |
| print('{') |
| if args.version_list: |
| print('global:') |
| result.sort() |
| for f in result: |
| print(u' %s;' % f) |
| if args.version_list: |
| print('local:') |
| print(' *;') |
| print('};') |
| |
| if __name__ == '__main__': |
| main(sys.argv) |