1#!/usr/bin/env bash 2# 3# Run as: CLANG=bin/clang build_symbolizer.sh out.o 4# If you want to use a local copy of zlib, set ZLIB_SRC. 5# zlib can be downloaded from http://www.zlib.net. 6# 7# Script compiles self-contained object file with symbolization code. 8# 9# Symbols exported by the object file will be used by Sanitizer runtime 10# libraries to symbolize code/data in-process. 11# 12# FIXME: We should really be using a simpler approach to building this object 13# file, and it should be available as a regular cmake rule. Conceptually, we 14# want to be doing "ld -r" followed by "objcopy -G" to create a relocatable 15# object file with only our entry points exposed. However, this does not work at 16# present, see https://github.com/llvm/llvm-project/issues/30098. 17 18set -x 19set -e 20set -u 21 22SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) 23SRC_DIR=$(readlink -f $SCRIPT_DIR/..) 24 25if [[ $# -ne 1 ]]; then 26 echo "Missing output file" 27 exit 1 28fi 29 30OUTPUT=$(readlink -f $1) 31COMPILER_RT_SRC=$(readlink -f ${SCRIPT_DIR}/../../../..) 32LLVM_SRC=${LLVM_SRC:-${COMPILER_RT_SRC}/../llvm} 33LLVM_SRC=$(readlink -f $LLVM_SRC) 34 35CLANG="${CLANG:-`which clang`}" 36CLANG_DIR=$(readlink -f $(dirname "$CLANG")) 37 38CC=$CLANG_DIR/clang 39CXX=$CLANG_DIR/clang++ 40TBLGEN=$CLANG_DIR/llvm-tblgen 41OPT=$CLANG_DIR/opt 42AR=$CLANG_DIR/llvm-ar 43LINK=$CLANG_DIR/llvm-link 44 45for F in $CC $CXX $TBLGEN $LINK $OPT $AR; do 46 if [[ ! -x "$F" ]]; then 47 echo "Missing $F" 48 exit 1 49 fi 50done 51 52BUILD_DIR=${PWD}/symbolizer 53mkdir -p $BUILD_DIR 54cd $BUILD_DIR 55 56ZLIB_BUILD=${BUILD_DIR}/zlib 57LIBCXX_BUILD=${BUILD_DIR}/libcxx 58LIBCXX_INSTALL=${BUILD_DIR}/libcxx-install 59LLVM_BUILD=${BUILD_DIR}/llvm 60SYMBOLIZER_BUILD=${BUILD_DIR}/symbolizer 61 62FLAGS=${FLAGS:-} 63ZLIB_SRC=${ZLIB_SRC:-} 64TARGET_TRIPLE=$($CC -print-target-triple $FLAGS) 65if [[ "$FLAGS" =~ "-m32" ]] ; then 66 # Avoid new wrappers. 67 FLAGS+=" -U_FILE_OFFSET_BITS" 68fi 69FLAGS+=" -fPIC -flto -Oz -g0 -DNDEBUG -target $TARGET_TRIPLE -Wno-unused-command-line-argument" 70FLAGS+=" -include ${SRC_DIR}/../sanitizer_redefine_builtins.h -DSANITIZER_COMMON_REDEFINE_BUILTINS_IN_STD -Wno-language-extension-token" 71 72LINKFLAGS="-fuse-ld=lld -target $TARGET_TRIPLE" 73 74# Build zlib. 75if [[ ! -d ${ZLIB_BUILD} ]]; then 76 if [[ -z "${ZLIB_SRC}" ]]; then 77 git clone https://github.com/madler/zlib ${ZLIB_BUILD} 78 else 79 ZLIB_SRC=$(readlink -f $ZLIB_SRC) 80 mkdir -p ${ZLIB_BUILD} 81 cp -r ${ZLIB_SRC}/* ${ZLIB_BUILD}/ 82 fi 83fi 84 85cd ${ZLIB_BUILD} 86AR="${AR}" CC="${CC}" CFLAGS="$FLAGS -Wno-deprecated-non-prototype" RANLIB=/bin/true ./configure --static 87make -j libz.a 88 89# Build and install libcxxabi and libcxx. 90if [[ ! -f ${LLVM_BUILD}/build.ninja ]]; then 91 rm -rf "${LIBCXX_BUILD}" "${LIBCXX_INSTALL}" 92 mkdir -p ${LIBCXX_BUILD} ${LIBCXX_INSTALL} 93 cd ${LIBCXX_BUILD} 94 LIBCXX_FLAGS="${FLAGS} -Wno-macro-redefined" 95 cmake -GNinja \ 96 -DCMAKE_INSTALL_PREFIX="${LIBCXX_INSTALL}" \ 97 -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ 98 -DCMAKE_BUILD_TYPE=Release \ 99 -DCMAKE_C_COMPILER_WORKS=ON \ 100 -DCMAKE_CXX_COMPILER_WORKS=ON \ 101 -DCMAKE_C_COMPILER=$CC \ 102 -DCMAKE_CXX_COMPILER=$CXX \ 103 -DLIBCXX_ABI_NAMESPACE=__InternalSymbolizer \ 104 '-DLIBCXX_EXTRA_SITE_DEFINES=_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS;_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS' \ 105 -DCMAKE_C_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 106 -DCMAKE_CXX_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 107 -DLIBCXXABI_ENABLE_ASSERTIONS=OFF \ 108 -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \ 109 -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ 110 -DLIBCXX_ENABLE_ASSERTIONS=OFF \ 111 -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ 112 -DLIBCXX_ENABLE_RTTI=OFF \ 113 -DCMAKE_SHARED_LINKER_FLAGS="$LINKFLAGS" \ 114 -DLIBCXX_ENABLE_SHARED=OFF \ 115 -DLIBCXXABI_ENABLE_SHARED=OFF \ 116 $LLVM_SRC/../runtimes 117fi 118cd ${LIBCXX_BUILD} 119ninja cxx cxxabi && ninja install-cxx install-cxxabi 120 121FLAGS="${FLAGS} -fno-rtti -fno-exceptions" 122LLVM_CFLAGS="${FLAGS} -Wno-global-constructors" 123LLVM_CXXFLAGS="${LLVM_CFLAGS} -nostdinc++ -I${ZLIB_BUILD} -isystem ${LIBCXX_INSTALL}/include -isystem ${LIBCXX_INSTALL}/include/c++/v1" 124 125# Build LLVM. 126if [[ ! -f ${LLVM_BUILD}/build.ninja ]]; then 127 rm -rf ${LLVM_BUILD} 128 mkdir -p ${LLVM_BUILD} 129 cd ${LLVM_BUILD} 130 cmake -GNinja \ 131 -DCMAKE_BUILD_TYPE=Release \ 132 -DCMAKE_C_COMPILER_WORKS=ON \ 133 -DCMAKE_CXX_COMPILER_WORKS=ON \ 134 -DCMAKE_C_COMPILER=$CC \ 135 -DCMAKE_CXX_COMPILER=$CXX \ 136 -DLLVM_ENABLE_LIBCXX=ON \ 137 -DCMAKE_C_FLAGS_RELEASE="${LLVM_CFLAGS}" \ 138 -DCMAKE_CXX_FLAGS_RELEASE="${LLVM_CXXFLAGS}" \ 139 -DCMAKE_EXE_LINKER_FLAGS="$LINKFLAGS -stdlib=libc++ -L${LIBCXX_INSTALL}/lib" \ 140 -DLLVM_TABLEGEN=$TBLGEN \ 141 -DLLVM_INCLUDE_TESTS=OFF \ 142 -DLLVM_ENABLE_ZLIB=ON \ 143 -DLLVM_ENABLE_ZSTD=OFF \ 144 -DLLVM_ENABLE_THREADS=OFF \ 145 $LLVM_SRC 146fi 147cd ${LLVM_BUILD} 148ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMDebuginfod LLVMMC LLVMDemangle LLVMTextAPI LLVMTargetParser LLVMCore 149 150cd ${BUILD_DIR} 151rm -rf ${SYMBOLIZER_BUILD} 152mkdir ${SYMBOLIZER_BUILD} 153cd ${SYMBOLIZER_BUILD} 154 155echo "Compiling..." 156SYMBOLIZER_FLAGS="$LLVM_CXXFLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++17" 157$CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cpp ${SRC_DIR}/sanitizer_wrappers.cpp -c 158$AR rc symbolizer.a sanitizer_symbolize.o sanitizer_wrappers.o 159 160SYMBOLIZER_API_LIST=__sanitizer_symbolize_code 161SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_data 162SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_frame 163SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_flush 164SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_demangle 165SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_set_demangle 166SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_set_inline_frames 167 168LIBCXX_ARCHIVE_DIR=$(dirname $(find $LIBCXX_INSTALL -name libc++.a | head -n1)) 169 170# Merge all the object files together and copy the resulting library back. 171$LINK $LIBCXX_ARCHIVE_DIR/libc++.a \ 172 $LIBCXX_ARCHIVE_DIR/libc++abi.a \ 173 $LLVM_BUILD/lib/libLLVMSymbolize.a \ 174 $LLVM_BUILD/lib/libLLVMObject.a \ 175 $LLVM_BUILD/lib/libLLVMBinaryFormat.a \ 176 $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \ 177 $LLVM_BUILD/lib/libLLVMSupport.a \ 178 $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ 179 $LLVM_BUILD/lib/libLLVMDebugInfoMSF.a \ 180 $LLVM_BUILD/lib/libLLVMDebugInfoCodeView.a \ 181 $LLVM_BUILD/lib/libLLVMDebuginfod.a \ 182 $LLVM_BUILD/lib/libLLVMDemangle.a \ 183 $LLVM_BUILD/lib/libLLVMMC.a \ 184 $LLVM_BUILD/lib/libLLVMTextAPI.a \ 185 $LLVM_BUILD/lib/libLLVMTargetParser.a \ 186 $LLVM_BUILD/lib/libLLVMCore.a \ 187 $ZLIB_BUILD/libz.a \ 188 symbolizer.a \ 189 -ignore-non-bitcode -o all.bc 190 191echo "Optimizing..." 192$OPT -passes=internalize -internalize-public-api-list=${SYMBOLIZER_API_LIST} all.bc -o opt.bc 193$CC $FLAGS -fno-lto -c opt.bc -o symbolizer.o 194 195echo "Checking undefined symbols..." 196export LC_ALL=C 197nm -f posix -g symbolizer.o | cut -f 1,2 -d \ | sort -u > undefined.new 198grep -Ev "^#|^$" $SCRIPT_DIR/global_symbols.txt | sort -u > expected.new 199(diff -u expected.new undefined.new | grep -E "^\+[^+]") && \ 200 (echo "Failed: unexpected symbols"; exit 1) 201 202cp -f symbolizer.o $OUTPUT 203 204echo "Success!" 205