|  | #!/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) |