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 58LLVM_BUILD=${BUILD_DIR}/llvm 59SYMBOLIZER_BUILD=${BUILD_DIR}/symbolizer 60 61FLAGS=${FLAGS:-} 62ZLIB_SRC=${ZLIB_SRC:-} 63TARGET_TRIPLE=$($CC -print-target-triple $FLAGS) 64if [[ "$FLAGS" =~ "-m32" ]] ; then 65 # Avoid new wrappers. 66 FLAGS+=" -U_FILE_OFFSET_BITS" 67fi 68FLAGS+=" -fPIC -flto -Oz -g0 -DNDEBUG -target $TARGET_TRIPLE -Wno-unused-command-line-argument" 69FLAGS+=" -include ${SRC_DIR}/../sanitizer_redefine_builtins.h -DSANITIZER_COMMON_REDEFINE_BUILTINS_IN_STD -Wno-language-extension-token" 70 71LINKFLAGS="-fuse-ld=lld -target $TARGET_TRIPLE" 72 73# Build zlib. 74if [[ ! -d ${ZLIB_BUILD} ]]; then 75 if [[ -z "${ZLIB_SRC}" ]]; then 76 git clone https://github.com/madler/zlib ${ZLIB_BUILD} 77 else 78 ZLIB_SRC=$(readlink -f $ZLIB_SRC) 79 mkdir -p ${ZLIB_BUILD} 80 cp -r ${ZLIB_SRC}/* ${ZLIB_BUILD}/ 81 fi 82fi 83 84cd ${ZLIB_BUILD} 85AR="${AR}" CC="${CC}" CFLAGS="$FLAGS -Wno-deprecated-non-prototype" RANLIB=/bin/true ./configure --static 86make -j libz.a 87 88# Build and install libcxxabi and libcxx. 89if [[ ! -f ${LLVM_BUILD}/build.ninja ]]; then 90 rm -rf ${LIBCXX_BUILD} 91 mkdir -p ${LIBCXX_BUILD} 92 cd ${LIBCXX_BUILD} 93 LIBCXX_FLAGS="${FLAGS} -Wno-macro-redefined" 94 cmake -GNinja \ 95 -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ 96 -DCMAKE_BUILD_TYPE=Release \ 97 -DCMAKE_C_COMPILER_WORKS=ON \ 98 -DCMAKE_CXX_COMPILER_WORKS=ON \ 99 -DCMAKE_C_COMPILER=$CC \ 100 -DCMAKE_CXX_COMPILER=$CXX \ 101 -DLIBCXX_ABI_NAMESPACE=__InternalSymbolizer \ 102 '-DLIBCXX_EXTRA_SITE_DEFINES=_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS;_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS' \ 103 -DCMAKE_C_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 104 -DCMAKE_CXX_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 105 -DLIBCXXABI_ENABLE_ASSERTIONS=OFF \ 106 -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \ 107 -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ 108 -DLIBCXX_ENABLE_ASSERTIONS=OFF \ 109 -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ 110 -DLIBCXX_ENABLE_RTTI=OFF \ 111 -DCMAKE_SHARED_LINKER_FLAGS="$LINKFLAGS" \ 112 -DLIBCXX_ENABLE_SHARED=OFF \ 113 -DLIBCXXABI_ENABLE_SHARED=OFF \ 114 $LLVM_SRC/../runtimes 115fi 116cd ${LIBCXX_BUILD} 117ninja cxx cxxabi 118 119FLAGS="${FLAGS} -fno-rtti -fno-exceptions" 120LLVM_CFLAGS="${FLAGS} -Wno-global-constructors" 121LLVM_CXXFLAGS="${LLVM_CFLAGS} -nostdinc++ -I${ZLIB_BUILD} -isystem ${LIBCXX_BUILD}/include -isystem ${LIBCXX_BUILD}/include/c++/v1" 122 123# Build LLVM. 124if [[ ! -f ${LLVM_BUILD}/build.ninja ]]; then 125 rm -rf ${LLVM_BUILD} 126 mkdir -p ${LLVM_BUILD} 127 cd ${LLVM_BUILD} 128 cmake -GNinja \ 129 -DCMAKE_BUILD_TYPE=Release \ 130 -DCMAKE_C_COMPILER_WORKS=ON \ 131 -DCMAKE_CXX_COMPILER_WORKS=ON \ 132 -DCMAKE_C_COMPILER=$CC \ 133 -DCMAKE_CXX_COMPILER=$CXX \ 134 -DLLVM_ENABLE_LIBCXX=ON \ 135 -DCMAKE_C_FLAGS_RELEASE="${LLVM_CFLAGS}" \ 136 -DCMAKE_CXX_FLAGS_RELEASE="${LLVM_CXXFLAGS}" \ 137 -DCMAKE_EXE_LINKER_FLAGS="$LINKFLAGS -stdlib=libc++ -L${LIBCXX_BUILD}/lib" \ 138 -DLLVM_TABLEGEN=$TBLGEN \ 139 -DLLVM_INCLUDE_TESTS=OFF \ 140 -DLLVM_ENABLE_ZLIB=ON \ 141 -DLLVM_ENABLE_ZSTD=OFF \ 142 -DLLVM_ENABLE_TERMINFO=OFF \ 143 -DLLVM_ENABLE_THREADS=OFF \ 144 $LLVM_SRC 145fi 146cd ${LLVM_BUILD} 147ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMDebuginfod LLVMMC LLVMDemangle LLVMTextAPI LLVMTargetParser 148 149cd ${BUILD_DIR} 150rm -rf ${SYMBOLIZER_BUILD} 151mkdir ${SYMBOLIZER_BUILD} 152cd ${SYMBOLIZER_BUILD} 153 154echo "Compiling..." 155SYMBOLIZER_FLAGS="$LLVM_CXXFLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++17" 156$CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cpp ${SRC_DIR}/sanitizer_wrappers.cpp -c 157$AR rc symbolizer.a sanitizer_symbolize.o sanitizer_wrappers.o 158 159SYMBOLIZER_API_LIST=__sanitizer_symbolize_code 160SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_data 161SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_frame 162SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_flush 163SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_demangle 164SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_set_demangle 165SYMBOLIZER_API_LIST+=,__sanitizer_symbolize_set_inline_frames 166 167LIBCXX_ARCHIVE_DIR=$(dirname $(find $LIBCXX_BUILD -name libc++.a | head -n1)) 168 169# Merge all the object files together and copy the resulting library back. 170$LINK $LIBCXX_ARCHIVE_DIR/libc++.a \ 171 $LIBCXX_ARCHIVE_DIR/libc++abi.a \ 172 $LLVM_BUILD/lib/libLLVMSymbolize.a \ 173 $LLVM_BUILD/lib/libLLVMObject.a \ 174 $LLVM_BUILD/lib/libLLVMBinaryFormat.a \ 175 $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \ 176 $LLVM_BUILD/lib/libLLVMSupport.a \ 177 $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ 178 $LLVM_BUILD/lib/libLLVMDebugInfoMSF.a \ 179 $LLVM_BUILD/lib/libLLVMDebugInfoCodeView.a \ 180 $LLVM_BUILD/lib/libLLVMDebuginfod.a \ 181 $LLVM_BUILD/lib/libLLVMDemangle.a \ 182 $LLVM_BUILD/lib/libLLVMMC.a \ 183 $LLVM_BUILD/lib/libLLVMTextAPI.a \ 184 $LLVM_BUILD/lib/libLLVMTargetParser.a \ 185 $ZLIB_BUILD/libz.a \ 186 symbolizer.a \ 187 -ignore-non-bitcode -o all.bc 188 189echo "Optimizing..." 190$OPT -passes=internalize -internalize-public-api-list=${SYMBOLIZER_API_LIST} all.bc -o opt.bc 191$CC $FLAGS -fno-lto -c opt.bc -o symbolizer.o 192 193echo "Checking undefined symbols..." 194nm -f posix -g symbolizer.o | cut -f 1,2 -d \ | LC_COLLATE=C sort -u > undefined.new 195(diff -u $SCRIPT_DIR/global_symbols.txt undefined.new | grep -E "^\+[^+]") && \ 196 (echo "Failed: unexpected symbols"; exit 1) 197 198cp -f symbolizer.o $OUTPUT 199 200echo "Success!" 201