Index: cmake/Modules/SanitizerUtils.cmake =================================================================== --- cmake/Modules/SanitizerUtils.cmake +++ cmake/Modules/SanitizerUtils.cmake @@ -1,7 +1,7 @@ include(CompilerRTUtils) set(SANITIZER_GEN_DYNAMIC_LIST - ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.py) + ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.sh) set(SANITIZER_LINT_SCRIPT ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/check_lint.sh) @@ -28,7 +28,7 @@ list(APPEND extra_args "--extra" ${arg}) endforeach() add_custom_command(OUTPUT ${stamp} - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${SANITIZER_GEN_DYNAMIC_LIST} ${extra_args} $ > $.syms COMMAND ${CMAKE_COMMAND} -E touch ${stamp} @@ -78,7 +78,7 @@ list(APPEND args "$") endforeach() add_custom_command(OUTPUT ${vers} - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${SANITIZER_GEN_DYNAMIC_LIST} --version-list ${args} > ${vers} DEPENDS ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA} ${ARG_LIBS} Index: lib/interception/interception.h =================================================================== --- lib/interception/interception.h +++ lib/interception/interception.h @@ -210,7 +210,7 @@ #if SANITIZER_FUCHSIA // We need to define the __interceptor_func name just to get -// sanitizer_common/scripts/gen_dynamic_list.py to export func. +// sanitizer_common/scripts/gen_dynamic_list.sh to export func. // But we don't need to export __interceptor_func to get that. #define INTERCEPTOR(ret_type, func, ...) \ extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \ Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -5157,7 +5157,7 @@ // Now carefully intercept __tls_get_offset. asm( ".text\n" -// The __intercept_ version has to exist, so that gen_dynamic_list.py +// The __intercept_ version has to exist, so that gen_dynamic_list.sh // exports our symbol. ".weak __tls_get_offset\n" ".type __tls_get_offset, @function\n" Index: lib/sanitizer_common/scripts/gen_dynamic_list.py =================================================================== --- lib/sanitizer_common/scripts/gen_dynamic_list.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/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) Index: lib/sanitizer_common/scripts/gen_dynamic_list.sh =================================================================== --- /dev/null +++ lib/sanitizer_common/scripts/gen_dynamic_list.sh @@ -0,0 +1,216 @@ +#!/bin/sh +#===- lib/sanitizer_common/scripts/gen_dynamic_list.sh ---------------------===# +# +# 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.sh libclang_rt.*san*.a [ files ... ] +# +#===------------------------------------------------------------------------===# + +usage() { + echo "usage: gen_dynamic_list.py [-h] [--version-list] [--extra EXTRA]" + echo " libraries [libraries ...]" +} + +get_global_functions() { + # On PowerPC, nm prints function descriptors from .data section. + $my_file $1 | grep -q "PowerPC" + if [ $? -eq 0 ]; then + export func_symbols="T|W|D" + else + export func_symbols="T|W" + fi + + $my_nm $1 > $tmpfile1 + if [ $? -ne 0 ]; then + printf 'Error calling: %s %s... bailing out\n' "$my_nm" "$1" + exit 1 + fi + + $my_awk '{if(NF == 3 && $2 ~ ENVIRON["func_symbols"]){print $3}}' \ + $tmpfile1 >> $tmpfile2 +} + +version_list= +extra= + +tmpfile1=`mktemp /tmp/${0##*/}.XXXXXX` || exit 1 +tmpfile2=`mktemp /tmp/${0##*/}.XXXXXX` || exit 1 + +trap "rm -f $tmpfile1 $tmpfile2" EXIT + +my_nm=${NM:-nm} +my_awk=${AWK:-awk} +my_file=${FILE:-file} + +while :; do + case $1 in + -h|--help) + usage + exit + ;; + --extra) + if [ "x$2" = "x" ]; then + usage + printf 'Error missing argument for the option\n' + else + extra=$2 + shift + fi + ;; + --extra=?*) + extra=${1#*=} + ;; + --extra=) + usage + printf 'Error missing argument: %s\n' "$1" + ;; + --version-list) + version_list=1 + ;; + --) + shift + break + ;; + -?*) + usage + printf 'Error parsing argument: %s\n' "$1" + ;; + *) + if [ "x$1" = "x" ]; then + break + else + get_global_functions "$1" + fi + ;; + esac + shift +done + +export version_list + +$my_awk " +BEGIN { + # operator new[](unsigned long) + new_delete[\"_Znam\"] = 1 + new_delete[\"_ZnamRKSt9nothrow_t\"] = 1 + # operator new(unsigned long) + new_delete[\"_Znwm\"] = 1 + new_delete[\"_ZnwmRKSt9nothrow_t\"] = 1 + # operator new[](unsigned int) + new_delete[\"_Znaj\"] = 1 + new_delete[\"_ZnajRKSt9nothrow_t\"] = 1 + # operator new(unsigned int) + new_delete[\"_Znwj\"] = 1 + new_delete[\"_ZnwjRKSt9nothrow_t\"] = 1 + # operator new(unsigned long, std::align_val_t) + new_delete[\"_ZnwmSt11align_val_t\"] = 1 + new_delete[\"_ZnwmSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator new(unsigned int, std::align_val_t) + new_delete[\"_ZnwjSt11align_val_t\"] = 1 + new_delete[\"_ZnwjSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator new[](unsigned long, std::align_val_t) + new_delete[\"_ZnamSt11align_val_t\"] = 1 + new_delete[\"_ZnamSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator new[](unsigned int, std::align_val_t) + new_delete[\"_ZnajSt11align_val_t\"] = 1 + new_delete[\"_ZnajSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator delete[](void *) + new_delete[\"_ZdaPv\"] = 1 + new_delete[\"_ZdaPvRKSt9nothrow_t\"] = 1 + # operator delete(void *) + new_delete[\"_ZdlPv\"] = 1 + new_delete[\"_ZdlPvRKSt9nothrow_t\"] = 1 + # operator delete[](void*, unsigned long) + new_delete[\"_ZdaPvm\"] = 1 + # operator delete(void*, unsigned long) + new_delete[\"_ZdlPvm\"] = 1 + # operator delete[](void*, unsigned int) + new_delete[\"_ZdaPvj\"] = 1 + # operator delete(void*, unsigned int) + new_delete[\"_ZdlPvj\"] = 1 + # operator delete(void*, std::align_val_t) + new_delete[\"_ZdlPvSt11align_val_t\"] = 1 + new_delete[\"_ZdlPvSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator delete[](void*, std::align_val_t) + new_delete[\"_ZdaPvSt11align_val_t\"] = 1 + new_delete[\"_ZdaPvSt11align_val_tRKSt9nothrow_t\"] = 1 + # operator delete(void*, unsigned long, std::align_val_t) + new_delete[\"_ZdlPvmSt11align_val_t\"] = 1 + # operator delete[](void*, unsigned long, std::align_val_t) + new_delete[\"_ZdaPvmSt11align_val_t\"] = 1 + # operator delete(void*, unsigned int, std::align_val_t) + new_delete[\"_ZdlPvjSt11align_val_t\"] = 1 + # operator delete[](void*, unsigned int, std::align_val_t) + new_delete[\"_ZdaPvjSt11align_val_t\"] = 1 + + versioned_functions[\"memcpy\"] = 1 + versioned_functions[\"pthread_attr_getaffinity_np\"] = 1 + versioned_functions[\"pthread_cond_broadcast\"] = 1 + versioned_functions[\"pthread_cond_destroy\"] = 1 + versioned_functions[\"pthread_cond_init\"] = 1 + versioned_functions[\"pthread_cond_signal\"] = 1 + versioned_functions[\"pthread_cond_timedwait\"] = 1 + versioned_functions[\"pthread_cond_wait\"] = 1 + versioned_functions[\"realpath\"] = 1 + versioned_functions[\"sched_getaffinity\"] = 1 + + len = 0 +} +NR==FNR { + function_set[\$0] = 1 + next +} +{ + if (\$0 in new_delete) { + result[len++] = \$0 + next + } + if (substr(\$0, 1, 14) == \"__interceptor_\") { + result[len++] = \$0 + # We have to avoid exporting the interceptors for versioned library + # functions due to gold internal error. + orig_name = substr(\$0, 15) + if ((orig_name in function_set) && + (ENVIRON["version_list"] == "1" || + !(orig_name in versioned_functions))) { + result[len++] = orig_name + } + next + } + if (substr(\$0, 1, 12) == \"__sanitizer_\") { + result[len++] = \$0 + next + } +} +END { + for (i in result) { + print result[i] + } +} +" $tmpfile2 $tmpfile2 > $tmpfile1 + +if [ "x$extra" != "x" ]; then + cat $extra >> $tmpfile1 +fi + +sort $tmpfile1 -o $tmpfile2 + +echo "{" +if [ "x$version_list" != "x" ]; then + echo "global:" +fi +$my_awk '{print " " $0 ";"}' $tmpfile2 +if [ "x$version_list" != "x" ]; then + echo "local:" + echo " *;" +fi +echo "};"