#!/usr/bin/env python # ===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===# # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # # ===------------------------------------------------------------------------===# # # 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 ... ] # # ===------------------------------------------------------------------------===# from __future__ import print_function 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(nm_executable, library): functions = [] nm = os.environ.get("NM", nm_executable) 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="+") parser.add_argument("--nm-executable", required=True) parser.add_argument("-o", "--output", required=True) args = parser.parse_args() result = set() all_functions = [] for library in args.libraries: all_functions.extend(get_global_functions(args.nm_executable, library)) function_set = set(all_functions) for func in all_functions: # Export new/delete operators. if func in new_delete: result.add(func) continue # Export interceptors. match = re.match("_?__interceptor_(.*)", func) if match: result.add(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.add(orig_name) continue # Export sanitizer interface functions. if re.match("__sanitizer_(.*)", func): result.add(func) # Additional exported functions from files. for fname in args.extra: f = open(fname, "r") for line in f: result.add(line.rstrip()) # Print the resulting list in the format recognized by ld. with open(args.output, "w") as f: print("{", file=f) if args.version_list: print("global:", file=f) for sym in sorted(result): print(" %s;" % sym, file=f) if args.version_list: print("local:", file=f) print(" *;", file=f) print("};", file=f) if __name__ == "__main__": main(sys.argv)