1#!/bin/bash -eu 2# 3# Run as: CLANG=bin/clang ZLIB_SRC=src/zlib \ 4# build_symbolizer.sh runtime_build/lib/clang/4.0.0/lib/linux/ 5# zlib can be downloaded from http://www.zlib.net. 6# 7# Script compiles self-contained object file with symbolization code and injects 8# it into the given set of runtime libraries. Script updates only libraries 9# which has unresolved __sanitizer_symbolize_* symbols and matches architecture. 10# Object file is be compiled from LLVM sources with dependencies like libc++ and 11# zlib. Then it internalizes symbols in the file, so that it can be linked 12# into arbitrary programs, avoiding conflicts with the program own symbols and 13# avoiding dependencies on any program symbols. The only acceptable dependencies 14# are libc and __sanitizer::internal_* from sanitizer runtime. 15# 16# Symbols exported by the object file will be used by Sanitizer runtime 17# libraries to symbolize code/data in-process. 18# 19# The script will modify the output directory which is given as the first 20# argument to the script. 21# 22# FIXME: We should really be using a simpler approach to building this object 23# file, and it should be available as a regular cmake rule. Conceptually, we 24# want to be doing "ld -r" followed by "objcopy -G" to create a relocatable 25# object file with only our entry points exposed. However, this does not work at 26# present, see PR30750. 27 28SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 29SRC_DIR=$(readlink -f $SCRIPT_DIR/..) 30TARGE_DIR=$(readlink -f $1) 31 32LLVM_SRC="${LLVM_SRC:-$SCRIPT_DIR/../../../../../..}" 33LLVM_SRC=$(readlink -f $LLVM_SRC) 34 35if [[ ! -d "${LLVM_SRC}/projects/libcxxabi" || 36 ! -d "${LLVM_SRC}/projects/libcxx" ]]; then 37 echo "Missing or incomplete LLVM_SRC" 38 exit 1 39fi 40 41if [[ "$ZLIB_SRC" == "" || 42 ! -x "${ZLIB_SRC}/configure" || 43 ! -f "${ZLIB_SRC}/zlib.h" ]]; then 44 echo "Missing or incomplete ZLIB_SRC" 45 exit 1 46fi 47ZLIB_SRC=$(readlink -f $ZLIB_SRC) 48 49J="${J:-50}" 50 51CLANG="${CLANG:-`which clang`}" 52CLANG_DIR=$(readlink -f $(dirname "$CLANG")) 53 54BUILD_DIR=$(readlink -f ./symbolizer) 55mkdir -p $BUILD_DIR 56cd $BUILD_DIR 57 58CC=$CLANG_DIR/clang 59CXX=$CLANG_DIR/clang++ 60TBLGEN=$CLANG_DIR/llvm-tblgen 61OPT=$CLANG_DIR/opt 62export AR=$CLANG_DIR/llvm-ar 63export LINK=$CLANG_DIR/llvm-link 64 65for F in $CC $CXX $TBLGEN $LINK $OPT $AR; do 66 if [[ ! -x "$F" ]]; then 67 echo "Missing $F" 68 exit 1 69 fi 70done 71 72ZLIB_BUILD=${BUILD_DIR}/zlib 73LIBCXX_BUILD=${BUILD_DIR}/libcxx 74LLVM_BUILD=${BUILD_DIR}/llvm 75SYMBOLIZER_BUILD=${BUILD_DIR}/symbolizer 76 77FLAGS=${FLAGS:-} 78FLAGS="$FLAGS -fPIC -flto -Os -g0 -DNDEBUG" 79 80# Build zlib. 81mkdir -p ${ZLIB_BUILD} 82cd ${ZLIB_BUILD} 83cp -r ${ZLIB_SRC}/* . 84CC=$CC CFLAGS="$FLAGS" RANLIB=/bin/true ./configure --static 85make -j${J} libz.a 86 87# Build and install libcxxabi and libcxx. 88if [[ ! -d ${LIBCXX_BUILD} ]]; then 89 mkdir -p ${LIBCXX_BUILD} 90 cd ${LIBCXX_BUILD} 91 LIBCXX_FLAGS="${FLAGS} -Wno-macro-redefined -I${LLVM_SRC}/projects/libcxxabi/include" 92 cmake -GNinja \ 93 -DCMAKE_BUILD_TYPE=Release \ 94 -DCMAKE_C_COMPILER=$CC \ 95 -DCMAKE_CXX_COMPILER=$CXX \ 96 -DCMAKE_C_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 97 -DCMAKE_CXX_FLAGS_RELEASE="${LIBCXX_FLAGS}" \ 98 -DLIBCXXABI_ENABLE_ASSERTIONS=OFF \ 99 -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \ 100 -DLIBCXXABI_ENABLE_SHARED=OFF \ 101 -DLIBCXX_ENABLE_ASSERTIONS=OFF \ 102 -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ 103 -DLIBCXX_ENABLE_RTTI=OFF \ 104 -DLIBCXX_ENABLE_SHARED=OFF \ 105 $LLVM_SRC 106fi 107cd ${LIBCXX_BUILD} 108ninja cxx cxxabi 109 110FLAGS="${FLAGS} -fno-rtti -fno-exceptions" 111LLVM_FLAGS="${FLAGS} -nostdinc++ -I${ZLIB_BUILD} -I${LIBCXX_BUILD}/include/c++/v1" 112 113# Build LLVM. 114if [[ ! -d ${LLVM_BUILD} ]]; then 115 mkdir -p ${LLVM_BUILD} 116 cd ${LLVM_BUILD} 117 cmake -GNinja \ 118 -DCMAKE_BUILD_TYPE=Release \ 119 -DCMAKE_C_COMPILER=$CC \ 120 -DCMAKE_CXX_COMPILER=$CXX \ 121 -DCMAKE_C_FLAGS_RELEASE="${LLVM_FLAGS}" \ 122 -DCMAKE_CXX_FLAGS_RELEASE="${LLVM_FLAGS}" \ 123 -DLLVM_TABLEGEN=$TBLGEN \ 124 -DLLVM_ENABLE_ZLIB=ON \ 125 -DLLVM_ENABLE_TERMINFO=OFF \ 126 -DLLVM_ENABLE_THREADS=OFF \ 127 $LLVM_SRC 128fi 129cd ${LLVM_BUILD} 130ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC LLVMDemangle 131 132cd ${BUILD_DIR} 133rm -rf ${SYMBOLIZER_BUILD} 134mkdir ${SYMBOLIZER_BUILD} 135cd ${SYMBOLIZER_BUILD} 136 137echo "Compiling..." 138SYMBOLIZER_FLAGS="$LLVM_FLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++11" 139$CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cc ${SRC_DIR}/sanitizer_wrappers.cc -c 140$AR rc symbolizer.a sanitizer_symbolize.o sanitizer_wrappers.o 141 142SYMBOLIZER_API_LIST=__sanitizer_symbolize_code,__sanitizer_symbolize_data,__sanitizer_symbolize_flush,__sanitizer_symbolize_demangle 143 144# Merge all the object files together and copy the resulting library back. 145$SCRIPT_DIR/ar_to_bc.sh $LIBCXX_BUILD/lib/libc++.a \ 146 $LIBCXX_BUILD/lib/libc++abi.a \ 147 $LLVM_BUILD/lib/libLLVMSymbolize.a \ 148 $LLVM_BUILD/lib/libLLVMObject.a \ 149 $LLVM_BUILD/lib/libLLVMBinaryFormat.a \ 150 $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \ 151 $LLVM_BUILD/lib/libLLVMSupport.a \ 152 $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ 153 $LLVM_BUILD/lib/libLLVMDemangle.a \ 154 $LLVM_BUILD/lib/libLLVMMC.a \ 155 $ZLIB_BUILD/libz.a \ 156 symbolizer.a \ 157 all.bc 158 159echo "Optimizing..." 160$OPT -internalize -internalize-public-api-list=${SYMBOLIZER_API_LIST} all.bc -o opt.bc 161$CC $FLAGS -fno-lto -c opt.bc -o symbolizer.o 162 163echo "Checking undefined symbols..." 164nm -f posix -g symbolizer.o | cut -f 1,2 -d \ | LC_COLLATE=C sort -u > undefined.new 165(diff -u $SCRIPT_DIR/global_symbols.txt undefined.new | grep -E "^\+[^+]") && \ 166 (echo "Failed: unexpected symbols"; exit 1) 167 168arch() { 169 objdump -f $1 | grep -m1 -Po "(?<=file format ).*$" 170} 171 172SYMBOLIZER_FORMAT=$(arch symbolizer.o) 173echo "Injecting $SYMBOLIZER_FORMAT symbolizer..." 174for A in $TARGE_DIR/libclang_rt.*san*.a; do 175 A_FORMAT=$(arch $A) 176 if [[ "$A_FORMAT" != "$SYMBOLIZER_FORMAT" ]] ; then 177 continue 178 fi 179 (nm -u $A 2>/dev/null | grep -E "__sanitizer_symbolize_code" >/dev/null) || continue 180 echo "$A" 181 $AR rcs $A symbolizer.o 182done 183 184echo "Success!" 185