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 [ 26 "_Znam", 27 "_ZnamRKSt9nothrow_t", # operator new[](unsigned long) 28 "_Znwm", 29 "_ZnwmRKSt9nothrow_t", # operator new(unsigned long) 30 "_Znaj", 31 "_ZnajRKSt9nothrow_t", # operator new[](unsigned int) 32 "_Znwj", 33 "_ZnwjRKSt9nothrow_t", # operator new(unsigned int) 34 # operator new(unsigned long, std::align_val_t) 35 "_ZnwmSt11align_val_t", 36 "_ZnwmSt11align_val_tRKSt9nothrow_t", 37 # operator new(unsigned int, std::align_val_t) 38 "_ZnwjSt11align_val_t", 39 "_ZnwjSt11align_val_tRKSt9nothrow_t", 40 # operator new[](unsigned long, std::align_val_t) 41 "_ZnamSt11align_val_t", 42 "_ZnamSt11align_val_tRKSt9nothrow_t", 43 # operator new[](unsigned int, std::align_val_t) 44 "_ZnajSt11align_val_t", 45 "_ZnajSt11align_val_tRKSt9nothrow_t", 46 "_ZdaPv", 47 "_ZdaPvRKSt9nothrow_t", # operator delete[](void *) 48 "_ZdlPv", 49 "_ZdlPvRKSt9nothrow_t", # operator delete(void *) 50 "_ZdaPvm", # operator delete[](void*, unsigned long) 51 "_ZdlPvm", # operator delete(void*, unsigned long) 52 "_ZdaPvj", # operator delete[](void*, unsigned int) 53 "_ZdlPvj", # operator delete(void*, unsigned int) 54 # operator delete(void*, std::align_val_t) 55 "_ZdlPvSt11align_val_t", 56 "_ZdlPvSt11align_val_tRKSt9nothrow_t", 57 # operator delete[](void*, std::align_val_t) 58 "_ZdaPvSt11align_val_t", 59 "_ZdaPvSt11align_val_tRKSt9nothrow_t", 60 # operator delete(void*, unsigned long, std::align_val_t) 61 "_ZdlPvmSt11align_val_t", 62 # operator delete[](void*, unsigned long, std::align_val_t) 63 "_ZdaPvmSt11align_val_t", 64 # operator delete(void*, unsigned int, std::align_val_t) 65 "_ZdlPvjSt11align_val_t", 66 # operator delete[](void*, unsigned int, std::align_val_t) 67 "_ZdaPvjSt11align_val_t", 68 ] 69) 70 71versioned_functions = set( 72 [ 73 "memcpy", 74 "pthread_attr_getaffinity_np", 75 "pthread_cond_broadcast", 76 "pthread_cond_destroy", 77 "pthread_cond_init", 78 "pthread_cond_signal", 79 "pthread_cond_timedwait", 80 "pthread_cond_wait", 81 "realpath", 82 "sched_getaffinity", 83 ] 84) 85 86 87def get_global_functions(nm_executable, library): 88 functions = [] 89 nm = os.environ.get("NM", nm_executable) 90 nm_proc = subprocess.Popen( 91 [nm, library], stdout=subprocess.PIPE, stderr=subprocess.PIPE 92 ) 93 nm_out = nm_proc.communicate()[0].decode().split("\n") 94 if nm_proc.returncode != 0: 95 raise subprocess.CalledProcessError(nm_proc.returncode, nm) 96 func_symbols = ["T", "W"] 97 # On PowerPC, nm prints function descriptors from .data section. 98 if platform.uname()[4] in ["powerpc", "ppc64"]: 99 func_symbols += ["D"] 100 for line in nm_out: 101 cols = line.split(" ") 102 if len(cols) == 3 and cols[1] in func_symbols: 103 functions.append(cols[2]) 104 return functions 105 106 107def main(argv): 108 parser = argparse.ArgumentParser() 109 parser.add_argument("--version-list", action="store_true") 110 parser.add_argument("--extra", default=[], action="append") 111 parser.add_argument("libraries", default=[], nargs="+") 112 parser.add_argument("--nm-executable", required=True) 113 parser.add_argument("-o", "--output", required=True) 114 args = parser.parse_args() 115 116 result = set() 117 118 all_functions = [] 119 for library in args.libraries: 120 all_functions.extend(get_global_functions(args.nm_executable, library)) 121 function_set = set(all_functions) 122 for func in all_functions: 123 # Export new/delete operators. 124 if func in new_delete: 125 result.add(func) 126 continue 127 # Export interceptors. 128 match = re.match("_?__interceptor_(.*)", func) 129 if match: 130 result.add(func) 131 # We have to avoid exporting the interceptors for versioned library 132 # functions due to gold internal error. 133 orig_name = match.group(1) 134 if orig_name in function_set and ( 135 args.version_list or orig_name not in versioned_functions 136 ): 137 result.add(orig_name) 138 continue 139 # Export sanitizer interface functions. 140 if re.match("__sanitizer_(.*)", func): 141 result.add(func) 142 143 # Additional exported functions from files. 144 for fname in args.extra: 145 f = open(fname, "r") 146 for line in f: 147 result.add(line.rstrip()) 148 # Print the resulting list in the format recognized by ld. 149 with open(args.output, "w") as f: 150 print("{", file=f) 151 if args.version_list: 152 print("global:", file=f) 153 for sym in sorted(result): 154 print(" %s;" % sym, file=f) 155 if args.version_list: 156 print("local:", file=f) 157 print(" *;", file=f) 158 print("};", file=f) 159 160 161if __name__ == "__main__": 162 main(sys.argv) 163