Project import
diff --git a/compiler-rt/.arcconfig b/compiler-rt/.arcconfig
new file mode 100644
index 0000000..ef3e327
--- /dev/null
+++ b/compiler-rt/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "project_id" : "compiler-rt",
+ "conduit_uri" : "http://reviews.llvm.org/"
+}
diff --git a/compiler-rt/Android.bp b/compiler-rt/Android.bp
new file mode 100644
index 0000000..b057c23
--- /dev/null
+++ b/compiler-rt/Android.bp
@@ -0,0 +1,441 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//=====================================================================
+// Static Library: libcompiler_rt-extras
+//=====================================================================
+
+cc_library_static {
+ name: "libcompiler_rt-extras",
+ host_supported: true,
+ clang: true,
+ sdk_version: "19",
+ // The following list contains functions that are not available in libgcc.a, so
+ // we potentially need them when using a Clang-built component (e.g., -ftrapv
+ // with 64-bit integer multiplies. See http://llvm.org/bugs/show_bug.cgi?id=14469.)
+ srcs: ["lib/builtins/mulodi4.c"],
+ sanitize: {
+ never: true,
+ },
+ stl: "none",
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Werror",
+ ],
+
+ arch: {
+ mips: {
+ srcs: ["lib/builtins/clear_cache.c"],
+ },
+ mips64: {
+ srcs: ["lib/builtins/clear_cache.c"],
+ },
+ // Clang generates call to __unorddf2 builtin when compiling s_fmal.c
+ // in bionic. Generate this builtin from compiler-rt for arm64 and
+ // x86_64 (where the corresponding libgcc does not have this builtin.
+ arm64: {
+ srcs: ["lib/builtins/comparedf2.c"],
+ },
+ x86_64: {
+ srcs: ["lib/builtins/comparedf2.c"],
+ },
+ },
+
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+//=====================================================================
+// Device and Host Static Library: libcompiler_rt
+//=====================================================================
+
+cc_library {
+ name: "libcompiler_rt",
+ host_supported: true,
+ // The following list contains platform-independent functionalities.
+ //
+ // Skip apple_versioning.c since it is unused.
+ // Skip atomic.c since it needs to be built separately according to the docs.
+ srcs: [
+ "lib/builtins/enable_execute_stack.c",
+ "lib/builtins/absvdi2.c",
+ "lib/builtins/absvsi2.c",
+ "lib/builtins/absvti2.c",
+ "lib/builtins/adddf3.c",
+ "lib/builtins/addsf3.c",
+ "lib/builtins/addtf3.c",
+ "lib/builtins/addvdi3.c",
+ "lib/builtins/addvsi3.c",
+ "lib/builtins/addvti3.c",
+ "lib/builtins/ashldi3.c",
+ "lib/builtins/ashlti3.c",
+ "lib/builtins/ashrdi3.c",
+ "lib/builtins/ashrti3.c",
+ "lib/builtins/clear_cache.c",
+ "lib/builtins/clzdi2.c",
+ "lib/builtins/clzsi2.c",
+ "lib/builtins/clzti2.c",
+ "lib/builtins/cmpdi2.c",
+ "lib/builtins/cmpti2.c",
+ "lib/builtins/comparedf2.c",
+ "lib/builtins/comparesf2.c",
+ "lib/builtins/comparetf2.c",
+ "lib/builtins/ctzdi2.c",
+ "lib/builtins/ctzsi2.c",
+ "lib/builtins/ctzti2.c",
+ "lib/builtins/divdc3.c",
+ "lib/builtins/divdf3.c",
+ "lib/builtins/divdi3.c",
+ "lib/builtins/divmoddi4.c",
+ "lib/builtins/divmodsi4.c",
+ "lib/builtins/divsc3.c",
+ "lib/builtins/divsf3.c",
+ "lib/builtins/divsi3.c",
+ "lib/builtins/divtf3.c",
+ "lib/builtins/divti3.c",
+ "lib/builtins/divxc3.c",
+ "lib/builtins/eprintf.c",
+ "lib/builtins/extenddftf2.c",
+ "lib/builtins/extendhfsf2.c",
+ "lib/builtins/extendsfdf2.c",
+ "lib/builtins/extendsftf2.c",
+ "lib/builtins/ffsdi2.c",
+ "lib/builtins/ffsti2.c",
+ "lib/builtins/fixdfdi.c",
+ "lib/builtins/fixdfsi.c",
+ "lib/builtins/fixdfti.c",
+ "lib/builtins/fixsfdi.c",
+ "lib/builtins/fixsfsi.c",
+ "lib/builtins/fixsfti.c",
+ "lib/builtins/fixtfdi.c",
+ "lib/builtins/fixtfsi.c",
+ "lib/builtins/fixtfti.c",
+ "lib/builtins/fixunsdfdi.c",
+ "lib/builtins/fixunsdfsi.c",
+ "lib/builtins/fixunsdfti.c",
+ "lib/builtins/fixunssfdi.c",
+ "lib/builtins/fixunssfsi.c",
+ "lib/builtins/fixunssfti.c",
+ "lib/builtins/fixunstfdi.c",
+ "lib/builtins/fixunstfsi.c",
+ "lib/builtins/fixunstfti.c",
+ "lib/builtins/fixunsxfdi.c",
+ "lib/builtins/fixunsxfsi.c",
+ "lib/builtins/fixunsxfti.c",
+ "lib/builtins/fixxfdi.c",
+ "lib/builtins/fixxfti.c",
+ "lib/builtins/floatdidf.c",
+ "lib/builtins/floatdisf.c",
+ "lib/builtins/floatdixf.c",
+ "lib/builtins/floatsidf.c",
+ "lib/builtins/floatsisf.c",
+ "lib/builtins/floatsitf.c",
+ "lib/builtins/floattidf.c",
+ "lib/builtins/floattisf.c",
+ "lib/builtins/floattixf.c",
+ "lib/builtins/floatundidf.c",
+ "lib/builtins/floatundisf.c",
+ "lib/builtins/floatundixf.c",
+ "lib/builtins/floatunsidf.c",
+ "lib/builtins/floatunsisf.c",
+ "lib/builtins/floatunsitf.c",
+ "lib/builtins/floatuntidf.c",
+ "lib/builtins/floatuntisf.c",
+ "lib/builtins/floatuntixf.c",
+ "lib/builtins/gcc_personality_v0.c",
+ "lib/builtins/int_util.c",
+ "lib/builtins/lshrdi3.c",
+ "lib/builtins/lshrti3.c",
+ "lib/builtins/moddi3.c",
+ "lib/builtins/modsi3.c",
+ "lib/builtins/modti3.c",
+ "lib/builtins/muldc3.c",
+ "lib/builtins/muldf3.c",
+ "lib/builtins/muldi3.c",
+ "lib/builtins/mulodi4.c",
+ "lib/builtins/mulosi4.c",
+ "lib/builtins/muloti4.c",
+ "lib/builtins/mulsc3.c",
+ "lib/builtins/mulsf3.c",
+ "lib/builtins/multf3.c",
+ "lib/builtins/multi3.c",
+ "lib/builtins/mulvdi3.c",
+ "lib/builtins/mulvsi3.c",
+ "lib/builtins/mulvti3.c",
+ "lib/builtins/mulxc3.c",
+ "lib/builtins/negdf2.c",
+ "lib/builtins/negdi2.c",
+ "lib/builtins/negsf2.c",
+ "lib/builtins/negti2.c",
+ "lib/builtins/negvdi2.c",
+ "lib/builtins/negvsi2.c",
+ "lib/builtins/negvti2.c",
+ "lib/builtins/paritydi2.c",
+ "lib/builtins/paritysi2.c",
+ "lib/builtins/parityti2.c",
+ "lib/builtins/popcountdi2.c",
+ "lib/builtins/popcountsi2.c",
+ "lib/builtins/popcountti2.c",
+ "lib/builtins/powidf2.c",
+ "lib/builtins/powisf2.c",
+ "lib/builtins/powitf2.c",
+ "lib/builtins/powixf2.c",
+ "lib/builtins/subdf3.c",
+ "lib/builtins/subsf3.c",
+ "lib/builtins/subtf3.c",
+ "lib/builtins/subvdi3.c",
+ "lib/builtins/subvsi3.c",
+ "lib/builtins/subvti3.c",
+ "lib/builtins/trampoline_setup.c",
+ "lib/builtins/truncdfhf2.c",
+ "lib/builtins/truncdfsf2.c",
+ "lib/builtins/truncsfhf2.c",
+ "lib/builtins/trunctfdf2.c",
+ "lib/builtins/trunctfsf2.c",
+ "lib/builtins/ucmpdi2.c",
+ "lib/builtins/ucmpti2.c",
+ "lib/builtins/udivdi3.c",
+ "lib/builtins/udivmoddi4.c",
+ "lib/builtins/udivmodsi4.c",
+ "lib/builtins/udivmodti4.c",
+ "lib/builtins/udivsi3.c",
+ "lib/builtins/udivti3.c",
+ "lib/builtins/umoddi3.c",
+ "lib/builtins/umodsi3.c",
+ "lib/builtins/umodti3.c",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Werror",
+ ],
+
+ arch: {
+ arm: {
+ cflags: ["-D__ARM_EABI__"],
+ srcs: [
+ "lib/builtins/arm/aeabi_dcmp.S",
+ "lib/builtins/arm/aeabi_div0.c",
+ "lib/builtins/arm/aeabi_fcmp.S",
+ "lib/builtins/arm/aeabi_idivmod.S",
+ "lib/builtins/arm/aeabi_ldivmod.S",
+ "lib/builtins/arm/aeabi_memcmp.S",
+ "lib/builtins/arm/aeabi_memcpy.S",
+ "lib/builtins/arm/aeabi_memmove.S",
+ "lib/builtins/arm/aeabi_memset.S",
+ "lib/builtins/arm/aeabi_uidivmod.S",
+ "lib/builtins/arm/aeabi_uldivmod.S",
+ "lib/builtins/arm/comparesf2.S",
+ "lib/builtins/arm/divmodsi4.S",
+ "lib/builtins/arm/divsi3.S",
+ "lib/builtins/arm/modsi3.S",
+ "lib/builtins/arm/udivmodsi4.S",
+ "lib/builtins/arm/udivsi3.S",
+ "lib/builtins/arm/umodsi3.S",
+ "lib/builtins/arm/adddf3vfp.S",
+ "lib/builtins/arm/addsf3vfp.S",
+ "lib/builtins/arm/divdf3vfp.S",
+ "lib/builtins/arm/divsf3vfp.S",
+ "lib/builtins/arm/eqdf2vfp.S",
+ "lib/builtins/arm/eqsf2vfp.S",
+ "lib/builtins/arm/extendsfdf2vfp.S",
+ "lib/builtins/arm/fixdfsivfp.S",
+ "lib/builtins/arm/fixsfsivfp.S",
+ "lib/builtins/arm/fixunsdfsivfp.S",
+ "lib/builtins/arm/fixunssfsivfp.S",
+ "lib/builtins/arm/floatsidfvfp.S",
+ "lib/builtins/arm/floatsisfvfp.S",
+ "lib/builtins/arm/floatunssidfvfp.S",
+ "lib/builtins/arm/floatunssisfvfp.S",
+ "lib/builtins/arm/gedf2vfp.S",
+ "lib/builtins/arm/gesf2vfp.S",
+ "lib/builtins/arm/gtdf2vfp.S",
+ "lib/builtins/arm/gtsf2vfp.S",
+ "lib/builtins/arm/ledf2vfp.S",
+ "lib/builtins/arm/lesf2vfp.S",
+ "lib/builtins/arm/ltdf2vfp.S",
+ "lib/builtins/arm/ltsf2vfp.S",
+ "lib/builtins/arm/muldf3vfp.S",
+ "lib/builtins/arm/mulsf3vfp.S",
+ "lib/builtins/arm/nedf2vfp.S",
+ "lib/builtins/arm/negdf2vfp.S",
+ "lib/builtins/arm/negsf2vfp.S",
+ "lib/builtins/arm/nesf2vfp.S",
+ "lib/builtins/arm/subdf3vfp.S",
+ "lib/builtins/arm/subsf3vfp.S",
+ "lib/builtins/arm/truncdfsf2vfp.S",
+ "lib/builtins/arm/unorddf2vfp.S",
+ "lib/builtins/arm/unordsf2vfp.S",
+ ],
+ exclude_srcs: [
+ "lib/builtins/comparesf2.c",
+ "lib/builtins/divmodsi4.c",
+ "lib/builtins/divsi3.c",
+ "lib/builtins/modsi3.c",
+ "lib/builtins/udivmodsi4.c",
+ "lib/builtins/udivsi3.c",
+ "lib/builtins/umodsi3.c",
+ ],
+ },
+ mips64: {
+ cflags: [
+ "-DCRT_HAS_128BIT",
+ ],
+ },
+ x86: {
+ srcs: [
+ "lib/builtins/i386/ashldi3.S",
+ "lib/builtins/i386/ashrdi3.S",
+ "lib/builtins/i386/divdi3.S",
+ "lib/builtins/i386/floatdidf.S",
+ "lib/builtins/i386/floatdisf.S",
+ "lib/builtins/i386/floatdixf.S",
+ "lib/builtins/i386/floatundidf.S",
+ "lib/builtins/i386/floatundisf.S",
+ "lib/builtins/i386/floatundixf.S",
+ "lib/builtins/i386/lshrdi3.S",
+ "lib/builtins/i386/moddi3.S",
+ "lib/builtins/i386/muldi3.S",
+ "lib/builtins/i386/udivdi3.S",
+ "lib/builtins/i386/umoddi3.S",
+ ],
+ exclude_srcs: [
+ "lib/builtins/ashldi3.c",
+ "lib/builtins/ashrdi3.c",
+ "lib/builtins/divdi3.c",
+ "lib/builtins/floatdidf.c",
+ "lib/builtins/floatdisf.c",
+ "lib/builtins/floatdixf.c",
+ "lib/builtins/floatundidf.c",
+ "lib/builtins/floatundisf.c",
+ "lib/builtins/floatundixf.c",
+ "lib/builtins/lshrdi3.c",
+ "lib/builtins/moddi3.c",
+ "lib/builtins/muldi3.c",
+ "lib/builtins/udivdi3.c",
+ "lib/builtins/umoddi3.c",
+ ],
+ },
+ x86_64: {
+ srcs: [
+ "lib/builtins/x86_64/floatundixf.S",
+ "lib/builtins/x86_64/floatdisf.c",
+ "lib/builtins/x86_64/floatdidf.c",
+ "lib/builtins/x86_64/floatdixf.c",
+ "lib/builtins/x86_64/floatundisf.S",
+ "lib/builtins/x86_64/floatundidf.S",
+ ],
+ exclude_srcs: [
+ "lib/builtins/floatundixf.c",
+ "lib/builtins/floatdisf.c",
+ "lib/builtins/floatdidf.c",
+ "lib/builtins/floatdixf.c",
+ "lib/builtins/floatundisf.c",
+ "lib/builtins/floatundidf.c",
+ ],
+ },
+ },
+
+ sdk_version: "21",
+ target: {
+ not_windows: {
+ host_ldlibs: [
+ "-lpthread",
+ "-lc",
+ "-lm",
+ ],
+ },
+ android: {
+ shared_libs: ["libdl", "liblog"],
+ static_libs: ["liblzma"],
+ },
+ android_arm: {
+ static_libs: ["libunwind_llvm"],
+ ldflags: ["-Wl,--exclude-libs,libunwind_llvm.a"],
+ },
+ android_arm64: {
+ static_libs: ["libunwindbacktrace"],
+ ldflags: ["-Wl,--exclude-libs,libunwindbacktrace.a"],
+ },
+ android_mips: {
+ static_libs: ["libunwindbacktrace"],
+ ldflags: ["-Wl,--exclude-libs,libunwindbacktrace.a"],
+ },
+ android_mips64: {
+ static_libs: ["libunwindbacktrace"],
+ ldflags: ["-Wl,--exclude-libs,libunwindbacktrace.a"],
+ },
+ android_x86: {
+ static_libs: ["libunwindbacktrace"],
+ ldflags: ["-Wl,--exclude-libs,libunwindbacktrace.a"],
+ },
+ android_x86_64: {
+ srcs: ["lib/builtins/ppc/floatditf.c"],
+ static_libs: ["libunwindbacktrace"],
+ ldflags: ["-Wl,--exclude-libs,libunwindbacktrace.a"],
+ },
+ linux: {
+ static_libs: ["libunwindbacktrace"],
+ },
+ windows: {
+ static_libs: ["libunwindbacktrace"],
+ // Only build enable_execute_stack.c on non-Windows hosts.
+ exclude_srcs: ["lib/builtins/enable_execute_stack.c"],
+ },
+ },
+
+ asflags: ["-integrated-as"],
+ clang: true,
+ no_libgcc: true,
+
+ sanitize: {
+ never: true,
+ },
+ stl: "none",
+}
+
+cc_defaults {
+ name: "asan_arch_defaults",
+
+ enabled: false,
+ target: {
+ android_arm: {
+ enabled: true,
+ },
+ android_arm64: {
+ enabled: true,
+ },
+ android_mips: {
+ enabled: true,
+ },
+ android_mips64: {
+ enabled: true,
+ },
+ android_x86: {
+ enabled: true,
+ },
+ linux: {
+ enabled: true,
+ },
+ },
+}
+
+subdirs=["lib/*"]
diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt
new file mode 100644
index 0000000..5f8b4d1
--- /dev/null
+++ b/compiler-rt/CMakeLists.txt
@@ -0,0 +1,323 @@
+# CMake build for CompilerRT.
+#
+# This build assumes that CompilerRT is checked out into the
+# 'projects/compiler-rt' inside of an LLVM tree.
+# Standalone build system for CompilerRT is not yet ready.
+#
+# An important constraint of the build is that it only produces libraries
+# based on the ability of the host toolchain to target various platforms.
+
+# Check if compiler-rt is built as a standalone project.
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ project(CompilerRT C CXX ASM)
+ set(COMPILER_RT_STANDALONE_BUILD TRUE)
+else()
+ set(COMPILER_RT_STANDALONE_BUILD FALSE)
+endif()
+
+# The CompilerRT build system requires CMake version 2.8.8 or higher in order
+# to use its support for building convenience "libraries" as a collection of
+# .o files. This is particularly useful in producing larger, more complex
+# runtime libraries.
+if (NOT MSVC)
+ cmake_minimum_required(VERSION 2.8.8)
+else()
+ # Version 2.8.12.1 is required to build with Visual Studio 2013.
+ cmake_minimum_required(VERSION 2.8.12.1)
+endif()
+
+# FIXME: It may be removed when we use 2.8.12.
+if(CMAKE_VERSION VERSION_LESS 2.8.12)
+ # Invalidate a couple of keywords.
+ set(cmake_2_8_12_INTERFACE)
+ set(cmake_2_8_12_PRIVATE)
+else()
+ # Use ${cmake_2_8_12_KEYWORD} intead of KEYWORD in target_link_libraries().
+ set(cmake_2_8_12_INTERFACE INTERFACE)
+ set(cmake_2_8_12_PRIVATE PRIVATE)
+ if(POLICY CMP0022)
+ cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required
+ endif()
+endif()
+
+# Top level target used to build all compiler-rt libraries.
+add_custom_target(compiler-rt ALL)
+
+option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
+mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
+option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
+mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
+
+if (NOT COMPILER_RT_STANDALONE_BUILD)
+ # Compute the Clang version from the LLVM version.
+ # FIXME: We should be able to reuse CLANG_VERSION variable calculated
+ # in Clang cmake files, instead of copying the rules here.
+ string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
+ ${PACKAGE_VERSION})
+ # Setup the paths where compiler-rt runtimes and headers should be stored.
+ set(COMPILER_RT_OUTPUT_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION})
+ set(COMPILER_RT_EXEC_OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
+ set(COMPILER_RT_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
+ option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests."
+ ${LLVM_INCLUDE_TESTS})
+ option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered"
+ ${LLVM_ENABLE_WERROR})
+ # Use just-built Clang to compile/link tests on all platforms, except for
+ # Windows where we need to use clang-cl instead.
+ if(NOT MSVC)
+ set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
+ else()
+ set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe)
+ endif()
+else()
+ # Take output dir and install path from the user.
+ set(COMPILER_RT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH
+ "Path where built compiler-rt libraries should be stored.")
+ set(COMPILER_RT_EXEC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin CACHE PATH
+ "Path where built compiler-rt executables should be stored.")
+ set(COMPILER_RT_INSTALL_PATH ${CMAKE_INSTALL_PREFIX} CACHE PATH
+ "Path where built compiler-rt libraries should be installed.")
+ option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests." OFF)
+ option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" OFF)
+ # Use a host compiler to compile/link tests.
+ set(COMPILER_RT_TEST_COMPILER ${CMAKE_C_COMPILER} CACHE PATH "Compiler to use for testing")
+
+ if (NOT LLVM_CONFIG_PATH)
+ find_program(LLVM_CONFIG_PATH "llvm-config"
+ DOC "Path to llvm-config binary")
+ if (NOT LLVM_CONFIG_PATH)
+ message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
+ endif()
+ endif()
+ execute_process(
+ COMMAND ${LLVM_CONFIG_PATH} "--obj-root" "--bindir" "--libdir" "--src-root"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT)
+ if (HAD_ERROR)
+ message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
+ endif()
+ string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
+ list(GET CONFIG_OUTPUT 0 LLVM_BINARY_DIR)
+ list(GET CONFIG_OUTPUT 1 LLVM_TOOLS_BINARY_DIR)
+ list(GET CONFIG_OUTPUT 2 LLVM_LIBRARY_DIR)
+ list(GET CONFIG_OUTPUT 3 LLVM_MAIN_SRC_DIR)
+
+ # Make use of LLVM CMake modules.
+ file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
+ set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/share/llvm/cmake")
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
+ # Get some LLVM variables from LLVMConfig.
+ include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+
+ set(LLVM_LIBRARY_OUTPUT_INTDIR
+ ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+
+ # Find Python interpreter.
+ set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5)
+ include(FindPythonInterp)
+ if(NOT PYTHONINTERP_FOUND)
+ message(FATAL_ERROR "
+ Unable to find Python interpreter required testing. Please install Python
+ or specify the PYTHON_EXECUTABLE CMake variable.")
+ endif()
+
+ # Define default arguments to lit.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+endif()
+
+if("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang[+]*$")
+ set(COMPILER_RT_TEST_COMPILER_ID Clang)
+elseif("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang.*.exe$")
+ set(COMPILER_RT_TEST_COMPILER_ID Clang)
+else()
+ set(COMPILER_RT_TEST_COMPILER_ID GNU)
+endif()
+
+set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${TARGET_TRIPLE} CACHE STRING
+ "Default triple for which compiler-rt runtimes will be built.")
+if(DEFINED COMPILER_RT_TEST_TARGET_TRIPLE)
+ # Backwards compatibility: this variable used to be called
+ # COMPILER_RT_TEST_TARGET_TRIPLE.
+ set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${COMPILER_RT_TEST_TARGET_TRIPLE})
+endif()
+
+string(REPLACE "-" ";" TARGET_TRIPLE_LIST ${COMPILER_RT_DEFAULT_TARGET_TRIPLE})
+list(GET TARGET_TRIPLE_LIST 0 COMPILER_RT_DEFAULT_TARGET_ARCH)
+list(GET TARGET_TRIPLE_LIST 1 COMPILER_RT_DEFAULT_TARGET_OS)
+list(GET TARGET_TRIPLE_LIST 2 COMPILER_RT_DEFAULT_TARGET_ABI)
+# Determine if test target triple is specified explicitly, and doesn't match the
+# default.
+if(NOT COMPILER_RT_DEFAULT_TARGET_TRIPLE STREQUAL TARGET_TRIPLE)
+ set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE TRUE)
+else()
+ set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE FALSE)
+endif()
+
+if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi")
+ set(ANDROID 1)
+endif()
+
+string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
+set(COMPILER_RT_LIBRARY_OUTPUT_DIR
+ ${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
+set(COMPILER_RT_LIBRARY_INSTALL_DIR
+ ${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
+
+# Add path for custom compiler-rt modules.
+set(CMAKE_MODULE_PATH
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+ ${CMAKE_MODULE_PATH}
+ )
+include(CompilerRTUtils)
+
+set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+# We support running instrumented tests when we're not cross compiling
+# and target a UNIX-like system or Windows.
+# We can run tests on Android even when we are cross-compiling.
+if(("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND (UNIX OR WIN32)) OR ANDROID
+ OR COMPILER_RT_EMULATOR)
+ option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
+else()
+ option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
+endif()
+
+option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
+option(COMPILER_RT_EXTERNALIZE_DEBUGINFO
+ "Generate dSYM files and strip executables and libraries (Darwin Only)" OFF)
+# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
+pythonize_bool(COMPILER_RT_DEBUG)
+
+#================================
+# Setup Compiler Flags
+#================================
+include(CheckIncludeFile)
+check_include_file(unwind.h HAVE_UNWIND_H)
+
+include(config-ix)
+
+if(MSVC)
+ append_string_if(COMPILER_RT_HAS_W3_FLAG /W3 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+else()
+ append_string_if(COMPILER_RT_HAS_WALL_FLAG -Wall CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+endif()
+if(COMPILER_RT_ENABLE_WERROR)
+ append_string_if(COMPILER_RT_HAS_WERROR_FLAG -Werror CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ append_string_if(COMPILER_RT_HAS_WX_FLAG /WX CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+endif()
+
+append_string_if(COMPILER_RT_HAS_STD_CXX11_FLAG -std=c++11 CMAKE_CXX_FLAGS)
+
+# Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP.
+if(NOT COMPILER_RT_HAS_FUNC_SYMBOL)
+ add_definitions(-D__func__=__FUNCTION__)
+endif()
+
+# Provide some common commmandline flags for Sanitizer runtimes.
+append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG -fno-sanitize=safe-stack SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG -fvisibility-inlines-hidden SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
+
+if(MSVC)
+ # Replace the /M[DT][d] flags with /MT, and strip any definitions of _DEBUG,
+ # which cause definition mismatches at link time.
+ # FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
+ if(COMPILER_RT_HAS_MT_FLAG)
+ foreach(flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ string(REGEX REPLACE "/M[DT]d" "/MT" ${flag_var} "${${flag_var}}")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ string(REGEX REPLACE "/D_DEBUG" "" ${flag_var} "${${flag_var}}")
+ endforeach()
+ endif()
+ append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
+ append_list_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
+endif()
+
+append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS)
+
+# Build with optimization, unless we're in debug mode. If we're using MSVC,
+# always respect the optimization flags set by CMAKE_BUILD_TYPE instead.
+if(NOT COMPILER_RT_DEBUG AND NOT MSVC)
+ list(APPEND SANITIZER_COMMON_CFLAGS -O3)
+endif()
+
+# Determine if we should restrict stack frame sizes.
+# Stack frames on PowerPC and Mips and in debug biuld can be much larger than
+# anticipated.
+# FIXME: Fix all sanitizers and add -Wframe-larger-than to
+# SANITIZER_COMMON_FLAGS
+if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG AND NOT COMPILER_RT_DEBUG
+ AND NOT ${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "powerpc|mips")
+ set(SANITIZER_LIMIT_FRAME_SIZE TRUE)
+else()
+ set(SANITIZER_LIMIT_FRAME_SIZE FALSE)
+endif()
+
+# Build sanitizer runtimes with debug info.
+if(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
+elseif(COMPILER_RT_HAS_G_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -g)
+elseif(COMPILER_RT_HAS_Zi_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS /Zi)
+endif()
+
+# Turn off several warnings.
+append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG -Wno-non-virtual-dtor SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
+
+if(APPLE AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9")
+ # Mac OS X prior to 10.9 had problems with exporting symbols from
+ # libc++/libc++abi.
+ set(SANITIZER_CAN_USE_CXXABI FALSE)
+else()
+ set(SANITIZER_CAN_USE_CXXABI TRUE)
+endif()
+pythonize_bool(SANITIZER_CAN_USE_CXXABI)
+
+add_subdirectory(include)
+
+set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
+if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/)
+ set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE)
+else()
+ set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE)
+endif()
+
+set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
+if(EXISTS ${COMPILER_RT_LLD_PATH}/)
+ set(COMPILER_RT_HAS_LLD_SOURCES TRUE)
+else()
+ set(COMPILER_RT_HAS_LLD_SOURCES FALSE)
+endif()
+pythonize_bool(COMPILER_RT_HAS_LLD_SOURCES)
+
+add_subdirectory(lib)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(unittests)
+ add_subdirectory(test)
+endif()
diff --git a/compiler-rt/CODE_OWNERS.TXT b/compiler-rt/CODE_OWNERS.TXT
new file mode 100644
index 0000000..2159ad7
--- /dev/null
+++ b/compiler-rt/CODE_OWNERS.TXT
@@ -0,0 +1,57 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular part of compiler-rt are reviewed, either by themself or by
+someone else. They are also the gatekeepers for their part of compiler-rt, with
+the final word on what goes in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Peter Collingbourne
+E: peter@pcc.me.uk
+D: DataFlowSanitizer
+
+N: Daniel Dunbar
+E: daniel@zuster.org
+D: Makefile build
+
+N: Timur Iskhodzhanov
+E: timurrrr@google.com
+D: AddressSanitizer for Windows
+
+N: Howard Hinnant
+E: howard.hinnant@gmail.com
+D: builtins library
+
+N: Sergey Matveev
+E: earthdok@google.com
+D: LeakSanitizer
+
+N: Alexander Potapenko
+E: glider@google.com
+D: MacOS/iOS port of sanitizers
+
+N: Alexey Samsonov
+E: samsonov@google.com
+D: CMake build, test suite
+
+N: Kostya Serebryany
+E: kcc@google.com
+D: AddressSanitizer, sanitizer_common, porting sanitizers to another platforms
+
+N: Richard Smith
+E: richard-llvm@metafoo.co.uk
+D: UndefinedBehaviorSanitizer
+
+N: Evgeniy Stepanov
+E: eugenis@google.com
+D: MemorySanitizer, Android port of sanitizers
+
+N: Dmitry Vyukov
+E: dvyukov@google.com
+D: ThreadSanitizer
+
+N: Bill Wendling
+E: isanbard@gmail.com
+D: Profile runtime library
diff --git a/compiler-rt/CREDITS.TXT b/compiler-rt/CREDITS.TXT
new file mode 100644
index 0000000..6964eba
--- /dev/null
+++ b/compiler-rt/CREDITS.TXT
@@ -0,0 +1,36 @@
+This file is a partial list of people who have contributed to the LLVM/CompilerRT
+project. If you have contributed a patch or made some other contribution to
+LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Craig van Vliet
+E: cvanvliet@auroraux.org
+W: http://www.auroraux.org
+D: Code style and Readability fixes.
+
+N: Edward O'Callaghan
+E: eocallaghan@auroraux.org
+W: http://www.auroraux.org
+D: CMake'ify Compiler-RT build system
+D: Maintain Solaris & AuroraUX ports of Compiler-RT
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary author of compiler-rt
+
+N: Guan-Hong Liu
+E: koviankevin@hotmail.com
+D: IEEE Quad-precision functions
+
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: Maintains NetBSD port.
+
+N: Matt Thomas
+E: matt@NetBSD.org
+D: ARM improvements.
diff --git a/compiler-rt/LICENSE.TXT b/compiler-rt/LICENSE.TXT
new file mode 100644
index 0000000..aa4115e
--- /dev/null
+++ b/compiler-rt/LICENSE.TXT
@@ -0,0 +1,91 @@
+==============================================================================
+compiler_rt License
+==============================================================================
+
+The compiler_rt library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
diff --git a/compiler-rt/MODULE_LICENSE_MIT b/compiler-rt/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compiler-rt/MODULE_LICENSE_MIT
diff --git a/compiler-rt/Makefile b/compiler-rt/Makefile
new file mode 100644
index 0000000..ac3daac
--- /dev/null
+++ b/compiler-rt/Makefile
@@ -0,0 +1,275 @@
+SubDirs := lib
+
+# Set default rule before anything else.
+all: help
+
+include make/config.mk
+include make/util.mk
+# If SRCROOT is defined, assume we are doing an Apple style build. We should be
+# able to use RC_XBS for this but that is unused during "make installsrc".
+ifdef SRCROOT
+ include make/AppleBI.mk
+endif
+
+# Make sure we don't build with a missing ProjObjRoot.
+ifeq ($(ProjObjRoot),)
+$(error Refusing to build with empty ProjObjRoot variable)
+endif
+
+##############
+
+###
+# Rules
+
+###
+# Top level targets
+
+# FIXME: Document the available subtargets.
+help:
+ @echo "usage: make [{VARIABLE=VALUE}*] target"
+ @echo
+ @echo "User variables:"
+ @echo " VERBOSE=1: Use to show all commands [default=0]"
+ @echo
+ @echo "Available targets:"
+ @echo " <platform name>: build the libraries for 'platform'"
+ @echo " clean: clean all configurations"
+ @echo " test: run unit tests"
+ @echo
+ @echo " info-platforms: list available platforms"
+ @echo " help-devel: print additional help for developers"
+ @echo
+
+help-devel: help
+ @echo "Development targets:"
+ @echo " <platform name>-<config name>:"
+ @echo " build the libraries for a single platform config"
+ @echo " <platform name>-<config name>-<arch name>:"
+ @echo " build the libraries for a single config and arch"
+ @echo " info-functions: list available compiler-rt functions"
+ @echo " help-hidden: print help for Makefile debugging"
+ @echo
+
+help-hidden: help-devel
+ @echo "Debugging variables:"
+ @echo " DEBUGMAKE=1: enable some Makefile logging [default=]"
+ @echo " =2: enable more Makefile logging"
+ @echo
+ @echo "Debugging targets:"
+ @echo " make-print-FOO: print information on the variable 'FOO'"
+ @echo
+
+info-functions:
+ @echo "compiler-rt Available Functions"
+ @echo
+ @echo "All Functions: $(AvailableFunctions)"
+ @$(foreach fn,$(AvailableFunctions),\
+ printf " %-20s - available in (%s)\n" $(fn)\
+ "$(foreach key,$(AvailableIn.$(fn)),$($(key).Dir))";)
+
+info-platforms:
+ @echo "compiler-rt Available Platforms"
+ @echo
+ @echo "Platforms:"
+ @$(foreach key,$(PlatformKeys),\
+ printf " %s - from '%s'\n" $($(key).Name) $($(key).Path);\
+ printf " %s\n" "$($(key).Description)";\
+ printf " Configurations: %s\n\n" "$($(key).Configs)";)
+
+# Provide default clean target which is extended by other templates.
+.PHONY: clean
+clean::
+
+# Test
+.PHONY: test
+test:
+ cd test/Unit && ./test
+
+###
+# Directory handling magic.
+
+# Create directories as needed, and timestamp their creation.
+%/.dir:
+ $(Summary) " MKDIR: $*"
+ $(Verb) $(MKDIR) $* > /dev/null
+ $(Verb) echo 'Created.' > $@
+
+# Remove directories
+%/.remove:
+ $(Verb) $(RM) -r $*
+
+###
+# Include child makefile fragments
+
+Dir := .
+include make/subdir.mk
+include make/lib_info.mk
+include make/lib_util.mk
+include make/lib_platforms.mk
+
+###
+# Define Platform Rules
+
+define PerPlatform_template
+$(call Set,Tmp.Key,$(1))
+$(call Set,Tmp.Name,$($(Tmp.Key).Name))
+$(call Set,Tmp.Configs,$($(Tmp.Key).Configs))
+$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name))
+
+# Top-Level Platform Target
+$(Tmp.Name):: $(Tmp.Configs:%=$(Tmp.Name)-%)
+.PHONY: $(Tmp.Name)
+
+clean::
+ $(Verb) rm -rf $(Tmp.ObjPath)
+
+# Per-Config Libraries
+$(foreach config,$(Tmp.Configs),\
+ $(call PerPlatformConfig_template,$(config)))
+endef
+
+define PerPlatformConfig_template
+$(call Set,Tmp.Config,$(1))
+$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config))
+$(call Set,Tmp.SHARED_LIBRARY,$(strip \
+ $(call GetCNAVar,SHARED_LIBRARY,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.SHARED_LIBRARY_SUFFIX,$(strip \
+ $(call GetCNAVar,SHARED_LIBRARY_SUFFIX,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+
+# Compute the library suffix.
+$(if $(call streq,1,$(Tmp.SHARED_LIBRARY)),
+ $(call Set,Tmp.LibrarySuffix,$(Tmp.SHARED_LIBRARY_SUFFIX)),
+ $(call Set,Tmp.LibrarySuffix,a))
+
+# Compute the archs to build, depending on whether this is a universal build or
+# not.
+$(call Set,Tmp.ArchsToBuild,\
+ $(if $(call IsDefined,$(Tmp.Key).UniversalArchs),\
+ $(strip \
+ $(or $($(Tmp.Key).UniversalArchs.$(Tmp.Config)),\
+ $($(Tmp.Key).UniversalArchs))),\
+ $(call VarOrDefault,$(Tmp.Key).Arch.$(Tmp.Config),$($(Tmp.Key).Arch))))
+
+# Copy or lipo to create the per-config library.
+$(call Set,Tmp.Inputs,$(Tmp.ArchsToBuild:%=$(Tmp.ObjPath)/%/libcompiler_rt.$(Tmp.LibrarySuffix)))
+$(Tmp.ObjPath)/libcompiler_rt.$(Tmp.LibrarySuffix): $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
+ $(Summary) " FINAL-ARCHIVE: $(Tmp.Name)/$(Tmp.Config): $$@"
+ -$(Verb) $(RM) $$@
+ $(if $(call streq,1,$(words $(Tmp.ArchsToBuild))), \
+ $(Verb) $(CP) $(Tmp.Inputs) $$@, \
+ $(Verb) $(LIPO) -create -output $$@ $(Tmp.Inputs))
+.PRECIOUS: $(Tmp.ObjPath)/.dir
+
+# Per-Config Targets
+$(Tmp.Name)-$(Tmp.Config):: $(Tmp.ObjPath)/libcompiler_rt.$(Tmp.LibrarySuffix)
+.PHONY: $(Tmp.Name)-$(Tmp.Config)
+
+# Per-Config-Arch Libraries
+$(foreach arch,$(Tmp.ArchsToBuild),\
+ $(call PerPlatformConfigArch_template,$(arch)))
+endef
+
+define PerPlatformConfigArch_template
+$(call Set,Tmp.Arch,$(1))
+$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch))
+$(call Set,Tmp.Functions,$(strip \
+ $(AlwaysRequiredModules) \
+ $(call GetCNAVar,FUNCTIONS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.Optimized,$(strip \
+ $(call GetCNAVar,OPTIMIZED,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.AR,$(strip \
+ $(call GetCNAVar,AR,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.ARFLAGS,$(strip \
+ $(call GetCNAVar,ARFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.CC,$(strip \
+ $(call GetCNAVar,CC,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.LDFLAGS,$(strip \
+ $(call GetCNAVar,LDFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.RANLIB,$(strip \
+ $(call GetCNAVar,RANLIB,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.RANLIBFLAGS,$(strip \
+ $(call GetCNAVar,RANLIBFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.SHARED_LIBRARY,$(strip \
+ $(call GetCNAVar,SHARED_LIBRARY,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+
+# Compute the library suffix.
+$(if $(call streq,1,$(Tmp.SHARED_LIBRARY)),
+ $(call Set,Tmp.LibrarySuffix,$(Tmp.SHARED_LIBRARY_SUFFIX)),
+ $(call Set,Tmp.LibrarySuffix,a))
+
+# Compute the object inputs for this library.
+$(call Set,Tmp.Inputs,\
+ $(foreach fn,$(sort $(Tmp.Functions)),\
+ $(call Set,Tmp.FnDir,\
+ $(call SelectFunctionDir,$(Tmp.Config),$(Tmp.Arch),$(fn),$(Tmp.Optimized)))\
+ $(Tmp.ObjPath)/$(Tmp.FnDir)/$(fn).o))
+$(Tmp.ObjPath)/libcompiler_rt.a: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
+ $(Summary) " ARCHIVE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$@"
+ -$(Verb) $(RM) $$@
+ $(Verb) $(Tmp.AR) $(Tmp.ARFLAGS) $$@ $(Tmp.Inputs)
+ $(Verb) $(Tmp.RANLIB) $(Tmp.RANLIBFLAGS) $$@
+$(Tmp.ObjPath)/libcompiler_rt.dylib: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
+ $(Summary) " DYLIB: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$@"
+ $(Verb) $(Tmp.CC) -arch $(Tmp.Arch) -dynamiclib -o $$@ \
+ $(Tmp.Inputs) $(Tmp.LDFLAGS)
+$(Tmp.ObjPath)/libcompiler_rt.so: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
+ $(Summary) " SO: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$@"
+ $(Verb) $(Tmp.CC) -shared -o $$@ \
+ $(Tmp.Inputs) $(Tmp.LDFLAGS)
+.PRECIOUS: $(Tmp.ObjPath)/.dir
+
+# Per-Config-Arch Targets
+$(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch):: $(Tmp.ObjPath)/libcompiler_rt.$(Tmp.LibrarySuffix)
+.PHONY: $(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch)
+
+# Per-Config-Arch-SubDir Objects
+$(foreach key,$(SubDirKeys),\
+ $(call PerPlatformConfigArchSubDir_template,$(key)))
+endef
+
+define PerPlatformConfigArchSubDir_template
+$(call Set,Tmp.SubDirKey,$(1))
+$(call Set,Tmp.SubDir,$($(Tmp.SubDirKey).Dir))
+$(call Set,Tmp.SrcPath,$(ProjSrcRoot)/$(Tmp.SubDir))
+$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch)/$(Tmp.SubDirKey))
+$(call Set,Tmp.Dependencies,$($(Tmp.SubDirKey).Dependencies))
+$(call Set,Tmp.CC,$(strip \
+ $(call GetCNAVar,CC,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.KERNEL_USE,$(strip \
+ $(call GetCNAVar,KERNEL_USE,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.VISIBILITY_HIDDEN,$(strip \
+ $(call GetCNAVar,VISIBILITY_HIDDEN,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+$(call Set,Tmp.CFLAGS,$(strip \
+ $(if $(call IsDefined,$(Tmp.Key).UniversalArchs),-arch $(Tmp.Arch),)\
+ $(if $(call streq,$(Tmp.VISIBILITY_HIDDEN),1),\
+ -fvisibility=hidden -DVISIBILITY_HIDDEN,)\
+ $(if $(call streq,$(Tmp.KERNEL_USE),1),\
+ -mkernel -DKERNEL_USE,)\
+ $(call GetCNAVar,CFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
+
+$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.s $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
+ $(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
+ $(Verb) $(Tmp.CC) $(COMMON_ASMFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
+$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.S $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
+ $(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
+ $(Verb) $(Tmp.CC) $(COMMON_ASMFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
+$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
+ $(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
+ $(Verb) $(Tmp.CC) $(COMMON_CFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
+$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.cc $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
+ $(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
+ $(Verb) $(Tmp.CC) $(COMMON_CXXFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
+.PRECIOUS: $(Tmp.ObjPath)/.dir
+
+endef
+
+# Run templates.
+$(foreach key,$(PlatformKeys),\
+ $(eval $(call PerPlatform_template,$(key))))
+
+###
+
+ifneq ($(DEBUGMAKE),)
+ $(info MAKE: Done processing Makefile)
+ $(info )
+endif
diff --git a/compiler-rt/NOTICE b/compiler-rt/NOTICE
new file mode 100644
index 0000000..aee8347
--- /dev/null
+++ b/compiler-rt/NOTICE
@@ -0,0 +1,91 @@
+==============================================================================
+compiler_rt License
+==============================================================================
+
+The compiler_rt library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
diff --git a/compiler-rt/README.android b/compiler-rt/README.android
new file mode 100644
index 0000000..587a6c6
--- /dev/null
+++ b/compiler-rt/README.android
@@ -0,0 +1,40 @@
+/*
+ * README.android describes in high-level the compiler-rt changes that we
+ * cannot push upstream to the llvm.org repository:
+ * - Changes due to Android's build system.
+ * - Changes due to Android's toolchain.
+ * - Changes due to the limitations in Android-based consumer electronics.
+ *
+ * Some of them are to-dos. If and when they are done, there will no longer be
+ * merge conflicts with upstream on those parts.
+ *
+ * The file contains useful hints when we try to resolve future 3-way merge
+ * conflicts.
+ */
+
+* For JellyBean: Synced to upstream r155350
+* For JellyBean MR1: Synced to upstream r162279
+* For Jellybean MR2: Synced to upstream r177337
+* For Key Lime Pie: Synced to upstream r187889
+* For FUTURE: Synced to LLVM 3.4 r197381
+
+* Cherry-pick on 2014/2/11: https://llvm.org/svn/llvm-project/compiler-rt/trunk@201068 and https://llvm.org/svn/llvm-project/compiler-rt/trunk@201070
+* Recent downstreaming on 2013/2/11: Synced to r197381 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/8/8: Synced to r187889 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/6/13: Synced to r183849 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/5/3: Synced to r180792 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/3/18: Synced to r177337 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/3/5: Synced to r176091 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/1/8: Synced to r171802 (Contact srhines for merge questions.)
+* Recent downstreaming on 2012/08/23: Synced to r162279 (Contact srhines for merge questions.)
+* Recent downstreaming on 2012/08/15: Synced to r159129 (Contact sliao for merge questions.)
+* Cherry-pick on 2012/07/27: https://llvm.org/svn/llvm-project/compiler-rt/trunk@160853 for ASan (Contact srhines for merge questions.)
+* Cherry-pick on 2012/05/23: https://llvm.org/svn/llvm-project/compiler-rt/trunk@157318 for ASan (Contact srhines for merge questions.)
+* Recent downstreaming on 2012/04/25: Synced to r155350 (Contact sliao for merge questions.)
+* Recent downstreaming on 2012/03/08: Synced to r152058 (Contact srhines for merge questions.)
+
+TODO: This is still not building by default (no Android.mk files are present
+yet). Look at frameworks/compile/libbcc/runtime for potential starting points.
+
+TODO: Switch libbcc to use this version of compiler-rt instead of its own
+tweaked version.
diff --git a/compiler-rt/README.txt b/compiler-rt/README.txt
new file mode 100644
index 0000000..fc88432
--- /dev/null
+++ b/compiler-rt/README.txt
@@ -0,0 +1,11 @@
+Compiler-RT
+================================
+
+This directory and its subdirectories contain source code for the compiler
+support routines.
+
+Compiler-RT is open source software. You may freely distribute it under the
+terms of the license agreement found in LICENSE.txt.
+
+================================
+
diff --git a/compiler-rt/README.version b/compiler-rt/README.version
new file mode 100644
index 0000000..c9d92df
--- /dev/null
+++ b/compiler-rt/README.version
@@ -0,0 +1,4 @@
+URL: http://llvm.org/git/compiler-rt.git
+Version: Rolling from upstream + cherry-picks
+BugComponent: 117395
+Owners: srhines, android-llvm
diff --git a/compiler-rt/cmake/Modules/AddCompilerRT.cmake b/compiler-rt/cmake/Modules/AddCompilerRT.cmake
new file mode 100644
index 0000000..6f401b1
--- /dev/null
+++ b/compiler-rt/cmake/Modules/AddCompilerRT.cmake
@@ -0,0 +1,337 @@
+include(AddLLVM)
+include(ExternalProject)
+include(CompilerRTUtils)
+
+# Tries to add an "object library" target for a given list of OSs and/or
+# architectures with name "<name>.<arch>" for non-Darwin platforms if
+# architecture can be targeted, and "<name>.<os>" for Darwin platforms.
+# add_compiler_rt_object_libraries(<name>
+# OS <os names>
+# ARCHS <architectures>
+# SOURCES <source files>
+# CFLAGS <compile flags>
+# DEFS <compile definitions>)
+function(add_compiler_rt_object_libraries name)
+ cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS" ${ARGN})
+ set(libnames)
+ if(APPLE)
+ foreach(os ${LIB_OS})
+ set(libname "${name}.${os}")
+ set(libnames ${libnames} ${libname})
+ set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS})
+ list_union(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
+ endforeach()
+ else()
+ foreach(arch ${LIB_ARCHS})
+ set(libname "${name}.${arch}")
+ set(libnames ${libnames} ${libname})
+ set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS})
+ if(NOT CAN_TARGET_${arch})
+ message(FATAL_ERROR "Architecture ${arch} can't be targeted")
+ return()
+ endif()
+ endforeach()
+ endif()
+
+ foreach(libname ${libnames})
+ add_library(${libname} OBJECT ${LIB_SOURCES})
+ set_target_compile_flags(${libname}
+ ${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${LIB_CFLAGS})
+ set_property(TARGET ${libname} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
+ if(APPLE)
+ set_target_properties(${libname} PROPERTIES
+ OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
+ endif()
+ endforeach()
+endfunction()
+
+# Takes a list of object library targets, and a suffix and appends the proper
+# TARGET_OBJECTS string to the output variable.
+# format_object_libs(<output> <suffix> ...)
+macro(format_object_libs output suffix)
+ foreach(lib ${ARGN})
+ list(APPEND ${output} $<TARGET_OBJECTS:${lib}.${suffix}>)
+ endforeach()
+endmacro()
+
+# Adds static or shared runtime for a list of architectures and operating
+# systems and puts it in the proper directory in the build and install trees.
+# add_compiler_rt_runtime(<name>
+# {STATIC|SHARED}
+# ARCHS <architectures>
+# OS <os list>
+# SOURCES <source files>
+# CFLAGS <compile flags>
+# LINKFLAGS <linker flags>
+# DEFS <compile definitions>
+# LINK_LIBS <linked libraries> (only for shared library)
+# OBJECT_LIBS <object libraries to use as sources>
+# PARENT_TARGET <convenience parent target>)
+function(add_compiler_rt_runtime name type)
+ if(NOT type MATCHES "^(STATIC|SHARED)$")
+ message(FATAL_ERROR "type argument must be STATIC or SHARED")
+ return()
+ endif()
+ cmake_parse_arguments(LIB
+ ""
+ "PARENT_TARGET"
+ "OS;ARCHS;SOURCES;CFLAGS;LINKFLAGS;DEFS;LINK_LIBS;OBJECT_LIBS"
+ ${ARGN})
+ set(libnames)
+ if(APPLE)
+ foreach(os ${LIB_OS})
+ if(type STREQUAL "STATIC")
+ set(libname "${name}_${os}")
+ else()
+ set(libname "${name}_${os}_dynamic")
+ set(extra_linkflags_${libname} ${DARWIN_${os}_LINKFLAGS} ${LIB_LINKFLAGS})
+ endif()
+ list_union(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
+ if(LIB_ARCHS_${libname})
+ list(APPEND libnames ${libname})
+ set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${LIB_CFLAGS})
+ set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
+ set(sources_${libname} ${LIB_SOURCES})
+ format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS})
+ endif()
+ endforeach()
+ else()
+ foreach(arch ${LIB_ARCHS})
+ if(NOT CAN_TARGET_${arch})
+ message(FATAL_ERROR "Architecture ${arch} can't be targeted")
+ return()
+ endif()
+ if(type STREQUAL "STATIC")
+ set(libname "${name}-${arch}")
+ set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
+ else()
+ set(libname "${name}-dynamic-${arch}")
+ set(extra_linkflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS} ${LIB_LINKFLAGS})
+ if(WIN32)
+ set(output_name_${libname} ${name}_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
+ else()
+ set(output_name_${libname} ${name}-${arch}${COMPILER_RT_OS_SUFFIX})
+ endif()
+ endif()
+ set(sources_${libname} ${LIB_SOURCES})
+ format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS})
+ set(libnames ${libnames} ${libname})
+ set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
+ endforeach()
+ endif()
+
+ if(NOT libnames)
+ return()
+ endif()
+
+ if(LIB_PARENT_TARGET)
+ set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET})
+ endif()
+
+ foreach(libname ${libnames})
+ add_library(${libname} ${type} ${sources_${libname}})
+ set_target_compile_flags(${libname} ${extra_cflags_${libname}})
+ set_target_link_flags(${libname} ${extra_linkflags_${libname}})
+ set_property(TARGET ${libname} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
+ set_target_properties(${libname} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
+ LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
+ set_target_properties(${libname} PROPERTIES
+ OUTPUT_NAME ${output_name_${libname}})
+ if(LIB_LINK_LIBS AND ${type} STREQUAL "SHARED")
+ target_link_libraries(${libname} ${LIB_LINK_LIBS})
+ endif()
+ install(TARGETS ${libname}
+ ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
+ ${COMPONENT_OPTION}
+ LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
+ ${COMPONENT_OPTION}
+ RUNTIME DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
+ ${COMPONENT_OPTION})
+ if(APPLE)
+ set_target_properties(${libname} PROPERTIES
+ OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
+ endif()
+
+ if(type STREQUAL "SHARED")
+ rt_externalize_debuginfo(${libname})
+ endif()
+ endforeach()
+ if(LIB_PARENT_TARGET)
+ add_dependencies(${LIB_PARENT_TARGET} ${libnames})
+ endif()
+endfunction()
+
+set(COMPILER_RT_TEST_CFLAGS)
+
+# Unittests support.
+set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
+set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc)
+set(COMPILER_RT_GTEST_CFLAGS
+ -DGTEST_NO_LLVM_RAW_OSTREAM=1
+ -DGTEST_HAS_RTTI=0
+ -I${COMPILER_RT_GTEST_PATH}/include
+ -I${COMPILER_RT_GTEST_PATH}
+)
+
+append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_TEST_CFLAGS)
+
+if(MSVC)
+ # clang doesn't support exceptions on Windows yet.
+ list(APPEND COMPILER_RT_TEST_CFLAGS -D_HAS_EXCEPTIONS=0)
+
+ # We should teach clang to understand "#pragma intrinsic", see PR19898.
+ list(APPEND COMPILER_RT_TEST_CFLAGS -Wno-undefined-inline)
+
+ # Clang doesn't support SEH on Windows yet.
+ list(APPEND COMPILER_RT_GTEST_CFLAGS -DGTEST_HAS_SEH=0)
+
+ # gtest use a lot of stuff marked as deprecated on Windows.
+ list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
+
+ # Visual Studio 2012 only supports up to 8 template parameters in
+ # std::tr1::tuple by default, but gtest requires 10
+ if(MSVC_VERSION EQUAL 1700)
+ list(APPEND COMPILER_RT_GTEST_CFLAGS -D_VARIADIC_MAX=10)
+ endif()
+endif()
+
+# Link objects into a single executable with COMPILER_RT_TEST_COMPILER,
+# using specified link flags. Make executable a part of provided
+# test_suite.
+# add_compiler_rt_test(<test_suite> <test_name>
+# SUBDIR <subdirectory for binary>
+# OBJECTS <object files>
+# DEPS <deps (e.g. runtime libs)>
+# LINK_FLAGS <link flags>)
+macro(add_compiler_rt_test test_suite test_name)
+ cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
+ if(TEST_SUBDIR)
+ set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SUBDIR}/${test_name}")
+ else()
+ set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
+ endif()
+ if(MSVC)
+ set(output_bin "${output_bin}.exe")
+ endif()
+ # Use host compiler in a standalone build, and just-built Clang otherwise.
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TEST_DEPS clang)
+ endif()
+ # If we're not on MSVC, include the linker flags from CMAKE but override them
+ # with the provided link flags. This ensures that flags which are required to
+ # link programs at all are included, but the changes needed for the test
+ # trump. With MSVC we can't do that because CMake is set up to run link.exe
+ # when linking, not the compiler. Here, we hack it to use the compiler
+ # because we want to use -fsanitize flags.
+ if(NOT MSVC)
+ set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}")
+ separate_arguments(TEST_LINK_FLAGS)
+ endif()
+ add_custom_target(${test_name}
+ COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS}
+ -o "${output_bin}"
+ ${TEST_LINK_FLAGS}
+ DEPENDS ${TEST_DEPS})
+ # Make the test suite depend on the binary.
+ add_dependencies(${test_suite} ${test_name})
+endmacro()
+
+macro(add_compiler_rt_resource_file target_name file_name)
+ set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
+ set(dst_file "${COMPILER_RT_OUTPUT_DIR}/${file_name}")
+ add_custom_command(OUTPUT ${dst_file}
+ DEPENDS ${src_file}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
+ COMMENT "Copying ${file_name}...")
+ add_custom_target(${target_name} DEPENDS ${dst_file})
+ # Install in Clang resource directory.
+ install(FILES ${file_name} DESTINATION ${COMPILER_RT_INSTALL_PATH})
+endmacro()
+
+macro(add_compiler_rt_script name)
+ set(dst ${COMPILER_RT_EXEC_OUTPUT_DIR}/${name})
+ set(src ${CMAKE_CURRENT_SOURCE_DIR}/${name})
+ add_custom_command(OUTPUT ${dst}
+ DEPENDS ${src}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
+ COMMENT "Copying ${name}...")
+ add_custom_target(${name} DEPENDS ${dst})
+ install(FILES ${dst}
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+ DESTINATION ${COMPILER_RT_INSTALL_PATH}/bin)
+endmacro(add_compiler_rt_script src name)
+
+# Builds custom version of libc++ and installs it in <prefix>.
+# Can be used to build sanitized versions of libc++ for running unit tests.
+# add_custom_libcxx(<name> <prefix>
+# DEPS <list of build deps>
+# CFLAGS <list of compile flags>)
+macro(add_custom_libcxx name prefix)
+ if(NOT COMPILER_RT_HAS_LIBCXX_SOURCES)
+ message(FATAL_ERROR "libcxx not found!")
+ endif()
+
+ cmake_parse_arguments(LIBCXX "" "" "DEPS;CFLAGS" ${ARGN})
+ foreach(flag ${LIBCXX_CFLAGS})
+ set(flagstr "${flagstr} ${flag}")
+ endforeach()
+ set(LIBCXX_CFLAGS ${flagstr})
+
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND LIBCXX_DEPS clang)
+ endif()
+
+ ExternalProject_Add(${name}
+ PREFIX ${prefix}
+ SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH}
+ CMAKE_ARGS -DCMAKE_MAKE_PROGRAM:STRING=${CMAKE_MAKE_PROGRAM}
+ -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER}
+ -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_COMPILER}
+ -DCMAKE_C_FLAGS=${LIBCXX_CFLAGS}
+ -DCMAKE_CXX_FLAGS=${LIBCXX_CFLAGS}
+ -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ LOG_BUILD 1
+ LOG_CONFIGURE 1
+ LOG_INSTALL 1
+ )
+ set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+ ExternalProject_Add_Step(${name} force-reconfigure
+ DEPENDERS configure
+ ALWAYS 1
+ )
+
+ ExternalProject_Add_Step(${name} clobber
+ COMMAND ${CMAKE_COMMAND} -E remove_directory <BINARY_DIR>
+ COMMAND ${CMAKE_COMMAND} -E make_directory <BINARY_DIR>
+ COMMENT "Clobberring ${name} build directory..."
+ DEPENDERS configure
+ DEPENDS ${LIBCXX_DEPS}
+ )
+endmacro()
+
+function(rt_externalize_debuginfo name)
+ if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO)
+ return()
+ endif()
+
+ if(APPLE)
+ if(CMAKE_CXX_FLAGS MATCHES "-flto"
+ OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto")
+
+ set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${name}-lto.o)
+ set_property(TARGET ${name} APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,-object_path_lto -Wl,${lto_object}")
+ endif()
+ add_custom_command(TARGET ${name} POST_BUILD
+ COMMAND xcrun dsymutil $<TARGET_FILE:${name}>
+ COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>)
+ else()
+ message(FATAL_ERROR "COMPILER_RT_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!")
+ endif()
+endfunction()
diff --git a/compiler-rt/cmake/Modules/CompilerRTCompile.cmake b/compiler-rt/cmake/Modules/CompilerRTCompile.cmake
new file mode 100644
index 0000000..48f40bf
--- /dev/null
+++ b/compiler-rt/cmake/Modules/CompilerRTCompile.cmake
@@ -0,0 +1,107 @@
+# On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe,
+# which uses completely different flags. Translate some common flag types, and
+# drop the rest.
+function(translate_msvc_cflags out_flags msvc_flags)
+ # Insert an empty string in the list to simplify processing.
+ set(msvc_flags ";${msvc_flags}")
+
+ # Canonicalize /flag to -flag.
+ string(REPLACE ";/" ";-" msvc_flags "${msvc_flags}")
+
+ # Make space separated -D and -U flags into joined flags.
+ string(REGEX REPLACE ";-\([DU]\);" ";-\\1" msvc_flags "${msvc_flags}")
+
+ set(clang_flags "")
+ foreach(flag ${msvc_flags})
+ if ("${flag}" MATCHES "^-[DU]")
+ # Pass through basic command line macro definitions (-DNDEBUG).
+ list(APPEND clang_flags "${flag}")
+ elseif ("${flag}" MATCHES "^-O[2x]")
+ # Canonicalize normal optimization flags to -O2.
+ list(APPEND clang_flags "-O2")
+ endif()
+ endforeach()
+ set(${out_flags} "${clang_flags}" PARENT_SCOPE)
+endfunction()
+
+# Compile a source into an object file with COMPILER_RT_TEST_COMPILER using
+# a provided compile flags and dependenices.
+# clang_compile(<object> <source>
+# CFLAGS <list of compile flags>
+# DEPS <list of dependencies>)
+macro(clang_compile object_file source)
+ cmake_parse_arguments(SOURCE "" "" "CFLAGS;DEPS" ${ARGN})
+ get_filename_component(source_rpath ${source} REALPATH)
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SOURCE_DEPS clang compiler-rt-headers)
+ endif()
+ if (TARGET CompilerRTUnitTestCheckCxx)
+ list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
+ endif()
+ string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
+ if(is_cxx)
+ string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
+ else()
+ string(REPLACE " " ";" global_flags "${CMAKE_C_FLAGS}")
+ endif()
+
+ if (MSVC)
+ translate_msvc_cflags(global_flags "${global_flags}")
+ endif()
+
+ if (APPLE)
+ set(global_flags ${OSX_SYSROOT_FLAG} ${global_flags})
+ endif()
+
+ # Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options
+ # which are not supported by Clang.
+ list(APPEND global_flags -Wno-unknown-warning-option)
+ set(compile_flags ${global_flags} ${SOURCE_CFLAGS})
+ add_custom_command(
+ OUTPUT ${object_file}
+ COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
+ -o "${object_file}"
+ ${source_rpath}
+ MAIN_DEPENDENCY ${source}
+ DEPENDS ${SOURCE_DEPS})
+endmacro()
+
+# On Darwin, there are no system-wide C++ headers and the just-built clang is
+# therefore not able to compile C++ files unless they are copied/symlinked into
+# ${LLVM_BINARY_DIR}/include/c++
+# The just-built clang is used to build compiler-rt unit tests. Let's detect
+# this before we try to build the tests and print out a suggestion how to fix
+# it.
+# On other platforms, this is currently not an issue.
+macro(clang_compiler_add_cxx_check)
+ if (APPLE)
+ set(CMD
+ "echo '#include <iostream>' | ${COMPILER_RT_TEST_COMPILER} ${OSX_SYSROOT_FLAG} -E -x c++ - > /dev/null"
+ "if [ $? != 0 ] "
+ " then echo"
+ " echo 'Your just-built clang cannot find C++ headers, which are needed to build and run compiler-rt tests.'"
+ " echo 'You should copy or symlink your system C++ headers into ${LLVM_BINARY_DIR}/include/c++'"
+ " if [ -d $(dirname $(dirname $(xcrun -f clang)))/include/c++ ]"
+ " then echo 'e.g. with:'"
+ " echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/include/c++ '${LLVM_BINARY_DIR}/include/'"
+ " elif [ -d $(dirname $(dirname $(xcrun -f clang)))/lib/c++ ]"
+ " then echo 'e.g. with:'"
+ " echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/lib/c++ '${LLVM_BINARY_DIR}/include/'"
+ " fi"
+ " echo 'This can also be fixed by checking out the libcxx project from llvm.org and installing the headers'"
+ " echo 'into your build directory:'"
+ " echo ' cd ${LLVM_SOURCE_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
+ " echo ' cd ${LLVM_BINARY_DIR} && make -C ${LLVM_SOURCE_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
+ " echo"
+ " false"
+ "fi"
+ )
+ add_custom_target(CompilerRTUnitTestCheckCxx
+ COMMAND bash -c "${CMD}"
+ COMMENT "Checking that just-built clang can find C++ headers..."
+ VERBATIM)
+ if (TARGET clang)
+ ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
+ endif()
+ endif()
+endmacro()
diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
new file mode 100644
index 0000000..511361b
--- /dev/null
+++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
@@ -0,0 +1,453 @@
+# On OS X SDKs can be installed anywhere on the base system and xcode-select can
+# set the default Xcode to use. This function finds the SDKs that are present in
+# the current Xcode.
+function(find_darwin_sdk_dir var sdk_name)
+ # Let's first try the internal SDK, otherwise use the public SDK.
+ execute_process(
+ COMMAND xcodebuild -version -sdk ${sdk_name}.internal Path
+ OUTPUT_VARIABLE var_internal
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_FILE /dev/null
+ )
+ if("" STREQUAL "${var_internal}")
+ execute_process(
+ COMMAND xcodebuild -version -sdk ${sdk_name} Path
+ OUTPUT_VARIABLE var_internal
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_FILE /dev/null
+ )
+ endif()
+ set(${var} ${var_internal} PARENT_SCOPE)
+endfunction()
+
+# There isn't a clear mapping of what architectures are supported with a given
+# target platform, but ld's version output does list the architectures it can
+# link for.
+function(darwin_get_toolchain_supported_archs output_var)
+ execute_process(
+ COMMAND ld -v
+ ERROR_VARIABLE LINKER_VERSION)
+
+ string(REGEX MATCH "configured to support archs: ([^\n]+)"
+ ARCHES_MATCHED "${LINKER_VERSION}")
+ if(ARCHES_MATCHED)
+ set(ARCHES "${CMAKE_MATCH_1}")
+ message(STATUS "Got ld supported ARCHES: ${ARCHES}")
+ string(REPLACE " " ";" ARCHES ${ARCHES})
+ else()
+ # If auto-detecting fails, fall back to a default set
+ message(WARNING "Detecting supported architectures from 'ld -v' failed. Returning default set.")
+ set(ARCHES "i386;x86_64;armv7;armv7s;arm64")
+ endif()
+
+ set(${output_var} ${ARCHES} PARENT_SCOPE)
+endfunction()
+
+# This function takes an OS and a list of architectures and identifies the
+# subset of the architectures list that the installed toolchain can target.
+function(darwin_test_archs os valid_archs)
+ if(${valid_archs})
+ message(STATUS "Using cached valid architectures for ${os}.")
+ return()
+ endif()
+
+ set(archs ${ARGN})
+ message(STATUS "Finding valid architectures for ${os}...")
+ set(SIMPLE_CPP ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.cpp)
+ file(WRITE ${SIMPLE_CPP} "#include <iostream>\nint main() { std::cout << std::endl; return 0; }\n")
+
+ set(os_linker_flags)
+ foreach(flag ${DARWIN_${os}_LINKFLAGS})
+ set(os_linker_flags "${os_linker_flags} ${flag}")
+ endforeach()
+
+ # The simple program will build for x86_64h on the simulator because it is
+ # compatible with x86_64 libraries (mostly), but since x86_64h isn't actually
+ # a valid or useful architecture for the iOS simulator we should drop it.
+ if(${os} STREQUAL "iossim")
+ list(REMOVE_ITEM archs "x86_64h")
+ endif()
+
+ set(working_archs)
+ foreach(arch ${archs})
+
+ set(arch_linker_flags "-arch ${arch} ${os_linker_flags}")
+ try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_CPP}
+ COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS}
+ CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${arch_linker_flags}"
+ OUTPUT_VARIABLE TEST_OUTPUT)
+ if(${CAN_TARGET_${os}_${arch}})
+ list(APPEND working_archs ${arch})
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Testing compiler for supporting ${os}-${arch}:\n"
+ "${TEST_OUTPUT}\n")
+ endif()
+ endforeach()
+ set(${valid_archs} ${working_archs}
+ CACHE STRING "List of valid architectures for platform ${os}.")
+endfunction()
+
+# This function checks the host cpusubtype to see if it is post-haswell. Haswell
+# and later machines can run x86_64h binaries. Haswell is cpusubtype 8.
+function(darwin_filter_host_archs input output)
+ list_union(tmp_var DARWIN_osx_ARCHS ${input})
+ execute_process(
+ COMMAND sysctl hw.cpusubtype
+ OUTPUT_VARIABLE SUBTYPE)
+
+ string(REGEX MATCH "hw.cpusubtype: ([0-9]*)"
+ SUBTYPE_MATCHED "${SUBTYPE}")
+ set(HASWELL_SUPPORTED Off)
+ if(SUBTYPE_MATCHED)
+ if(${CMAKE_MATCH_1} GREATER 7)
+ set(HASWELL_SUPPORTED On)
+ endif()
+ endif()
+ if(NOT HASWELL_SUPPORTED)
+ list(REMOVE_ITEM tmp_var x86_64h)
+ endif()
+ set(${output} ${tmp_var} PARENT_SCOPE)
+endfunction()
+
+# Read and process the exclude file into a list of symbols
+function(darwin_read_list_from_file output_var file)
+ if(EXISTS ${file})
+ file(READ ${file} EXCLUDES)
+ string(REPLACE "\n" ";" EXCLUDES ${EXCLUDES})
+ set(${output_var} ${EXCLUDES} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# this function takes an OS, architecture and minimum version and provides a
+# list of builtin functions to exclude
+function(darwin_find_excluded_builtins_list output_var)
+ cmake_parse_arguments(LIB
+ ""
+ "OS;ARCH;MIN_VERSION"
+ ""
+ ${ARGN})
+
+ if(NOT LIB_OS OR NOT LIB_ARCH)
+ message(FATAL_ERROR "Must specify OS and ARCH to darwin_find_excluded_builtins_list!")
+ endif()
+
+ darwin_read_list_from_file(${LIB_OS}_BUILTINS
+ ${DARWIN_EXCLUDE_DIR}/${LIB_OS}.txt)
+ darwin_read_list_from_file(${LIB_OS}_${LIB_ARCH}_BASE_BUILTINS
+ ${DARWIN_EXCLUDE_DIR}/${LIB_OS}-${LIB_ARCH}.txt)
+
+ if(LIB_MIN_VERSION)
+ file(GLOB builtin_lists ${DARWIN_EXCLUDE_DIR}/${LIB_OS}*-${LIB_ARCH}.txt)
+ foreach(builtin_list ${builtin_lists})
+ string(REGEX MATCH "${LIB_OS}([0-9\\.]*)-${LIB_ARCH}.txt" VERSION_MATCHED "${builtin_list}")
+ if (VERSION_MATCHED AND NOT CMAKE_MATCH_1 VERSION_LESS LIB_MIN_VERSION)
+ if(NOT smallest_version)
+ set(smallest_version ${CMAKE_MATCH_1})
+ elseif(CMAKE_MATCH_1 VERSION_LESS smallest_version)
+ set(smallest_version ${CMAKE_MATCH_1})
+ endif()
+ endif()
+ endforeach()
+
+ if(smallest_version)
+ darwin_read_list_from_file(${LIB_ARCH}_${LIB_OS}_BUILTINS
+ ${DARWIN_EXCLUDE_DIR}/${LIB_OS}${smallest_version}-${LIB_ARCH}.txt)
+ endif()
+ endif()
+
+ set(${output_var}
+ ${${LIB_ARCH}_${LIB_OS}_BUILTINS}
+ ${${LIB_OS}_${LIB_ARCH}_BASE_BUILTINS}
+ ${${LIB_OS}_BUILTINS} PARENT_SCOPE)
+endfunction()
+
+# adds a single builtin library for a single OS & ARCH
+macro(darwin_add_builtin_library name suffix)
+ cmake_parse_arguments(LIB
+ ""
+ "PARENT_TARGET;OS;ARCH"
+ "SOURCES;CFLAGS;DEFS"
+ ${ARGN})
+ set(libname "${name}.${suffix}_${LIB_ARCH}_${LIB_OS}")
+ add_library(${libname} STATIC ${LIB_SOURCES})
+ if(DARWIN_${LIB_OS}_SYSROOT)
+ set(sysroot_flag -isysroot ${DARWIN_${LIB_OS}_SYSROOT})
+ endif()
+ set_target_compile_flags(${libname}
+ ${sysroot_flag}
+ ${DARWIN_${LIB_OS}_BUILTIN_MIN_VER_FLAG}
+ ${LIB_CFLAGS})
+ set_property(TARGET ${libname} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
+ set_target_properties(${libname} PROPERTIES
+ OUTPUT_NAME ${libname}${COMPILER_RT_OS_SUFFIX})
+ set_target_properties(${libname} PROPERTIES
+ OSX_ARCHITECTURES ${LIB_ARCH})
+
+ if(LIB_PARENT_TARGET)
+ add_dependencies(${LIB_PARENT_TARGET} ${libname})
+ endif()
+
+ list(APPEND ${LIB_OS}_${suffix}_libs ${libname})
+ list(APPEND ${LIB_OS}_${suffix}_lipo_flags -arch ${arch} $<TARGET_FILE:${libname}>)
+endmacro()
+
+function(darwin_lipo_libs name)
+ cmake_parse_arguments(LIB
+ ""
+ "PARENT_TARGET;OUTPUT_DIR;INSTALL_DIR"
+ "LIPO_FLAGS;DEPENDS"
+ ${ARGN})
+ if(LIB_DEPENDS AND LIB_LIPO_FLAGS)
+ add_custom_command(OUTPUT ${LIB_OUTPUT_DIR}/lib${name}.a
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_OUTPUT_DIR}
+ COMMAND lipo -output
+ ${LIB_OUTPUT_DIR}/lib${name}.a
+ -create ${LIB_LIPO_FLAGS}
+ DEPENDS ${LIB_DEPENDS}
+ )
+ add_custom_target(${name}
+ DEPENDS ${LIB_OUTPUT_DIR}/lib${name}.a)
+ add_dependencies(${LIB_PARENT_TARGET} ${name})
+ install(FILES ${LIB_OUTPUT_DIR}/lib${name}.a
+ DESTINATION ${LIB_INSTALL_DIR})
+ else()
+ message(WARNING "Not generating lipo target for ${name} because no input libraries exist.")
+ endif()
+endfunction()
+
+# Filter out generic versions of routines that are re-implemented in
+# architecture specific manner. This prevents multiple definitions of the
+# same symbols, making the symbol selection non-deterministic.
+function(darwin_filter_builtin_sources output_var exclude_or_include excluded_list)
+ if(exclude_or_include STREQUAL "EXCLUDE")
+ set(filter_action GREATER)
+ set(filter_value -1)
+ elseif(exclude_or_include STREQUAL "INCLUDE")
+ set(filter_action LESS)
+ set(filter_value 0)
+ else()
+ message(FATAL_ERROR "darwin_filter_builtin_sources called without EXCLUDE|INCLUDE")
+ endif()
+
+ set(intermediate ${ARGN})
+ foreach (_file ${intermediate})
+ get_filename_component(_name_we ${_file} NAME_WE)
+ list(FIND ${excluded_list} ${_name_we} _found)
+ if(_found ${filter_action} ${filter_value})
+ list(REMOVE_ITEM intermediate ${_file})
+ elseif(${_file} MATCHES ".*/.*\\.S" OR ${_file} MATCHES ".*/.*\\.c")
+ get_filename_component(_name ${_file} NAME)
+ string(REPLACE ".S" ".c" _cname "${_name}")
+ list(REMOVE_ITEM intermediate ${_cname})
+ endif ()
+ endforeach ()
+ set(${output_var} ${intermediate} PARENT_SCOPE)
+endfunction()
+
+function(darwin_add_eprintf_library)
+ cmake_parse_arguments(LIB
+ ""
+ ""
+ "CFLAGS"
+ ${ARGN})
+
+ add_library(clang_rt.eprintf STATIC eprintf.c)
+ set_target_compile_flags(clang_rt.eprintf
+ -isysroot ${DARWIN_osx_SYSROOT}
+ ${DARWIN_osx_BUILTIN_MIN_VER_FLAG}
+ -arch i386
+ ${LIB_CFLAGS})
+ set_target_properties(clang_rt.eprintf PROPERTIES
+ OUTPUT_NAME clang_rt.eprintf${COMPILER_RT_OS_SUFFIX})
+ set_target_properties(clang_rt.eprintf PROPERTIES
+ OSX_ARCHITECTURES i386)
+ add_dependencies(builtins clang_rt.eprintf)
+ set_target_properties(clang_rt.eprintf PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
+ install(TARGETS clang_rt.eprintf
+ ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+endfunction()
+
+# Generates builtin libraries for all operating systems specified in ARGN. Each
+# OS library is constructed by lipo-ing together single-architecture libraries.
+macro(darwin_add_builtin_libraries)
+ set(DARWIN_EXCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Darwin-excludes)
+
+ set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer")
+ set(CMAKE_C_FLAGS "")
+ set(CMAKE_CXX_FLAGS "")
+ set(CMAKE_ASM_FLAGS "")
+
+ set(PROFILE_SOURCES ../profile/InstrProfiling
+ ../profile/InstrProfilingBuffer
+ ../profile/InstrProfilingPlatformDarwin)
+ foreach (os ${ARGN})
+ list_union(DARWIN_BUILTIN_ARCHS DARWIN_${os}_ARCHS BUILTIN_SUPPORTED_ARCH)
+ foreach (arch ${DARWIN_BUILTIN_ARCHS})
+ darwin_find_excluded_builtins_list(${arch}_${os}_EXCLUDED_BUILTINS
+ OS ${os}
+ ARCH ${arch}
+ MIN_VERSION ${DARWIN_${os}_BUILTIN_MIN_VER})
+
+ darwin_filter_builtin_sources(filtered_sources
+ EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
+ ${${arch}_SOURCES})
+
+ darwin_add_builtin_library(clang_rt builtins
+ OS ${os}
+ ARCH ${arch}
+ SOURCES ${filtered_sources}
+ CFLAGS ${CFLAGS} -arch ${arch}
+ PARENT_TARGET builtins)
+ endforeach()
+
+ # Don't build cc_kext libraries for simulator platforms
+ if(NOT DARWIN_${os}_SKIP_CC_KEXT)
+ foreach (arch ${DARWIN_BUILTIN_ARCHS})
+ # By not specifying MIN_VERSION this only reads the OS and OS-arch lists.
+ # We don't want to filter out the builtins that are present in libSystem
+ # because kexts can't link libSystem.
+ darwin_find_excluded_builtins_list(${arch}_${os}_EXCLUDED_BUILTINS
+ OS ${os}
+ ARCH ${arch})
+
+ darwin_filter_builtin_sources(filtered_sources
+ EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
+ ${${arch}_SOURCES})
+
+ # In addition to the builtins cc_kext includes some profile sources
+ darwin_add_builtin_library(clang_rt cc_kext
+ OS ${os}
+ ARCH ${arch}
+ SOURCES ${filtered_sources} ${PROFILE_SOURCES}
+ CFLAGS ${CFLAGS} -arch ${arch} -mkernel
+ DEFS KERNEL_USE
+ PARENT_TARGET builtins)
+ endforeach()
+ set(archive_name clang_rt.cc_kext_${os})
+ if(${os} STREQUAL "osx")
+ set(archive_name clang_rt.cc_kext)
+ endif()
+ darwin_lipo_libs(${archive_name}
+ PARENT_TARGET builtins
+ LIPO_FLAGS ${${os}_cc_kext_lipo_flags}
+ DEPENDS ${${os}_cc_kext_libs}
+ OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
+ INSTALL_DIR ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ endif()
+ endforeach()
+
+ darwin_add_eprintf_library(CFLAGS ${CFLAGS})
+
+ # We put the x86 sim slices into the archives for their base OS
+ foreach (os ${ARGN})
+ if(NOT ${os} MATCHES ".*sim$")
+ darwin_lipo_libs(clang_rt.${os}
+ PARENT_TARGET builtins
+ LIPO_FLAGS ${${os}_builtins_lipo_flags} ${${os}sim_builtins_lipo_flags}
+ DEPENDS ${${os}_builtins_libs} ${${os}sim_builtins_libs}
+ OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
+ INSTALL_DIR ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ endif()
+ endforeach()
+ darwin_add_embedded_builtin_libraries()
+endmacro()
+
+macro(darwin_add_embedded_builtin_libraries)
+ # this is a hacky opt-out. If you can't target both intel and arm
+ # architectures we bail here.
+ set(DARWIN_SOFT_FLOAT_ARCHS armv6m armv7m armv7em armv7)
+ set(DARWIN_HARD_FLOAT_ARCHS armv7em armv7)
+ if(COMPILER_RT_SUPPORTED_ARCH MATCHES ".*armv.*")
+ list(FIND COMPILER_RT_SUPPORTED_ARCH i386 i386_idx)
+ if(i386_idx GREATER -1)
+ list(APPEND DARWIN_HARD_FLOAT_ARCHS i386)
+ endif()
+
+ list(FIND COMPILER_RT_SUPPORTED_ARCH x86_64 x86_64_idx)
+ if(x86_64_idx GREATER -1)
+ list(APPEND DARWIN_HARD_FLOAT_ARCHS x86_64)
+ endif()
+
+ set(MACHO_SYM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/macho_embedded)
+
+ set(CFLAGS "-Oz -Wall -fomit-frame-pointer -ffreestanding")
+ set(CMAKE_C_FLAGS "")
+ set(CMAKE_CXX_FLAGS "")
+ set(CMAKE_ASM_FLAGS "")
+
+ set(SOFT_FLOAT_FLAG -mfloat-abi=soft)
+ set(HARD_FLOAT_FLAG -mfloat-abi=hard)
+
+ set(ENABLE_PIC Off)
+ set(PIC_FLAG -fPIC)
+ set(STATIC_FLAG -static)
+
+ set(DARWIN_macho_embedded_ARCHS armv6m armv7m armv7em armv7 i386 x86_64)
+
+ set(DARWIN_macho_embedded_LIBRARY_OUTPUT_DIR
+ ${COMPILER_RT_OUTPUT_DIR}/lib/macho_embedded)
+ set(DARWIN_macho_embedded_LIBRARY_INSTALL_DIR
+ ${COMPILER_RT_INSTALL_PATH}/lib/macho_embedded)
+
+ set(CFLAGS_armv7 "-target thumbv7-apple-darwin-eabi")
+ set(CFLAGS_i386 "-march=pentium")
+
+ darwin_read_list_from_file(common_FUNCTIONS ${MACHO_SYM_DIR}/common.txt)
+ darwin_read_list_from_file(thumb2_FUNCTIONS ${MACHO_SYM_DIR}/thumb2.txt)
+ darwin_read_list_from_file(thumb2_64_FUNCTIONS ${MACHO_SYM_DIR}/thumb2-64.txt)
+ darwin_read_list_from_file(arm_FUNCTIONS ${MACHO_SYM_DIR}/arm.txt)
+ darwin_read_list_from_file(i386_FUNCTIONS ${MACHO_SYM_DIR}/i386.txt)
+
+
+ set(armv6m_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS})
+ set(armv7m_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS})
+ set(armv7em_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS})
+ set(armv7_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS} ${thumb2_64_FUNCTIONS})
+ set(i386_FUNCTIONS ${common_FUNCTIONS} ${i386_FUNCTIONS})
+ set(x86_64_FUNCTIONS ${common_FUNCTIONS})
+
+ foreach(arch ${DARWIN_macho_embedded_ARCHS})
+ darwin_filter_builtin_sources(${arch}_filtered_sources
+ INCLUDE ${arch}_FUNCTIONS
+ ${${arch}_SOURCES})
+ if(NOT ${arch}_filtered_sources)
+ message("${arch}_SOURCES: ${${arch}_SOURCES}")
+ message("${arch}_FUNCTIONS: ${${arch}_FUNCTIONS}")
+ message(FATAL_ERROR "Empty filtered sources!")
+ endif()
+ endforeach()
+
+ foreach(float_type SOFT HARD)
+ foreach(type PIC STATIC)
+ string(TOLOWER "${float_type}_${type}" lib_suffix)
+ foreach(arch ${DARWIN_${float_type}_FLOAT_ARCHS})
+ set(DARWIN_macho_embedded_SYSROOT ${DARWIN_osx_SYSROOT})
+ set(float_flag)
+ if(${arch} MATCHES "^arm")
+ # x86 targets are hard float by default, but the complain about the
+ # float ABI flag, so don't pass it unless we're targeting arm.
+ set(float_flag ${${float_type}_FLOAT_FLAG})
+ endif()
+ darwin_add_builtin_library(clang_rt ${lib_suffix}
+ OS macho_embedded
+ ARCH ${arch}
+ SOURCES ${${arch}_filtered_sources}
+ CFLAGS ${CFLAGS} -arch ${arch} ${${type}_FLAG} ${float_flag} ${CFLAGS_${arch}}
+ PARENT_TARGET builtins)
+ endforeach()
+ foreach(lib ${macho_embedded_${lib_suffix}_libs})
+ set_target_properties(${lib} PROPERTIES LINKER_LANGUAGE C)
+ endforeach()
+ darwin_lipo_libs(clang_rt.${lib_suffix}
+ PARENT_TARGET builtins
+ LIPO_FLAGS ${macho_embedded_${lib_suffix}_lipo_flags}
+ DEPENDS ${macho_embedded_${lib_suffix}_libs}
+ OUTPUT_DIR ${DARWIN_macho_embedded_LIBRARY_OUTPUT_DIR}
+ INSTALL_DIR ${DARWIN_macho_embedded_LIBRARY_INSTALL_DIR})
+ endforeach()
+ endforeach()
+ endif()
+endmacro()
diff --git a/compiler-rt/cmake/Modules/CompilerRTLink.cmake b/compiler-rt/cmake/Modules/CompilerRTLink.cmake
new file mode 100644
index 0000000..bb96869
--- /dev/null
+++ b/compiler-rt/cmake/Modules/CompilerRTLink.cmake
@@ -0,0 +1,16 @@
+# Link a shared library with COMPILER_RT_TEST_COMPILER.
+# clang_link_shared(<output.so>
+# OBJECTS <list of input objects>
+# LINKFLAGS <list of link flags>
+# DEPS <list of dependencies>)
+macro(clang_link_shared so_file)
+ cmake_parse_arguments(SOURCE "" "" "OBJECTS;LINKFLAGS;DEPS" ${ARGN})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SOURCE_DEPS clang)
+ endif()
+ add_custom_command(
+ OUTPUT ${so_file}
+ COMMAND ${COMPILER_RT_TEST_COMPILER} -o "${so_file}" -shared
+ ${SOURCE_LINKFLAGS} ${SOURCE_OBJECTS}
+ DEPENDS ${SOURCE_DEPS})
+endmacro()
diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
new file mode 100644
index 0000000..cf690f4
--- /dev/null
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -0,0 +1,69 @@
+# Because compiler-rt spends a lot of time setting up custom compile flags,
+# define a handy helper function for it. The compile flags setting in CMake
+# has serious issues that make its syntax challenging at best.
+function(set_target_compile_flags target)
+ set(argstring "")
+ foreach(arg ${ARGN})
+ set(argstring "${argstring} ${arg}")
+ endforeach()
+ set_property(TARGET ${target} PROPERTY COMPILE_FLAGS "${argstring}")
+endfunction()
+
+function(set_target_link_flags target)
+ set(argstring "")
+ foreach(arg ${ARGN})
+ set(argstring "${argstring} ${arg}")
+ endforeach()
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
+endfunction()
+
+# Set the variable var_PYBOOL to True if var holds a true-ish string,
+# otherwise set it to False.
+macro(pythonize_bool var)
+ if (${var})
+ set(${var}_PYBOOL True)
+ else()
+ set(${var}_PYBOOL False)
+ endif()
+endmacro()
+
+# Appends value to all lists in ARGN, if the condition is true.
+macro(append_list_if condition value)
+ if(${condition})
+ foreach(list ${ARGN})
+ list(APPEND ${list} ${value})
+ endforeach()
+ endif()
+endmacro()
+
+# Appends value to all strings in ARGN, if the condition is true.
+macro(append_string_if condition value)
+ if(${condition})
+ foreach(str ${ARGN})
+ set(${str} "${${str}} ${value}")
+ endforeach()
+ endif()
+endmacro()
+
+macro(append_no_rtti_flag list)
+ append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
+ append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
+endmacro()
+
+macro(append_have_file_definition filename varname list)
+ check_include_file("${filename}" "${varname}")
+ if (NOT ${varname})
+ set("${varname}" 0)
+ endif()
+ list(APPEND ${list} "${varname}=${${varname}}")
+endmacro()
+
+macro(list_union output input1 input2)
+ set(${output})
+ foreach(it ${${input1}})
+ list(FIND ${input2} ${it} index)
+ if( NOT (index EQUAL -1))
+ list(APPEND ${output} ${it})
+ endif()
+ endforeach()
+endmacro()
diff --git a/compiler-rt/cmake/Modules/SanitizerUtils.cmake b/compiler-rt/cmake/Modules/SanitizerUtils.cmake
new file mode 100644
index 0000000..3eb49c8
--- /dev/null
+++ b/compiler-rt/cmake/Modules/SanitizerUtils.cmake
@@ -0,0 +1,97 @@
+set(SANITIZER_GEN_DYNAMIC_LIST
+ ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.py)
+
+set(SANITIZER_LINT_SCRIPT
+ ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/check_lint.sh)
+
+# Create a target "<name>-<arch>-symbols" that would generate the list of
+# symbols that need to be exported from sanitizer runtime "<name>". Function
+# interceptors are exported automatically, user can also provide files with
+# symbol names that should be exported as well.
+# add_sanitizer_rt_symbols(<name>
+# ARCHS <architectures>
+# PARENT_TARGET <convenience parent target>
+# EXTRA <files with extra symbols to export>)
+macro(add_sanitizer_rt_symbols name)
+ cmake_parse_arguments(ARG
+ ""
+ "PARENT_TARGET"
+ "ARCHS;EXTRA"
+ ${ARGN})
+ foreach(arch ${ARG_ARCHS})
+ set(target_name ${name}-${arch})
+ set(stamp ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.syms-stamp)
+ set(extra_args)
+ foreach(arg ${ARG_EXTRA})
+ list(APPEND extra_args "--extra" ${arg})
+ endforeach()
+ add_custom_command(OUTPUT ${stamp}
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${SANITIZER_GEN_DYNAMIC_LIST} ${extra_args} $<TARGET_FILE:${target_name}>
+ > $<TARGET_FILE:${target_name}>.syms
+ COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
+ DEPENDS ${target_name} ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Generating exported symbols for ${target_name}"
+ VERBATIM)
+ add_custom_target(${target_name}-symbols ALL
+ DEPENDS ${stamp}
+ SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA})
+
+ if(NOT CMAKE_VERSION VERSION_LESS 3.0)
+ install(FILES $<TARGET_FILE:${target_name}>.syms
+ DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ else()
+ # Per-config install location.
+ if(CMAKE_CONFIGURATION_TYPES)
+ foreach(c ${CMAKE_CONFIGURATION_TYPES})
+ get_target_property(libfile ${target_name} LOCATION_${c})
+ install(FILES ${libfile}.syms CONFIGURATIONS ${c}
+ DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ endforeach()
+ else()
+ get_target_property(libfile ${target_name} LOCATION_${CMAKE_BUILD_TYPE})
+ install(FILES ${libfile}.syms DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ endif()
+ endif()
+ if(ARG_PARENT_TARGET)
+ add_dependencies(${ARG_PARENT_TARGET} ${target_name}-symbols)
+ endif()
+ endforeach()
+endmacro()
+
+macro(add_sanitizer_rt_version_list name)
+ set(vers ${CMAKE_CURRENT_BINARY_DIR}/${name}.vers)
+ cmake_parse_arguments(ARG "" "" "LIBS;EXTRA" ${ARGN})
+ set(args)
+ foreach(arg ${ARG_EXTRA})
+ list(APPEND args "--extra" ${arg})
+ endforeach()
+ foreach(arg ${ARG_LIBS})
+ list(APPEND args "$<TARGET_FILE:${arg}>")
+ endforeach()
+ add_custom_command(OUTPUT ${vers}
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${SANITIZER_GEN_DYNAMIC_LIST} --version-list ${args}
+ > ${vers}
+ DEPENDS ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA} ${ARG_LIBS}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Generating version list for ${name}"
+ VERBATIM)
+
+ add_custom_target(${name}-version-list ALL
+ DEPENDS ${vers})
+endmacro()
+
+# Add target to check code style for sanitizer runtimes.
+if(UNIX)
+ add_custom_target(SanitizerLintCheck
+ COMMAND LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
+ PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
+ COMPILER_RT=${COMPILER_RT_SOURCE_DIR}
+ ${SANITIZER_LINT_SCRIPT}
+ DEPENDS ${SANITIZER_LINT_SCRIPT}
+ COMMENT "Running lint check for sanitizer sources..."
+ VERBATIM)
+endif()
+
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
new file mode 100644
index 0000000..f91530b
--- /dev/null
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -0,0 +1,594 @@
+include(CMakePushCheckState)
+include(CheckCXXCompilerFlag)
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+include(TestBigEndian)
+
+function(check_linker_flag flag out_var)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}")
+ check_cxx_compiler_flag("" ${out_var})
+ cmake_pop_check_state()
+endfunction()
+
+# CodeGen options.
+check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
+check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
+check_cxx_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
+check_cxx_compiler_flag(-fno-exceptions COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG)
+check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)
+check_cxx_compiler_flag(-funwind-tables COMPILER_RT_HAS_FUNWIND_TABLES_FLAG)
+check_cxx_compiler_flag(-fno-stack-protector COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG)
+check_cxx_compiler_flag(-fno-sanitize=safe-stack COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG)
+check_cxx_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
+check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
+check_cxx_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
+check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
+check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
+check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)
+check_cxx_compiler_flag(-fno-lto COMPILER_RT_HAS_FNO_LTO_FLAG)
+check_cxx_compiler_flag("-Werror -msse3" COMPILER_RT_HAS_MSSE3_FLAG)
+check_cxx_compiler_flag(-std=c99 COMPILER_RT_HAS_STD_C99_FLAG)
+check_cxx_compiler_flag(--sysroot=. COMPILER_RT_HAS_SYSROOT_FLAG)
+
+if(NOT WIN32 AND NOT CYGWIN)
+ # MinGW warns if -fvisibility-inlines-hidden is used.
+ check_cxx_compiler_flag("-fvisibility-inlines-hidden" COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG)
+endif()
+
+check_cxx_compiler_flag(/GR COMPILER_RT_HAS_GR_FLAG)
+check_cxx_compiler_flag(/GS COMPILER_RT_HAS_GS_FLAG)
+check_cxx_compiler_flag(/MT COMPILER_RT_HAS_MT_FLAG)
+check_cxx_compiler_flag(/Oy COMPILER_RT_HAS_Oy_FLAG)
+
+# Debug info flags.
+check_cxx_compiler_flag(-gline-tables-only COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG)
+check_cxx_compiler_flag(-g COMPILER_RT_HAS_G_FLAG)
+check_cxx_compiler_flag(/Zi COMPILER_RT_HAS_Zi_FLAG)
+
+# Warnings.
+check_cxx_compiler_flag(-Wall COMPILER_RT_HAS_WALL_FLAG)
+check_cxx_compiler_flag(-Werror COMPILER_RT_HAS_WERROR_FLAG)
+check_cxx_compiler_flag("-Werror -Wframe-larger-than=512" COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG)
+check_cxx_compiler_flag("-Werror -Wglobal-constructors" COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG)
+check_cxx_compiler_flag("-Werror -Wc99-extensions" COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG)
+check_cxx_compiler_flag("-Werror -Wgnu" COMPILER_RT_HAS_WGNU_FLAG)
+check_cxx_compiler_flag("-Werror -Wnon-virtual-dtor" COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG)
+check_cxx_compiler_flag("-Werror -Wvariadic-macros" COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG)
+
+check_cxx_compiler_flag(/W3 COMPILER_RT_HAS_W3_FLAG)
+check_cxx_compiler_flag(/WX COMPILER_RT_HAS_WX_FLAG)
+check_cxx_compiler_flag(/wd4146 COMPILER_RT_HAS_WD4146_FLAG)
+check_cxx_compiler_flag(/wd4291 COMPILER_RT_HAS_WD4291_FLAG)
+check_cxx_compiler_flag(/wd4391 COMPILER_RT_HAS_WD4391_FLAG)
+check_cxx_compiler_flag(/wd4722 COMPILER_RT_HAS_WD4722_FLAG)
+check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG)
+
+# Symbols.
+check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
+
+# Libraries.
+check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC)
+check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL)
+check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT)
+check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
+check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD)
+check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
+
+# Linker flags.
+if(ANDROID)
+ check_linker_flag("-Wl,-z,global" COMPILER_RT_HAS_Z_GLOBAL)
+ check_library_exists(log __android_log_write "" COMPILER_RT_HAS_LIBLOG)
+endif()
+
+# Architectures.
+
+# List of all architectures we can target.
+set(COMPILER_RT_SUPPORTED_ARCH)
+
+# Try to compile a very simple source file to ensure we can target the given
+# platform. We use the results of these tests to build only the various target
+# runtime libraries supported by our current compilers cross-compiling
+# abilities.
+set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
+file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <limits>\nint main() {}\n")
+
+function(check_compile_definition def argstring out_var)
+ if("${def}" STREQUAL "")
+ set(${out_var} TRUE PARENT_SCOPE)
+ return()
+ endif()
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${argstring}")
+ check_symbol_exists(${def} "" ${out_var})
+ cmake_pop_check_state()
+endfunction()
+
+# test_target_arch(<arch> <def> <target flags...>)
+# Checks if architecture is supported: runs host compiler with provided
+# flags to verify that:
+# 1) <def> is defined (if non-empty)
+# 2) simple file can be successfully built.
+# If successful, saves target flags for this architecture.
+macro(test_target_arch arch def)
+ set(TARGET_${arch}_CFLAGS ${ARGN})
+ set(argstring "")
+ foreach(arg ${ARGN})
+ set(argstring "${argstring} ${arg}")
+ endforeach()
+ check_compile_definition("${def}" "${argstring}" HAS_${arch}_DEF)
+ if(NOT HAS_${arch}_DEF)
+ set(CAN_TARGET_${arch} FALSE)
+ else()
+ set(argstring "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
+ try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
+ COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
+ OUTPUT_VARIABLE TARGET_${arch}_OUTPUT
+ CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${argstring}")
+ endif()
+ if(${CAN_TARGET_${arch}})
+ list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "${arch}" AND
+ COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE)
+ # Bail out if we cannot target the architecture we plan to test.
+ message(FATAL_ERROR "Cannot compile for ${arch}:\n${TARGET_${arch}_OUTPUT}")
+ endif()
+endmacro()
+
+# Add $arch as supported with no additional flags.
+macro(add_default_target_arch arch)
+ set(TARGET_${arch}_CFLAGS "")
+ set(CAN_TARGET_${arch} 1)
+ list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+endmacro()
+
+macro(detect_target_arch)
+ check_symbol_exists(__arm__ "" __ARM)
+ check_symbol_exists(__aarch64__ "" __AARCH64)
+ check_symbol_exists(__x86_64__ "" __X86_64)
+ check_symbol_exists(__i686__ "" __I686)
+ check_symbol_exists(__i386__ "" __I386)
+ check_symbol_exists(__mips__ "" __MIPS)
+ check_symbol_exists(__mips64__ "" __MIPS64)
+ if(__ARM)
+ add_default_target_arch(arm)
+ elseif(__AARCH64)
+ add_default_target_arch(aarch64)
+ elseif(__X86_64)
+ add_default_target_arch(x86_64)
+ elseif(__I686)
+ add_default_target_arch(i686)
+ elseif(__I386)
+ add_default_target_arch(i386)
+ elseif(__MIPS64) # must be checked before __MIPS
+ add_default_target_arch(mips64)
+ elseif(__MIPS)
+ add_default_target_arch(mips)
+ endif()
+endmacro()
+
+# Detect whether the current target platform is 32-bit or 64-bit, and setup
+# the correct commandline flags needed to attempt to target 32-bit and 64-bit.
+if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
+ NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
+ message(FATAL_ERROR "Please use architecture with 4 or 8 byte pointers.")
+endif()
+
+# Generate the COMPILER_RT_SUPPORTED_ARCH list.
+if(ANDROID)
+ # Examine compiler output to determine target architecture.
+ detect_target_arch()
+ set(COMPILER_RT_OS_SUFFIX "-android")
+elseif(NOT APPLE) # Supported archs for Apple platforms are generated later
+ if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64")
+ if(NOT MSVC)
+ test_target_arch(x86_64 "" "-m64")
+ # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may
+ # target different variant than "$CMAKE_C_COMPILER -m32". This part should
+ # be gone after we resolve PR14109.
+ test_target_arch(i686 __i686__ "-m32")
+ test_target_arch(i386 __i386__ "-m32")
+ else()
+ if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ test_target_arch(i386 "" "")
+ else()
+ test_target_arch(x86_64 "" "")
+ endif()
+ endif()
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
+ TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN)
+ if(HOST_IS_BIG_ENDIAN)
+ test_target_arch(powerpc64 "" "-m64")
+ else()
+ test_target_arch(powerpc64le "" "-m64")
+ endif()
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mipsel|mips64el")
+ # Gcc doesn't accept -m32/-m64 so we do the next best thing and use
+ # -mips32r2/-mips64r2. We don't use -mips1/-mips3 because we want to match
+ # clang's default CPU's. In the 64-bit case, we must also specify the ABI
+ # since the default ABI differs between gcc and clang.
+ # FIXME: Ideally, we would build the N32 library too.
+ test_target_arch(mipsel "" "-mips32r2" "--target=mipsel-linux-gnu")
+ test_target_arch(mips64el "" "-mips64r2" "--target=mips64el-linux-gnu" "-mabi=n64")
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mips")
+ test_target_arch(mips "" "-mips32r2" "--target=mips-linux-gnu")
+ test_target_arch(mips64 "" "-mips64r2" "--target=mips64-linux-gnu" "-mabi=n64")
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "arm")
+ test_target_arch(arm "" "-march=armv7-a" "-mfloat-abi=soft")
+ test_target_arch(armhf "" "-march=armv7-a" "-mfloat-abi=hard")
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch32")
+ test_target_arch(aarch32 "" "-march=armv8-a")
+ elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64")
+ test_target_arch(aarch64 "" "-march=armv8-a")
+ endif()
+ set(COMPILER_RT_OS_SUFFIX "")
+endif()
+
+# Takes ${ARGN} and puts only supported architectures in @out_var list.
+function(filter_available_targets out_var)
+ set(archs ${${out_var}})
+ foreach(arch ${ARGN})
+ list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
+ if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
+ list(APPEND archs ${arch})
+ endif()
+ endforeach()
+ set(${out_var} ${archs} PARENT_SCOPE)
+endfunction()
+
+# Returns a list of architecture specific target cflags in @out_var list.
+function(get_target_flags_for_arch arch out_var)
+ list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
+ if(ARCH_INDEX EQUAL -1)
+ message(FATAL_ERROR "Unsupported architecture: ${arch}")
+ else()
+ if (NOT APPLE)
+ set(${out_var} ${TARGET_${arch}_CFLAGS} PARENT_SCOPE)
+ else()
+ # This is only called in constructing cflags for tests executing on the
+ # host. This will need to all be cleaned up to support building tests
+ # for cross-targeted hardware (i.e. iOS).
+ set(${out_var} -arch ${arch} PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+set(ARM64 aarch64)
+set(ARM32 arm armhf)
+set(X86 i386 i686)
+set(X86_64 x86_64)
+set(MIPS32 mips mipsel)
+set(MIPS64 mips64 mips64el)
+set(PPC64 powerpc64 powerpc64le)
+
+if(APPLE)
+ set(ARM64 arm64)
+ set(ARM32 armv7 armv7s)
+ set(X86_64 x86_64 x86_64h)
+endif()
+
+set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
+ ${MIPS32} ${MIPS64})
+set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
+ ${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
+set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
+ ${MIPS32} ${MIPS64} ${PPC64})
+set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
+set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
+set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
+set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
+ ${MIPS32} ${MIPS64})
+set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
+set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
+ ${MIPS32} ${MIPS64} ${PPC64})
+set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64})
+set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64})
+
+if(APPLE)
+ include(CompilerRTDarwinUtils)
+
+ # On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
+ # the command line tools. If this is the case, we need to find the OS X
+ # sysroot to pass to clang.
+ if(NOT EXISTS /usr/include)
+ execute_process(COMMAND xcodebuild -version -sdk macosx Path
+ OUTPUT_VARIABLE OSX_SYSROOT
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
+ endif()
+
+ option(COMPILER_RT_ENABLE_IOS "Enable building for iOS - Experimental" Off)
+
+ find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)
+ find_darwin_sdk_dir(DARWIN_iossim_SYSROOT iphonesimulator)
+ find_darwin_sdk_dir(DARWIN_ios_SYSROOT iphoneos)
+
+ # Note: In order to target x86_64h on OS X the minimum deployment target must
+ # be 10.8 or higher.
+ set(SANITIZER_COMMON_SUPPORTED_OS osx)
+ set(BUILTIN_SUPPORTED_OS osx)
+ set(PROFILE_SUPPORTED_OS osx)
+ set(TSAN_SUPPORTED_OS osx)
+ if(NOT SANITIZER_MIN_OSX_VERSION)
+ string(REGEX MATCH "-mmacosx-version-min=([.0-9]+)"
+ MACOSX_VERSION_MIN_FLAG "${CMAKE_CXX_FLAGS}")
+ if(MACOSX_VERSION_MIN_FLAG)
+ set(SANITIZER_MIN_OSX_VERSION "${CMAKE_MATCH_1}")
+ elseif(CMAKE_OSX_DEPLOYMENT_TARGET)
+ set(SANITIZER_MIN_OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
+ else()
+ set(SANITIZER_MIN_OSX_VERSION 10.9)
+ endif()
+ if(SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.7")
+ message(FATAL_ERROR "Too old OS X version: ${SANITIZER_MIN_OSX_VERSION}")
+ endif()
+ endif()
+
+ # We're setting the flag manually for each target OS
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "")
+
+ set(DARWIN_COMMON_CFLAGS -stdlib=libc++)
+ set(DARWIN_COMMON_LINKFLAGS
+ -stdlib=libc++
+ -lc++
+ -lc++abi)
+
+ set(DARWIN_osx_CFLAGS
+ ${DARWIN_COMMON_CFLAGS}
+ -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
+ set(DARWIN_osx_LINKFLAGS
+ ${DARWIN_COMMON_LINKFLAGS}
+ -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
+ set(DARWIN_osx_BUILTIN_MIN_VER 10.5)
+ set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
+ -mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
+
+ if(DARWIN_osx_SYSROOT)
+ list(APPEND DARWIN_osx_CFLAGS -isysroot ${DARWIN_osx_SYSROOT})
+ list(APPEND DARWIN_osx_LINKFLAGS -isysroot ${DARWIN_osx_SYSROOT})
+ endif()
+
+ # Figure out which arches to use for each OS
+ darwin_get_toolchain_supported_archs(toolchain_arches)
+ message(STATUS "Toolchain supported arches: ${toolchain_arches}")
+
+ if(NOT MACOSX_VERSION_MIN_FLAG)
+ darwin_test_archs(osx
+ DARWIN_osx_ARCHS
+ ${toolchain_arches})
+ message(STATUS "OSX supported arches: ${DARWIN_osx_ARCHS}")
+ foreach(arch ${DARWIN_osx_ARCHS})
+ list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+ set(CAN_TARGET_${arch} 1)
+ endforeach()
+
+ # Need to build a 10.4 compatible libclang_rt
+ set(DARWIN_10.4_SYSROOT ${DARWIN_osx_SYSROOT})
+ set(DARWIN_10.4_BUILTIN_MIN_VER 10.4)
+ set(DARWIN_10.4_BUILTIN_MIN_VER_FLAG
+ -mmacosx-version-min=${DARWIN_10.4_BUILTIN_MIN_VER})
+ set(DARWIN_10.4_SKIP_CC_KEXT On)
+ darwin_test_archs(10.4
+ DARWIN_10.4_ARCHS
+ ${toolchain_arches})
+ message(STATUS "OSX 10.4 supported arches: ${DARWIN_10.4_ARCHS}")
+ if(DARWIN_10.4_ARCHS)
+ # don't include the Haswell slice in the 10.4 compatibility library
+ list(REMOVE_ITEM DARWIN_10.4_ARCHS x86_64h)
+ list(APPEND BUILTIN_SUPPORTED_OS 10.4)
+ endif()
+
+ if(DARWIN_iossim_SYSROOT)
+ set(DARWIN_iossim_CFLAGS
+ ${DARWIN_COMMON_CFLAGS}
+ -mios-simulator-version-min=7.0
+ -isysroot ${DARWIN_iossim_SYSROOT})
+ set(DARWIN_iossim_LINKFLAGS
+ ${DARWIN_COMMON_LINKFLAGS}
+ -mios-simulator-version-min=7.0
+ -isysroot ${DARWIN_iossim_SYSROOT})
+ set(DARWIN_iossim_BUILTIN_MIN_VER 6.0)
+ set(DARWIN_iossim_BUILTIN_MIN_VER_FLAG
+ -mios-simulator-version-min=${DARWIN_iossim_BUILTIN_MIN_VER})
+
+ set(DARWIN_iossim_SKIP_CC_KEXT On)
+ darwin_test_archs(iossim
+ DARWIN_iossim_ARCHS
+ ${toolchain_arches})
+ message(STATUS "iOS Simulator supported arches: ${DARWIN_iossim_ARCHS}")
+ if(DARWIN_iossim_ARCHS)
+ list(APPEND SANITIZER_COMMON_SUPPORTED_OS iossim)
+ list(APPEND BUILTIN_SUPPORTED_OS iossim)
+ list(APPEND PROFILE_SUPPORTED_OS iossim)
+ endif()
+ foreach(arch ${DARWIN_iossim_ARCHS})
+ list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+ set(CAN_TARGET_${arch} 1)
+ endforeach()
+ endif()
+
+ if(DARWIN_ios_SYSROOT AND COMPILER_RT_ENABLE_IOS)
+ set(DARWIN_ios_CFLAGS
+ ${DARWIN_COMMON_CFLAGS}
+ -miphoneos-version-min=7.0
+ -isysroot ${DARWIN_ios_SYSROOT})
+ set(DARWIN_ios_LINKFLAGS
+ ${DARWIN_COMMON_LINKFLAGS}
+ -miphoneos-version-min=7.0
+ -isysroot ${DARWIN_ios_SYSROOT})
+ set(DARWIN_ios_BUILTIN_MIN_VER 6.0)
+ set(DARWIN_ios_BUILTIN_MIN_VER_FLAG
+ -miphoneos-version-min=${DARWIN_ios_BUILTIN_MIN_VER})
+
+ darwin_test_archs(ios
+ DARWIN_ios_ARCHS
+ ${toolchain_arches})
+ message(STATUS "iOS supported arches: ${DARWIN_ios_ARCHS}")
+ if(DARWIN_ios_ARCHS)
+ list(APPEND SANITIZER_COMMON_SUPPORTED_OS ios)
+ list(APPEND BUILTIN_SUPPORTED_OS ios)
+ list(APPEND PROFILE_SUPPORTED_OS ios)
+ endif()
+ foreach(arch ${DARWIN_ios_ARCHS})
+ list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+ set(CAN_TARGET_${arch} 1)
+ endforeach()
+ endif()
+ endif()
+
+ # for list_union
+ include(CompilerRTUtils)
+
+ list_union(BUILTIN_SUPPORTED_ARCH ALL_BUILTIN_SUPPORTED_ARCH toolchain_arches)
+
+ list_union(SANITIZER_COMMON_SUPPORTED_ARCH
+ ALL_SANITIZER_COMMON_SUPPORTED_ARCH
+ COMPILER_RT_SUPPORTED_ARCH
+ )
+ set(LSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ set(UBSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ list_union(ASAN_SUPPORTED_ARCH
+ ALL_ASAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(DFSAN_SUPPORTED_ARCH
+ ALL_DFSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(LSAN_SUPPORTED_ARCH
+ ALL_LSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(MSAN_SUPPORTED_ARCH
+ ALL_MSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(PROFILE_SUPPORTED_ARCH
+ ALL_PROFILE_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(TSAN_SUPPORTED_ARCH
+ ALL_TSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(UBSAN_SUPPORTED_ARCH
+ ALL_UBSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(SAFESTACK_SUPPORTED_ARCH
+ ALL_SAFESTACK_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_union(CFI_SUPPORTED_ARCH
+ ALL_CFI_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
+else()
+ # Architectures supported by compiler-rt libraries.
+ filter_available_targets(BUILTIN_SUPPORTED_ARCH
+ ${ALL_BUILTIN_SUPPORTED_ARCH})
+ filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
+ ${ALL_SANITIZER_COMMON_SUPPORTED_ARCH})
+ # LSan and UBSan common files should be available on all architectures
+ # supported by other sanitizers (even if they build into dummy object files).
+ filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
+ ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH
+ ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ filter_available_targets(ASAN_SUPPORTED_ARCH ${ALL_ASAN_SUPPORTED_ARCH})
+ filter_available_targets(DFSAN_SUPPORTED_ARCH ${ALL_DFSAN_SUPPORTED_ARCH})
+ filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH})
+ filter_available_targets(MSAN_SUPPORTED_ARCH ${ALL_MSAN_SUPPORTED_ARCH})
+ filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
+ filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
+ filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
+ filter_available_targets(SAFESTACK_SUPPORTED_ARCH
+ ${ALL_SAFESTACK_SUPPORTED_ARCH})
+ filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH})
+endif()
+
+message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
+
+if(ANDROID)
+ set(OS_NAME "Android")
+else()
+ set(OS_NAME "${CMAKE_SYSTEM_NAME}")
+endif()
+
+if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
+ (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD" OR
+ (OS_NAME MATCHES "Windows" AND MSVC)))
+ set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
+else()
+ set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND
+ (NOT OS_NAME MATCHES "Windows" OR CMAKE_SIZEOF_VOID_P EQUAL 4))
+ set(COMPILER_RT_HAS_INTERCEPTION TRUE)
+else()
+ set(COMPILER_RT_HAS_INTERCEPTION FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND
+ (NOT OS_NAME MATCHES "Windows" OR CMAKE_SIZEOF_VOID_P EQUAL 4))
+ set(COMPILER_RT_HAS_ASAN TRUE)
+else()
+ set(COMPILER_RT_HAS_ASAN FALSE)
+endif()
+
+if (OS_NAME MATCHES "Linux|FreeBSD|Windows")
+ set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
+else()
+ set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE)
+endif()
+
+# TODO: Add builtins support.
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND DFSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Linux")
+ set(COMPILER_RT_HAS_DFSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_DFSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Linux|FreeBSD")
+ set(COMPILER_RT_HAS_LSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_LSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Linux")
+ set(COMPILER_RT_HAS_MSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_MSAN FALSE)
+endif()
+
+if (PROFILE_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+ set(COMPILER_RT_HAS_PROFILE TRUE)
+else()
+ set(COMPILER_RT_HAS_PROFILE FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+ set(COMPILER_RT_HAS_TSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_TSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows")
+ set(COMPILER_RT_HAS_UBSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_UBSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+ set(COMPILER_RT_HAS_SAFESTACK TRUE)
+else()
+ set(COMPILER_RT_HAS_SAFESTACK FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Linux")
+ set(COMPILER_RT_HAS_CFI TRUE)
+else()
+ set(COMPILER_RT_HAS_CFI FALSE)
+endif()
diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt
new file mode 100644
index 0000000..ad1437e
--- /dev/null
+++ b/compiler-rt/include/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(SANITIZER_HEADERS
+ sanitizer/allocator_interface.h
+ sanitizer/asan_interface.h
+ sanitizer/common_interface_defs.h
+ sanitizer/coverage_interface.h
+ sanitizer/dfsan_interface.h
+ sanitizer/linux_syscall_hooks.h
+ sanitizer/lsan_interface.h
+ sanitizer/msan_interface.h
+ sanitizer/tsan_interface_atomic.h)
+
+set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
+
+# Copy compiler-rt headers to the build tree.
+set(out_files)
+foreach( f ${SANITIZER_HEADERS} )
+ set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} )
+ set( dst ${output_dir}/${f} )
+ add_custom_command(OUTPUT ${dst}
+ DEPENDS ${src}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
+ COMMENT "Copying compiler-rt's ${f}...")
+ list(APPEND out_files ${dst})
+endforeach( f )
+
+add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
+add_dependencies(compiler-rt compiler-rt-headers)
+
+# Install sanitizer headers.
+install(FILES ${SANITIZER_HEADERS}
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/sanitizer)
diff --git a/compiler-rt/include/sanitizer/allocator_interface.h b/compiler-rt/include/sanitizer/allocator_interface.h
new file mode 100644
index 0000000..ab251f8
--- /dev/null
+++ b/compiler-rt/include/sanitizer/allocator_interface.h
@@ -0,0 +1,66 @@
+//===-- allocator_interface.h ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Public interface header for allocator used in sanitizers (ASan/TSan/MSan).
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
+#define SANITIZER_ALLOCATOR_INTERFACE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Returns the estimated number of bytes that will be reserved by allocator
+ for request of "size" bytes. If allocator can't allocate that much
+ memory, returns the maximal possible allocation size, otherwise returns
+ "size". */
+ size_t __sanitizer_get_estimated_allocated_size(size_t size);
+
+ /* Returns true if p was returned by the allocator and
+ is not yet freed. */
+ int __sanitizer_get_ownership(const volatile void *p);
+
+ /* Returns the number of bytes reserved for the pointer p.
+ Requires (get_ownership(p) == true) or (p == 0). */
+ size_t __sanitizer_get_allocated_size(const volatile void *p);
+
+ /* Number of bytes, allocated and not yet freed by the application. */
+ size_t __sanitizer_get_current_allocated_bytes();
+
+ /* Number of bytes, mmaped by the allocator to fulfill allocation requests.
+ Generally, for request of X bytes, allocator can reserve and add to free
+ lists a large number of chunks of size X to use them for future requests.
+ All these chunks count toward the heap size. Currently, allocator never
+ releases memory to OS (instead, it just puts freed chunks to free
+ lists). */
+ size_t __sanitizer_get_heap_size();
+
+ /* Number of bytes, mmaped by the allocator, which can be used to fulfill
+ allocation requests. When a user program frees memory chunk, it can first
+ fall into quarantine and will count toward __sanitizer_get_free_bytes()
+ later. */
+ size_t __sanitizer_get_free_bytes();
+
+ /* Number of bytes in unmapped pages, that are released to OS. Currently,
+ always returns 0. */
+ size_t __sanitizer_get_unmapped_bytes();
+
+ /* Malloc hooks that may be optionally provided by user.
+ __sanitizer_malloc_hook(ptr, size) is called immediately after
+ allocation of "size" bytes, which returned "ptr".
+ __sanitizer_free_hook(ptr) is called immediately before
+ deallocation of "ptr". */
+ void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
+ void __sanitizer_free_hook(const volatile void *ptr);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
new file mode 100644
index 0000000..97ba0ce
--- /dev/null
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -0,0 +1,151 @@
+//===-- sanitizer/asan_interface.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ASAN_INTERFACE_H
+#define SANITIZER_ASAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Marks memory region [addr, addr+size) as unaddressable.
+ // This memory must be previously allocated by the user program. Accessing
+ // addresses in this region from instrumented code is forbidden until
+ // this region is unpoisoned. This function is not guaranteed to poison
+ // the whole region - it may poison only subregion of [addr, addr+size) due
+ // to ASan alignment restrictions.
+ // Method is NOT thread-safe in the sense that no two threads can
+ // (un)poison memory in the same memory region simultaneously.
+ void __asan_poison_memory_region(void const volatile *addr, size_t size);
+ // Marks memory region [addr, addr+size) as addressable.
+ // This memory must be previously allocated by the user program. Accessing
+ // addresses in this region is allowed until this region is poisoned again.
+ // This function may unpoison a superregion of [addr, addr+size) due to
+ // ASan alignment restrictions.
+ // Method is NOT thread-safe in the sense that no two threads can
+ // (un)poison memory in the same memory region simultaneously.
+ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+
+// User code should use macros instead of functions.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#endif
+
+ // Returns 1 if addr is poisoned (i.e. 1-byte read/write access to this
+ // address will result in error report from AddressSanitizer).
+ // Otherwise returns 0.
+ int __asan_address_is_poisoned(void const volatile *addr);
+
+ // If at least one byte in [beg, beg+size) is poisoned, return the address
+ // of the first such byte. Otherwise return 0.
+ void *__asan_region_is_poisoned(void *beg, size_t size);
+
+ // Print the description of addr (useful when debugging in gdb).
+ void __asan_describe_address(void *addr);
+
+ // Useful for calling from a debugger to get information about an ASan error.
+ // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+ int __asan_report_present();
+
+ // Useful for calling from a debugger to get information about an ASan error.
+ // If an error has been (or is being) reported, the following functions return
+ // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
+ // bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
+ void *__asan_get_report_pc();
+ void *__asan_get_report_bp();
+ void *__asan_get_report_sp();
+ void *__asan_get_report_address();
+ int __asan_get_report_access_type();
+ size_t __asan_get_report_access_size();
+ const char *__asan_get_report_description();
+
+ // Useful for calling from the debugger to get information about a pointer.
+ // Returns the category of the given pointer as a constant string.
+ // Possible return values are "global", "stack", "stack-fake", "heap",
+ // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+ // If global or stack, tries to also return the variable name, address and
+ // size. If heap, tries to return the chunk address and size. 'name' should
+ // point to an allocated buffer of size 'name_size'.
+ const char *__asan_locate_address(void *addr, char *name, size_t name_size,
+ void **region_address, size_t *region_size);
+
+ // Useful for calling from the debugger to get the allocation stack trace
+ // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+ // returns the number of stored frames or 0 on error.
+ size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
+ int *thread_id);
+
+ // Useful for calling from the debugger to get the free stack trace
+ // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+ // returns the number of stored frames or 0 on error.
+ size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
+ int *thread_id);
+
+ // Useful for calling from the debugger to get the current shadow memory
+ // mapping.
+ void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
+
+ // This is an internal function that is called to report an error.
+ // However it is still a part of the interface because users may want to
+ // set a breakpoint on this function in a debugger.
+ void __asan_report_error(void *pc, void *bp, void *sp,
+ void *addr, int is_write, size_t access_size);
+
+ // Deprecated. Call __sanitizer_set_death_callback instead.
+ void __asan_set_death_callback(void (*callback)(void));
+
+ void __asan_set_error_report_callback(void (*callback)(const char*));
+
+ // User may provide function that would be called right when ASan detects
+ // an error. This can be used to notice cases when ASan detects an error, but
+ // the program crashes before ASan report is printed.
+ void __asan_on_error();
+
+ // Prints accumulated stats to stderr. Used for debugging.
+ void __asan_print_accumulated_stats();
+
+ // This function may be optionally provided by user and should return
+ // a string containing ASan runtime options. See asan_flags.h for details.
+ const char* __asan_default_options();
+
+ // The following 2 functions facilitate garbage collection in presence of
+ // asan's fake stack.
+
+ // Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack.
+ // Returns NULL if the current thread does not have a fake stack.
+ void *__asan_get_current_fake_stack();
+
+ // If fake_stack is non-NULL and addr belongs to a fake frame in
+ // fake_stack, returns the address on real stack that corresponds to
+ // the fake frame and sets beg/end to the boundaries of this fake frame.
+ // Otherwise returns NULL and does not touch beg/end.
+ // If beg/end are NULL, they are not touched.
+ // This function may be called from a thread other than the owner of
+ // fake_stack, but the owner thread need to be alive.
+ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
+ void **end);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_ASAN_INTERFACE_H
diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h
new file mode 100644
index 0000000..b736ed9
--- /dev/null
+++ b/compiler-rt/include/sanitizer/common_interface_defs.h
@@ -0,0 +1,135 @@
+//===-- sanitizer/common_interface_defs.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common part of the public sanitizer interface.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
+#define SANITIZER_COMMON_INTERFACE_DEFS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+// GCC does not understand __has_feature.
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Arguments for __sanitizer_sandbox_on_notify() below.
+ typedef struct {
+ // Enable sandbox support in sanitizer coverage.
+ int coverage_sandboxed;
+ // File descriptor to write coverage data to. If -1 is passed, a file will
+ // be pre-opened by __sanitizer_sandobx_on_notify(). This field has no
+ // effect if coverage_sandboxed == 0.
+ intptr_t coverage_fd;
+ // If non-zero, split the coverage data into well-formed blocks. This is
+ // useful when coverage_fd is a socket descriptor. Each block will contain
+ // a header, allowing data from multiple processes to be sent over the same
+ // socket.
+ unsigned int coverage_max_block_size;
+ } __sanitizer_sandbox_arguments;
+
+ // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+ void __sanitizer_set_report_path(const char *path);
+
+ // Notify the tools that the sandbox is going to be turned on. The reserved
+ // parameter will be used in the future to hold a structure with functions
+ // that the tools may call to bypass the sandbox.
+ void __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ void __sanitizer_report_error_summary(const char *error_summary);
+
+ // Some of the sanitizers (e.g. asan/tsan) may miss bugs that happen
+ // in unaligned loads/stores. In order to find such bugs reliably one needs
+ // to replace plain unaligned loads/stores with these calls.
+ uint16_t __sanitizer_unaligned_load16(const void *p);
+ uint32_t __sanitizer_unaligned_load32(const void *p);
+ uint64_t __sanitizer_unaligned_load64(const void *p);
+ void __sanitizer_unaligned_store16(void *p, uint16_t x);
+ void __sanitizer_unaligned_store32(void *p, uint32_t x);
+ void __sanitizer_unaligned_store64(void *p, uint64_t x);
+
+ // Annotate the current state of a contiguous container, such as
+ // std::vector, std::string or similar.
+ // A contiguous container is a container that keeps all of its elements
+ // in a contiguous region of memory. The container owns the region of memory
+ // [beg, end); the memory [beg, mid) is used to store the current elements
+ // and the memory [mid, end) is reserved for future elements;
+ // beg <= mid <= end. For example, in "std::vector<> v"
+ // beg = &v[0];
+ // end = beg + v.capacity() * sizeof(v[0]);
+ // mid = beg + v.size() * sizeof(v[0]);
+ //
+ // This annotation tells the Sanitizer tool about the current state of the
+ // container so that the tool can report errors when memory from [mid, end)
+ // is accessed. Insert this annotation into methods like push_back/pop_back.
+ // Supply the old and the new values of mid (old_mid/new_mid).
+ // In the initial state mid == end and so should be the final
+ // state when the container is destroyed or when it reallocates the storage.
+ //
+ // Use with caution and don't use for anything other than vector-like classes.
+ //
+ // For AddressSanitizer, 'beg' should be 8-aligned and 'end' should
+ // be either 8-aligned or it should point to the end of a separate heap-,
+ // stack-, or global- allocated buffer. I.e. the following will not work:
+ // int64_t x[2]; // 16 bytes, 8-aligned.
+ // char *beg = (char *)&x[0];
+ // char *end = beg + 12; // Not 8 aligned, not the end of the buffer.
+ // This however will work fine:
+ // int32_t x[3]; // 12 bytes, but 8-aligned under AddressSanitizer.
+ // char *beg = (char*)&x[0];
+ // char *end = beg + 12; // Not 8-aligned, but is the end of the buffer.
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+ // Returns true if the contiguous container [beg, end) is properly poisoned
+ // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if
+ // - [beg, mid) is addressable,
+ // - [mid, end) is unaddressable.
+ // Full verification requires O(end-beg) time; this function tries to avoid
+ // such complexity by touching only parts of the container around beg/mid/end.
+ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+ const void *end);
+
+ // Similar to __sanitizer_verify_contiguous_container but returns the address
+ // of the first improperly poisoned byte otherwise. Returns null if the area
+ // is poisoned properly.
+ const void *__sanitizer_contiguous_container_find_bad_address(
+ const void *beg, const void *mid, const void *end);
+
+ // Print the stack trace leading to this call. Useful for debugging user code.
+ void __sanitizer_print_stack_trace();
+
+ // Sets the callback to be called right before death on error.
+ // Passing 0 will unset the callback.
+ void __sanitizer_set_death_callback(void (*callback)(void));
+
+ // Interceptor hooks.
+ // Whenever a libc function interceptor is called it checks if the
+ // corresponding weak hook is defined, and it so -- calls it.
+ // The primary use case is data-flow-guided fuzzing, where the fuzzer needs
+ // to know what is being passed to libc functions, e.g. memcmp.
+ // FIXME: implement more hooks.
+ void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
+ const void *s2, size_t n);
+ void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
+ const char *s2, size_t n);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_COMMON_INTERFACE_DEFS_H
diff --git a/compiler-rt/include/sanitizer/coverage_interface.h b/compiler-rt/include/sanitizer/coverage_interface.h
new file mode 100644
index 0000000..b93111b
--- /dev/null
+++ b/compiler-rt/include/sanitizer/coverage_interface.h
@@ -0,0 +1,65 @@
+//===-- sanitizer/coverage_interface.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Public interface for sanitizer coverage.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_COVERAG_INTERFACE_H
+#define SANITIZER_COVERAG_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Initialize coverage.
+ void __sanitizer_cov_init();
+ // Record and dump coverage info.
+ void __sanitizer_cov_dump();
+ // Open <name>.sancov.packed in the coverage directory and return the file
+ // descriptor. Returns -1 on failure, or if coverage dumping is disabled.
+ // This is intended for use by sandboxing code.
+ intptr_t __sanitizer_maybe_open_cov_file(const char *name);
+ // Get the number of unique covered blocks (or edges).
+ // This can be useful for coverage-directed in-process fuzzers.
+ uintptr_t __sanitizer_get_total_unique_coverage();
+ // Get the number of unique indirect caller-callee pairs.
+ uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
+
+ // Reset the basic-block (edge) coverage to the initial state.
+ // Useful for in-process fuzzing to start collecting coverage from scratch.
+ // Experimental, will likely not work for multi-threaded process.
+ void __sanitizer_reset_coverage();
+ // Set *data to the array of covered PCs and return the size of that array.
+ // Some of the entries in *data will be zero.
+ uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
+
+ // The coverage instrumentation may optionally provide imprecise counters.
+ // Rather than exposing the counter values to the user we instead map
+ // the counters to a bitset.
+ // Every counter is associated with 8 bits in the bitset.
+ // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
+ // The i-th bit is set to 1 if the counter value is in the i-th range.
+ // This counter-based coverage implementation is *not* thread-safe.
+
+ // Returns the number of registered coverage counters.
+ uintptr_t __sanitizer_get_number_of_counters();
+ // Updates the counter 'bitset', clears the counters and returns the number of
+ // new bits in 'bitset'.
+ // If 'bitset' is nullptr, only clears the counters.
+ // Otherwise 'bitset' should be at least
+ // __sanitizer_get_number_of_counters bytes long and 8-aligned.
+ uintptr_t
+ __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_COVERAG_INTERFACE_H
diff --git a/compiler-rt/include/sanitizer/dfsan_interface.h b/compiler-rt/include/sanitizer/dfsan_interface.h
new file mode 100644
index 0000000..05666f7
--- /dev/null
+++ b/compiler-rt/include/sanitizer/dfsan_interface.h
@@ -0,0 +1,116 @@
+//===-- dfsan_interface.h -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef DFSAN_INTERFACE_H
+#define DFSAN_INTERFACE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint16_t dfsan_label;
+
+/// Stores information associated with a specific label identifier. A label
+/// may be a base label created using dfsan_create_label, with associated
+/// text description and user data, or an automatically created union label,
+/// which represents the union of two label identifiers (which may themselves
+/// be base or union labels).
+struct dfsan_label_info {
+ // Fields for union labels, set to 0 for base labels.
+ dfsan_label l1;
+ dfsan_label l2;
+
+ // Fields for base labels.
+ const char *desc;
+ void *userdata;
+};
+
+/// Signature of the callback argument to dfsan_set_write_callback().
+typedef void (*dfsan_write_callback_t)(int fd, const void *buf, size_t count);
+
+/// Computes the union of \c l1 and \c l2, possibly creating a union label in
+/// the process.
+dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
+
+/// Creates and returns a base label with the given description and user data.
+dfsan_label dfsan_create_label(const char *desc, void *userdata);
+
+/// Sets the label for each address in [addr,addr+size) to \c label.
+void dfsan_set_label(dfsan_label label, void *addr, size_t size);
+
+/// Sets the label for each address in [addr,addr+size) to the union of the
+/// current label for that address and \c label.
+void dfsan_add_label(dfsan_label label, void *addr, size_t size);
+
+/// Retrieves the label associated with the given data.
+///
+/// The type of 'data' is arbitrary. The function accepts a value of any type,
+/// which can be truncated or extended (implicitly or explicitly) as necessary.
+/// The truncation/extension operations will preserve the label of the original
+/// value.
+dfsan_label dfsan_get_label(long data);
+
+/// Retrieves the label associated with the data at the given address.
+dfsan_label dfsan_read_label(const void *addr, size_t size);
+
+/// Retrieves a pointer to the dfsan_label_info struct for the given label.
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
+
+/// Returns whether the given label label contains the label elem.
+int dfsan_has_label(dfsan_label label, dfsan_label elem);
+
+/// If the given label label contains a label with the description desc, returns
+/// that label, else returns 0.
+dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
+
+/// Returns the number of labels allocated.
+size_t dfsan_get_label_count(void);
+
+/// Sets a callback to be invoked on calls to write(). The callback is invoked
+/// before the write is done. The write is not guaranteed to succeed when the
+/// callback executes. Pass in NULL to remove any callback.
+void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
+
+/// Writes the labels currently used by the program to the given file
+/// descriptor. The lines of the output have the following format:
+///
+/// <label> <parent label 1> <parent label 2> <label description if any>
+void dfsan_dump_labels(int fd);
+
+/// Interceptor hooks.
+/// Whenever a dfsan's custom function is called the corresponding
+/// hook is called it non-zero. The hooks should be defined by the user.
+/// The primary use case is taint-guided fuzzing, where the fuzzer
+/// needs to see the parameters of the function and the labels.
+/// FIXME: implement more hooks.
+void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label);
+void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label);
+#ifdef __cplusplus
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+#endif
+
+#endif // DFSAN_INTERFACE_H
diff --git a/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/compiler-rt/include/sanitizer/linux_syscall_hooks.h
new file mode 100644
index 0000000..89867c1
--- /dev/null
+++ b/compiler-rt/include/sanitizer/linux_syscall_hooks.h
@@ -0,0 +1,3070 @@
+//===-- linux_syscall_hooks.h ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of public sanitizer interface.
+//
+// System call handlers.
+//
+// Interface methods declared in this header implement pre- and post- syscall
+// actions for the active sanitizer.
+// Usage:
+// __sanitizer_syscall_pre_getfoo(...args...);
+// long res = syscall(__NR_getfoo, ...args...);
+// __sanitizer_syscall_post_getfoo(res, ...args...);
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
+#define SANITIZER_LINUX_SYSCALL_HOOKS_H
+
+#define __sanitizer_syscall_pre_time(tloc) \
+ __sanitizer_syscall_pre_impl_time((long)(tloc))
+#define __sanitizer_syscall_post_time(res, tloc) \
+ __sanitizer_syscall_post_impl_time(res, (long)(tloc))
+#define __sanitizer_syscall_pre_stime(tptr) \
+ __sanitizer_syscall_pre_impl_stime((long)(tptr))
+#define __sanitizer_syscall_post_stime(res, tptr) \
+ __sanitizer_syscall_post_impl_stime(res, (long)(tptr))
+#define __sanitizer_syscall_pre_gettimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_gettimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_gettimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_gettimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_settimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_settimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_settimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_settimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_adjtimex(txc_p) \
+ __sanitizer_syscall_pre_impl_adjtimex((long)(txc_p))
+#define __sanitizer_syscall_post_adjtimex(res, txc_p) \
+ __sanitizer_syscall_post_impl_adjtimex(res, (long)(txc_p))
+#define __sanitizer_syscall_pre_times(tbuf) \
+ __sanitizer_syscall_pre_impl_times((long)(tbuf))
+#define __sanitizer_syscall_post_times(res, tbuf) \
+ __sanitizer_syscall_post_impl_times(res, (long)(tbuf))
+#define __sanitizer_syscall_pre_gettid() __sanitizer_syscall_pre_impl_gettid()
+#define __sanitizer_syscall_post_gettid(res) \
+ __sanitizer_syscall_post_impl_gettid(res)
+#define __sanitizer_syscall_pre_nanosleep(rqtp, rmtp) \
+ __sanitizer_syscall_pre_impl_nanosleep((long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_nanosleep(res, rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_nanosleep(res, (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_alarm(seconds) \
+ __sanitizer_syscall_pre_impl_alarm((long)(seconds))
+#define __sanitizer_syscall_post_alarm(res, seconds) \
+ __sanitizer_syscall_post_impl_alarm(res, (long)(seconds))
+#define __sanitizer_syscall_pre_getpid() __sanitizer_syscall_pre_impl_getpid()
+#define __sanitizer_syscall_post_getpid(res) \
+ __sanitizer_syscall_post_impl_getpid(res)
+#define __sanitizer_syscall_pre_getppid() __sanitizer_syscall_pre_impl_getppid()
+#define __sanitizer_syscall_post_getppid(res) \
+ __sanitizer_syscall_post_impl_getppid(res)
+#define __sanitizer_syscall_pre_getuid() __sanitizer_syscall_pre_impl_getuid()
+#define __sanitizer_syscall_post_getuid(res) \
+ __sanitizer_syscall_post_impl_getuid(res)
+#define __sanitizer_syscall_pre_geteuid() __sanitizer_syscall_pre_impl_geteuid()
+#define __sanitizer_syscall_post_geteuid(res) \
+ __sanitizer_syscall_post_impl_geteuid(res)
+#define __sanitizer_syscall_pre_getgid() __sanitizer_syscall_pre_impl_getgid()
+#define __sanitizer_syscall_post_getgid(res) \
+ __sanitizer_syscall_post_impl_getgid(res)
+#define __sanitizer_syscall_pre_getegid() __sanitizer_syscall_pre_impl_getegid()
+#define __sanitizer_syscall_post_getegid(res) \
+ __sanitizer_syscall_post_impl_getegid(res)
+#define __sanitizer_syscall_pre_getresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_getresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_getpgid(pid) \
+ __sanitizer_syscall_pre_impl_getpgid((long)(pid))
+#define __sanitizer_syscall_post_getpgid(res, pid) \
+ __sanitizer_syscall_post_impl_getpgid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getpgrp() __sanitizer_syscall_pre_impl_getpgrp()
+#define __sanitizer_syscall_post_getpgrp(res) \
+ __sanitizer_syscall_post_impl_getpgrp(res)
+#define __sanitizer_syscall_pre_getsid(pid) \
+ __sanitizer_syscall_pre_impl_getsid((long)(pid))
+#define __sanitizer_syscall_post_getsid(res, pid) \
+ __sanitizer_syscall_post_impl_getsid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setregid(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid((long)(rgid), (long)(egid))
+#define __sanitizer_syscall_post_setregid(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid(res, (long)(rgid), (long)(egid))
+#define __sanitizer_syscall_pre_setgid(gid) \
+ __sanitizer_syscall_pre_impl_setgid((long)(gid))
+#define __sanitizer_syscall_post_setgid(res, gid) \
+ __sanitizer_syscall_post_impl_setgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setreuid(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid((long)(ruid), (long)(euid))
+#define __sanitizer_syscall_post_setreuid(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid(res, (long)(ruid), (long)(euid))
+#define __sanitizer_syscall_pre_setuid(uid) \
+ __sanitizer_syscall_pre_impl_setuid((long)(uid))
+#define __sanitizer_syscall_post_setuid(res, uid) \
+ __sanitizer_syscall_post_impl_setuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_setresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_setresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid((long)(uid))
+#define __sanitizer_syscall_post_setfsuid(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setfsgid(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid((long)(gid))
+#define __sanitizer_syscall_post_setfsgid(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setpgid(pid, pgid) \
+ __sanitizer_syscall_pre_impl_setpgid((long)(pid), (long)(pgid))
+#define __sanitizer_syscall_post_setpgid(res, pid, pgid) \
+ __sanitizer_syscall_post_impl_setpgid(res, (long)(pid), (long)(pgid))
+#define __sanitizer_syscall_pre_setsid() __sanitizer_syscall_pre_impl_setsid()
+#define __sanitizer_syscall_post_setsid(res) \
+ __sanitizer_syscall_post_impl_setsid(res)
+#define __sanitizer_syscall_pre_setgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_acct(name) \
+ __sanitizer_syscall_pre_impl_acct((long)(name))
+#define __sanitizer_syscall_post_acct(res, name) \
+ __sanitizer_syscall_post_impl_acct(res, (long)(name))
+#define __sanitizer_syscall_pre_capget(header, dataptr) \
+ __sanitizer_syscall_pre_impl_capget((long)(header), (long)(dataptr))
+#define __sanitizer_syscall_post_capget(res, header, dataptr) \
+ __sanitizer_syscall_post_impl_capget(res, (long)(header), (long)(dataptr))
+#define __sanitizer_syscall_pre_capset(header, data) \
+ __sanitizer_syscall_pre_impl_capset((long)(header), (long)(data))
+#define __sanitizer_syscall_post_capset(res, header, data) \
+ __sanitizer_syscall_post_impl_capset(res, (long)(header), (long)(data))
+#define __sanitizer_syscall_pre_personality(personality) \
+ __sanitizer_syscall_pre_impl_personality((long)(personality))
+#define __sanitizer_syscall_post_personality(res, personality) \
+ __sanitizer_syscall_post_impl_personality(res, (long)(personality))
+#define __sanitizer_syscall_pre_sigpending(set) \
+ __sanitizer_syscall_pre_impl_sigpending((long)(set))
+#define __sanitizer_syscall_post_sigpending(res, set) \
+ __sanitizer_syscall_post_impl_sigpending(res, (long)(set))
+#define __sanitizer_syscall_pre_sigprocmask(how, set, oset) \
+ __sanitizer_syscall_pre_impl_sigprocmask((long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_post_sigprocmask(res, how, set, oset) \
+ __sanitizer_syscall_post_impl_sigprocmask(res, (long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_pre_getitimer(which, value) \
+ __sanitizer_syscall_pre_impl_getitimer((long)(which), (long)(value))
+#define __sanitizer_syscall_post_getitimer(res, which, value) \
+ __sanitizer_syscall_post_impl_getitimer(res, (long)(which), (long)(value))
+#define __sanitizer_syscall_pre_setitimer(which, value, ovalue) \
+ __sanitizer_syscall_pre_impl_setitimer((long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_post_setitimer(res, which, value, ovalue) \
+ __sanitizer_syscall_post_impl_setitimer(res, (long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_pre_timer_create(which_clock, timer_event_spec, \
+ created_timer_id) \
+ __sanitizer_syscall_pre_impl_timer_create( \
+ (long)(which_clock), (long)(timer_event_spec), (long)(created_timer_id))
+#define __sanitizer_syscall_post_timer_create( \
+ res, which_clock, timer_event_spec, created_timer_id) \
+ __sanitizer_syscall_post_impl_timer_create(res, (long)(which_clock), \
+ (long)(timer_event_spec), \
+ (long)(created_timer_id))
+#define __sanitizer_syscall_pre_timer_gettime(timer_id, setting) \
+ __sanitizer_syscall_pre_impl_timer_gettime((long)(timer_id), (long)(setting))
+#define __sanitizer_syscall_post_timer_gettime(res, timer_id, setting) \
+ __sanitizer_syscall_post_impl_timer_gettime(res, (long)(timer_id), \
+ (long)(setting))
+#define __sanitizer_syscall_pre_timer_getoverrun(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_getoverrun((long)(timer_id))
+#define __sanitizer_syscall_post_timer_getoverrun(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_getoverrun(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_timer_settime(timer_id, flags, new_setting, \
+ old_setting) \
+ __sanitizer_syscall_pre_impl_timer_settime((long)(timer_id), (long)(flags), \
+ (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_post_timer_settime(res, timer_id, flags, \
+ new_setting, old_setting) \
+ __sanitizer_syscall_post_impl_timer_settime( \
+ res, (long)(timer_id), (long)(flags), (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_pre_timer_delete(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_delete((long)(timer_id))
+#define __sanitizer_syscall_post_timer_delete(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_delete(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_clock_settime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_settime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_settime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_settime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_gettime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_gettime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_gettime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_gettime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_adjtime(which_clock, tx) \
+ __sanitizer_syscall_pre_impl_clock_adjtime((long)(which_clock), (long)(tx))
+#define __sanitizer_syscall_post_clock_adjtime(res, which_clock, tx) \
+ __sanitizer_syscall_post_impl_clock_adjtime(res, (long)(which_clock), \
+ (long)(tx))
+#define __sanitizer_syscall_pre_clock_getres(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_getres((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_getres(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_getres(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_nanosleep(which_clock, flags, rqtp, \
+ rmtp) \
+ __sanitizer_syscall_pre_impl_clock_nanosleep( \
+ (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_clock_nanosleep(res, which_clock, flags, \
+ rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_clock_nanosleep( \
+ res, (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_nice(increment) \
+ __sanitizer_syscall_pre_impl_nice((long)(increment))
+#define __sanitizer_syscall_post_nice(res, increment) \
+ __sanitizer_syscall_post_impl_nice(res, (long)(increment))
+#define __sanitizer_syscall_pre_sched_setscheduler(pid, policy, param) \
+ __sanitizer_syscall_pre_impl_sched_setscheduler((long)(pid), (long)(policy), \
+ (long)(param))
+#define __sanitizer_syscall_post_sched_setscheduler(res, pid, policy, param) \
+ __sanitizer_syscall_post_impl_sched_setscheduler( \
+ res, (long)(pid), (long)(policy), (long)(param))
+#define __sanitizer_syscall_pre_sched_setparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_setparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_setparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_setparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_getscheduler(pid) \
+ __sanitizer_syscall_pre_impl_sched_getscheduler((long)(pid))
+#define __sanitizer_syscall_post_sched_getscheduler(res, pid) \
+ __sanitizer_syscall_post_impl_sched_getscheduler(res, (long)(pid))
+#define __sanitizer_syscall_pre_sched_getparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_getparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_getparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_getparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_setaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_setaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_setaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_setaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_getaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_getaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_getaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_getaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_yield() \
+ __sanitizer_syscall_pre_impl_sched_yield()
+#define __sanitizer_syscall_post_sched_yield(res) \
+ __sanitizer_syscall_post_impl_sched_yield(res)
+#define __sanitizer_syscall_pre_sched_get_priority_max(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_max((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_max(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_max(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_get_priority_min(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_min((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_min(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_min(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_rr_get_interval(pid, interval) \
+ __sanitizer_syscall_pre_impl_sched_rr_get_interval((long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_post_sched_rr_get_interval(res, pid, interval) \
+ __sanitizer_syscall_post_impl_sched_rr_get_interval(res, (long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_pre_setpriority(which, who, niceval) \
+ __sanitizer_syscall_pre_impl_setpriority((long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_post_setpriority(res, which, who, niceval) \
+ __sanitizer_syscall_post_impl_setpriority(res, (long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_pre_getpriority(which, who) \
+ __sanitizer_syscall_pre_impl_getpriority((long)(which), (long)(who))
+#define __sanitizer_syscall_post_getpriority(res, which, who) \
+ __sanitizer_syscall_post_impl_getpriority(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_shutdown(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_shutdown((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_shutdown(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_shutdown(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_reboot(magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_pre_impl_reboot((long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_reboot(res, magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_post_impl_reboot(res, (long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_restart_syscall() \
+ __sanitizer_syscall_pre_impl_restart_syscall()
+#define __sanitizer_syscall_post_restart_syscall(res) \
+ __sanitizer_syscall_post_impl_restart_syscall(res)
+#define __sanitizer_syscall_pre_kexec_load(entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_pre_impl_kexec_load((long)(entry), (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_post_kexec_load(res, entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_post_impl_kexec_load(res, (long)(entry), \
+ (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_pre_exit(error_code) \
+ __sanitizer_syscall_pre_impl_exit((long)(error_code))
+#define __sanitizer_syscall_post_exit(res, error_code) \
+ __sanitizer_syscall_post_impl_exit(res, (long)(error_code))
+#define __sanitizer_syscall_pre_exit_group(error_code) \
+ __sanitizer_syscall_pre_impl_exit_group((long)(error_code))
+#define __sanitizer_syscall_post_exit_group(res, error_code) \
+ __sanitizer_syscall_post_impl_exit_group(res, (long)(error_code))
+#define __sanitizer_syscall_pre_wait4(pid, stat_addr, options, ru) \
+ __sanitizer_syscall_pre_impl_wait4((long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_wait4(res, pid, stat_addr, options, ru) \
+ __sanitizer_syscall_post_impl_wait4(res, (long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_pre_waitid(which, pid, infop, options, ru) \
+ __sanitizer_syscall_pre_impl_waitid( \
+ (long)(which), (long)(pid), (long)(infop), (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_waitid(res, which, pid, infop, options, ru) \
+ __sanitizer_syscall_post_impl_waitid(res, (long)(which), (long)(pid), \
+ (long)(infop), (long)(options), \
+ (long)(ru))
+#define __sanitizer_syscall_pre_waitpid(pid, stat_addr, options) \
+ __sanitizer_syscall_pre_impl_waitpid((long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_post_waitpid(res, pid, stat_addr, options) \
+ __sanitizer_syscall_post_impl_waitpid(res, (long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_pre_set_tid_address(tidptr) \
+ __sanitizer_syscall_pre_impl_set_tid_address((long)(tidptr))
+#define __sanitizer_syscall_post_set_tid_address(res, tidptr) \
+ __sanitizer_syscall_post_impl_set_tid_address(res, (long)(tidptr))
+#define __sanitizer_syscall_pre_init_module(umod, len, uargs) \
+ __sanitizer_syscall_pre_impl_init_module((long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_post_init_module(res, umod, len, uargs) \
+ __sanitizer_syscall_post_impl_init_module(res, (long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_pre_delete_module(name_user, flags) \
+ __sanitizer_syscall_pre_impl_delete_module((long)(name_user), (long)(flags))
+#define __sanitizer_syscall_post_delete_module(res, name_user, flags) \
+ __sanitizer_syscall_post_impl_delete_module(res, (long)(name_user), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_rt_sigprocmask(how, set, oset, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigprocmask( \
+ (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigprocmask(res, how, set, oset, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigprocmask( \
+ res, (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigpending(set, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigpending((long)(set), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigpending(res, set, sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigpending(res, (long)(set), \
+ (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigtimedwait(uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigtimedwait( \
+ (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigtimedwait(res, uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigtimedwait( \
+ res, (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo((long)(tgid), (long)(pid), \
+ (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_tgsigqueueinfo( \
+ res, (long)(tgid), (long)(pid), (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_pre_kill(pid, sig) \
+ __sanitizer_syscall_pre_impl_kill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_kill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_kill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_tgkill(tgid, pid, sig) \
+ __sanitizer_syscall_pre_impl_tgkill((long)(tgid), (long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tgkill(res, tgid, pid, sig) \
+ __sanitizer_syscall_post_impl_tgkill(res, (long)(tgid), (long)(pid), \
+ (long)(sig))
+#define __sanitizer_syscall_pre_tkill(pid, sig) \
+ __sanitizer_syscall_pre_impl_tkill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tkill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_tkill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_rt_sigqueueinfo(pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_sigqueueinfo((long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_post_rt_sigqueueinfo(res, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_sigqueueinfo(res, (long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_pre_sgetmask() \
+ __sanitizer_syscall_pre_impl_sgetmask()
+#define __sanitizer_syscall_post_sgetmask(res) \
+ __sanitizer_syscall_post_impl_sgetmask(res)
+#define __sanitizer_syscall_pre_ssetmask(newmask) \
+ __sanitizer_syscall_pre_impl_ssetmask((long)(newmask))
+#define __sanitizer_syscall_post_ssetmask(res, newmask) \
+ __sanitizer_syscall_post_impl_ssetmask(res, (long)(newmask))
+#define __sanitizer_syscall_pre_signal(sig, handler) \
+ __sanitizer_syscall_pre_impl_signal((long)(sig), (long)(handler))
+#define __sanitizer_syscall_post_signal(res, sig, handler) \
+ __sanitizer_syscall_post_impl_signal(res, (long)(sig), (long)(handler))
+#define __sanitizer_syscall_pre_pause() __sanitizer_syscall_pre_impl_pause()
+#define __sanitizer_syscall_post_pause(res) \
+ __sanitizer_syscall_post_impl_pause(res)
+#define __sanitizer_syscall_pre_sync() __sanitizer_syscall_pre_impl_sync()
+#define __sanitizer_syscall_post_sync(res) \
+ __sanitizer_syscall_post_impl_sync(res)
+#define __sanitizer_syscall_pre_fsync(fd) \
+ __sanitizer_syscall_pre_impl_fsync((long)(fd))
+#define __sanitizer_syscall_post_fsync(res, fd) \
+ __sanitizer_syscall_post_impl_fsync(res, (long)(fd))
+#define __sanitizer_syscall_pre_fdatasync(fd) \
+ __sanitizer_syscall_pre_impl_fdatasync((long)(fd))
+#define __sanitizer_syscall_post_fdatasync(res, fd) \
+ __sanitizer_syscall_post_impl_fdatasync(res, (long)(fd))
+#define __sanitizer_syscall_pre_bdflush(func, data) \
+ __sanitizer_syscall_pre_impl_bdflush((long)(func), (long)(data))
+#define __sanitizer_syscall_post_bdflush(res, func, data) \
+ __sanitizer_syscall_post_impl_bdflush(res, (long)(func), (long)(data))
+#define __sanitizer_syscall_pre_mount(dev_name, dir_name, type, flags, data) \
+ __sanitizer_syscall_pre_impl_mount((long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_post_mount(res, dev_name, dir_name, type, flags, \
+ data) \
+ __sanitizer_syscall_post_impl_mount(res, (long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_pre_umount(name, flags) \
+ __sanitizer_syscall_pre_impl_umount((long)(name), (long)(flags))
+#define __sanitizer_syscall_post_umount(res, name, flags) \
+ __sanitizer_syscall_post_impl_umount(res, (long)(name), (long)(flags))
+#define __sanitizer_syscall_pre_oldumount(name) \
+ __sanitizer_syscall_pre_impl_oldumount((long)(name))
+#define __sanitizer_syscall_post_oldumount(res, name) \
+ __sanitizer_syscall_post_impl_oldumount(res, (long)(name))
+#define __sanitizer_syscall_pre_truncate(path, length) \
+ __sanitizer_syscall_pre_impl_truncate((long)(path), (long)(length))
+#define __sanitizer_syscall_post_truncate(res, path, length) \
+ __sanitizer_syscall_post_impl_truncate(res, (long)(path), (long)(length))
+#define __sanitizer_syscall_pre_ftruncate(fd, length) \
+ __sanitizer_syscall_pre_impl_ftruncate((long)(fd), (long)(length))
+#define __sanitizer_syscall_post_ftruncate(res, fd, length) \
+ __sanitizer_syscall_post_impl_ftruncate(res, (long)(fd), (long)(length))
+#define __sanitizer_syscall_pre_stat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_statfs(path, buf) \
+ __sanitizer_syscall_pre_impl_statfs((long)(path), (long)(buf))
+#define __sanitizer_syscall_post_statfs(res, path, buf) \
+ __sanitizer_syscall_post_impl_statfs(res, (long)(path), (long)(buf))
+#define __sanitizer_syscall_pre_statfs64(path, sz, buf) \
+ __sanitizer_syscall_pre_impl_statfs64((long)(path), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_statfs64(res, path, sz, buf) \
+ __sanitizer_syscall_post_impl_statfs64(res, (long)(path), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs(fd, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs((long)(fd), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs(res, fd, buf) \
+ __sanitizer_syscall_post_impl_fstatfs(res, (long)(fd), (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs64(fd, sz, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs64((long)(fd), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs64(res, fd, sz, buf) \
+ __sanitizer_syscall_post_impl_fstatfs64(res, (long)(fd), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_lstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_newstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newlstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newlstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newlstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newlstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newfstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_newfstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_newfstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_newfstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_ustat(dev, ubuf) \
+ __sanitizer_syscall_pre_impl_ustat((long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_post_ustat(res, dev, ubuf) \
+ __sanitizer_syscall_post_impl_ustat(res, (long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_pre_stat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat64(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat64((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat64(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat64(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_lstat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_setxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_setxattr(res, path, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_setxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_lsetxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size, \
+ flags) \
+ __sanitizer_syscall_post_impl_lsetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_fsetxattr( \
+ (long)(fd), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_fsetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_getxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_getxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_getxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_getxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_lgetxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_lgetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size) \
+ __sanitizer_syscall_pre_impl_fgetxattr((long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size) \
+ __sanitizer_syscall_post_impl_fgetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_listxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_listxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_listxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_listxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_llistxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_llistxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_llistxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_llistxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_flistxattr(fd, list, size) \
+ __sanitizer_syscall_pre_impl_flistxattr((long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_flistxattr(res, fd, list, size) \
+ __sanitizer_syscall_post_impl_flistxattr(res, (long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_removexattr(path, name) \
+ __sanitizer_syscall_pre_impl_removexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_removexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_removexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_lremovexattr(path, name) \
+ __sanitizer_syscall_pre_impl_lremovexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_lremovexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_lremovexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_fremovexattr(fd, name) \
+ __sanitizer_syscall_pre_impl_fremovexattr((long)(fd), (long)(name))
+#define __sanitizer_syscall_post_fremovexattr(res, fd, name) \
+ __sanitizer_syscall_post_impl_fremovexattr(res, (long)(fd), (long)(name))
+#define __sanitizer_syscall_pre_brk(brk) \
+ __sanitizer_syscall_pre_impl_brk((long)(brk))
+#define __sanitizer_syscall_post_brk(res, brk) \
+ __sanitizer_syscall_post_impl_brk(res, (long)(brk))
+#define __sanitizer_syscall_pre_mprotect(start, len, prot) \
+ __sanitizer_syscall_pre_impl_mprotect((long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_post_mprotect(res, start, len, prot) \
+ __sanitizer_syscall_post_impl_mprotect(res, (long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_pre_mremap(addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_pre_impl_mremap((long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_post_mremap(res, addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_post_impl_mremap(res, (long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_pre_remap_file_pages(start, size, prot, pgoff, \
+ flags) \
+ __sanitizer_syscall_pre_impl_remap_file_pages( \
+ (long)(start), (long)(size), (long)(prot), (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_post_remap_file_pages(res, start, size, prot, \
+ pgoff, flags) \
+ __sanitizer_syscall_post_impl_remap_file_pages(res, (long)(start), \
+ (long)(size), (long)(prot), \
+ (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_pre_msync(start, len, flags) \
+ __sanitizer_syscall_pre_impl_msync((long)(start), (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_msync(res, start, len, flags) \
+ __sanitizer_syscall_post_impl_msync(res, (long)(start), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_munmap(addr, len) \
+ __sanitizer_syscall_pre_impl_munmap((long)(addr), (long)(len))
+#define __sanitizer_syscall_post_munmap(res, addr, len) \
+ __sanitizer_syscall_post_impl_munmap(res, (long)(addr), (long)(len))
+#define __sanitizer_syscall_pre_mlock(start, len) \
+ __sanitizer_syscall_pre_impl_mlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_mlock(res, start, len) \
+ __sanitizer_syscall_post_impl_mlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_munlock(start, len) \
+ __sanitizer_syscall_pre_impl_munlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_munlock(res, start, len) \
+ __sanitizer_syscall_post_impl_munlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_mlockall(flags) \
+ __sanitizer_syscall_pre_impl_mlockall((long)(flags))
+#define __sanitizer_syscall_post_mlockall(res, flags) \
+ __sanitizer_syscall_post_impl_mlockall(res, (long)(flags))
+#define __sanitizer_syscall_pre_munlockall() \
+ __sanitizer_syscall_pre_impl_munlockall()
+#define __sanitizer_syscall_post_munlockall(res) \
+ __sanitizer_syscall_post_impl_munlockall(res)
+#define __sanitizer_syscall_pre_madvise(start, len, behavior) \
+ __sanitizer_syscall_pre_impl_madvise((long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_post_madvise(res, start, len, behavior) \
+ __sanitizer_syscall_post_impl_madvise(res, (long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_pre_mincore(start, len, vec) \
+ __sanitizer_syscall_pre_impl_mincore((long)(start), (long)(len), (long)(vec))
+#define __sanitizer_syscall_post_mincore(res, start, len, vec) \
+ __sanitizer_syscall_post_impl_mincore(res, (long)(start), (long)(len), \
+ (long)(vec))
+#define __sanitizer_syscall_pre_pivot_root(new_root, put_old) \
+ __sanitizer_syscall_pre_impl_pivot_root((long)(new_root), (long)(put_old))
+#define __sanitizer_syscall_post_pivot_root(res, new_root, put_old) \
+ __sanitizer_syscall_post_impl_pivot_root(res, (long)(new_root), \
+ (long)(put_old))
+#define __sanitizer_syscall_pre_chroot(filename) \
+ __sanitizer_syscall_pre_impl_chroot((long)(filename))
+#define __sanitizer_syscall_post_chroot(res, filename) \
+ __sanitizer_syscall_post_impl_chroot(res, (long)(filename))
+#define __sanitizer_syscall_pre_mknod(filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknod((long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_post_mknod(res, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknod(res, (long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_pre_link(oldname, newname) \
+ __sanitizer_syscall_pre_impl_link((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_link(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_link(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_symlink(old, new_) \
+ __sanitizer_syscall_pre_impl_symlink((long)(old), (long)(new_))
+#define __sanitizer_syscall_post_symlink(res, old, new_) \
+ __sanitizer_syscall_post_impl_symlink(res, (long)(old), (long)(new_))
+#define __sanitizer_syscall_pre_unlink(pathname) \
+ __sanitizer_syscall_pre_impl_unlink((long)(pathname))
+#define __sanitizer_syscall_post_unlink(res, pathname) \
+ __sanitizer_syscall_post_impl_unlink(res, (long)(pathname))
+#define __sanitizer_syscall_pre_rename(oldname, newname) \
+ __sanitizer_syscall_pre_impl_rename((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_rename(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_rename(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_chmod(filename, mode) \
+ __sanitizer_syscall_pre_impl_chmod((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_chmod(res, filename, mode) \
+ __sanitizer_syscall_post_impl_chmod(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_fchmod(fd, mode) \
+ __sanitizer_syscall_pre_impl_fchmod((long)(fd), (long)(mode))
+#define __sanitizer_syscall_post_fchmod(res, fd, mode) \
+ __sanitizer_syscall_post_impl_fchmod(res, (long)(fd), (long)(mode))
+#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_fcntl64(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl64((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl64(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl64(res, (long)(fd), (long)(cmd), \
+ (long)(arg))
+#define __sanitizer_syscall_pre_pipe(fildes) \
+ __sanitizer_syscall_pre_impl_pipe((long)(fildes))
+#define __sanitizer_syscall_post_pipe(res, fildes) \
+ __sanitizer_syscall_post_impl_pipe(res, (long)(fildes))
+#define __sanitizer_syscall_pre_pipe2(fildes, flags) \
+ __sanitizer_syscall_pre_impl_pipe2((long)(fildes), (long)(flags))
+#define __sanitizer_syscall_post_pipe2(res, fildes, flags) \
+ __sanitizer_syscall_post_impl_pipe2(res, (long)(fildes), (long)(flags))
+#define __sanitizer_syscall_pre_dup(fildes) \
+ __sanitizer_syscall_pre_impl_dup((long)(fildes))
+#define __sanitizer_syscall_post_dup(res, fildes) \
+ __sanitizer_syscall_post_impl_dup(res, (long)(fildes))
+#define __sanitizer_syscall_pre_dup2(oldfd, newfd) \
+ __sanitizer_syscall_pre_impl_dup2((long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_post_dup2(res, oldfd, newfd) \
+ __sanitizer_syscall_post_impl_dup2(res, (long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_pre_dup3(oldfd, newfd, flags) \
+ __sanitizer_syscall_pre_impl_dup3((long)(oldfd), (long)(newfd), (long)(flags))
+#define __sanitizer_syscall_post_dup3(res, oldfd, newfd, flags) \
+ __sanitizer_syscall_post_impl_dup3(res, (long)(oldfd), (long)(newfd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_ioperm(from, num, on) \
+ __sanitizer_syscall_pre_impl_ioperm((long)(from), (long)(num), (long)(on))
+#define __sanitizer_syscall_post_ioperm(res, from, num, on) \
+ __sanitizer_syscall_post_impl_ioperm(res, (long)(from), (long)(num), \
+ (long)(on))
+#define __sanitizer_syscall_pre_ioctl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_ioctl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_ioctl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_ioctl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_flock(fd, cmd) \
+ __sanitizer_syscall_pre_impl_flock((long)(fd), (long)(cmd))
+#define __sanitizer_syscall_post_flock(res, fd, cmd) \
+ __sanitizer_syscall_post_impl_flock(res, (long)(fd), (long)(cmd))
+#define __sanitizer_syscall_pre_io_setup(nr_reqs, ctx) \
+ __sanitizer_syscall_pre_impl_io_setup((long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_post_io_setup(res, nr_reqs, ctx) \
+ __sanitizer_syscall_post_impl_io_setup(res, (long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_pre_io_destroy(ctx) \
+ __sanitizer_syscall_pre_impl_io_destroy((long)(ctx))
+#define __sanitizer_syscall_post_io_destroy(res, ctx) \
+ __sanitizer_syscall_post_impl_io_destroy(res, (long)(ctx))
+#define __sanitizer_syscall_pre_io_getevents(ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_pre_impl_io_getevents((long)(ctx_id), (long)(min_nr), \
+ (long)(nr), (long)(events), \
+ (long)(timeout))
+#define __sanitizer_syscall_post_io_getevents(res, ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_post_impl_io_getevents(res, (long)(ctx_id), \
+ (long)(min_nr), (long)(nr), \
+ (long)(events), (long)(timeout))
+#define __sanitizer_syscall_pre_io_submit(ctx_id, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_io_submit((long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_io_submit(res, ctx_id, arg1, arg2) \
+ __sanitizer_syscall_post_impl_io_submit(res, (long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_io_cancel(ctx_id, iocb, result) \
+ __sanitizer_syscall_pre_impl_io_cancel((long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_post_io_cancel(res, ctx_id, iocb, result) \
+ __sanitizer_syscall_post_impl_io_cancel(res, (long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_pre_sendfile(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_sendfile64(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile64((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile64(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile64(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_readlink(path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlink((long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_post_readlink(res, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlink(res, (long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_pre_creat(pathname, mode) \
+ __sanitizer_syscall_pre_impl_creat((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_creat(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_creat(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_open(filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_open((long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_post_open(res, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_open(res, (long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_close(fd) \
+ __sanitizer_syscall_pre_impl_close((long)(fd))
+#define __sanitizer_syscall_post_close(res, fd) \
+ __sanitizer_syscall_post_impl_close(res, (long)(fd))
+#define __sanitizer_syscall_pre_access(filename, mode) \
+ __sanitizer_syscall_pre_impl_access((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_access(res, filename, mode) \
+ __sanitizer_syscall_post_impl_access(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_vhangup() __sanitizer_syscall_pre_impl_vhangup()
+#define __sanitizer_syscall_post_vhangup(res) \
+ __sanitizer_syscall_post_impl_vhangup(res)
+#define __sanitizer_syscall_pre_chown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_chown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_lchown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_lchown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_fchown(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown((long)(fd), (long)(user), (long)(group))
+#define __sanitizer_syscall_post_fchown(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown(res, (long)(fd), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_chown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_chown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_lchown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_lchown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_fchown16(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown16((long)(fd), (long)user, (long)group)
+#define __sanitizer_syscall_post_fchown16(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown16(res, (long)(fd), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_setregid16(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid16((long)rgid, (long)egid)
+#define __sanitizer_syscall_post_setregid16(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid16(res, (long)rgid, (long)egid)
+#define __sanitizer_syscall_pre_setgid16(gid) \
+ __sanitizer_syscall_pre_impl_setgid16((long)gid)
+#define __sanitizer_syscall_post_setgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_setreuid16(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid16((long)ruid, (long)euid)
+#define __sanitizer_syscall_post_setreuid16(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid16(res, (long)ruid, (long)euid)
+#define __sanitizer_syscall_pre_setuid16(uid) \
+ __sanitizer_syscall_pre_impl_setuid16((long)uid)
+#define __sanitizer_syscall_post_setuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid16((long)ruid, (long)euid, (long)suid)
+#define __sanitizer_syscall_post_setresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid16(res, (long)ruid, (long)euid, \
+ (long)suid)
+#define __sanitizer_syscall_pre_getresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid16((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid16(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid16((long)rgid, (long)egid, (long)sgid)
+#define __sanitizer_syscall_post_setresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid16(res, (long)rgid, (long)egid, \
+ (long)sgid)
+#define __sanitizer_syscall_pre_getresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid16((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid16(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid16(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid16((long)uid)
+#define __sanitizer_syscall_post_setfsuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setfsgid16(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid16((long)gid)
+#define __sanitizer_syscall_post_setfsgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_getgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_getuid16() \
+ __sanitizer_syscall_pre_impl_getuid16()
+#define __sanitizer_syscall_post_getuid16(res) \
+ __sanitizer_syscall_post_impl_getuid16(res)
+#define __sanitizer_syscall_pre_geteuid16() \
+ __sanitizer_syscall_pre_impl_geteuid16()
+#define __sanitizer_syscall_post_geteuid16(res) \
+ __sanitizer_syscall_post_impl_geteuid16(res)
+#define __sanitizer_syscall_pre_getgid16() \
+ __sanitizer_syscall_pre_impl_getgid16()
+#define __sanitizer_syscall_post_getgid16(res) \
+ __sanitizer_syscall_post_impl_getgid16(res)
+#define __sanitizer_syscall_pre_getegid16() \
+ __sanitizer_syscall_pre_impl_getegid16()
+#define __sanitizer_syscall_post_getegid16(res) \
+ __sanitizer_syscall_post_impl_getegid16(res)
+#define __sanitizer_syscall_pre_utime(filename, times) \
+ __sanitizer_syscall_pre_impl_utime((long)(filename), (long)(times))
+#define __sanitizer_syscall_post_utime(res, filename, times) \
+ __sanitizer_syscall_post_impl_utime(res, (long)(filename), (long)(times))
+#define __sanitizer_syscall_pre_utimes(filename, utimes) \
+ __sanitizer_syscall_pre_impl_utimes((long)(filename), (long)(utimes))
+#define __sanitizer_syscall_post_utimes(res, filename, utimes) \
+ __sanitizer_syscall_post_impl_utimes(res, (long)(filename), (long)(utimes))
+#define __sanitizer_syscall_pre_lseek(fd, offset, origin) \
+ __sanitizer_syscall_pre_impl_lseek((long)(fd), (long)(offset), (long)(origin))
+#define __sanitizer_syscall_post_lseek(res, fd, offset, origin) \
+ __sanitizer_syscall_post_impl_lseek(res, (long)(fd), (long)(offset), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_llseek(fd, offset_high, offset_low, result, \
+ origin) \
+ __sanitizer_syscall_pre_impl_llseek((long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_post_llseek(res, fd, offset_high, offset_low, \
+ result, origin) \
+ __sanitizer_syscall_post_impl_llseek(res, (long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_read(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_read((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_read(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_read(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_readv(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_readv((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_readv(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_readv(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
+#define __sanitizer_syscall_pre_write(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_write((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_write(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_write(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_writev(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_writev((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_writev(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_writev(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
+
+#ifdef _LP64
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pwrite64((long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pwrite64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#else
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos0), \
+ (long)(pos1))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pwrite64( \
+ (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pwrite64( \
+ res, (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#endif
+
+#define __sanitizer_syscall_pre_preadv(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_preadv((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_preadv(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_preadv(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_pwritev(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_pwritev((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_pwritev(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_pwritev(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_getcwd(buf, size) \
+ __sanitizer_syscall_pre_impl_getcwd((long)(buf), (long)(size))
+#define __sanitizer_syscall_post_getcwd(res, buf, size) \
+ __sanitizer_syscall_post_impl_getcwd(res, (long)(buf), (long)(size))
+#define __sanitizer_syscall_pre_mkdir(pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdir((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_mkdir(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdir(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_chdir(filename) \
+ __sanitizer_syscall_pre_impl_chdir((long)(filename))
+#define __sanitizer_syscall_post_chdir(res, filename) \
+ __sanitizer_syscall_post_impl_chdir(res, (long)(filename))
+#define __sanitizer_syscall_pre_fchdir(fd) \
+ __sanitizer_syscall_pre_impl_fchdir((long)(fd))
+#define __sanitizer_syscall_post_fchdir(res, fd) \
+ __sanitizer_syscall_post_impl_fchdir(res, (long)(fd))
+#define __sanitizer_syscall_pre_rmdir(pathname) \
+ __sanitizer_syscall_pre_impl_rmdir((long)(pathname))
+#define __sanitizer_syscall_post_rmdir(res, pathname) \
+ __sanitizer_syscall_post_impl_rmdir(res, (long)(pathname))
+#define __sanitizer_syscall_pre_lookup_dcookie(cookie64, buf, len) \
+ __sanitizer_syscall_pre_impl_lookup_dcookie((long)(cookie64), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_post_lookup_dcookie(res, cookie64, buf, len) \
+ __sanitizer_syscall_post_impl_lookup_dcookie(res, (long)(cookie64), \
+ (long)(buf), (long)(len))
+#define __sanitizer_syscall_pre_quotactl(cmd, special, id, addr) \
+ __sanitizer_syscall_pre_impl_quotactl((long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_post_quotactl(res, cmd, special, id, addr) \
+ __sanitizer_syscall_post_impl_quotactl(res, (long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_pre_getdents(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_getdents64(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents64((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents64(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents64(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_setsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_setsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_setsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_setsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_getsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_getsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_getsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_getsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_bind(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_bind((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_bind(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_bind(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_connect(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_connect((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_connect(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_connect(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_accept((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_accept(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_accept(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept4(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_accept4((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_accept4(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_accept4(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_getsockname(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getsockname((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getsockname(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getsockname(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_getpeername(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getpeername((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getpeername(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getpeername(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_send(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_send((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_send(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_send(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_sendto(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_sendto((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_sendto(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_sendto(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_sendmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_sendmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_sendmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_sendmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_sendmmsg(fd, msg, vlen, flags) \
+ __sanitizer_syscall_pre_impl_sendmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags))
+#define __sanitizer_syscall_post_sendmmsg(res, fd, msg, vlen, flags) \
+ __sanitizer_syscall_post_impl_sendmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags))
+#define __sanitizer_syscall_pre_recv(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_recv((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_recv(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_recv(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_recvfrom(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_recvfrom((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_recvfrom(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_recvfrom(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_recvmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_recvmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_recvmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_recvmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_recvmmsg(fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_pre_impl_recvmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags), (long)(timeout))
+#define __sanitizer_syscall_post_recvmmsg(res, fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_post_impl_recvmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_socket(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_socket((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_socket(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_socket(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_socketpair(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_socketpair((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_socketpair(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_socketpair(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_socketcall(call, args) \
+ __sanitizer_syscall_pre_impl_socketcall((long)(call), (long)(args))
+#define __sanitizer_syscall_post_socketcall(res, call, args) \
+ __sanitizer_syscall_post_impl_socketcall(res, (long)(call), (long)(args))
+#define __sanitizer_syscall_pre_listen(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_listen((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_listen(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_listen(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_poll(ufds, nfds, timeout) \
+ __sanitizer_syscall_pre_impl_poll((long)(ufds), (long)(nfds), (long)(timeout))
+#define __sanitizer_syscall_post_poll(res, ufds, nfds, timeout) \
+ __sanitizer_syscall_post_impl_poll(res, (long)(ufds), (long)(nfds), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_select(n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_pre_impl_select((long)(n), (long)(inp), (long)(outp), \
+ (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_post_select(res, n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_post_impl_select(res, (long)(n), (long)(inp), \
+ (long)(outp), (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_pre_old_select(arg) \
+ __sanitizer_syscall_pre_impl_old_select((long)(arg))
+#define __sanitizer_syscall_post_old_select(res, arg) \
+ __sanitizer_syscall_post_impl_old_select(res, (long)(arg))
+#define __sanitizer_syscall_pre_epoll_create(size) \
+ __sanitizer_syscall_pre_impl_epoll_create((long)(size))
+#define __sanitizer_syscall_post_epoll_create(res, size) \
+ __sanitizer_syscall_post_impl_epoll_create(res, (long)(size))
+#define __sanitizer_syscall_pre_epoll_create1(flags) \
+ __sanitizer_syscall_pre_impl_epoll_create1((long)(flags))
+#define __sanitizer_syscall_post_epoll_create1(res, flags) \
+ __sanitizer_syscall_post_impl_epoll_create1(res, (long)(flags))
+#define __sanitizer_syscall_pre_epoll_ctl(epfd, op, fd, event) \
+ __sanitizer_syscall_pre_impl_epoll_ctl((long)(epfd), (long)(op), (long)(fd), \
+ (long)(event))
+#define __sanitizer_syscall_post_epoll_ctl(res, epfd, op, fd, event) \
+ __sanitizer_syscall_post_impl_epoll_ctl(res, (long)(epfd), (long)(op), \
+ (long)(fd), (long)(event))
+#define __sanitizer_syscall_pre_epoll_wait(epfd, events, maxevents, timeout) \
+ __sanitizer_syscall_pre_impl_epoll_wait((long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_post_epoll_wait(res, epfd, events, maxevents, \
+ timeout) \
+ __sanitizer_syscall_post_impl_epoll_wait(res, (long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_pre_epoll_pwait(epfd, events, maxevents, timeout, \
+ sigmask, sigsetsize) \
+ __sanitizer_syscall_pre_impl_epoll_pwait( \
+ (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_post_epoll_pwait(res, epfd, events, maxevents, \
+ timeout, sigmask, sigsetsize) \
+ __sanitizer_syscall_post_impl_epoll_pwait( \
+ res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_gethostname(name, len) \
+ __sanitizer_syscall_pre_impl_gethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_gethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_gethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_sethostname(name, len) \
+ __sanitizer_syscall_pre_impl_sethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_sethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_sethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_setdomainname(name, len) \
+ __sanitizer_syscall_pre_impl_setdomainname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_setdomainname(res, name, len) \
+ __sanitizer_syscall_post_impl_setdomainname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_newuname(name) \
+ __sanitizer_syscall_pre_impl_newuname((long)(name))
+#define __sanitizer_syscall_post_newuname(res, name) \
+ __sanitizer_syscall_post_impl_newuname(res, (long)(name))
+#define __sanitizer_syscall_pre_uname(arg0) \
+ __sanitizer_syscall_pre_impl_uname((long)(arg0))
+#define __sanitizer_syscall_post_uname(res, arg0) \
+ __sanitizer_syscall_post_impl_uname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_olduname(arg0) \
+ __sanitizer_syscall_pre_impl_olduname((long)(arg0))
+#define __sanitizer_syscall_post_olduname(res, arg0) \
+ __sanitizer_syscall_post_impl_olduname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_getrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_old_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_old_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_old_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_old_getrlimit(res, (long)(resource), \
+ (long)(rlim))
+#define __sanitizer_syscall_pre_setrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_setrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_setrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_setrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_prlimit64(pid, resource, new_rlim, old_rlim) \
+ __sanitizer_syscall_pre_impl_prlimit64((long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_post_prlimit64(res, pid, resource, new_rlim, \
+ old_rlim) \
+ __sanitizer_syscall_post_impl_prlimit64(res, (long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_pre_getrusage(who, ru) \
+ __sanitizer_syscall_pre_impl_getrusage((long)(who), (long)(ru))
+#define __sanitizer_syscall_post_getrusage(res, who, ru) \
+ __sanitizer_syscall_post_impl_getrusage(res, (long)(who), (long)(ru))
+#define __sanitizer_syscall_pre_umask(mask) \
+ __sanitizer_syscall_pre_impl_umask((long)(mask))
+#define __sanitizer_syscall_post_umask(res, mask) \
+ __sanitizer_syscall_post_impl_umask(res, (long)(mask))
+#define __sanitizer_syscall_pre_msgget(key, msgflg) \
+ __sanitizer_syscall_pre_impl_msgget((long)(key), (long)(msgflg))
+#define __sanitizer_syscall_post_msgget(res, key, msgflg) \
+ __sanitizer_syscall_post_impl_msgget(res, (long)(key), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_pre_impl_msgsnd((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_post_impl_msgsnd(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) \
+ __sanitizer_syscall_pre_impl_msgrcv((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp, \
+ msgflg) \
+ __sanitizer_syscall_post_impl_msgrcv(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_pre_msgctl(msqid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_msgctl((long)(msqid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_msgctl(res, msqid, cmd, buf) \
+ __sanitizer_syscall_post_impl_msgctl(res, (long)(msqid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_semget(key, nsems, semflg) \
+ __sanitizer_syscall_pre_impl_semget((long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_post_semget(res, key, nsems, semflg) \
+ __sanitizer_syscall_post_impl_semget(res, (long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_pre_semop(semid, sops, nsops) \
+ __sanitizer_syscall_pre_impl_semop((long)(semid), (long)(sops), (long)(nsops))
+#define __sanitizer_syscall_post_semop(res, semid, sops, nsops) \
+ __sanitizer_syscall_post_impl_semop(res, (long)(semid), (long)(sops), \
+ (long)(nsops))
+#define __sanitizer_syscall_pre_semctl(semid, semnum, cmd, arg) \
+ __sanitizer_syscall_pre_impl_semctl((long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_semctl(res, semid, semnum, cmd, arg) \
+ __sanitizer_syscall_post_impl_semctl(res, (long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_semtimedop(semid, sops, nsops, timeout) \
+ __sanitizer_syscall_pre_impl_semtimedop((long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_post_semtimedop(res, semid, sops, nsops, timeout) \
+ __sanitizer_syscall_post_impl_semtimedop(res, (long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_pre_impl_shmat((long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_post_impl_shmat(res, (long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_pre_shmget(key, size, flag) \
+ __sanitizer_syscall_pre_impl_shmget((long)(key), (long)(size), (long)(flag))
+#define __sanitizer_syscall_post_shmget(res, key, size, flag) \
+ __sanitizer_syscall_post_impl_shmget(res, (long)(key), (long)(size), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_shmdt(shmaddr) \
+ __sanitizer_syscall_pre_impl_shmdt((long)(shmaddr))
+#define __sanitizer_syscall_post_shmdt(res, shmaddr) \
+ __sanitizer_syscall_post_impl_shmdt(res, (long)(shmaddr))
+#define __sanitizer_syscall_pre_shmctl(shmid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_shmctl((long)(shmid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_shmctl(res, shmid, cmd, buf) \
+ __sanitizer_syscall_post_impl_shmctl(res, (long)(shmid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_ipc(call, first, second, third, ptr, fifth) \
+ __sanitizer_syscall_pre_impl_ipc((long)(call), (long)(first), \
+ (long)(second), (long)(third), (long)(ptr), \
+ (long)(fifth))
+#define __sanitizer_syscall_post_ipc(res, call, first, second, third, ptr, \
+ fifth) \
+ __sanitizer_syscall_post_impl_ipc(res, (long)(call), (long)(first), \
+ (long)(second), (long)(third), \
+ (long)(ptr), (long)(fifth))
+#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr) \
+ __sanitizer_syscall_pre_impl_mq_open((long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr) \
+ __sanitizer_syscall_post_impl_mq_open(res, (long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_pre_mq_unlink(name) \
+ __sanitizer_syscall_pre_impl_mq_unlink((long)(name))
+#define __sanitizer_syscall_post_mq_unlink(res, name) \
+ __sanitizer_syscall_post_impl_mq_unlink(res, (long)(name))
+#define __sanitizer_syscall_pre_mq_timedsend(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedsend((long)(mqdes), (long)(msg_ptr), \
+ (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedsend(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedsend( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_timedreceive(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedreceive( \
+ (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedreceive(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedreceive( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_notify(mqdes, notification) \
+ __sanitizer_syscall_pre_impl_mq_notify((long)(mqdes), (long)(notification))
+#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification) \
+ __sanitizer_syscall_post_impl_mq_notify(res, (long)(mqdes), \
+ (long)(notification))
+#define __sanitizer_syscall_pre_mq_getsetattr(mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_pre_impl_mq_getsetattr((long)(mqdes), (long)(mqstat), \
+ (long)(omqstat))
+#define __sanitizer_syscall_post_mq_getsetattr(res, mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_post_impl_mq_getsetattr(res, (long)(mqdes), \
+ (long)(mqstat), (long)(omqstat))
+#define __sanitizer_syscall_pre_pciconfig_iobase(which, bus, devfn) \
+ __sanitizer_syscall_pre_impl_pciconfig_iobase((long)(which), (long)(bus), \
+ (long)(devfn))
+#define __sanitizer_syscall_post_pciconfig_iobase(res, which, bus, devfn) \
+ __sanitizer_syscall_post_impl_pciconfig_iobase(res, (long)(which), \
+ (long)(bus), (long)(devfn))
+#define __sanitizer_syscall_pre_pciconfig_read(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_read( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_read(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_read( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_pciconfig_write(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_write( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_write(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_write( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_swapon(specialfile, swap_flags) \
+ __sanitizer_syscall_pre_impl_swapon((long)(specialfile), (long)(swap_flags))
+#define __sanitizer_syscall_post_swapon(res, specialfile, swap_flags) \
+ __sanitizer_syscall_post_impl_swapon(res, (long)(specialfile), \
+ (long)(swap_flags))
+#define __sanitizer_syscall_pre_swapoff(specialfile) \
+ __sanitizer_syscall_pre_impl_swapoff((long)(specialfile))
+#define __sanitizer_syscall_post_swapoff(res, specialfile) \
+ __sanitizer_syscall_post_impl_swapoff(res, (long)(specialfile))
+#define __sanitizer_syscall_pre_sysctl(args) \
+ __sanitizer_syscall_pre_impl_sysctl((long)(args))
+#define __sanitizer_syscall_post_sysctl(res, args) \
+ __sanitizer_syscall_post_impl_sysctl(res, (long)(args))
+#define __sanitizer_syscall_pre_sysinfo(info) \
+ __sanitizer_syscall_pre_impl_sysinfo((long)(info))
+#define __sanitizer_syscall_post_sysinfo(res, info) \
+ __sanitizer_syscall_post_impl_sysinfo(res, (long)(info))
+#define __sanitizer_syscall_pre_sysfs(option, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_sysfs((long)(option), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_sysfs(res, option, arg1, arg2) \
+ __sanitizer_syscall_post_impl_sysfs(res, (long)(option), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_syslog(type, buf, len) \
+ __sanitizer_syscall_pre_impl_syslog((long)(type), (long)(buf), (long)(len))
+#define __sanitizer_syscall_post_syslog(res, type, buf, len) \
+ __sanitizer_syscall_post_impl_syslog(res, (long)(type), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_pre_uselib(library) \
+ __sanitizer_syscall_pre_impl_uselib((long)(library))
+#define __sanitizer_syscall_post_uselib(res, library) \
+ __sanitizer_syscall_post_impl_uselib(res, (long)(library))
+#define __sanitizer_syscall_pre_ni_syscall() \
+ __sanitizer_syscall_pre_impl_ni_syscall()
+#define __sanitizer_syscall_post_ni_syscall(res) \
+ __sanitizer_syscall_post_impl_ni_syscall(res)
+#define __sanitizer_syscall_pre_ptrace(request, pid, addr, data) \
+ __sanitizer_syscall_pre_impl_ptrace((long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_post_ptrace(res, request, pid, addr, data) \
+ __sanitizer_syscall_post_impl_ptrace(res, (long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_pre_add_key(_type, _description, _payload, plen, \
+ destringid) \
+ __sanitizer_syscall_pre_impl_add_key((long)(_type), (long)(_description), \
+ (long)(_payload), (long)(plen), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_add_key(res, _type, _description, _payload, \
+ plen, destringid) \
+ __sanitizer_syscall_post_impl_add_key( \
+ res, (long)(_type), (long)(_description), (long)(_payload), \
+ (long)(plen), (long)(destringid))
+#define __sanitizer_syscall_pre_request_key(_type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_pre_impl_request_key( \
+ (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_request_key(res, _type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_post_impl_request_key( \
+ res, (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_pre_keyctl(cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_keyctl((long)(cmd), (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_keyctl(res, cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_post_impl_keyctl(res, (long)(cmd), (long)(arg2), \
+ (long)(arg3), (long)(arg4), \
+ (long)(arg5))
+#define __sanitizer_syscall_pre_ioprio_set(which, who, ioprio) \
+ __sanitizer_syscall_pre_impl_ioprio_set((long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_post_ioprio_set(res, which, who, ioprio) \
+ __sanitizer_syscall_post_impl_ioprio_set(res, (long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_pre_ioprio_get(which, who) \
+ __sanitizer_syscall_pre_impl_ioprio_get((long)(which), (long)(who))
+#define __sanitizer_syscall_post_ioprio_get(res, which, who) \
+ __sanitizer_syscall_post_impl_ioprio_get(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_set_mempolicy(mode, nmask, maxnode) \
+ __sanitizer_syscall_pre_impl_set_mempolicy((long)(mode), (long)(nmask), \
+ (long)(maxnode))
+#define __sanitizer_syscall_post_set_mempolicy(res, mode, nmask, maxnode) \
+ __sanitizer_syscall_post_impl_set_mempolicy(res, (long)(mode), \
+ (long)(nmask), (long)(maxnode))
+#define __sanitizer_syscall_pre_migrate_pages(pid, maxnode, from, to) \
+ __sanitizer_syscall_pre_impl_migrate_pages((long)(pid), (long)(maxnode), \
+ (long)(from), (long)(to))
+#define __sanitizer_syscall_post_migrate_pages(res, pid, maxnode, from, to) \
+ __sanitizer_syscall_post_impl_migrate_pages( \
+ res, (long)(pid), (long)(maxnode), (long)(from), (long)(to))
+#define __sanitizer_syscall_pre_move_pages(pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_pre_impl_move_pages((long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_post_move_pages(res, pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_post_impl_move_pages(res, (long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_pre_mbind(start, len, mode, nmask, maxnode, flags) \
+ __sanitizer_syscall_pre_impl_mbind((long)(start), (long)(len), (long)(mode), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(flags))
+#define __sanitizer_syscall_post_mbind(res, start, len, mode, nmask, maxnode, \
+ flags) \
+ __sanitizer_syscall_post_impl_mbind(res, (long)(start), (long)(len), \
+ (long)(mode), (long)(nmask), \
+ (long)(maxnode), (long)(flags))
+#define __sanitizer_syscall_pre_get_mempolicy(policy, nmask, maxnode, addr, \
+ flags) \
+ __sanitizer_syscall_pre_impl_get_mempolicy((long)(policy), (long)(nmask), \
+ (long)(maxnode), (long)(addr), \
+ (long)(flags))
+#define __sanitizer_syscall_post_get_mempolicy(res, policy, nmask, maxnode, \
+ addr, flags) \
+ __sanitizer_syscall_post_impl_get_mempolicy(res, (long)(policy), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(addr), (long)(flags))
+#define __sanitizer_syscall_pre_inotify_init() \
+ __sanitizer_syscall_pre_impl_inotify_init()
+#define __sanitizer_syscall_post_inotify_init(res) \
+ __sanitizer_syscall_post_impl_inotify_init(res)
+#define __sanitizer_syscall_pre_inotify_init1(flags) \
+ __sanitizer_syscall_pre_impl_inotify_init1((long)(flags))
+#define __sanitizer_syscall_post_inotify_init1(res, flags) \
+ __sanitizer_syscall_post_impl_inotify_init1(res, (long)(flags))
+#define __sanitizer_syscall_pre_inotify_add_watch(fd, path, mask) \
+ __sanitizer_syscall_pre_impl_inotify_add_watch((long)(fd), (long)(path), \
+ (long)(mask))
+#define __sanitizer_syscall_post_inotify_add_watch(res, fd, path, mask) \
+ __sanitizer_syscall_post_impl_inotify_add_watch(res, (long)(fd), \
+ (long)(path), (long)(mask))
+#define __sanitizer_syscall_pre_inotify_rm_watch(fd, wd) \
+ __sanitizer_syscall_pre_impl_inotify_rm_watch((long)(fd), (long)(wd))
+#define __sanitizer_syscall_post_inotify_rm_watch(res, fd, wd) \
+ __sanitizer_syscall_post_impl_inotify_rm_watch(res, (long)(fd), (long)(wd))
+#define __sanitizer_syscall_pre_spu_run(fd, unpc, ustatus) \
+ __sanitizer_syscall_pre_impl_spu_run((long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_post_spu_run(res, fd, unpc, ustatus) \
+ __sanitizer_syscall_post_impl_spu_run(res, (long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_pre_spu_create(name, flags, mode, fd) \
+ __sanitizer_syscall_pre_impl_spu_create((long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_post_spu_create(res, name, flags, mode, fd) \
+ __sanitizer_syscall_post_impl_spu_create(res, (long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_pre_mknodat(dfd, filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknodat((long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_post_mknodat(res, dfd, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_pre_mkdirat(dfd, pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdirat((long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_post_mkdirat(res, dfd, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdirat(res, (long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_unlinkat(dfd, pathname, flag) \
+ __sanitizer_syscall_pre_impl_unlinkat((long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_post_unlinkat(res, dfd, pathname, flag) \
+ __sanitizer_syscall_post_impl_unlinkat(res, (long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_symlinkat(oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_symlinkat((long)(oldname), (long)(newdfd), \
+ (long)(newname))
+#define __sanitizer_syscall_post_symlinkat(res, oldname, newdfd, newname) \
+ __sanitizer_syscall_post_impl_symlinkat(res, (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_linkat(olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_pre_impl_linkat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_post_linkat(res, olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_post_impl_linkat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_renameat(olddfd, oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_renameat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_post_renameat(res, olddfd, oldname, newdfd, \
+ newname) \
+ __sanitizer_syscall_post_impl_renameat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_futimesat(dfd, filename, utimes) \
+ __sanitizer_syscall_pre_impl_futimesat((long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_post_futimesat(res, dfd, filename, utimes) \
+ __sanitizer_syscall_post_impl_futimesat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_pre_faccessat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_faccessat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_faccessat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_faccessat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchmodat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_fchmodat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_fchmodat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_fchmodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchownat(dfd, filename, user, group, flag) \
+ __sanitizer_syscall_pre_impl_fchownat((long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_post_fchownat(res, dfd, filename, user, group, \
+ flag) \
+ __sanitizer_syscall_post_impl_fchownat(res, (long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_openat(dfd, filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_openat((long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_post_openat(res, dfd, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_openat(res, (long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_pre_newfstatat(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_newfstatat((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_newfstatat(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_newfstatat(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_fstatat64(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_fstatat64((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_fstatat64(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_fstatat64(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_readlinkat(dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlinkat((long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_post_readlinkat(res, dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlinkat(res, (long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_pre_utimensat(dfd, filename, utimes, flags) \
+ __sanitizer_syscall_pre_impl_utimensat((long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_post_utimensat(res, dfd, filename, utimes, flags) \
+ __sanitizer_syscall_post_impl_utimensat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_pre_unshare(unshare_flags) \
+ __sanitizer_syscall_pre_impl_unshare((long)(unshare_flags))
+#define __sanitizer_syscall_post_unshare(res, unshare_flags) \
+ __sanitizer_syscall_post_impl_unshare(res, (long)(unshare_flags))
+#define __sanitizer_syscall_pre_splice(fd_in, off_in, fd_out, off_out, len, \
+ flags) \
+ __sanitizer_syscall_pre_impl_splice((long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_splice(res, fd_in, off_in, fd_out, off_out, \
+ len, flags) \
+ __sanitizer_syscall_post_impl_splice(res, (long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_vmsplice(fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_pre_impl_vmsplice((long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_post_vmsplice(res, fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_post_impl_vmsplice(res, (long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_pre_tee(fdin, fdout, len, flags) \
+ __sanitizer_syscall_pre_impl_tee((long)(fdin), (long)(fdout), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_post_tee(res, fdin, fdout, len, flags) \
+ __sanitizer_syscall_post_impl_tee(res, (long)(fdin), (long)(fdout), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_get_robust_list(pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_pre_impl_get_robust_list((long)(pid), (long)(head_ptr), \
+ (long)(len_ptr))
+#define __sanitizer_syscall_post_get_robust_list(res, pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_post_impl_get_robust_list( \
+ res, (long)(pid), (long)(head_ptr), (long)(len_ptr))
+#define __sanitizer_syscall_pre_set_robust_list(head, len) \
+ __sanitizer_syscall_pre_impl_set_robust_list((long)(head), (long)(len))
+#define __sanitizer_syscall_post_set_robust_list(res, head, len) \
+ __sanitizer_syscall_post_impl_set_robust_list(res, (long)(head), (long)(len))
+#define __sanitizer_syscall_pre_getcpu(cpu, node, cache) \
+ __sanitizer_syscall_pre_impl_getcpu((long)(cpu), (long)(node), (long)(cache))
+#define __sanitizer_syscall_post_getcpu(res, cpu, node, cache) \
+ __sanitizer_syscall_post_impl_getcpu(res, (long)(cpu), (long)(node), \
+ (long)(cache))
+#define __sanitizer_syscall_pre_signalfd(ufd, user_mask, sizemask) \
+ __sanitizer_syscall_pre_impl_signalfd((long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_post_signalfd(res, ufd, user_mask, sizemask) \
+ __sanitizer_syscall_post_impl_signalfd(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_pre_signalfd4(ufd, user_mask, sizemask, flags) \
+ __sanitizer_syscall_pre_impl_signalfd4((long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_post_signalfd4(res, ufd, user_mask, sizemask, \
+ flags) \
+ __sanitizer_syscall_post_impl_signalfd4(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_create(clockid, flags) \
+ __sanitizer_syscall_pre_impl_timerfd_create((long)(clockid), (long)(flags))
+#define __sanitizer_syscall_post_timerfd_create(res, clockid, flags) \
+ __sanitizer_syscall_post_impl_timerfd_create(res, (long)(clockid), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_settime(ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_settime((long)(ufd), (long)(flags), \
+ (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_settime(res, ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_settime( \
+ res, (long)(ufd), (long)(flags), (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_pre_timerfd_gettime(ufd, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_gettime((long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_gettime(res, ufd, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_gettime(res, (long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_pre_eventfd(count) \
+ __sanitizer_syscall_pre_impl_eventfd((long)(count))
+#define __sanitizer_syscall_post_eventfd(res, count) \
+ __sanitizer_syscall_post_impl_eventfd(res, (long)(count))
+#define __sanitizer_syscall_pre_eventfd2(count, flags) \
+ __sanitizer_syscall_pre_impl_eventfd2((long)(count), (long)(flags))
+#define __sanitizer_syscall_post_eventfd2(res, count, flags) \
+ __sanitizer_syscall_post_impl_eventfd2(res, (long)(count), (long)(flags))
+#define __sanitizer_syscall_pre_old_readdir(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_old_readdir((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_old_readdir(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_old_readdir(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_pselect6(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_pselect6((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_pselect6(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_pselect6(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_ppoll(arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_pre_impl_ppoll((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3), (long)(arg4))
+#define __sanitizer_syscall_post_ppoll(res, arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_post_impl_ppoll(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4))
+#define __sanitizer_syscall_pre_syncfs(fd) \
+ __sanitizer_syscall_pre_impl_syncfs((long)(fd))
+#define __sanitizer_syscall_post_syncfs(res, fd) \
+ __sanitizer_syscall_post_impl_syncfs(res, (long)(fd))
+#define __sanitizer_syscall_pre_perf_event_open(attr_uptr, pid, cpu, group_fd, \
+ flags) \
+ __sanitizer_syscall_pre_impl_perf_event_open((long)(attr_uptr), (long)(pid), \
+ (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_post_perf_event_open(res, attr_uptr, pid, cpu, \
+ group_fd, flags) \
+ __sanitizer_syscall_post_impl_perf_event_open( \
+ res, (long)(attr_uptr), (long)(pid), (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_mmap_pgoff(addr, len, prot, flags, fd, pgoff) \
+ __sanitizer_syscall_pre_impl_mmap_pgoff((long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_post_mmap_pgoff(res, addr, len, prot, flags, fd, \
+ pgoff) \
+ __sanitizer_syscall_post_impl_mmap_pgoff(res, (long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_pre_old_mmap(arg) \
+ __sanitizer_syscall_pre_impl_old_mmap((long)(arg))
+#define __sanitizer_syscall_post_old_mmap(res, arg) \
+ __sanitizer_syscall_post_impl_old_mmap(res, (long)(arg))
+#define __sanitizer_syscall_pre_name_to_handle_at(dfd, name, handle, mnt_id, \
+ flag) \
+ __sanitizer_syscall_pre_impl_name_to_handle_at( \
+ (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), (long)(flag))
+#define __sanitizer_syscall_post_name_to_handle_at(res, dfd, name, handle, \
+ mnt_id, flag) \
+ __sanitizer_syscall_post_impl_name_to_handle_at( \
+ res, (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_open_by_handle_at(mountdirfd, handle, flags) \
+ __sanitizer_syscall_pre_impl_open_by_handle_at( \
+ (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_post_open_by_handle_at(res, mountdirfd, handle, \
+ flags) \
+ __sanitizer_syscall_post_impl_open_by_handle_at( \
+ res, (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_pre_setns(fd, nstype) \
+ __sanitizer_syscall_pre_impl_setns((long)(fd), (long)(nstype))
+#define __sanitizer_syscall_post_setns(res, fd, nstype) \
+ __sanitizer_syscall_post_impl_setns(res, (long)(fd), (long)(nstype))
+#define __sanitizer_syscall_pre_process_vm_readv(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_readv( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_readv(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_readv( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_process_vm_writev(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_writev( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_writev(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_writev( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_fork() \
+ __sanitizer_syscall_pre_impl_fork()
+#define __sanitizer_syscall_post_fork(res) \
+ __sanitizer_syscall_post_impl_fork(res)
+#define __sanitizer_syscall_pre_vfork() \
+ __sanitizer_syscall_pre_impl_vfork()
+#define __sanitizer_syscall_post_vfork(res) \
+ __sanitizer_syscall_post_impl_vfork(res)
+
+// And now a few syscalls we don't handle yet.
+#define __sanitizer_syscall_pre_afs_syscall(...)
+#define __sanitizer_syscall_pre_arch_prctl(...)
+#define __sanitizer_syscall_pre_break(...)
+#define __sanitizer_syscall_pre_chown32(...)
+#define __sanitizer_syscall_pre_clone(...)
+#define __sanitizer_syscall_pre_create_module(...)
+#define __sanitizer_syscall_pre_epoll_ctl_old(...)
+#define __sanitizer_syscall_pre_epoll_wait_old(...)
+#define __sanitizer_syscall_pre_execve(...)
+#define __sanitizer_syscall_pre_fadvise64(...)
+#define __sanitizer_syscall_pre_fadvise64_64(...)
+#define __sanitizer_syscall_pre_fallocate(...)
+#define __sanitizer_syscall_pre_fanotify_init(...)
+#define __sanitizer_syscall_pre_fanotify_mark(...)
+#define __sanitizer_syscall_pre_fchown32(...)
+#define __sanitizer_syscall_pre_ftime(...)
+#define __sanitizer_syscall_pre_ftruncate64(...)
+#define __sanitizer_syscall_pre_futex(...)
+#define __sanitizer_syscall_pre_getegid32(...)
+#define __sanitizer_syscall_pre_geteuid32(...)
+#define __sanitizer_syscall_pre_getgid32(...)
+#define __sanitizer_syscall_pre_getgroups32(...)
+#define __sanitizer_syscall_pre_get_kernel_syms(...)
+#define __sanitizer_syscall_pre_getpmsg(...)
+#define __sanitizer_syscall_pre_getresgid32(...)
+#define __sanitizer_syscall_pre_getresuid32(...)
+#define __sanitizer_syscall_pre_get_thread_area(...)
+#define __sanitizer_syscall_pre_getuid32(...)
+#define __sanitizer_syscall_pre_gtty(...)
+#define __sanitizer_syscall_pre_idle(...)
+#define __sanitizer_syscall_pre_iopl(...)
+#define __sanitizer_syscall_pre_lchown32(...)
+#define __sanitizer_syscall_pre__llseek(...)
+#define __sanitizer_syscall_pre_lock(...)
+#define __sanitizer_syscall_pre_madvise1(...)
+#define __sanitizer_syscall_pre_mmap(...)
+#define __sanitizer_syscall_pre_mmap2(...)
+#define __sanitizer_syscall_pre_modify_ldt(...)
+#define __sanitizer_syscall_pre_mpx(...)
+#define __sanitizer_syscall_pre__newselect(...)
+#define __sanitizer_syscall_pre_nfsservctl(...)
+#define __sanitizer_syscall_pre_oldfstat(...)
+#define __sanitizer_syscall_pre_oldlstat(...)
+#define __sanitizer_syscall_pre_oldolduname(...)
+#define __sanitizer_syscall_pre_oldstat(...)
+#define __sanitizer_syscall_pre_prctl(...)
+#define __sanitizer_syscall_pre_prof(...)
+#define __sanitizer_syscall_pre_profil(...)
+#define __sanitizer_syscall_pre_putpmsg(...)
+#define __sanitizer_syscall_pre_query_module(...)
+#define __sanitizer_syscall_pre_readahead(...)
+#define __sanitizer_syscall_pre_readdir(...)
+#define __sanitizer_syscall_pre_rt_sigaction(...)
+#define __sanitizer_syscall_pre_rt_sigreturn(...)
+#define __sanitizer_syscall_pre_rt_sigsuspend(...)
+#define __sanitizer_syscall_pre_security(...)
+#define __sanitizer_syscall_pre_setfsgid32(...)
+#define __sanitizer_syscall_pre_setfsuid32(...)
+#define __sanitizer_syscall_pre_setgid32(...)
+#define __sanitizer_syscall_pre_setgroups32(...)
+#define __sanitizer_syscall_pre_setregid32(...)
+#define __sanitizer_syscall_pre_setresgid32(...)
+#define __sanitizer_syscall_pre_setresuid32(...)
+#define __sanitizer_syscall_pre_setreuid32(...)
+#define __sanitizer_syscall_pre_set_thread_area(...)
+#define __sanitizer_syscall_pre_setuid32(...)
+#define __sanitizer_syscall_pre_sigaction(...)
+#define __sanitizer_syscall_pre_sigaltstack(...)
+#define __sanitizer_syscall_pre_sigreturn(...)
+#define __sanitizer_syscall_pre_sigsuspend(...)
+#define __sanitizer_syscall_pre_stty(...)
+#define __sanitizer_syscall_pre_sync_file_range(...)
+#define __sanitizer_syscall_pre__sysctl(...)
+#define __sanitizer_syscall_pre_truncate64(...)
+#define __sanitizer_syscall_pre_tuxcall(...)
+#define __sanitizer_syscall_pre_ugetrlimit(...)
+#define __sanitizer_syscall_pre_ulimit(...)
+#define __sanitizer_syscall_pre_umount2(...)
+#define __sanitizer_syscall_pre_vm86(...)
+#define __sanitizer_syscall_pre_vm86old(...)
+#define __sanitizer_syscall_pre_vserver(...)
+
+#define __sanitizer_syscall_post_afs_syscall(res, ...)
+#define __sanitizer_syscall_post_arch_prctl(res, ...)
+#define __sanitizer_syscall_post_break(res, ...)
+#define __sanitizer_syscall_post_chown32(res, ...)
+#define __sanitizer_syscall_post_clone(res, ...)
+#define __sanitizer_syscall_post_create_module(res, ...)
+#define __sanitizer_syscall_post_epoll_ctl_old(res, ...)
+#define __sanitizer_syscall_post_epoll_wait_old(res, ...)
+#define __sanitizer_syscall_post_execve(res, ...)
+#define __sanitizer_syscall_post_fadvise64(res, ...)
+#define __sanitizer_syscall_post_fadvise64_64(res, ...)
+#define __sanitizer_syscall_post_fallocate(res, ...)
+#define __sanitizer_syscall_post_fanotify_init(res, ...)
+#define __sanitizer_syscall_post_fanotify_mark(res, ...)
+#define __sanitizer_syscall_post_fchown32(res, ...)
+#define __sanitizer_syscall_post_ftime(res, ...)
+#define __sanitizer_syscall_post_ftruncate64(res, ...)
+#define __sanitizer_syscall_post_futex(res, ...)
+#define __sanitizer_syscall_post_getegid32(res, ...)
+#define __sanitizer_syscall_post_geteuid32(res, ...)
+#define __sanitizer_syscall_post_getgid32(res, ...)
+#define __sanitizer_syscall_post_getgroups32(res, ...)
+#define __sanitizer_syscall_post_get_kernel_syms(res, ...)
+#define __sanitizer_syscall_post_getpmsg(res, ...)
+#define __sanitizer_syscall_post_getresgid32(res, ...)
+#define __sanitizer_syscall_post_getresuid32(res, ...)
+#define __sanitizer_syscall_post_get_thread_area(res, ...)
+#define __sanitizer_syscall_post_getuid32(res, ...)
+#define __sanitizer_syscall_post_gtty(res, ...)
+#define __sanitizer_syscall_post_idle(res, ...)
+#define __sanitizer_syscall_post_iopl(res, ...)
+#define __sanitizer_syscall_post_lchown32(res, ...)
+#define __sanitizer_syscall_post__llseek(res, ...)
+#define __sanitizer_syscall_post_lock(res, ...)
+#define __sanitizer_syscall_post_madvise1(res, ...)
+#define __sanitizer_syscall_post_mmap2(res, ...)
+#define __sanitizer_syscall_post_mmap(res, ...)
+#define __sanitizer_syscall_post_modify_ldt(res, ...)
+#define __sanitizer_syscall_post_mpx(res, ...)
+#define __sanitizer_syscall_post__newselect(res, ...)
+#define __sanitizer_syscall_post_nfsservctl(res, ...)
+#define __sanitizer_syscall_post_oldfstat(res, ...)
+#define __sanitizer_syscall_post_oldlstat(res, ...)
+#define __sanitizer_syscall_post_oldolduname(res, ...)
+#define __sanitizer_syscall_post_oldstat(res, ...)
+#define __sanitizer_syscall_post_prctl(res, ...)
+#define __sanitizer_syscall_post_profil(res, ...)
+#define __sanitizer_syscall_post_prof(res, ...)
+#define __sanitizer_syscall_post_putpmsg(res, ...)
+#define __sanitizer_syscall_post_query_module(res, ...)
+#define __sanitizer_syscall_post_readahead(res, ...)
+#define __sanitizer_syscall_post_readdir(res, ...)
+#define __sanitizer_syscall_post_rt_sigaction(res, ...)
+#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
+#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_security(res, ...)
+#define __sanitizer_syscall_post_setfsgid32(res, ...)
+#define __sanitizer_syscall_post_setfsuid32(res, ...)
+#define __sanitizer_syscall_post_setgid32(res, ...)
+#define __sanitizer_syscall_post_setgroups32(res, ...)
+#define __sanitizer_syscall_post_setregid32(res, ...)
+#define __sanitizer_syscall_post_setresgid32(res, ...)
+#define __sanitizer_syscall_post_setresuid32(res, ...)
+#define __sanitizer_syscall_post_setreuid32(res, ...)
+#define __sanitizer_syscall_post_set_thread_area(res, ...)
+#define __sanitizer_syscall_post_setuid32(res, ...)
+#define __sanitizer_syscall_post_sigaction(res, ...)
+#define __sanitizer_syscall_post_sigaltstack(res, ...)
+#define __sanitizer_syscall_post_sigreturn(res, ...)
+#define __sanitizer_syscall_post_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_stty(res, ...)
+#define __sanitizer_syscall_post_sync_file_range(res, ...)
+#define __sanitizer_syscall_post__sysctl(res, ...)
+#define __sanitizer_syscall_post_truncate64(res, ...)
+#define __sanitizer_syscall_post_tuxcall(res, ...)
+#define __sanitizer_syscall_post_ugetrlimit(res, ...)
+#define __sanitizer_syscall_post_ulimit(res, ...)
+#define __sanitizer_syscall_post_umount2(res, ...)
+#define __sanitizer_syscall_post_vm86old(res, ...)
+#define __sanitizer_syscall_post_vm86(res, ...)
+#define __sanitizer_syscall_post_vserver(res, ...)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Private declarations. Do not call directly from user code. Use macros above.
+void __sanitizer_syscall_pre_impl_time(long tloc);
+void __sanitizer_syscall_post_impl_time(long res, long tloc);
+void __sanitizer_syscall_pre_impl_stime(long tptr);
+void __sanitizer_syscall_post_impl_stime(long res, long tptr);
+void __sanitizer_syscall_pre_impl_gettimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_gettimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_settimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_settimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_adjtimex(long txc_p);
+void __sanitizer_syscall_post_impl_adjtimex(long res, long txc_p);
+void __sanitizer_syscall_pre_impl_times(long tbuf);
+void __sanitizer_syscall_post_impl_times(long res, long tbuf);
+void __sanitizer_syscall_pre_impl_gettid();
+void __sanitizer_syscall_post_impl_gettid(long res);
+void __sanitizer_syscall_pre_impl_nanosleep(long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_nanosleep(long res, long rqtp, long rmtp);
+void __sanitizer_syscall_pre_impl_alarm(long seconds);
+void __sanitizer_syscall_post_impl_alarm(long res, long seconds);
+void __sanitizer_syscall_pre_impl_getpid();
+void __sanitizer_syscall_post_impl_getpid(long res);
+void __sanitizer_syscall_pre_impl_getppid();
+void __sanitizer_syscall_post_impl_getppid(long res);
+void __sanitizer_syscall_pre_impl_getuid();
+void __sanitizer_syscall_post_impl_getuid(long res);
+void __sanitizer_syscall_pre_impl_geteuid();
+void __sanitizer_syscall_post_impl_geteuid(long res);
+void __sanitizer_syscall_pre_impl_getgid();
+void __sanitizer_syscall_post_impl_getgid(long res);
+void __sanitizer_syscall_pre_impl_getegid();
+void __sanitizer_syscall_post_impl_getegid(long res);
+void __sanitizer_syscall_pre_impl_getresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getpgid(long pid);
+void __sanitizer_syscall_post_impl_getpgid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getpgrp();
+void __sanitizer_syscall_post_impl_getpgrp(long res);
+void __sanitizer_syscall_pre_impl_getsid(long pid);
+void __sanitizer_syscall_post_impl_getsid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setregid(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid(long gid);
+void __sanitizer_syscall_post_impl_setgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid(long uid);
+void __sanitizer_syscall_post_impl_setuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid(long uid);
+void __sanitizer_syscall_post_impl_setfsuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid(long gid);
+void __sanitizer_syscall_post_impl_setfsgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setpgid(long pid, long pgid);
+void __sanitizer_syscall_post_impl_setpgid(long res, long pid, long pgid);
+void __sanitizer_syscall_pre_impl_setsid();
+void __sanitizer_syscall_post_impl_setsid(long res);
+void __sanitizer_syscall_pre_impl_setgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_acct(long name);
+void __sanitizer_syscall_post_impl_acct(long res, long name);
+void __sanitizer_syscall_pre_impl_capget(long header, long dataptr);
+void __sanitizer_syscall_post_impl_capget(long res, long header, long dataptr);
+void __sanitizer_syscall_pre_impl_capset(long header, long data);
+void __sanitizer_syscall_post_impl_capset(long res, long header, long data);
+void __sanitizer_syscall_pre_impl_personality(long personality);
+void __sanitizer_syscall_post_impl_personality(long res, long personality);
+void __sanitizer_syscall_pre_impl_sigpending(long set);
+void __sanitizer_syscall_post_impl_sigpending(long res, long set);
+void __sanitizer_syscall_pre_impl_sigprocmask(long how, long set, long oset);
+void __sanitizer_syscall_post_impl_sigprocmask(long res, long how, long set,
+ long oset);
+void __sanitizer_syscall_pre_impl_getitimer(long which, long value);
+void __sanitizer_syscall_post_impl_getitimer(long res, long which, long value);
+void __sanitizer_syscall_pre_impl_setitimer(long which, long value,
+ long ovalue);
+void __sanitizer_syscall_post_impl_setitimer(long res, long which, long value,
+ long ovalue);
+void __sanitizer_syscall_pre_impl_timer_create(long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_post_impl_timer_create(long res, long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_pre_impl_timer_gettime(long timer_id, long setting);
+void __sanitizer_syscall_post_impl_timer_gettime(long res, long timer_id,
+ long setting);
+void __sanitizer_syscall_pre_impl_timer_getoverrun(long timer_id);
+void __sanitizer_syscall_post_impl_timer_getoverrun(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_timer_settime(long timer_id, long flags,
+ long new_setting,
+ long old_setting);
+void __sanitizer_syscall_post_impl_timer_settime(long res, long timer_id,
+ long flags, long new_setting,
+ long old_setting);
+void __sanitizer_syscall_pre_impl_timer_delete(long timer_id);
+void __sanitizer_syscall_post_impl_timer_delete(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_clock_settime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_settime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_gettime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_gettime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_adjtime(long which_clock, long tx);
+void __sanitizer_syscall_post_impl_clock_adjtime(long res, long which_clock,
+ long tx);
+void __sanitizer_syscall_pre_impl_clock_getres(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_getres(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_nanosleep(long which_clock, long flags,
+ long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_clock_nanosleep(long res, long which_clock,
+ long flags, long rqtp,
+ long rmtp);
+void __sanitizer_syscall_pre_impl_nice(long increment);
+void __sanitizer_syscall_post_impl_nice(long res, long increment);
+void __sanitizer_syscall_pre_impl_sched_setscheduler(long pid, long policy,
+ long param);
+void __sanitizer_syscall_post_impl_sched_setscheduler(long res, long pid,
+ long policy, long param);
+void __sanitizer_syscall_pre_impl_sched_setparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_setparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_getscheduler(long pid);
+void __sanitizer_syscall_post_impl_sched_getscheduler(long res, long pid);
+void __sanitizer_syscall_pre_impl_sched_getparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_getparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_setaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_setaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_getaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_getaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_yield();
+void __sanitizer_syscall_post_impl_sched_yield(long res);
+void __sanitizer_syscall_pre_impl_sched_get_priority_max(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_max(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_get_priority_min(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_min(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_rr_get_interval(long pid,
+ long interval);
+void __sanitizer_syscall_post_impl_sched_rr_get_interval(long res, long pid,
+ long interval);
+void __sanitizer_syscall_pre_impl_setpriority(long which, long who,
+ long niceval);
+void __sanitizer_syscall_post_impl_setpriority(long res, long which, long who,
+ long niceval);
+void __sanitizer_syscall_pre_impl_getpriority(long which, long who);
+void __sanitizer_syscall_post_impl_getpriority(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_shutdown(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_shutdown(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_reboot(long magic1, long magic2, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_reboot(long res, long magic1, long magic2,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_restart_syscall();
+void __sanitizer_syscall_post_impl_restart_syscall(long res);
+void __sanitizer_syscall_pre_impl_kexec_load(long entry, long nr_segments,
+ long segments, long flags);
+void __sanitizer_syscall_post_impl_kexec_load(long res, long entry,
+ long nr_segments, long segments,
+ long flags);
+void __sanitizer_syscall_pre_impl_exit(long error_code);
+void __sanitizer_syscall_post_impl_exit(long res, long error_code);
+void __sanitizer_syscall_pre_impl_exit_group(long error_code);
+void __sanitizer_syscall_post_impl_exit_group(long res, long error_code);
+void __sanitizer_syscall_pre_impl_wait4(long pid, long stat_addr, long options,
+ long ru);
+void __sanitizer_syscall_post_impl_wait4(long res, long pid, long stat_addr,
+ long options, long ru);
+void __sanitizer_syscall_pre_impl_waitid(long which, long pid, long infop,
+ long options, long ru);
+void __sanitizer_syscall_post_impl_waitid(long res, long which, long pid,
+ long infop, long options, long ru);
+void __sanitizer_syscall_pre_impl_waitpid(long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_post_impl_waitpid(long res, long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_pre_impl_set_tid_address(long tidptr);
+void __sanitizer_syscall_post_impl_set_tid_address(long res, long tidptr);
+void __sanitizer_syscall_pre_impl_init_module(long umod, long len, long uargs);
+void __sanitizer_syscall_post_impl_init_module(long res, long umod, long len,
+ long uargs);
+void __sanitizer_syscall_pre_impl_delete_module(long name_user, long flags);
+void __sanitizer_syscall_post_impl_delete_module(long res, long name_user,
+ long flags);
+void __sanitizer_syscall_pre_impl_rt_sigprocmask(long how, long set, long oset,
+ long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigprocmask(long res, long how, long set,
+ long oset, long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigpending(long set, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigpending(long res, long set,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigtimedwait(long uthese, long uinfo,
+ long uts, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigtimedwait(long res, long uthese,
+ long uinfo, long uts,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo(long tgid, long pid,
+ long sig, long uinfo);
+void __sanitizer_syscall_post_impl_rt_tgsigqueueinfo(long res, long tgid,
+ long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_kill(long pid, long sig);
+void __sanitizer_syscall_post_impl_kill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_tgkill(long tgid, long pid, long sig);
+void __sanitizer_syscall_post_impl_tgkill(long res, long tgid, long pid,
+ long sig);
+void __sanitizer_syscall_pre_impl_tkill(long pid, long sig);
+void __sanitizer_syscall_post_impl_tkill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_rt_sigqueueinfo(long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_post_impl_rt_sigqueueinfo(long res, long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_sgetmask();
+void __sanitizer_syscall_post_impl_sgetmask(long res);
+void __sanitizer_syscall_pre_impl_ssetmask(long newmask);
+void __sanitizer_syscall_post_impl_ssetmask(long res, long newmask);
+void __sanitizer_syscall_pre_impl_signal(long sig, long handler);
+void __sanitizer_syscall_post_impl_signal(long res, long sig, long handler);
+void __sanitizer_syscall_pre_impl_pause();
+void __sanitizer_syscall_post_impl_pause(long res);
+void __sanitizer_syscall_pre_impl_sync();
+void __sanitizer_syscall_post_impl_sync(long res);
+void __sanitizer_syscall_pre_impl_fsync(long fd);
+void __sanitizer_syscall_post_impl_fsync(long res, long fd);
+void __sanitizer_syscall_pre_impl_fdatasync(long fd);
+void __sanitizer_syscall_post_impl_fdatasync(long res, long fd);
+void __sanitizer_syscall_pre_impl_bdflush(long func, long data);
+void __sanitizer_syscall_post_impl_bdflush(long res, long func, long data);
+void __sanitizer_syscall_pre_impl_mount(long dev_name, long dir_name, long type,
+ long flags, long data);
+void __sanitizer_syscall_post_impl_mount(long res, long dev_name, long dir_name,
+ long type, long flags, long data);
+void __sanitizer_syscall_pre_impl_umount(long name, long flags);
+void __sanitizer_syscall_post_impl_umount(long res, long name, long flags);
+void __sanitizer_syscall_pre_impl_oldumount(long name);
+void __sanitizer_syscall_post_impl_oldumount(long res, long name);
+void __sanitizer_syscall_pre_impl_truncate(long path, long length);
+void __sanitizer_syscall_post_impl_truncate(long res, long path, long length);
+void __sanitizer_syscall_pre_impl_ftruncate(long fd, long length);
+void __sanitizer_syscall_post_impl_ftruncate(long res, long fd, long length);
+void __sanitizer_syscall_pre_impl_stat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_statfs(long path, long buf);
+void __sanitizer_syscall_post_impl_statfs(long res, long path, long buf);
+void __sanitizer_syscall_pre_impl_statfs64(long path, long sz, long buf);
+void __sanitizer_syscall_post_impl_statfs64(long res, long path, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_fstatfs(long fd, long buf);
+void __sanitizer_syscall_post_impl_fstatfs(long res, long fd, long buf);
+void __sanitizer_syscall_pre_impl_fstatfs64(long fd, long sz, long buf);
+void __sanitizer_syscall_post_impl_fstatfs64(long res, long fd, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_lstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_fstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_newstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newlstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newlstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newfstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_newfstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_ustat(long dev, long ubuf);
+void __sanitizer_syscall_post_impl_ustat(long res, long dev, long ubuf);
+void __sanitizer_syscall_pre_impl_stat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_fstat64(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat64(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_lstat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_setxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_setxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_lsetxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_lsetxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_fsetxattr(long fd, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_fsetxattr(long res, long fd, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_getxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_getxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_lgetxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_lgetxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_fgetxattr(long fd, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_fgetxattr(long res, long fd, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_listxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_listxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_llistxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_llistxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_flistxattr(long fd, long list, long size);
+void __sanitizer_syscall_post_impl_flistxattr(long res, long fd, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_removexattr(long path, long name);
+void __sanitizer_syscall_post_impl_removexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_lremovexattr(long path, long name);
+void __sanitizer_syscall_post_impl_lremovexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_fremovexattr(long fd, long name);
+void __sanitizer_syscall_post_impl_fremovexattr(long res, long fd, long name);
+void __sanitizer_syscall_pre_impl_brk(long brk);
+void __sanitizer_syscall_post_impl_brk(long res, long brk);
+void __sanitizer_syscall_pre_impl_mprotect(long start, long len, long prot);
+void __sanitizer_syscall_post_impl_mprotect(long res, long start, long len,
+ long prot);
+void __sanitizer_syscall_pre_impl_mremap(long addr, long old_len, long new_len,
+ long flags, long new_addr);
+void __sanitizer_syscall_post_impl_mremap(long res, long addr, long old_len,
+ long new_len, long flags,
+ long new_addr);
+void __sanitizer_syscall_pre_impl_remap_file_pages(long start, long size,
+ long prot, long pgoff,
+ long flags);
+void __sanitizer_syscall_post_impl_remap_file_pages(long res, long start,
+ long size, long prot,
+ long pgoff, long flags);
+void __sanitizer_syscall_pre_impl_msync(long start, long len, long flags);
+void __sanitizer_syscall_post_impl_msync(long res, long start, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_munmap(long addr, long len);
+void __sanitizer_syscall_post_impl_munmap(long res, long addr, long len);
+void __sanitizer_syscall_pre_impl_mlock(long start, long len);
+void __sanitizer_syscall_post_impl_mlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_munlock(long start, long len);
+void __sanitizer_syscall_post_impl_munlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_mlockall(long flags);
+void __sanitizer_syscall_post_impl_mlockall(long res, long flags);
+void __sanitizer_syscall_pre_impl_munlockall();
+void __sanitizer_syscall_post_impl_munlockall(long res);
+void __sanitizer_syscall_pre_impl_madvise(long start, long len, long behavior);
+void __sanitizer_syscall_post_impl_madvise(long res, long start, long len,
+ long behavior);
+void __sanitizer_syscall_pre_impl_mincore(long start, long len, long vec);
+void __sanitizer_syscall_post_impl_mincore(long res, long start, long len,
+ long vec);
+void __sanitizer_syscall_pre_impl_pivot_root(long new_root, long put_old);
+void __sanitizer_syscall_post_impl_pivot_root(long res, long new_root,
+ long put_old);
+void __sanitizer_syscall_pre_impl_chroot(long filename);
+void __sanitizer_syscall_post_impl_chroot(long res, long filename);
+void __sanitizer_syscall_pre_impl_mknod(long filename, long mode, long dev);
+void __sanitizer_syscall_post_impl_mknod(long res, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_pre_impl_link(long oldname, long newname);
+void __sanitizer_syscall_post_impl_link(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_symlink(long old, long new_);
+void __sanitizer_syscall_post_impl_symlink(long res, long old, long new_);
+void __sanitizer_syscall_pre_impl_unlink(long pathname);
+void __sanitizer_syscall_post_impl_unlink(long res, long pathname);
+void __sanitizer_syscall_pre_impl_rename(long oldname, long newname);
+void __sanitizer_syscall_post_impl_rename(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_chmod(long filename, long mode);
+void __sanitizer_syscall_post_impl_chmod(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_fchmod(long fd, long mode);
+void __sanitizer_syscall_post_impl_fchmod(long res, long fd, long mode);
+void __sanitizer_syscall_pre_impl_fcntl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_fcntl64(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl64(long res, long fd, long cmd,
+ long arg);
+void __sanitizer_syscall_pre_impl_pipe(long fildes);
+void __sanitizer_syscall_post_impl_pipe(long res, long fildes);
+void __sanitizer_syscall_pre_impl_pipe2(long fildes, long flags);
+void __sanitizer_syscall_post_impl_pipe2(long res, long fildes, long flags);
+void __sanitizer_syscall_pre_impl_dup(long fildes);
+void __sanitizer_syscall_post_impl_dup(long res, long fildes);
+void __sanitizer_syscall_pre_impl_dup2(long oldfd, long newfd);
+void __sanitizer_syscall_post_impl_dup2(long res, long oldfd, long newfd);
+void __sanitizer_syscall_pre_impl_dup3(long oldfd, long newfd, long flags);
+void __sanitizer_syscall_post_impl_dup3(long res, long oldfd, long newfd,
+ long flags);
+void __sanitizer_syscall_pre_impl_ioperm(long from, long num, long on);
+void __sanitizer_syscall_post_impl_ioperm(long res, long from, long num,
+ long on);
+void __sanitizer_syscall_pre_impl_ioctl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_ioctl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_flock(long fd, long cmd);
+void __sanitizer_syscall_post_impl_flock(long res, long fd, long cmd);
+void __sanitizer_syscall_pre_impl_io_setup(long nr_reqs, long ctx);
+void __sanitizer_syscall_post_impl_io_setup(long res, long nr_reqs, long ctx);
+void __sanitizer_syscall_pre_impl_io_destroy(long ctx);
+void __sanitizer_syscall_post_impl_io_destroy(long res, long ctx);
+void __sanitizer_syscall_pre_impl_io_getevents(long ctx_id, long min_nr,
+ long nr, long events,
+ long timeout);
+void __sanitizer_syscall_post_impl_io_getevents(long res, long ctx_id,
+ long min_nr, long nr,
+ long events, long timeout);
+void __sanitizer_syscall_pre_impl_io_submit(long ctx_id, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_io_submit(long res, long ctx_id, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_io_cancel(long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_post_impl_io_cancel(long res, long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_pre_impl_sendfile(long out_fd, long in_fd, long offset,
+ long count);
+void __sanitizer_syscall_post_impl_sendfile(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_sendfile64(long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_post_impl_sendfile64(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_readlink(long path, long buf, long bufsiz);
+void __sanitizer_syscall_post_impl_readlink(long res, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_pre_impl_creat(long pathname, long mode);
+void __sanitizer_syscall_post_impl_creat(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_open(long filename, long flags, long mode);
+void __sanitizer_syscall_post_impl_open(long res, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_pre_impl_close(long fd);
+void __sanitizer_syscall_post_impl_close(long res, long fd);
+void __sanitizer_syscall_pre_impl_access(long filename, long mode);
+void __sanitizer_syscall_post_impl_access(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_vhangup();
+void __sanitizer_syscall_post_impl_vhangup(long res);
+void __sanitizer_syscall_pre_impl_chown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_lchown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_chown16(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown16(long filename, long user,
+ long group);
+void __sanitizer_syscall_post_impl_lchown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown16(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown16(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_setregid16(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid16(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid16(long gid);
+void __sanitizer_syscall_post_impl_setgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid16(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid16(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid16(long uid);
+void __sanitizer_syscall_post_impl_setuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid16(long uid);
+void __sanitizer_syscall_post_impl_setfsuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid16(long gid);
+void __sanitizer_syscall_post_impl_setfsgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_getgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_getuid16();
+void __sanitizer_syscall_post_impl_getuid16(long res);
+void __sanitizer_syscall_pre_impl_geteuid16();
+void __sanitizer_syscall_post_impl_geteuid16(long res);
+void __sanitizer_syscall_pre_impl_getgid16();
+void __sanitizer_syscall_post_impl_getgid16(long res);
+void __sanitizer_syscall_pre_impl_getegid16();
+void __sanitizer_syscall_post_impl_getegid16(long res);
+void __sanitizer_syscall_pre_impl_utime(long filename, long times);
+void __sanitizer_syscall_post_impl_utime(long res, long filename, long times);
+void __sanitizer_syscall_pre_impl_utimes(long filename, long utimes);
+void __sanitizer_syscall_post_impl_utimes(long res, long filename, long utimes);
+void __sanitizer_syscall_pre_impl_lseek(long fd, long offset, long origin);
+void __sanitizer_syscall_post_impl_lseek(long res, long fd, long offset,
+ long origin);
+void __sanitizer_syscall_pre_impl_llseek(long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_post_impl_llseek(long res, long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_pre_impl_read(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_read(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_readv(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_readv(long res, long fd, long vec,
+ long vlen);
+void __sanitizer_syscall_pre_impl_write(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_write(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_writev(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_writev(long res, long fd, long vec,
+ long vlen);
+
+#ifdef _LP64
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos);
+#else
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+#endif
+
+void __sanitizer_syscall_pre_impl_preadv(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_preadv(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_pwritev(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_pwritev(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_getcwd(long buf, long size);
+void __sanitizer_syscall_post_impl_getcwd(long res, long buf, long size);
+void __sanitizer_syscall_pre_impl_mkdir(long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdir(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_chdir(long filename);
+void __sanitizer_syscall_post_impl_chdir(long res, long filename);
+void __sanitizer_syscall_pre_impl_fchdir(long fd);
+void __sanitizer_syscall_post_impl_fchdir(long res, long fd);
+void __sanitizer_syscall_pre_impl_rmdir(long pathname);
+void __sanitizer_syscall_post_impl_rmdir(long res, long pathname);
+void __sanitizer_syscall_pre_impl_lookup_dcookie(long cookie64, long buf,
+ long len);
+void __sanitizer_syscall_post_impl_lookup_dcookie(long res, long cookie64,
+ long buf, long len);
+void __sanitizer_syscall_pre_impl_quotactl(long cmd, long special, long id,
+ long addr);
+void __sanitizer_syscall_post_impl_quotactl(long res, long cmd, long special,
+ long id, long addr);
+void __sanitizer_syscall_pre_impl_getdents(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_getdents64(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents64(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_setsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_setsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_getsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_getsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_bind(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_bind(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_connect(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_connect(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_accept(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept4(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_accept4(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_getsockname(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getsockname(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_getpeername(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getpeername(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_send(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_send(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_sendto(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_sendto(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_sendmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_sendmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_sendmmsg(long fd, long msg, long vlen,
+ long flags);
+void __sanitizer_syscall_post_impl_sendmmsg(long res, long fd, long msg,
+ long vlen, long flags);
+void __sanitizer_syscall_pre_impl_recv(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_recv(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_recvfrom(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_recvfrom(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_recvmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_recvmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_recvmmsg(long fd, long msg, long vlen,
+ long flags, long timeout);
+void __sanitizer_syscall_post_impl_recvmmsg(long res, long fd, long msg,
+ long vlen, long flags,
+ long timeout);
+void __sanitizer_syscall_pre_impl_socket(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_socket(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_socketpair(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_socketpair(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_socketcall(long call, long args);
+void __sanitizer_syscall_post_impl_socketcall(long res, long call, long args);
+void __sanitizer_syscall_pre_impl_listen(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_listen(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_poll(long ufds, long nfds, long timeout);
+void __sanitizer_syscall_post_impl_poll(long res, long ufds, long nfds,
+ long timeout);
+void __sanitizer_syscall_pre_impl_select(long n, long inp, long outp, long exp,
+ long tvp);
+void __sanitizer_syscall_post_impl_select(long res, long n, long inp, long outp,
+ long exp, long tvp);
+void __sanitizer_syscall_pre_impl_old_select(long arg);
+void __sanitizer_syscall_post_impl_old_select(long res, long arg);
+void __sanitizer_syscall_pre_impl_epoll_create(long size);
+void __sanitizer_syscall_post_impl_epoll_create(long res, long size);
+void __sanitizer_syscall_pre_impl_epoll_create1(long flags);
+void __sanitizer_syscall_post_impl_epoll_create1(long res, long flags);
+void __sanitizer_syscall_pre_impl_epoll_ctl(long epfd, long op, long fd,
+ long event);
+void __sanitizer_syscall_post_impl_epoll_ctl(long res, long epfd, long op,
+ long fd, long event);
+void __sanitizer_syscall_pre_impl_epoll_wait(long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_post_impl_epoll_wait(long res, long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_pre_impl_epoll_pwait(long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_post_impl_epoll_pwait(long res, long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_pre_impl_gethostname(long name, long len);
+void __sanitizer_syscall_post_impl_gethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_sethostname(long name, long len);
+void __sanitizer_syscall_post_impl_sethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_setdomainname(long name, long len);
+void __sanitizer_syscall_post_impl_setdomainname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_newuname(long name);
+void __sanitizer_syscall_post_impl_newuname(long res, long name);
+void __sanitizer_syscall_pre_impl_uname(long arg0);
+void __sanitizer_syscall_post_impl_uname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_olduname(long arg0);
+void __sanitizer_syscall_post_impl_olduname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_old_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_old_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_setrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_setrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_prlimit64(long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_post_impl_prlimit64(long res, long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_pre_impl_getrusage(long who, long ru);
+void __sanitizer_syscall_post_impl_getrusage(long res, long who, long ru);
+void __sanitizer_syscall_pre_impl_umask(long mask);
+void __sanitizer_syscall_post_impl_umask(long res, long mask);
+void __sanitizer_syscall_pre_impl_msgget(long key, long msgflg);
+void __sanitizer_syscall_post_impl_msgget(long res, long key, long msgflg);
+void __sanitizer_syscall_pre_impl_msgsnd(long msqid, long msgp, long msgsz,
+ long msgflg);
+void __sanitizer_syscall_post_impl_msgsnd(long res, long msqid, long msgp,
+ long msgsz, long msgflg);
+void __sanitizer_syscall_pre_impl_msgrcv(long msqid, long msgp, long msgsz,
+ long msgtyp, long msgflg);
+void __sanitizer_syscall_post_impl_msgrcv(long res, long msqid, long msgp,
+ long msgsz, long msgtyp, long msgflg);
+void __sanitizer_syscall_pre_impl_msgctl(long msqid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_msgctl(long res, long msqid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_semget(long key, long nsems, long semflg);
+void __sanitizer_syscall_post_impl_semget(long res, long key, long nsems,
+ long semflg);
+void __sanitizer_syscall_pre_impl_semop(long semid, long sops, long nsops);
+void __sanitizer_syscall_post_impl_semop(long res, long semid, long sops,
+ long nsops);
+void __sanitizer_syscall_pre_impl_semctl(long semid, long semnum, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_semctl(long res, long semid, long semnum,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_semtimedop(long semid, long sops, long nsops,
+ long timeout);
+void __sanitizer_syscall_post_impl_semtimedop(long res, long semid, long sops,
+ long nsops, long timeout);
+void __sanitizer_syscall_pre_impl_shmat(long shmid, long shmaddr, long shmflg);
+void __sanitizer_syscall_post_impl_shmat(long res, long shmid, long shmaddr,
+ long shmflg);
+void __sanitizer_syscall_pre_impl_shmget(long key, long size, long flag);
+void __sanitizer_syscall_post_impl_shmget(long res, long key, long size,
+ long flag);
+void __sanitizer_syscall_pre_impl_shmdt(long shmaddr);
+void __sanitizer_syscall_post_impl_shmdt(long res, long shmaddr);
+void __sanitizer_syscall_pre_impl_shmctl(long shmid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_shmctl(long res, long shmid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_ipc(long call, long first, long second,
+ long third, long ptr, long fifth);
+void __sanitizer_syscall_post_impl_ipc(long res, long call, long first,
+ long second, long third, long ptr,
+ long fifth);
+void __sanitizer_syscall_pre_impl_mq_open(long name, long oflag, long mode,
+ long attr);
+void __sanitizer_syscall_post_impl_mq_open(long res, long name, long oflag,
+ long mode, long attr);
+void __sanitizer_syscall_pre_impl_mq_unlink(long name);
+void __sanitizer_syscall_post_impl_mq_unlink(long res, long name);
+void __sanitizer_syscall_pre_impl_mq_timedsend(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedsend(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_timedreceive(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedreceive(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_notify(long mqdes, long notification);
+void __sanitizer_syscall_post_impl_mq_notify(long res, long mqdes,
+ long notification);
+void __sanitizer_syscall_pre_impl_mq_getsetattr(long mqdes, long mqstat,
+ long omqstat);
+void __sanitizer_syscall_post_impl_mq_getsetattr(long res, long mqdes,
+ long mqstat, long omqstat);
+void __sanitizer_syscall_pre_impl_pciconfig_iobase(long which, long bus,
+ long devfn);
+void __sanitizer_syscall_post_impl_pciconfig_iobase(long res, long which,
+ long bus, long devfn);
+void __sanitizer_syscall_pre_impl_pciconfig_read(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_read(long res, long bus, long dfn,
+ long off, long len, long buf);
+void __sanitizer_syscall_pre_impl_pciconfig_write(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_write(long res, long bus, long dfn,
+ long off, long len,
+ long buf);
+void __sanitizer_syscall_pre_impl_swapon(long specialfile, long swap_flags);
+void __sanitizer_syscall_post_impl_swapon(long res, long specialfile,
+ long swap_flags);
+void __sanitizer_syscall_pre_impl_swapoff(long specialfile);
+void __sanitizer_syscall_post_impl_swapoff(long res, long specialfile);
+void __sanitizer_syscall_pre_impl_sysctl(long args);
+void __sanitizer_syscall_post_impl_sysctl(long res, long args);
+void __sanitizer_syscall_pre_impl_sysinfo(long info);
+void __sanitizer_syscall_post_impl_sysinfo(long res, long info);
+void __sanitizer_syscall_pre_impl_sysfs(long option, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_sysfs(long res, long option, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_syslog(long type, long buf, long len);
+void __sanitizer_syscall_post_impl_syslog(long res, long type, long buf,
+ long len);
+void __sanitizer_syscall_pre_impl_uselib(long library);
+void __sanitizer_syscall_post_impl_uselib(long res, long library);
+void __sanitizer_syscall_pre_impl_ni_syscall();
+void __sanitizer_syscall_post_impl_ni_syscall(long res);
+void __sanitizer_syscall_pre_impl_ptrace(long request, long pid, long addr,
+ long data);
+void __sanitizer_syscall_post_impl_ptrace(long res, long request, long pid,
+ long addr, long data);
+void __sanitizer_syscall_pre_impl_add_key(long _type, long _description,
+ long _payload, long plen,
+ long destringid);
+void __sanitizer_syscall_post_impl_add_key(long res, long _type,
+ long _description, long _payload,
+ long plen, long destringid);
+void __sanitizer_syscall_pre_impl_request_key(long _type, long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_post_impl_request_key(long res, long _type,
+ long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_pre_impl_keyctl(long cmd, long arg2, long arg3,
+ long arg4, long arg5);
+void __sanitizer_syscall_post_impl_keyctl(long res, long cmd, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_pre_impl_ioprio_set(long which, long who, long ioprio);
+void __sanitizer_syscall_post_impl_ioprio_set(long res, long which, long who,
+ long ioprio);
+void __sanitizer_syscall_pre_impl_ioprio_get(long which, long who);
+void __sanitizer_syscall_post_impl_ioprio_get(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_set_mempolicy(long mode, long nmask,
+ long maxnode);
+void __sanitizer_syscall_post_impl_set_mempolicy(long res, long mode,
+ long nmask, long maxnode);
+void __sanitizer_syscall_pre_impl_migrate_pages(long pid, long maxnode,
+ long from, long to);
+void __sanitizer_syscall_post_impl_migrate_pages(long res, long pid,
+ long maxnode, long from,
+ long to);
+void __sanitizer_syscall_pre_impl_move_pages(long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_post_impl_move_pages(long res, long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_pre_impl_mbind(long start, long len, long mode,
+ long nmask, long maxnode, long flags);
+void __sanitizer_syscall_post_impl_mbind(long res, long start, long len,
+ long mode, long nmask, long maxnode,
+ long flags);
+void __sanitizer_syscall_pre_impl_get_mempolicy(long policy, long nmask,
+ long maxnode, long addr,
+ long flags);
+void __sanitizer_syscall_post_impl_get_mempolicy(long res, long policy,
+ long nmask, long maxnode,
+ long addr, long flags);
+void __sanitizer_syscall_pre_impl_inotify_init();
+void __sanitizer_syscall_post_impl_inotify_init(long res);
+void __sanitizer_syscall_pre_impl_inotify_init1(long flags);
+void __sanitizer_syscall_post_impl_inotify_init1(long res, long flags);
+void __sanitizer_syscall_pre_impl_inotify_add_watch(long fd, long path,
+ long mask);
+void __sanitizer_syscall_post_impl_inotify_add_watch(long res, long fd,
+ long path, long mask);
+void __sanitizer_syscall_pre_impl_inotify_rm_watch(long fd, long wd);
+void __sanitizer_syscall_post_impl_inotify_rm_watch(long res, long fd, long wd);
+void __sanitizer_syscall_pre_impl_spu_run(long fd, long unpc, long ustatus);
+void __sanitizer_syscall_post_impl_spu_run(long res, long fd, long unpc,
+ long ustatus);
+void __sanitizer_syscall_pre_impl_spu_create(long name, long flags, long mode,
+ long fd);
+void __sanitizer_syscall_post_impl_spu_create(long res, long name, long flags,
+ long mode, long fd);
+void __sanitizer_syscall_pre_impl_mknodat(long dfd, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_post_impl_mknodat(long res, long dfd, long filename,
+ long mode, long dev);
+void __sanitizer_syscall_pre_impl_mkdirat(long dfd, long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdirat(long res, long dfd, long pathname,
+ long mode);
+void __sanitizer_syscall_pre_impl_unlinkat(long dfd, long pathname, long flag);
+void __sanitizer_syscall_post_impl_unlinkat(long res, long dfd, long pathname,
+ long flag);
+void __sanitizer_syscall_pre_impl_symlinkat(long oldname, long newdfd,
+ long newname);
+void __sanitizer_syscall_post_impl_symlinkat(long res, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_linkat(long olddfd, long oldname, long newdfd,
+ long newname, long flags);
+void __sanitizer_syscall_post_impl_linkat(long res, long olddfd, long oldname,
+ long newdfd, long newname,
+ long flags);
+void __sanitizer_syscall_pre_impl_renameat(long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_post_impl_renameat(long res, long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_futimesat(long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_post_impl_futimesat(long res, long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_pre_impl_faccessat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_faccessat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchmodat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_fchmodat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchownat(long dfd, long filename, long user,
+ long group, long flag);
+void __sanitizer_syscall_post_impl_fchownat(long res, long dfd, long filename,
+ long user, long group, long flag);
+void __sanitizer_syscall_pre_impl_openat(long dfd, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_post_impl_openat(long res, long dfd, long filename,
+ long flags, long mode);
+void __sanitizer_syscall_pre_impl_newfstatat(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_newfstatat(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_fstatat64(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_fstatat64(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_readlinkat(long dfd, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_post_impl_readlinkat(long res, long dfd, long path,
+ long buf, long bufsiz);
+void __sanitizer_syscall_pre_impl_utimensat(long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_post_impl_utimensat(long res, long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_pre_impl_unshare(long unshare_flags);
+void __sanitizer_syscall_post_impl_unshare(long res, long unshare_flags);
+void __sanitizer_syscall_pre_impl_splice(long fd_in, long off_in, long fd_out,
+ long off_out, long len, long flags);
+void __sanitizer_syscall_post_impl_splice(long res, long fd_in, long off_in,
+ long fd_out, long off_out, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_vmsplice(long fd, long iov, long nr_segs,
+ long flags);
+void __sanitizer_syscall_post_impl_vmsplice(long res, long fd, long iov,
+ long nr_segs, long flags);
+void __sanitizer_syscall_pre_impl_tee(long fdin, long fdout, long len,
+ long flags);
+void __sanitizer_syscall_post_impl_tee(long res, long fdin, long fdout,
+ long len, long flags);
+void __sanitizer_syscall_pre_impl_get_robust_list(long pid, long head_ptr,
+ long len_ptr);
+void __sanitizer_syscall_post_impl_get_robust_list(long res, long pid,
+ long head_ptr, long len_ptr);
+void __sanitizer_syscall_pre_impl_set_robust_list(long head, long len);
+void __sanitizer_syscall_post_impl_set_robust_list(long res, long head,
+ long len);
+void __sanitizer_syscall_pre_impl_getcpu(long cpu, long node, long cache);
+void __sanitizer_syscall_post_impl_getcpu(long res, long cpu, long node,
+ long cache);
+void __sanitizer_syscall_pre_impl_signalfd(long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_post_impl_signalfd(long res, long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_pre_impl_signalfd4(long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_post_impl_signalfd4(long res, long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_pre_impl_timerfd_create(long clockid, long flags);
+void __sanitizer_syscall_post_impl_timerfd_create(long res, long clockid,
+ long flags);
+void __sanitizer_syscall_pre_impl_timerfd_settime(long ufd, long flags,
+ long utmr, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_settime(long res, long ufd,
+ long flags, long utmr,
+ long otmr);
+void __sanitizer_syscall_pre_impl_timerfd_gettime(long ufd, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_gettime(long res, long ufd,
+ long otmr);
+void __sanitizer_syscall_pre_impl_eventfd(long count);
+void __sanitizer_syscall_post_impl_eventfd(long res, long count);
+void __sanitizer_syscall_pre_impl_eventfd2(long count, long flags);
+void __sanitizer_syscall_post_impl_eventfd2(long res, long count, long flags);
+void __sanitizer_syscall_pre_impl_old_readdir(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_old_readdir(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_pselect6(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_pselect6(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_ppoll(long arg0, long arg1, long arg2,
+ long arg3, long arg4);
+void __sanitizer_syscall_post_impl_ppoll(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4);
+void __sanitizer_syscall_pre_impl_fanotify_init(long flags, long event_f_flags);
+void __sanitizer_syscall_post_impl_fanotify_init(long res, long flags,
+ long event_f_flags);
+void __sanitizer_syscall_pre_impl_fanotify_mark(long fanotify_fd, long flags,
+ long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_post_impl_fanotify_mark(long res, long fanotify_fd,
+ long flags, long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_pre_impl_syncfs(long fd);
+void __sanitizer_syscall_post_impl_syncfs(long res, long fd);
+void __sanitizer_syscall_pre_impl_perf_event_open(long attr_uptr, long pid,
+ long cpu, long group_fd,
+ long flags);
+void __sanitizer_syscall_post_impl_perf_event_open(long res, long attr_uptr,
+ long pid, long cpu,
+ long group_fd, long flags);
+void __sanitizer_syscall_pre_impl_mmap_pgoff(long addr, long len, long prot,
+ long flags, long fd, long pgoff);
+void __sanitizer_syscall_post_impl_mmap_pgoff(long res, long addr, long len,
+ long prot, long flags, long fd,
+ long pgoff);
+void __sanitizer_syscall_pre_impl_old_mmap(long arg);
+void __sanitizer_syscall_post_impl_old_mmap(long res, long arg);
+void __sanitizer_syscall_pre_impl_name_to_handle_at(long dfd, long name,
+ long handle, long mnt_id,
+ long flag);
+void __sanitizer_syscall_post_impl_name_to_handle_at(long res, long dfd,
+ long name, long handle,
+ long mnt_id, long flag);
+void __sanitizer_syscall_pre_impl_open_by_handle_at(long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_post_impl_open_by_handle_at(long res, long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_pre_impl_setns(long fd, long nstype);
+void __sanitizer_syscall_post_impl_setns(long res, long fd, long nstype);
+void __sanitizer_syscall_pre_impl_process_vm_readv(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_readv(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_process_vm_writev(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_writev(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_fork();
+void __sanitizer_syscall_post_impl_fork(long res);
+void __sanitizer_syscall_pre_impl_vfork();
+void __sanitizer_syscall_post_impl_vfork(long res);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H
diff --git a/compiler-rt/include/sanitizer/lsan_interface.h b/compiler-rt/include/sanitizer/lsan_interface.h
new file mode 100644
index 0000000..8fb8e75
--- /dev/null
+++ b/compiler-rt/include/sanitizer/lsan_interface.h
@@ -0,0 +1,84 @@
+//===-- sanitizer/lsan_interface.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LSAN_INTERFACE_H
+#define SANITIZER_LSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Allocations made between calls to __lsan_disable() and __lsan_enable() will
+ // be treated as non-leaks. Disable/enable pairs may be nested.
+ void __lsan_disable();
+ void __lsan_enable();
+
+ // The heap object into which p points will be treated as a non-leak.
+ void __lsan_ignore_object(const void *p);
+
+ // Memory regions registered through this interface will be treated as sources
+ // of live pointers during leak checking. Useful if you store pointers in
+ // mapped memory.
+ // Points of note:
+ // - __lsan_unregister_root_region() must be called with the same pointer and
+ // size that have earlier been passed to __lsan_register_root_region()
+ // - LSan will skip any inaccessible memory when scanning a root region. E.g.,
+ // if you map memory within a larger region that you have mprotect'ed, you can
+ // register the entire large region.
+ // - the implementation is not optimized for performance. This interface is
+ // intended to be used for a small number of relatively static regions.
+ void __lsan_register_root_region(const void *p, size_t size);
+ void __lsan_unregister_root_region(const void *p, size_t size);
+
+ // Check for leaks now. This function behaves identically to the default
+ // end-of-process leak check. In particular, it will terminate the process if
+ // leaks are found and the exitcode runtime flag is non-zero.
+ // Subsequent calls to this function will have no effect and end-of-process
+ // leak check will not run. Effectively, end-of-process leak check is moved to
+ // the time of first invocation of this function.
+ // By calling this function early during process shutdown, you can instruct
+ // LSan to ignore shutdown-only leaks which happen later on.
+ void __lsan_do_leak_check();
+
+ // Check for leaks now. Returns zero if no leaks have been found or if leak
+ // detection is disabled, non-zero otherwise.
+ // This function may be called repeatedly, e.g. to periodically check a
+ // long-running process. It prints a leak report if appropriate, but does not
+ // terminate the process. It does not affect the behavior of
+ // __lsan_do_leak_check() or the end-of-process leak check, and is not
+ // affected by them.
+ int __lsan_do_recoverable_leak_check();
+
+ // The user may optionally provide this function to disallow leak checking
+ // for the program it is linked into (if the return value is non-zero). This
+ // function must be defined as returning a constant value; any behavior beyond
+ // that is unsupported.
+ int __lsan_is_turned_off();
+
+ // This function may be optionally provided by the user and should return
+ // a string containing LSan suppressions.
+ const char *__lsan_default_suppressions();
+#ifdef __cplusplus
+} // extern "C"
+
+namespace __lsan {
+class ScopedDisabler {
+ public:
+ ScopedDisabler() { __lsan_disable(); }
+ ~ScopedDisabler() { __lsan_enable(); }
+};
+} // namespace __lsan
+#endif
+
+#endif // SANITIZER_LSAN_INTERFACE_H
diff --git a/compiler-rt/include/sanitizer/msan_interface.h b/compiler-rt/include/sanitizer/msan_interface.h
new file mode 100644
index 0000000..6d6a376
--- /dev/null
+++ b/compiler-rt/include/sanitizer/msan_interface.h
@@ -0,0 +1,111 @@
+//===-- msan_interface.h --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_INTERFACE_H
+#define MSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Set raw origin for the memory range. */
+ void __msan_set_origin(const volatile void *a, size_t size, uint32_t origin);
+
+ /* Get raw origin for an address. */
+ uint32_t __msan_get_origin(const volatile void *a);
+
+ /* Test that this_id is a descendant of prev_id (or they are simply equal).
+ * "descendant" here means they are part of the same chain, created with
+ * __msan_chain_origin. */
+ int __msan_origin_is_descendant_or_same(uint32_t this_id, uint32_t prev_id);
+
+ /* Returns non-zero if tracking origins. */
+ int __msan_get_track_origins();
+
+ /* Returns the origin id of the latest UMR in the calling thread. */
+ uint32_t __msan_get_umr_origin();
+
+ /* Make memory region fully initialized (without changing its contents). */
+ void __msan_unpoison(const volatile void *a, size_t size);
+
+ /* Make a null-terminated string fully initialized (without changing its
+ contents). */
+ void __msan_unpoison_string(const volatile char *a);
+
+ /* Make memory region fully uninitialized (without changing its contents).
+ This is a legacy interface that does not update origin information. Use
+ __msan_allocated_memory() instead. */
+ void __msan_poison(const volatile void *a, size_t size);
+
+ /* Make memory region partially uninitialized (without changing its contents).
+ */
+ void __msan_partial_poison(const volatile void *data, void *shadow,
+ size_t size);
+
+ /* Returns the offset of the first (at least partially) poisoned byte in the
+ memory range, or -1 if the whole range is good. */
+ intptr_t __msan_test_shadow(const volatile void *x, size_t size);
+
+ /* Checks that memory range is fully initialized, and reports an error if it
+ * is not. */
+ void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
+
+ /* For testing:
+ __msan_set_expect_umr(1);
+ ... some buggy code ...
+ __msan_set_expect_umr(0);
+ The last line will verify that a UMR happened. */
+ void __msan_set_expect_umr(int expect_umr);
+
+ /* Change the value of keep_going flag. Non-zero value means don't terminate
+ program execution when an error is detected. This will not affect error in
+ modules that were compiled without the corresponding compiler flag. */
+ void __msan_set_keep_going(int keep_going);
+
+ /* Print shadow and origin for the memory range to stderr in a human-readable
+ format. */
+ void __msan_print_shadow(const volatile void *x, size_t size);
+
+ /* Print shadow for the memory range to stderr in a minimalistic
+ human-readable format. */
+ void __msan_dump_shadow(const volatile void *x, size_t size);
+
+ /* Returns true if running under a dynamic tool (DynamoRio-based). */
+ int __msan_has_dynamic_component();
+
+ /* Tell MSan about newly allocated memory (ex.: custom allocator).
+ Memory will be marked uninitialized, with origin at the call site. */
+ void __msan_allocated_memory(const volatile void* data, size_t size);
+
+ /* Tell MSan about newly destroyed memory. Mark memory as uninitialized. */
+ void __sanitizer_dtor_callback(const volatile void* data, size_t size);
+
+ /* This function may be optionally provided by user and should return
+ a string containing Msan runtime options. See msan_flags.h for details. */
+ const char* __msan_default_options();
+
+ /* Deprecated. Call __sanitizer_set_death_callback instead. */
+ void __msan_set_death_callback(void (*callback)(void));
+
+ /* Update shadow for the application copy of size bytes from src to dst.
+ Src and dst are application addresses. This function does not copy the
+ actual application memory, it only updates shadow and origin for such
+ copy. Source and destination regions can overlap. */
+ void __msan_copy_shadow(const volatile void *dst, const volatile void *src,
+ size_t size);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/compiler-rt/include/sanitizer/tsan_interface_atomic.h b/compiler-rt/include/sanitizer/tsan_interface_atomic.h
new file mode 100644
index 0000000..4ea77d2
--- /dev/null
+++ b/compiler-rt/include/sanitizer/tsan_interface_atomic.h
@@ -0,0 +1,222 @@
+//===-- tsan_interface_atomic.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Public interface header for TSan atomics.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char __tsan_atomic8;
+typedef short __tsan_atomic16; // NOLINT
+typedef int __tsan_atomic32;
+typedef long __tsan_atomic64; // NOLINT
+#if defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302)
+__extension__ typedef __int128 __tsan_atomic128;
+# define __TSAN_HAS_INT128 1
+#else
+# define __TSAN_HAS_INT128 0
+#endif
+
+// Part of ABI, do not change.
+// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
+typedef enum {
+ __tsan_memory_order_relaxed,
+ __tsan_memory_order_consume,
+ __tsan_memory_order_acquire,
+ __tsan_memory_order_release,
+ __tsan_memory_order_acq_rel,
+ __tsan_memory_order_seq_cst
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
+ __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
+ __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
+ __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
+ __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
+ __tsan_memory_order mo);
+#endif
+
+void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
+ __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
+ __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
+ __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
+ __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
+ __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_sub(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_sub(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_sub(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_sub(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_sub(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+#endif
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#endif
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+#endif
+
+__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
+ volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
+ volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
+ volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
+ volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+#if __TSAN_HAS_INT128
+__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
+ volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+#endif
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+void __tsan_atomic_signal_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // TSAN_INTERFACE_ATOMIC_H
diff --git a/compiler-rt/lib/BlocksRuntime/Block.h b/compiler-rt/lib/BlocksRuntime/Block.h
new file mode 100644
index 0000000..55cdd01
--- /dev/null
+++ b/compiler-rt/lib/BlocksRuntime/Block.h
@@ -0,0 +1,59 @@
+/*
+ * Block.h
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _BLOCK_H_
+#define _BLOCK_H_
+
+#if !defined(BLOCK_EXPORT)
+# if defined(__cplusplus)
+# define BLOCK_EXPORT extern "C"
+# else
+# define BLOCK_EXPORT extern
+# endif
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Create a heap based copy of a Block or simply add a reference to an existing one.
+ * This must be paired with Block_release to recover memory, even when running
+ * under Objective-C Garbage Collection.
+ */
+BLOCK_EXPORT void *_Block_copy(const void *aBlock);
+
+/* Lose the reference, and if heap based and last reference, recover the memory. */
+BLOCK_EXPORT void _Block_release(const void *aBlock);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* Type correct macros. */
+
+#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
+#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
+
+
+#endif
diff --git a/compiler-rt/lib/BlocksRuntime/Block_private.h b/compiler-rt/lib/BlocksRuntime/Block_private.h
new file mode 100644
index 0000000..8ae8218
--- /dev/null
+++ b/compiler-rt/lib/BlocksRuntime/Block_private.h
@@ -0,0 +1,179 @@
+/*
+ * Block_private.h
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _BLOCK_PRIVATE_H_
+#define _BLOCK_PRIVATE_H_
+
+#if !defined(BLOCK_EXPORT)
+# if defined(__cplusplus)
+# define BLOCK_EXPORT extern "C"
+# else
+# define BLOCK_EXPORT extern
+# endif
+#endif
+
+#ifndef _MSC_VER
+#include <stdbool.h>
+#else
+/* MSVC doesn't have <stdbool.h>. Compensate. */
+typedef char bool;
+#define true (bool)1
+#define false (bool)0
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+enum {
+ BLOCK_REFCOUNT_MASK = (0xffff),
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29)
+};
+
+
+/* Revised new layout. */
+struct Block_descriptor {
+ unsigned long int reserved;
+ unsigned long int size;
+ void (*copy)(void *dst, void *src);
+ void (*dispose)(void *);
+};
+
+
+struct Block_layout {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(void *, ...);
+ struct Block_descriptor *descriptor;
+ /* Imported variables. */
+};
+
+
+struct Block_byref {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags; /* refcount; */
+ int size;
+ void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
+ void (*byref_destroy)(struct Block_byref *);
+ /* long shared[0]; */
+};
+
+
+struct Block_byref_header {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags;
+ int size;
+};
+
+
+/* Runtime support functions used by compiler when generating copy/dispose helpers. */
+
+enum {
+ /* See function implementation for a more complete description of these fields and combinations */
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */
+ BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */
+};
+
+/* Runtime entry point called by compiler when assigning objects inside copy helper routines */
+BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags);
+ /* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */
+
+
+/* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */
+BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags);
+
+
+
+/* Other support functions */
+
+/* Runtime entry to get total size of a closure */
+BLOCK_EXPORT unsigned long int Block_size(void *block_basic);
+
+
+
+/* the raw data space for runtime classes for blocks */
+/* class+meta used for stack, malloc, and collectable based blocks */
+BLOCK_EXPORT void * _NSConcreteStackBlock[32];
+BLOCK_EXPORT void * _NSConcreteMallocBlock[32];
+BLOCK_EXPORT void * _NSConcreteAutoBlock[32];
+BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32];
+BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
+BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32];
+
+
+/* the intercept routines that must be used under GC */
+BLOCK_EXPORT void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign_strong)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *),
+ void (*gc_memmove)(void *, void *, unsigned long));
+
+/* earlier version, now simply transitional */
+BLOCK_EXPORT void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign_strong)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *));
+
+BLOCK_EXPORT void _Block_use_RR( void (*retain)(const void *),
+ void (*release)(const void *));
+
+/* make a collectable GC heap based Block. Not useful under non-GC. */
+BLOCK_EXPORT void *_Block_copy_collectable(const void *aBlock);
+
+/* thread-unsafe diagnostic */
+BLOCK_EXPORT const char *_Block_dump(const void *block);
+
+
+/* Obsolete */
+
+/* first layout */
+struct Block_basic {
+ void *isa;
+ int Block_flags; /* int32_t */
+ int Block_size; /* XXX should be packed into Block_flags */
+ void (*Block_invoke)(void *);
+ void (*Block_copy)(void *dst, void *src); /* iff BLOCK_HAS_COPY_DISPOSE */
+ void (*Block_dispose)(void *); /* iff BLOCK_HAS_COPY_DISPOSE */
+ /* long params[0]; // where const imports, __block storage references, etc. get laid down */
+};
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif /* _BLOCK_PRIVATE_H_ */
diff --git a/compiler-rt/lib/BlocksRuntime/data.c b/compiler-rt/lib/BlocksRuntime/data.c
new file mode 100644
index 0000000..b4eb02e
--- /dev/null
+++ b/compiler-rt/lib/BlocksRuntime/data.c
@@ -0,0 +1,41 @@
+/*
+ * data.c
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/********************
+NSBlock support
+
+We allocate space and export a symbol to be used as the Class for the on-stack and malloc'ed copies until ObjC arrives on the scene. These data areas are set up by Foundation to link in as real classes post facto.
+
+We keep these in a separate file so that we can include the runtime code in test subprojects but not include the data so that compiled code that sees the data in libSystem doesn't get confused by a second copy. Somehow these don't get unified in a common block.
+**********************/
+
+void * _NSConcreteStackBlock[32] = { 0 };
+void * _NSConcreteMallocBlock[32] = { 0 };
+void * _NSConcreteAutoBlock[32] = { 0 };
+void * _NSConcreteFinalizingBlock[32] = { 0 };
+void * _NSConcreteGlobalBlock[32] = { 0 };
+void * _NSConcreteWeakBlockVariable[32] = { 0 };
+
+void _Block_copy_error(void) {
+}
diff --git a/compiler-rt/lib/BlocksRuntime/runtime.c b/compiler-rt/lib/BlocksRuntime/runtime.c
new file mode 100644
index 0000000..a059c22
--- /dev/null
+++ b/compiler-rt/lib/BlocksRuntime/runtime.c
@@ -0,0 +1,700 @@
+/*
+ * runtime.c
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "Block_private.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "config.h"
+
+#ifdef HAVE_AVAILABILITY_MACROS_H
+#include <AvailabilityMacros.h>
+#endif /* HAVE_AVAILABILITY_MACROS_H */
+
+#ifdef HAVE_TARGET_CONDITIONALS_H
+#include <TargetConditionals.h>
+#endif /* HAVE_TARGET_CONDITIONALS_H */
+
+#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
+
+#ifdef HAVE_LIBKERN_OSATOMIC_H
+#include <libkern/OSAtomic.h>
+#endif /* HAVE_LIBKERN_OSATOMIC_H */
+
+#elif defined(__WIN32__) || defined(_WIN32)
+#define _CRT_SECURE_NO_WARNINGS 1
+#include <windows.h>
+
+static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
+ /* fixme barrier is overkill -- see objc-os.h */
+ long original = InterlockedCompareExchange(dst, newl, oldl);
+ return (original == oldl);
+}
+
+static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
+ /* fixme barrier is overkill -- see objc-os.h */
+ int original = InterlockedCompareExchange(dst, newi, oldi);
+ return (original == oldi);
+}
+
+/*
+ * Check to see if the GCC atomic built-ins are available. If we're on
+ * a 64-bit system, make sure we have an 8-byte atomic function
+ * available.
+ *
+ */
+
+#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
+
+static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
+ return __sync_bool_compare_and_swap(dst, oldl, newl);
+}
+
+static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
+ return __sync_bool_compare_and_swap(dst, oldi, newi);
+}
+
+#else
+#error unknown atomic compare-and-swap primitive
+#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
+
+
+/*
+ * Globals:
+ */
+
+static void *_Block_copy_class = _NSConcreteMallocBlock;
+static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
+static int _Block_copy_flag = BLOCK_NEEDS_FREE;
+static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
+
+static const int WANTS_ONE = (1 << 16);
+
+static bool isGC = false;
+
+/*
+ * Internal Utilities:
+ */
+
+#if 0
+static unsigned long int latching_incr_long(unsigned long int *where) {
+ while (1) {
+ unsigned long int old_value = *(volatile unsigned long int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
+ return old_value+1;
+ }
+ }
+}
+#endif /* if 0 */
+
+static int latching_incr_int(int *where) {
+ while (1) {
+ int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
+ return old_value+1;
+ }
+ }
+}
+
+#if 0
+static int latching_decr_long(unsigned long int *where) {
+ while (1) {
+ unsigned long int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
+ return 0;
+ }
+ if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
+ return old_value-1;
+ }
+ }
+}
+#endif /* if 0 */
+
+static int latching_decr_int(int *where) {
+ while (1) {
+ int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
+ return 0;
+ }
+ if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
+ return old_value-1;
+ }
+ }
+}
+
+
+/*
+ * GC support stub routines:
+ */
+#if 0
+#pragma mark GC Support Routines
+#endif /* if 0 */
+
+
+static void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
+ return malloc(size);
+}
+
+static void _Block_assign_default(void *value, void **destptr) {
+ *destptr = value;
+}
+
+static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
+}
+
+static void _Block_do_nothing(const void *aBlock) { }
+
+static void _Block_retain_object_default(const void *ptr) {
+ if (!ptr) return;
+}
+
+static void _Block_release_object_default(const void *ptr) {
+ if (!ptr) return;
+}
+
+static void _Block_assign_weak_default(const void *ptr, void *dest) {
+ *(void **)dest = (void *)ptr;
+}
+
+static void _Block_memmove_default(void *dst, void *src, unsigned long size) {
+ memmove(dst, src, (size_t)size);
+}
+
+static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
+ void **destp = (void **)dest;
+ void **srcp = (void **)src;
+ while (size) {
+ _Block_assign_default(*srcp, destp);
+ destp++;
+ srcp++;
+ size -= sizeof(void *);
+ }
+}
+
+/*
+ * GC support callout functions - initially set to stub routines:
+ */
+
+static void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
+static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
+static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
+static void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
+static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
+static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
+static void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
+static void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
+
+
+/*
+ * GC support SPI functions - called from ObjC runtime and CoreFoundation:
+ */
+
+/* Public SPI
+ * Called from objc-auto to turn on GC.
+ * version 3, 4 arg, but changed 1st arg
+ */
+void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *),
+ void (*gc_memmove)(void *, void *, unsigned long)) {
+
+ isGC = true;
+ _Block_allocator = alloc;
+ _Block_deallocator = _Block_do_nothing;
+ _Block_assign = gc_assign;
+ _Block_copy_flag = BLOCK_IS_GC;
+ _Block_copy_class = _NSConcreteAutoBlock;
+ /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
+ _Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
+ _Block_setHasRefcount = setHasRefcount;
+ _Byref_flag_initial_value = BLOCK_IS_GC; // no refcount
+ _Block_retain_object = _Block_do_nothing;
+ _Block_release_object = _Block_do_nothing;
+ _Block_assign_weak = gc_assign_weak;
+ _Block_memmove = gc_memmove;
+}
+
+/* transitional */
+void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *)) {
+ /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
+ _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
+}
+
+
+/*
+ * Called from objc-auto to alternatively turn on retain/release.
+ * Prior to this the only "object" support we can provide is for those
+ * super special objects that live in libSystem, namely dispatch queues.
+ * Blocks and Block_byrefs have their own special entry points.
+ *
+ */
+void _Block_use_RR( void (*retain)(const void *),
+ void (*release)(const void *)) {
+ _Block_retain_object = retain;
+ _Block_release_object = release;
+}
+
+/*
+ * Internal Support routines for copying:
+ */
+
+#if 0
+#pragma mark Copy/Release support
+#endif /* if 0 */
+
+/* Copy, or bump refcount, of a block. If really copying, call the copy helper if present. */
+static void *_Block_copy_internal(const void *arg, const int flags) {
+ struct Block_layout *aBlock;
+ const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
+
+ //printf("_Block_copy_internal(%p, %x)\n", arg, flags);
+ if (!arg) return NULL;
+
+
+ // The following would be better done as a switch statement
+ aBlock = (struct Block_layout *)arg;
+ if (aBlock->flags & BLOCK_NEEDS_FREE) {
+ // latches on high
+ latching_incr_int(&aBlock->flags);
+ return aBlock;
+ }
+ else if (aBlock->flags & BLOCK_IS_GC) {
+ // GC refcounting is expensive so do most refcounting here.
+ if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
+ // Tell collector to hang on this - it will bump the GC refcount version
+ _Block_setHasRefcount(aBlock, true);
+ }
+ return aBlock;
+ }
+ else if (aBlock->flags & BLOCK_IS_GLOBAL) {
+ return aBlock;
+ }
+
+ // Its a stack block. Make a copy.
+ if (!isGC) {
+ struct Block_layout *result = malloc(aBlock->descriptor->size);
+ if (!result) return (void *)0;
+ memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
+ // reset refcount
+ result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed
+ result->flags |= BLOCK_NEEDS_FREE | 1;
+ result->isa = _NSConcreteMallocBlock;
+ if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
+ (*aBlock->descriptor->copy)(result, aBlock); // do fixup
+ }
+ return result;
+ }
+ else {
+ // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
+ // This allows the copy helper routines to make non-refcounted block copies under GC
+ unsigned long int flags = aBlock->flags;
+ bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
+ struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
+ if (!result) return (void *)0;
+ memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
+ // reset refcount
+ // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
+ flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK); // XXX not needed
+ if (wantsOne)
+ flags |= BLOCK_IS_GC | 1;
+ else
+ flags |= BLOCK_IS_GC;
+ result->flags = flags;
+ if (flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling block copy helper...\n");
+ (*aBlock->descriptor->copy)(result, aBlock); // do fixup
+ }
+ if (hasCTOR) {
+ result->isa = _NSConcreteFinalizingBlock;
+ }
+ else {
+ result->isa = _NSConcreteAutoBlock;
+ }
+ return result;
+ }
+}
+
+
+/*
+ * Runtime entry points for maintaining the sharing knowledge of byref data blocks.
+ *
+ * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
+ * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
+ * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
+ * Otherwise we need to copy it and update the stack forwarding pointer
+ * XXX We need to account for weak/nonretained read-write barriers.
+ */
+
+static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
+ struct Block_byref **destp = (struct Block_byref **)dest;
+ struct Block_byref *src = (struct Block_byref *)arg;
+
+ //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
+ //printf("src dump: %s\n", _Block_byref_dump(src));
+ if (src->forwarding->flags & BLOCK_IS_GC) {
+ ; // don't need to do any more work
+ }
+ else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
+ //printf("making copy\n");
+ // src points to stack
+ bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
+ // if its weak ask for an object (only matters under GC)
+ struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
+ copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
+ copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
+ src->forwarding = copy; // patch stack to point to heap copy
+ copy->size = src->size;
+ if (isWeak) {
+ copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning
+ }
+ if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
+ // Trust copy helper to copy everything of interest
+ // If more than one field shows up in a byref block this is wrong XXX
+ copy->byref_keep = src->byref_keep;
+ copy->byref_destroy = src->byref_destroy;
+ (*src->byref_keep)(copy, src);
+ }
+ else {
+ // just bits. Blast 'em using _Block_memmove in case they're __strong
+ _Block_memmove(
+ (void *)©->byref_keep,
+ (void *)&src->byref_keep,
+ src->size - sizeof(struct Block_byref_header));
+ }
+ }
+ // already copied to heap
+ else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
+ latching_incr_int(&src->forwarding->flags);
+ }
+ // assign byref data block pointer into new Block
+ _Block_assign(src->forwarding, (void **)destp);
+}
+
+// Old compiler SPI
+static void _Block_byref_release(const void *arg) {
+ struct Block_byref *shared_struct = (struct Block_byref *)arg;
+ int refcount;
+
+ // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
+ shared_struct = shared_struct->forwarding;
+
+ //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
+ // To support C++ destructors under GC we arrange for there to be a finalizer for this
+ // by using an isa that directs the code to a finalizer that calls the byref_destroy method.
+ if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
+ return; // stack or GC or global
+ }
+ refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
+ if (refcount <= 0) {
+ printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
+ }
+ else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
+ //printf("disposing of heap based byref block\n");
+ if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling out to helper\n");
+ (*shared_struct->byref_destroy)(shared_struct);
+ }
+ _Block_deallocator((struct Block_layout *)shared_struct);
+ }
+}
+
+
+/*
+ *
+ * API supporting SPI
+ * _Block_copy, _Block_release, and (old) _Block_destroy
+ *
+ */
+
+#if 0
+#pragma mark SPI/API
+#endif /* if 0 */
+
+void *_Block_copy(const void *arg) {
+ return _Block_copy_internal(arg, WANTS_ONE);
+}
+
+
+// API entry point to release a copied Block
+void _Block_release(void *arg) {
+ struct Block_layout *aBlock = (struct Block_layout *)arg;
+ int32_t newCount;
+ if (!aBlock) return;
+ newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
+ if (newCount > 0) return;
+ // Hit zero
+ if (aBlock->flags & BLOCK_IS_GC) {
+ // Tell GC we no longer have our own refcounts. GC will decr its refcount
+ // and unless someone has done a CFRetain or marked it uncollectable it will
+ // now be subject to GC reclamation.
+ _Block_setHasRefcount(aBlock, false);
+ }
+ else if (aBlock->flags & BLOCK_NEEDS_FREE) {
+ if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
+ _Block_deallocator(aBlock);
+ }
+ else if (aBlock->flags & BLOCK_IS_GLOBAL) {
+ ;
+ }
+ else {
+ printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
+ }
+}
+
+
+
+// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
+static void _Block_destroy(const void *arg) {
+ struct Block_layout *aBlock;
+ if (!arg) return;
+ aBlock = (struct Block_layout *)arg;
+ if (aBlock->flags & BLOCK_IS_GC) {
+ // assert(aBlock->Block_flags & BLOCK_HAS_CTOR);
+ return; // ignore, we are being called because of a DTOR
+ }
+ _Block_release(aBlock);
+}
+
+
+
+/*
+ *
+ * SPI used by other layers
+ *
+ */
+
+// SPI, also internal. Called from NSAutoBlock only under GC
+void *_Block_copy_collectable(const void *aBlock) {
+ return _Block_copy_internal(aBlock, 0);
+}
+
+
+// SPI
+unsigned long int Block_size(void *arg) {
+ return ((struct Block_layout *)arg)->descriptor->size;
+}
+
+
+#if 0
+#pragma mark Compiler SPI entry points
+#endif /* if 0 */
+
+
+/*******************************************************
+
+Entry points used by the compiler - the real API!
+
+
+A Block can reference four different kinds of things that require help when the Block is copied to the heap.
+1) C++ stack based objects
+2) References to Objective-C objects
+3) Other Blocks
+4) __block variables
+
+In these cases helper functions are synthesized by the compiler for use in Block_copy and Block_release, called the copy and dispose helpers. The copy helper emits a call to the C++ const copy constructor for C++ stack based objects and for the rest calls into the runtime support function _Block_object_assign. The dispose helper has a call to the C++ destructor for case 1 and a call into _Block_object_dispose for the rest.
+
+The flags parameter of _Block_object_assign and _Block_object_dispose is set to
+ * BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
+ * BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
+ * BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
+If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
+
+So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
+
+When a __block variable is either a C++ object, an Objective-C object, or another Block then the compiler also generates copy/dispose helper functions. Similarly to the Block copy helper, the "__block" copy helper (formerly and still a.k.a. "byref" copy helper) will do a C++ copy constructor (not a const one though!) and the dispose helper will do the destructor. And similarly the helpers will call into the same two support functions with the same values for objects and Blocks with the additional BLOCK_BYREF_CALLER (128) bit of information supplied.
+
+So the __block copy/dispose helpers will generate flag values of 3 or 7 for objects and Blocks respectively, with BLOCK_FIELD_IS_WEAK (16) or'ed as appropriate and always 128 or'd in, for the following set of possibilities:
+ __block id 128+3
+ __weak block id 128+3+16
+ __block (^Block) 128+7
+ __weak __block (^Block) 128+7+16
+
+The implementation of the two routines would be improved by switch statements enumerating the eight cases.
+
+********************************************************/
+
+/*
+ * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
+ * to do the assignment.
+ */
+void _Block_object_assign(void *destAddr, const void *object, const int flags) {
+ //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
+ if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
+ if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
+ _Block_assign_weak(object, destAddr);
+ }
+ else {
+ // do *not* retain or *copy* __block variables whatever they are
+ _Block_assign((void *)object, destAddr);
+ }
+ }
+ else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
+ // copying a __block reference from the stack Block to the heap
+ // flags will indicate if it holds a __weak reference and needs a special isa
+ _Block_byref_assign_copy(destAddr, object, flags);
+ }
+ // (this test must be before next one)
+ else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
+ // copying a Block declared variable from the stack Block to the heap
+ _Block_assign(_Block_copy_internal(object, flags), destAddr);
+ }
+ // (this test must be after previous one)
+ else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
+ //printf("retaining object at %p\n", object);
+ _Block_retain_object(object);
+ //printf("done retaining object at %p\n", object);
+ _Block_assign((void *)object, destAddr);
+ }
+}
+
+// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
+// to help dispose of the contents
+// Used initially only for __attribute__((NSObject)) marked pointers.
+void _Block_object_dispose(const void *object, const int flags) {
+ //printf("_Block_object_dispose(%p, %x)\n", object, flags);
+ if (flags & BLOCK_FIELD_IS_BYREF) {
+ // get rid of the __block data structure held in a Block
+ _Block_byref_release(object);
+ }
+ else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
+ // get rid of a referenced Block held by this Block
+ // (ignore __block Block variables, compiler doesn't need to call us)
+ _Block_destroy(object);
+ }
+ else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
+ // get rid of a referenced object held by this Block
+ // (ignore __block object variables, compiler doesn't need to call us)
+ _Block_release_object(object);
+ }
+}
+
+
+/*
+ * Debugging support:
+ */
+#if 0
+#pragma mark Debugging
+#endif /* if 0 */
+
+
+const char *_Block_dump(const void *block) {
+ struct Block_layout *closure = (struct Block_layout *)block;
+ static char buffer[512];
+ char *cp = buffer;
+ if (closure == NULL) {
+ sprintf(cp, "NULL passed to _Block_dump\n");
+ return buffer;
+ }
+ if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
+ printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
+ exit(1);
+ }
+ cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
+ if (closure->isa == NULL) {
+ cp += sprintf(cp, "isa: NULL\n");
+ }
+ else if (closure->isa == _NSConcreteStackBlock) {
+ cp += sprintf(cp, "isa: stack Block\n");
+ }
+ else if (closure->isa == _NSConcreteMallocBlock) {
+ cp += sprintf(cp, "isa: malloc heap Block\n");
+ }
+ else if (closure->isa == _NSConcreteAutoBlock) {
+ cp += sprintf(cp, "isa: GC heap Block\n");
+ }
+ else if (closure->isa == _NSConcreteGlobalBlock) {
+ cp += sprintf(cp, "isa: global Block\n");
+ }
+ else if (closure->isa == _NSConcreteFinalizingBlock) {
+ cp += sprintf(cp, "isa: finalizing Block\n");
+ }
+ else {
+ cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
+ }
+ cp += sprintf(cp, "flags:");
+ if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
+ cp += sprintf(cp, " HASDESCRIPTOR");
+ }
+ if (closure->flags & BLOCK_NEEDS_FREE) {
+ cp += sprintf(cp, " FREEME");
+ }
+ if (closure->flags & BLOCK_IS_GC) {
+ cp += sprintf(cp, " ISGC");
+ }
+ if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, " HASHELP");
+ }
+ if (closure->flags & BLOCK_HAS_CTOR) {
+ cp += sprintf(cp, " HASCTOR");
+ }
+ cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
+ cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
+ {
+ struct Block_descriptor *dp = closure->descriptor;
+ cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
+ cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
+ cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
+
+ if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
+ cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
+ }
+ }
+ return buffer;
+}
+
+
+const char *_Block_byref_dump(struct Block_byref *src) {
+ static char buffer[256];
+ char *cp = buffer;
+ cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
+ cp += sprintf(cp, " forwarding: %p\n", (void *)src->forwarding);
+ cp += sprintf(cp, " flags: 0x%x\n", src->flags);
+ cp += sprintf(cp, " size: %d\n", src->size);
+ if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, " copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
+ cp += sprintf(cp, " dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
+ }
+ return buffer;
+}
+
diff --git a/compiler-rt/lib/CMakeLists.txt b/compiler-rt/lib/CMakeLists.txt
new file mode 100644
index 0000000..4bc6f7a
--- /dev/null
+++ b/compiler-rt/lib/CMakeLists.txt
@@ -0,0 +1,50 @@
+# First, add the subdirectories which contain feature-based runtime libraries
+# and several convenience helper libraries.
+
+include(AddCompilerRT)
+include(SanitizerUtils)
+
+if(COMPILER_RT_BUILD_BUILTINS)
+ add_subdirectory(builtins)
+endif()
+
+if(COMPILER_RT_BUILD_SANITIZERS)
+ if(COMPILER_RT_HAS_INTERCEPTION)
+ add_subdirectory(interception)
+ endif()
+
+ if(COMPILER_RT_HAS_SANITIZER_COMMON)
+ add_subdirectory(sanitizer_common)
+ add_subdirectory(lsan)
+ add_subdirectory(ubsan)
+ endif()
+
+ if(COMPILER_RT_HAS_ASAN)
+ add_subdirectory(asan)
+ endif()
+
+ if(COMPILER_RT_HAS_DFSAN)
+ add_subdirectory(dfsan)
+ endif()
+
+ if(COMPILER_RT_HAS_MSAN)
+ add_subdirectory(msan)
+ endif()
+
+ if(COMPILER_RT_HAS_PROFILE)
+ add_subdirectory(profile)
+ endif()
+
+ if(COMPILER_RT_HAS_TSAN)
+ add_subdirectory(tsan)
+ add_subdirectory(tsan/dd)
+ endif()
+
+ if(COMPILER_RT_HAS_SAFESTACK)
+ add_subdirectory(safestack)
+ endif()
+
+ if(COMPILER_RT_HAS_CFI)
+ add_subdirectory(cfi)
+ endif()
+endif()
diff --git a/compiler-rt/lib/Makefile.mk b/compiler-rt/lib/Makefile.mk
new file mode 100644
index 0000000..7eb6489
--- /dev/null
+++ b/compiler-rt/lib/Makefile.mk
@@ -0,0 +1,19 @@
+#===- lib/Makefile.mk --------------------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+SubDirs :=
+
+# Add submodules.
+SubDirs += asan
+SubDirs += builtins
+SubDirs += interception
+SubDirs += lsan
+SubDirs += profile
+SubDirs += sanitizer_common
+SubDirs += ubsan
diff --git a/compiler-rt/lib/asan/.clang-format b/compiler-rt/lib/asan/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/asan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/asan/Android.bp b/compiler-rt/lib/asan/Android.bp
new file mode 100644
index 0000000..3e20843
--- /dev/null
+++ b/compiler-rt/lib/asan/Android.bp
@@ -0,0 +1,218 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+ASAN_NEEDS_SEGV = "0"
+ASAN_HAS_EXCEPTIONS = "1"
+ASAN_FLEXIBLE_MAPPING_AND_OFFSET = "0"
+
+asan_rtl_files = [
+ "asan_activation.cc",
+ "asan_allocator.cc",
+ "asan_fake_stack.cc",
+ "asan_flags.cc",
+ "asan_globals.cc",
+ "asan_interceptors.cc",
+ "asan_linux.cc",
+ "asan_mac.cc",
+ "asan_malloc_linux.cc",
+ "asan_malloc_mac.cc",
+ "asan_malloc_win.cc",
+ "asan_poisoning.cc",
+ "asan_posix.cc",
+ "asan_report.cc",
+ "asan_rtl.cc",
+ "asan_stack.cc",
+ "asan_stats.cc",
+ "asan_suppressions.cc",
+ "asan_thread.cc",
+ "asan_win.cc",
+]
+
+asan_rtl_cxx_files = ["asan_new_delete.cc"]
+
+asan_rtl_cflags = [
+ "-fvisibility=hidden",
+ "-fno-exceptions",
+ "-DASAN_LOW_MEMORY=1",
+ "-DASAN_NEEDS_SEGV=" + ASAN_NEEDS_SEGV,
+ "-DASAN_HAS_EXCEPTIONS=" + ASAN_HAS_EXCEPTIONS,
+ "-DASAN_FLEXIBLE_MAPPING_AND_OFFSET=" + ASAN_FLEXIBLE_MAPPING_AND_OFFSET,
+ "-Wno-covered-switch-default",
+ "-Wno-non-virtual-dtor",
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ "-std=c++11",
+ "-fno-rtti",
+ "-fno-builtin",
+]
+
+cc_library_static {
+ name: "libasan",
+ host_supported: true,
+ defaults: ["asan_arch_defaults"],
+ include_dirs: [
+ "external/compiler-rt/lib",
+ "external/compiler-rt/include",
+ ],
+ cflags: asan_rtl_cflags,
+ target: {
+ android: {
+ srcs: ["asan_preinit.cc"],
+ },
+ host: {
+ srcs: asan_rtl_files,
+ whole_static_libs: ["libubsan"],
+ static_libs: [
+ "libinterception",
+ "liblsan",
+ "libsan",
+ ],
+ },
+ },
+
+ clang: true,
+ sdk_version: "19",
+ stl: "none",
+
+ sanitize: {
+ never: true,
+ },
+}
+
+cc_library_host_static {
+ name: "libasan_cxx",
+ include_dirs: [
+ "external/compiler-rt/lib",
+ "external/compiler-rt/include",
+ ],
+ cflags: asan_rtl_cflags,
+ srcs: asan_rtl_cxx_files,
+
+ clang: true,
+ compile_multilib: "both",
+
+ sanitize: {
+ never: true,
+ },
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_binary {
+ name: "asanwrapper",
+ defaults: ["asan_arch_defaults"],
+
+ srcs: ["asanwrapper.cc"],
+
+ cppflags: ["-std=c++11"],
+ sanitize: {
+ never: true,
+ },
+
+ stl: "libc++",
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifneq (true,$(SKIP_LLVM_TESTS))
+cc_library_static {
+ name: "libasan_noinst_test",
+ host_supported: true,
+ defaults: ["asan_arch_defaults"],
+
+ tags: ["tests"],
+ include_dirs: [
+ "external/gtest/include",
+ "external/compiler-rt/include",
+ "external/compiler-rt/lib",
+ "external/compiler-rt/lib/asan/tests",
+ "external/compiler-rt/lib/sanitizer_common/tests",
+ ],
+ cflags: [
+ "-Wno-non-virtual-dtor",
+ "-Wno-unused-parameter",
+ "-Wno-sign-compare",
+ "-DASAN_UAR=0",
+ "-DASAN_HAS_BLACKLIST=1",
+ "-DASAN_HAS_EXCEPTIONS=" + ASAN_HAS_EXCEPTIONS,
+ "-DASAN_NEEDS_SEGV=" + ASAN_NEEDS_SEGV,
+ "-std=c++11",
+ ],
+ srcs: [
+ "tests/asan_noinst_test.cc",
+ "tests/asan_test_main.cc",
+ ],
+
+ clang: true,
+ sanitize: {
+ never: true,
+ },
+
+ stl: "libc++",
+}
+
+cc_test {
+ name: "asan_test",
+ host_supported: true,
+ defaults: ["asan_arch_defaults"],
+
+ tags: ["tests"],
+ include_dirs: [
+ "external/compiler-rt/lib",
+ "external/compiler-rt/lib/asan/tests",
+ "external/compiler-rt/lib/sanitizer_common/tests",
+ ],
+ cflags: [
+ "-DASAN_LOW_MEMORY=1",
+ "-DASAN_UAR=0",
+ "-DASAN_NEEDS_SEGV=" + ASAN_NEEDS_SEGV,
+ "-DASAN_HAS_EXCEPTIONS=" + ASAN_HAS_EXCEPTIONS,
+ "-DASAN_HAS_BLACKLIST=1",
+ "-Wno-covered-switch-default",
+ "-Wno-non-virtual-dtor",
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ "-std=c++11",
+ ],
+
+ srcs: [
+ "tests/asan_globals_test.cc",
+ "tests/asan_test.cc",
+ //"tests/asan_noinst_test.cc",
+ //"tests/asan_test_main.cc",
+ ],
+
+ static_libs: ["libasan_noinst_test"],
+ sanitize: {
+ address: true,
+ blacklist: "tests/asan_test.ignore",
+ },
+ clang: true,
+
+ stl: "libc++",
+ target: {
+ host: {
+ host_ldlibs: ["-lrt"],
+ },
+ },
+}
+
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
+// SKIP_LLVM_TESTS
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
new file mode 100644
index 0000000..6716f48
--- /dev/null
+++ b/compiler-rt/lib/asan/CMakeLists.txt
@@ -0,0 +1,230 @@
+# Build for the AddressSanitizer runtime support library.
+
+set(ASAN_SOURCES
+ asan_allocator.cc
+ asan_activation.cc
+ asan_debugging.cc
+ asan_fake_stack.cc
+ asan_flags.cc
+ asan_globals.cc
+ asan_interceptors.cc
+ asan_linux.cc
+ asan_mac.cc
+ asan_malloc_linux.cc
+ asan_malloc_mac.cc
+ asan_malloc_win.cc
+ asan_poisoning.cc
+ asan_posix.cc
+ asan_report.cc
+ asan_rtl.cc
+ asan_stack.cc
+ asan_stats.cc
+ asan_suppressions.cc
+ asan_thread.cc
+ asan_win.cc)
+
+set(ASAN_CXX_SOURCES
+ asan_new_delete.cc)
+
+set(ASAN_PREINIT_SOURCES
+ asan_preinit.cc)
+
+include_directories(..)
+
+set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(ASAN_CFLAGS)
+
+set(ASAN_COMMON_DEFINITIONS
+ ASAN_HAS_EXCEPTIONS=1)
+
+set(ASAN_DYNAMIC_LINK_FLAGS)
+
+if(ANDROID)
+ list(APPEND ASAN_COMMON_DEFINITIONS
+ ASAN_LOW_MEMORY=1)
+# On Android, -z global does not do what it is documented to do.
+# On Android, -z global moves the library ahead in the lookup order,
+# placing it right after the LD_PRELOADs. This is used to compensate for the fact
+# that Android linker does not look at the dependencies of the main executable
+# that aren't dependencies of the current DSO when resolving symbols from said DSO.
+# As a net result, this allows running ASan executables without LD_PRELOAD-ing the
+# ASan runtime library.
+# The above is applicable to L MR1 or newer.
+ if (COMPILER_RT_HAS_Z_GLOBAL)
+ list(APPEND ASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global)
+ endif()
+endif()
+
+set(ASAN_DYNAMIC_DEFINITIONS
+ ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
+append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
+
+set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
+append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
+ -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
+append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
+
+append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
+
+# Compile ASan sources into an object library.
+
+add_compiler_rt_object_libraries(RTAsan_dynamic
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+
+if(NOT APPLE)
+ add_compiler_rt_object_libraries(RTAsan
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_libraries(RTAsan_cxx
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_libraries(RTAsan_preinit
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
+ add_compiler_rt_object_libraries(RTAsan_dynamic_version_script_dummy
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+endif()
+
+# Build ASan runtimes shipped with Clang.
+add_custom_target(asan)
+if(APPLE)
+ add_compiler_rt_runtime(clang_rt.asan
+ SHARED
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_dynamic
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTLSanCommon
+ RTUbsan
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ PARENT_TARGET asan)
+else()
+ # Build separate libraries for each target.
+
+ set(ASAN_COMMON_RUNTIME_OBJECT_LIBS
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTLSanCommon
+ RTUbsan)
+
+ add_compiler_rt_runtime(clang_rt.asan
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_preinit
+ RTAsan
+ ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+
+ add_compiler_rt_runtime(clang_rt.asan_cxx
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_cxx
+ RTUbsan_cxx
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+
+ add_compiler_rt_runtime(clang_rt.asan-preinit
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_preinit
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ if (UNIX AND NOT ${arch} MATCHES "i386|i686")
+ add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch}
+ LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch}
+ EXTRA asan.syms.extra)
+ set(VERSION_SCRIPT_FLAG
+ -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
+ set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
+ PROPERTIES
+ OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
+ else()
+ set(VERSION_SCRIPT_FLAG)
+ endif()
+
+ add_compiler_rt_runtime(clang_rt.asan
+ SHARED
+ ARCHS ${arch}
+ OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
+ RTAsan_dynamic
+ # The only purpose of RTAsan_dynamic_version_script_dummy is to carry
+ # a dependency of the shared runtime on the version script. With CMake
+ # 3.1 or later it can be replaced with a straightforward
+ # add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
+ RTAsan_dynamic_version_script_dummy
+ RTUbsan_cxx
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ LINKFLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
+ ${VERSION_SCRIPT_FLAG}
+ LINK_LIBS ${ASAN_DYNAMIC_LIBS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ PARENT_TARGET asan)
+
+ if (UNIX AND NOT ${arch} MATCHES "i386|i686")
+ add_sanitizer_rt_symbols(clang_rt.asan_cxx
+ ARCHS ${arch})
+ add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
+ add_sanitizer_rt_symbols(clang_rt.asan
+ ARCHS ${arch}
+ EXTRA asan.syms.extra)
+ add_dependencies(asan clang_rt.asan-${arch}-symbols)
+ endif()
+
+ if (WIN32)
+ add_compiler_rt_runtime(clang_rt.asan_dll_thunk
+ STATIC
+ ARCHS ${arch}
+ SOURCES asan_win_dll_thunk.cc
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+ add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
+ STATIC
+ ARCHS ${arch}
+ SOURCES asan_win_dynamic_runtime_thunk.cc
+ CFLAGS ${ASAN_CFLAGS} -DASAN_DYNAMIC_RUNTIME_THUNK -Zl
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+ endif()
+ endforeach()
+endif()
+
+add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
+add_dependencies(asan asan_blacklist)
+add_dependencies(compiler-rt asan)
+
+add_subdirectory(scripts)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(tests)
+endif()
diff --git a/compiler-rt/lib/asan/Makefile.mk b/compiler-rt/lib/asan/Makefile.mk
new file mode 100644
index 0000000..0dafefc
--- /dev/null
+++ b/compiler-rt/lib/asan/Makefile.mk
@@ -0,0 +1,29 @@
+#===- lib/asan/Makefile.mk ---------------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := asan
+SubDirs :=
+
+CCSources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+CXXOnlySources := asan_new_delete.cc
+COnlySources := $(filter-out $(CXXOnlySources),$(CCSources))
+SSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(CCSources) $(SSources)
+ObjNames := $(CCSources:%.cc=%.o) $(SSources:%.S=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../interception/*.h)
+Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
+
+# Define a convenience variable for all the asan functions.
+AsanFunctions := $(COnlySources:%.cc=%) $(SSources:%.S=%)
+AsanCXXFunctions := $(CXXOnlySources:%.cc=%)
diff --git a/compiler-rt/lib/asan/README.txt b/compiler-rt/lib/asan/README.txt
new file mode 100644
index 0000000..bb6ff42
--- /dev/null
+++ b/compiler-rt/lib/asan/README.txt
@@ -0,0 +1,26 @@
+AddressSanitizer RT
+================================
+This directory contains sources of the AddressSanitizer (ASan) runtime library.
+
+Directory structure:
+README.txt : This file.
+Makefile.mk : File for make-based build.
+CMakeLists.txt : File for cmake-based build.
+asan_*.{cc,h} : Sources of the asan runtime library.
+scripts/* : Helper scripts.
+tests/* : ASan unit tests.
+
+Also ASan runtime needs the following libraries:
+lib/interception/ : Machinery used to intercept function calls.
+lib/sanitizer_common/ : Code shared between various sanitizers.
+
+ASan runtime currently also embeds part of LeakSanitizer runtime for
+leak detection (lib/lsan/lsan_common.{cc,h}).
+
+ASan runtime can only be built by CMake. You can run ASan tests
+from the root of your CMake build tree:
+
+make check-asan
+
+For more instructions see:
+https://github.com/google/sanitizers/wiki/AddressSanitizerHowToBuild
diff --git a/compiler-rt/lib/asan/asan.syms.extra b/compiler-rt/lib/asan/asan.syms.extra
new file mode 100644
index 0000000..007aafe
--- /dev/null
+++ b/compiler-rt/lib/asan/asan.syms.extra
@@ -0,0 +1,3 @@
+__asan_*
+__lsan_*
+__ubsan_*
diff --git a/compiler-rt/lib/asan/asan_activation.cc b/compiler-rt/lib/asan/asan_activation.cc
new file mode 100644
index 0000000..9df3b97
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_activation.cc
@@ -0,0 +1,139 @@
+//===-- asan_activation.cc --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_poisoning.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static struct AsanDeactivatedFlags {
+ AllocatorOptions allocator_options;
+ int malloc_context_size;
+ bool poison_heap;
+ bool coverage;
+ const char *coverage_dir;
+
+ void RegisterActivationFlags(FlagParser *parser, Flags *f, CommonFlags *cf) {
+#define ASAN_ACTIVATION_FLAG(Type, Name) \
+ RegisterFlag(parser, #Name, "", &f->Name);
+#define COMMON_ACTIVATION_FLAG(Type, Name) \
+ RegisterFlag(parser, #Name, "", &cf->Name);
+#include "asan_activation_flags.inc"
+#undef ASAN_ACTIVATION_FLAG
+#undef COMMON_ACTIVATION_FLAG
+
+ RegisterIncludeFlags(parser, cf);
+ }
+
+ void OverrideFromActivationFlags() {
+ Flags f;
+ CommonFlags cf;
+ FlagParser parser;
+ RegisterActivationFlags(&parser, &f, &cf);
+
+ // Copy the current activation flags.
+ allocator_options.CopyTo(&f, &cf);
+ cf.malloc_context_size = malloc_context_size;
+ f.poison_heap = poison_heap;
+ cf.coverage = coverage;
+ cf.coverage_dir = coverage_dir;
+ cf.verbosity = Verbosity();
+ cf.help = false; // this is activation-specific help
+
+ // Check if activation flags need to be overriden.
+ if (const char *env = GetEnv("ASAN_ACTIVATION_OPTIONS")) {
+ parser.ParseString(env);
+ }
+
+ SetVerbosity(cf.verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (cf.help) parser.PrintFlagDescriptions();
+
+ allocator_options.SetFrom(&f, &cf);
+ malloc_context_size = cf.malloc_context_size;
+ poison_heap = f.poison_heap;
+ coverage = cf.coverage;
+ coverage_dir = cf.coverage_dir;
+ }
+
+ void Print() {
+ Report(
+ "quarantine_size_mb %d, max_redzone %d, poison_heap %d, "
+ "malloc_context_size %d, alloc_dealloc_mismatch %d, "
+ "allocator_may_return_null %d, coverage %d, coverage_dir %s\n",
+ allocator_options.quarantine_size_mb, allocator_options.max_redzone,
+ poison_heap, malloc_context_size,
+ allocator_options.alloc_dealloc_mismatch,
+ allocator_options.may_return_null, coverage, coverage_dir);
+ }
+} asan_deactivated_flags;
+
+static bool asan_is_deactivated;
+
+void AsanDeactivate() {
+ CHECK(!asan_is_deactivated);
+ VReport(1, "Deactivating ASan\n");
+
+ // Stash runtime state.
+ GetAllocatorOptions(&asan_deactivated_flags.allocator_options);
+ asan_deactivated_flags.malloc_context_size = GetMallocContextSize();
+ asan_deactivated_flags.poison_heap = CanPoisonMemory();
+ asan_deactivated_flags.coverage = common_flags()->coverage;
+ asan_deactivated_flags.coverage_dir = common_flags()->coverage_dir;
+
+ // Deactivate the runtime.
+ SetCanPoisonMemory(false);
+ SetMallocContextSize(1);
+ ReInitializeCoverage(false, nullptr);
+
+ AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
+ disabled.quarantine_size_mb = 0;
+ disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
+ disabled.max_redzone = 16;
+ disabled.alloc_dealloc_mismatch = false;
+ disabled.may_return_null = true;
+ ReInitializeAllocator(disabled);
+
+ asan_is_deactivated = true;
+}
+
+void AsanActivate() {
+ if (!asan_is_deactivated) return;
+ VReport(1, "Activating ASan\n");
+
+ UpdateProcessName();
+
+ asan_deactivated_flags.OverrideFromActivationFlags();
+
+ SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
+ SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
+ ReInitializeCoverage(asan_deactivated_flags.coverage,
+ asan_deactivated_flags.coverage_dir);
+ ReInitializeAllocator(asan_deactivated_flags.allocator_options);
+
+ asan_is_deactivated = false;
+ if (Verbosity()) {
+ Report("Activated with flags:\n");
+ asan_deactivated_flags.Print();
+ }
+}
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_activation.h b/compiler-rt/lib/asan/asan_activation.h
new file mode 100644
index 0000000..d5e1ce4
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_activation.h
@@ -0,0 +1,23 @@
+//===-- asan_activation.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ACTIVATION_H
+#define ASAN_ACTIVATION_H
+
+namespace __asan {
+void AsanDeactivate();
+void AsanActivate();
+} // namespace __asan
+
+#endif // ASAN_ACTIVATION_H
diff --git a/compiler-rt/lib/asan/asan_activation_flags.inc b/compiler-rt/lib/asan/asan_activation_flags.inc
new file mode 100644
index 0000000..d4c089e
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_activation_flags.inc
@@ -0,0 +1,35 @@
+//===-- asan_activation_flags.inc -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A subset of ASan (and common) runtime flags supported at activation time.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_ACTIVATION_FLAG
+# error "Define ASAN_ACTIVATION_FLAG prior to including this file!"
+#endif
+
+#ifndef COMMON_ACTIVATION_FLAG
+# error "Define COMMON_ACTIVATION_FLAG prior to including this file!"
+#endif
+
+// ASAN_ACTIVATION_FLAG(Type, Name)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+ASAN_ACTIVATION_FLAG(int, redzone)
+ASAN_ACTIVATION_FLAG(int, max_redzone)
+ASAN_ACTIVATION_FLAG(int, quarantine_size_mb)
+ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch)
+ASAN_ACTIVATION_FLAG(bool, poison_heap)
+
+COMMON_ACTIVATION_FLAG(bool, allocator_may_return_null)
+COMMON_ACTIVATION_FLAG(int, malloc_context_size)
+COMMON_ACTIVATION_FLAG(bool, coverage)
+COMMON_ACTIVATION_FLAG(const char *, coverage_dir)
+COMMON_ACTIVATION_FLAG(int, verbosity)
+COMMON_ACTIVATION_FLAG(bool, help)
diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc
new file mode 100644
index 0000000..56f184a
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_allocator.cc
@@ -0,0 +1,908 @@
+//===-- asan_allocator.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Implementation of ASan's memory allocator, 2-nd version.
+// This variant uses the allocator from sanitizer_common, i.e. the one shared
+// with ThreadSanitizer and MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_list.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_quarantine.h"
+#include "lsan/lsan_common.h"
+
+namespace __asan {
+
+// Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits.
+// We use adaptive redzones: for larger allocation larger redzones are used.
+static u32 RZLog2Size(u32 rz_log) {
+ CHECK_LT(rz_log, 8);
+ return 16 << rz_log;
+}
+
+static u32 RZSize2Log(u32 rz_size) {
+ CHECK_GE(rz_size, 16);
+ CHECK_LE(rz_size, 2048);
+ CHECK(IsPowerOfTwo(rz_size));
+ u32 res = Log2(rz_size) - 4;
+ CHECK_EQ(rz_size, RZLog2Size(res));
+ return res;
+}
+
+static AsanAllocator &get_allocator();
+
+// The memory chunk allocated from the underlying allocator looks like this:
+// L L L L L L H H U U U U U U R R
+// L -- left redzone words (0 or more bytes)
+// H -- ChunkHeader (16 bytes), which is also a part of the left redzone.
+// U -- user memory.
+// R -- right redzone (0 or more bytes)
+// ChunkBase consists of ChunkHeader and other bytes that overlap with user
+// memory.
+
+// If the left redzone is greater than the ChunkHeader size we store a magic
+// value in the first uptr word of the memory block and store the address of
+// ChunkBase in the next uptr.
+// M B L L L L L L L L L H H U U U U U U
+// | ^
+// ---------------------|
+// M -- magic value kAllocBegMagic
+// B -- address of ChunkHeader pointing to the first 'H'
+static const uptr kAllocBegMagic = 0xCC6E96B9;
+
+struct ChunkHeader {
+ // 1-st 8 bytes.
+ u32 chunk_state : 8; // Must be first.
+ u32 alloc_tid : 24;
+
+ u32 free_tid : 24;
+ u32 from_memalign : 1;
+ u32 alloc_type : 2;
+ u32 rz_log : 3;
+ u32 lsan_tag : 2;
+ // 2-nd 8 bytes
+ // This field is used for small sizes. For large sizes it is equal to
+ // SizeClassMap::kMaxSize and the actual size is stored in the
+ // SecondaryAllocator's metadata.
+ u32 user_requested_size;
+ u32 alloc_context_id;
+};
+
+struct ChunkBase : ChunkHeader {
+ // Header2, intersects with user memory.
+ u32 free_context_id;
+};
+
+static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
+static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize;
+COMPILER_CHECK(kChunkHeaderSize == 16);
+COMPILER_CHECK(kChunkHeader2Size <= 16);
+
+// Every chunk of memory allocated by this allocator can be in one of 3 states:
+// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
+// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
+// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
+enum {
+ CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it.
+ CHUNK_ALLOCATED = 2,
+ CHUNK_QUARANTINE = 3
+};
+
+struct AsanChunk: ChunkBase {
+ uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
+ uptr UsedSize(bool locked_version = false) {
+ if (user_requested_size != SizeClassMap::kMaxSize)
+ return user_requested_size;
+ return *reinterpret_cast<uptr *>(
+ get_allocator().GetMetaData(AllocBeg(locked_version)));
+ }
+ void *AllocBeg(bool locked_version = false) {
+ if (from_memalign) {
+ if (locked_version)
+ return get_allocator().GetBlockBeginFastLocked(
+ reinterpret_cast<void *>(this));
+ return get_allocator().GetBlockBegin(reinterpret_cast<void *>(this));
+ }
+ return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
+ }
+ bool AddrIsInside(uptr addr, bool locked_version = false) {
+ return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
+ }
+};
+
+struct QuarantineCallback {
+ explicit QuarantineCallback(AllocatorCache *cache)
+ : cache_(cache) {
+ }
+
+ void Recycle(AsanChunk *m) {
+ CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+ atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
+ CHECK_NE(m->alloc_tid, kInvalidTid);
+ CHECK_NE(m->free_tid, kInvalidTid);
+ PoisonShadow(m->Beg(),
+ RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
+ kAsanHeapLeftRedzoneMagic);
+ void *p = reinterpret_cast<void *>(m->AllocBeg());
+ if (p != m) {
+ uptr *alloc_magic = reinterpret_cast<uptr *>(p);
+ CHECK_EQ(alloc_magic[0], kAllocBegMagic);
+ // Clear the magic value, as allocator internals may overwrite the
+ // contents of deallocated chunk, confusing GetAsanChunk lookup.
+ alloc_magic[0] = 0;
+ CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m));
+ }
+
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.real_frees++;
+ thread_stats.really_freed += m->UsedSize();
+
+ get_allocator().Deallocate(cache_, p);
+ }
+
+ void *Allocate(uptr size) {
+ return get_allocator().Allocate(cache_, size, 1, false);
+ }
+
+ void Deallocate(void *p) {
+ get_allocator().Deallocate(cache_, p);
+ }
+
+ AllocatorCache *cache_;
+};
+
+typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine;
+typedef AsanQuarantine::Cache QuarantineCache;
+
+void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
+ PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mmaps++;
+ thread_stats.mmaped += size;
+}
+void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
+ PoisonShadow(p, size, 0);
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededASanShadowMemory(p, size);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.munmaps++;
+ thread_stats.munmaped += size;
+}
+
+// We can not use THREADLOCAL because it is not supported on some of the
+// platforms we care about (OSX 10.6, Android).
+// static THREADLOCAL AllocatorCache cache;
+AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ return &ms->allocator_cache;
+}
+
+QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache));
+ return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache);
+}
+
+void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
+ quarantine_size_mb = f->quarantine_size_mb;
+ min_redzone = f->redzone;
+ max_redzone = f->max_redzone;
+ may_return_null = cf->allocator_may_return_null;
+ alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
+}
+
+void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
+ f->quarantine_size_mb = quarantine_size_mb;
+ f->redzone = min_redzone;
+ f->max_redzone = max_redzone;
+ cf->allocator_may_return_null = may_return_null;
+ f->alloc_dealloc_mismatch = alloc_dealloc_mismatch;
+}
+
+struct Allocator {
+ static const uptr kMaxAllowedMallocSize =
+ FIRST_32_SECOND_64(3UL << 30, 1UL << 40);
+ static const uptr kMaxThreadLocalQuarantine =
+ FIRST_32_SECOND_64(1 << 18, 1 << 20);
+
+ AsanAllocator allocator;
+ AsanQuarantine quarantine;
+ StaticSpinMutex fallback_mutex;
+ AllocatorCache fallback_allocator_cache;
+ QuarantineCache fallback_quarantine_cache;
+
+ // ------------------- Options --------------------------
+ atomic_uint16_t min_redzone;
+ atomic_uint16_t max_redzone;
+ atomic_uint8_t alloc_dealloc_mismatch;
+
+ // ------------------- Initialization ------------------------
+ explicit Allocator(LinkerInitialized)
+ : quarantine(LINKER_INITIALIZED),
+ fallback_quarantine_cache(LINKER_INITIALIZED) {}
+
+ void CheckOptions(const AllocatorOptions &options) const {
+ CHECK_GE(options.min_redzone, 16);
+ CHECK_GE(options.max_redzone, options.min_redzone);
+ CHECK_LE(options.max_redzone, 2048);
+ CHECK(IsPowerOfTwo(options.min_redzone));
+ CHECK(IsPowerOfTwo(options.max_redzone));
+ }
+
+ void SharedInitCode(const AllocatorOptions &options) {
+ CheckOptions(options);
+ quarantine.Init((uptr)options.quarantine_size_mb << 20,
+ kMaxThreadLocalQuarantine);
+ atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
+ memory_order_release);
+ atomic_store(&min_redzone, options.min_redzone, memory_order_release);
+ atomic_store(&max_redzone, options.max_redzone, memory_order_release);
+ }
+
+ void Initialize(const AllocatorOptions &options) {
+ allocator.Init(options.may_return_null);
+ SharedInitCode(options);
+ }
+
+ void ReInitialize(const AllocatorOptions &options) {
+ allocator.SetMayReturnNull(options.may_return_null);
+ SharedInitCode(options);
+ }
+
+ void GetOptions(AllocatorOptions *options) const {
+ options->quarantine_size_mb = quarantine.GetSize() >> 20;
+ options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
+ options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
+ options->may_return_null = allocator.MayReturnNull();
+ options->alloc_dealloc_mismatch =
+ atomic_load(&alloc_dealloc_mismatch, memory_order_acquire);
+ }
+
+ // -------------------- Helper methods. -------------------------
+ uptr ComputeRZLog(uptr user_requested_size) {
+ u32 rz_log =
+ user_requested_size <= 64 - 16 ? 0 :
+ user_requested_size <= 128 - 32 ? 1 :
+ user_requested_size <= 512 - 64 ? 2 :
+ user_requested_size <= 4096 - 128 ? 3 :
+ user_requested_size <= (1 << 14) - 256 ? 4 :
+ user_requested_size <= (1 << 15) - 512 ? 5 :
+ user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
+ u32 min_rz = atomic_load(&min_redzone, memory_order_acquire);
+ u32 max_rz = atomic_load(&max_redzone, memory_order_acquire);
+ return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
+ }
+
+ // We have an address between two chunks, and we want to report just one.
+ AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
+ AsanChunk *right_chunk) {
+ // Prefer an allocated chunk over freed chunk and freed chunk
+ // over available chunk.
+ if (left_chunk->chunk_state != right_chunk->chunk_state) {
+ if (left_chunk->chunk_state == CHUNK_ALLOCATED)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_ALLOCATED)
+ return right_chunk;
+ if (left_chunk->chunk_state == CHUNK_QUARANTINE)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_QUARANTINE)
+ return right_chunk;
+ }
+ // Same chunk_state: choose based on offset.
+ sptr l_offset = 0, r_offset = 0;
+ CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
+ CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
+ if (l_offset < r_offset)
+ return left_chunk;
+ return right_chunk;
+ }
+
+ // -------------------- Allocation/Deallocation routines ---------------
+ void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
+ AllocType alloc_type, bool can_fill) {
+ if (UNLIKELY(!asan_inited))
+ AsanInitFromRtl();
+ Flags &fl = *flags();
+ CHECK(stack);
+ const uptr min_alignment = SHADOW_GRANULARITY;
+ if (alignment < min_alignment)
+ alignment = min_alignment;
+ if (size == 0) {
+ // We'd be happy to avoid allocating memory for zero-size requests, but
+ // some programs/tests depend on this behavior and assume that malloc
+ // would not return NULL even for zero-size allocations. Moreover, it
+ // looks like operator new should never return NULL, and results of
+ // consecutive "new" calls must be different even if the allocated size
+ // is zero.
+ size = 1;
+ }
+ CHECK(IsPowerOfTwo(alignment));
+ uptr rz_log = ComputeRZLog(size);
+ uptr rz_size = RZLog2Size(rz_log);
+ uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
+ uptr needed_size = rounded_size + rz_size;
+ if (alignment > min_alignment)
+ needed_size += alignment;
+ bool using_primary_allocator = true;
+ // If we are allocating from the secondary allocator, there will be no
+ // automatic right redzone, so add the right redzone manually.
+ if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) {
+ needed_size += rz_size;
+ using_primary_allocator = false;
+ }
+ CHECK(IsAligned(needed_size, min_alignment));
+ if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
+ Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
+ (void*)size);
+ return allocator.ReturnNullOrDie();
+ }
+
+ AsanThread *t = GetCurrentThread();
+ void *allocated;
+ bool check_rss_limit = true;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated =
+ allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated =
+ allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ }
+
+ if (!allocated)
+ return allocator.ReturnNullOrDie();
+
+ if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
+ // Heap poisoning is enabled, but the allocator provides an unpoisoned
+ // chunk. This is possible if CanPoisonMemory() was false for some
+ // time, for example, due to flags()->start_disabled.
+ // Anyway, poison the block before using it for anything else.
+ uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
+ PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+
+ uptr alloc_beg = reinterpret_cast<uptr>(allocated);
+ uptr alloc_end = alloc_beg + needed_size;
+ uptr beg_plus_redzone = alloc_beg + rz_size;
+ uptr user_beg = beg_plus_redzone;
+ if (!IsAligned(user_beg, alignment))
+ user_beg = RoundUpTo(user_beg, alignment);
+ uptr user_end = user_beg + size;
+ CHECK_LE(user_end, alloc_end);
+ uptr chunk_beg = user_beg - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ m->alloc_type = alloc_type;
+ m->rz_log = rz_log;
+ u32 alloc_tid = t ? t->tid() : 0;
+ m->alloc_tid = alloc_tid;
+ CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield?
+ m->free_tid = kInvalidTid;
+ m->from_memalign = user_beg != beg_plus_redzone;
+ if (alloc_beg != chunk_beg) {
+ CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg);
+ reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic;
+ reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg;
+ }
+ if (using_primary_allocator) {
+ CHECK(size);
+ m->user_requested_size = size;
+ CHECK(allocator.FromPrimary(allocated));
+ } else {
+ CHECK(!allocator.FromPrimary(allocated));
+ m->user_requested_size = SizeClassMap::kMaxSize;
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
+ meta[0] = size;
+ meta[1] = chunk_beg;
+ }
+
+ m->alloc_context_id = StackDepotPut(*stack);
+
+ uptr size_rounded_down_to_granularity =
+ RoundDownTo(size, SHADOW_GRANULARITY);
+ // Unpoison the bulk of the memory region.
+ if (size_rounded_down_to_granularity)
+ PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
+ // Deal with the end of the region if size is not aligned to granularity.
+ if (size != size_rounded_down_to_granularity && CanPoisonMemory()) {
+ u8 *shadow =
+ (u8 *)MemToShadow(user_beg + size_rounded_down_to_granularity);
+ *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
+ }
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mallocs++;
+ thread_stats.malloced += size;
+ thread_stats.malloced_redzones += needed_size - size;
+ if (needed_size > SizeClassMap::kMaxSize)
+ thread_stats.malloc_large++;
+ else
+ thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++;
+
+ void *res = reinterpret_cast<void *>(user_beg);
+ if (can_fill && fl.max_malloc_fill_size) {
+ uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
+ REAL(memset)(res, fl.malloc_fill_byte, fill_size);
+ }
+#if CAN_SANITIZE_LEAKS
+ m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored
+ : __lsan::kDirectlyLeaked;
+#endif
+ // Must be the last mutation of metadata in this function.
+ atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
+ ASAN_MALLOC_HOOK(res, size);
+ return res;
+ }
+
+ void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ BufferedStackTrace *stack) {
+ u8 old_chunk_state = CHUNK_ALLOCATED;
+ // Flip the chunk_state atomically to avoid race on double-free.
+ if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
+ CHUNK_QUARANTINE, memory_order_acquire))
+ ReportInvalidFree(ptr, old_chunk_state, stack);
+ CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+ }
+
+ // Expects the chunk to already be marked as quarantined by using
+ // AtomicallySetQuarantineFlag.
+ void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+
+ if (m->alloc_type != alloc_type) {
+ if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
+ ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
+ (AllocType)alloc_type);
+ }
+ }
+
+ CHECK_GE(m->alloc_tid, 0);
+ if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
+ CHECK_EQ(m->free_tid, kInvalidTid);
+ AsanThread *t = GetCurrentThread();
+ m->free_tid = t ? t->tid() : 0;
+ m->free_context_id = StackDepotPut(*stack);
+ // Poison the region.
+ PoisonShadow(m->Beg(),
+ RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
+ kAsanHeapFreeMagic);
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.frees++;
+ thread_stats.freed += m->UsedSize();
+
+ // Push into quarantine.
+ if (t) {
+ AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
+ AllocatorCache *ac = GetAllocatorCache(ms);
+ quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m,
+ m->UsedSize());
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *ac = &fallback_allocator_cache;
+ quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m,
+ m->UsedSize());
+ }
+ }
+
+ void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ uptr p = reinterpret_cast<uptr>(ptr);
+ if (p == 0) return;
+
+ uptr chunk_beg = p - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ if (delete_size && flags()->new_delete_type_mismatch &&
+ delete_size != m->UsedSize()) {
+ ReportNewDeleteSizeMismatch(p, delete_size, stack);
+ }
+ ASAN_FREE_HOOK(ptr);
+ // Must mark the chunk as quarantined before any changes to its metadata.
+ AtomicallySetQuarantineFlag(m, ptr, stack);
+ QuarantineChunk(m, ptr, stack, alloc_type);
+ }
+
+ void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
+ CHECK(old_ptr && new_size);
+ uptr p = reinterpret_cast<uptr>(old_ptr);
+ uptr chunk_beg = p - kChunkHeaderSize;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.reallocs++;
+ thread_stats.realloced += new_size;
+
+ void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
+ if (new_ptr) {
+ u8 chunk_state = m->chunk_state;
+ if (chunk_state != CHUNK_ALLOCATED)
+ ReportInvalidFree(old_ptr, chunk_state, stack);
+ CHECK_NE(REAL(memcpy), nullptr);
+ uptr memcpy_size = Min(new_size, m->UsedSize());
+ // If realloc() races with free(), we may start copying freed memory.
+ // However, we will report racy double-free later anyway.
+ REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
+ Deallocate(old_ptr, 0, stack, FROM_MALLOC);
+ }
+ return new_ptr;
+ }
+
+ void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return allocator.ReturnNullOrDie();
+ void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
+ // If the memory comes from the secondary allocator no need to clear it
+ // as it comes directly from mmap.
+ if (ptr && allocator.FromPrimary(ptr))
+ REAL(memset)(ptr, 0, nmemb * size);
+ return ptr;
+ }
+
+ void ReportInvalidFree(void *ptr, u8 chunk_state, BufferedStackTrace *stack) {
+ if (chunk_state == CHUNK_QUARANTINE)
+ ReportDoubleFree((uptr)ptr, stack);
+ else
+ ReportFreeNotMalloced((uptr)ptr, stack);
+ }
+
+ void CommitBack(AsanThreadLocalMallocStorage *ms) {
+ AllocatorCache *ac = GetAllocatorCache(ms);
+ quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac));
+ allocator.SwallowCache(ac);
+ }
+
+ // -------------------------- Chunk lookup ----------------------
+
+ // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+ AsanChunk *GetAsanChunk(void *alloc_beg) {
+ if (!alloc_beg) return nullptr;
+ if (!allocator.FromPrimary(alloc_beg)) {
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
+ return m;
+ }
+ uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg);
+ if (alloc_magic[0] == kAllocBegMagic)
+ return reinterpret_cast<AsanChunk *>(alloc_magic[1]);
+ return reinterpret_cast<AsanChunk *>(alloc_beg);
+ }
+
+ AsanChunk *GetAsanChunkByAddr(uptr p) {
+ void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
+ }
+
+ // Allocator must be locked when this function is called.
+ AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
+ void *alloc_beg =
+ allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
+ }
+
+ uptr AllocationSize(uptr p) {
+ AsanChunk *m = GetAsanChunkByAddr(p);
+ if (!m) return 0;
+ if (m->chunk_state != CHUNK_ALLOCATED) return 0;
+ if (m->Beg() != p) return 0;
+ return m->UsedSize();
+ }
+
+ AsanChunkView FindHeapChunkByAddress(uptr addr) {
+ AsanChunk *m1 = GetAsanChunkByAddr(addr);
+ if (!m1) return AsanChunkView(m1);
+ sptr offset = 0;
+ if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
+ // The address is in the chunk's left redzone, so maybe it is actually
+ // a right buffer overflow from the other chunk to the left.
+ // Search a bit to the left to see if there is another chunk.
+ AsanChunk *m2 = nullptr;
+ for (uptr l = 1; l < GetPageSizeCached(); l++) {
+ m2 = GetAsanChunkByAddr(addr - l);
+ if (m2 == m1) continue; // Still the same chunk.
+ break;
+ }
+ if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
+ m1 = ChooseChunk(addr, m2, m1);
+ }
+ return AsanChunkView(m1);
+ }
+
+ void PrintStats() {
+ allocator.PrintStats();
+ }
+
+ void ForceLock() {
+ allocator.ForceLock();
+ fallback_mutex.Lock();
+ }
+
+ void ForceUnlock() {
+ fallback_mutex.Unlock();
+ allocator.ForceUnlock();
+ }
+};
+
+static Allocator instance(LINKER_INITIALIZED);
+
+static AsanAllocator &get_allocator() {
+ return instance.allocator;
+}
+
+bool AsanChunkView::IsValid() {
+ return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
+}
+uptr AsanChunkView::Beg() { return chunk_->Beg(); }
+uptr AsanChunkView::End() { return Beg() + UsedSize(); }
+uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
+uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
+uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
+
+static StackTrace GetStackTraceFromId(u32 id) {
+ CHECK(id);
+ StackTrace res = StackDepotGet(id);
+ CHECK(res.trace);
+ return res;
+}
+
+StackTrace AsanChunkView::GetAllocStack() {
+ return GetStackTraceFromId(chunk_->alloc_context_id);
+}
+
+StackTrace AsanChunkView::GetFreeStack() {
+ return GetStackTraceFromId(chunk_->free_context_id);
+}
+
+void InitializeAllocator(const AllocatorOptions &options) {
+ instance.Initialize(options);
+}
+
+void ReInitializeAllocator(const AllocatorOptions &options) {
+ instance.ReInitialize(options);
+}
+
+void GetAllocatorOptions(AllocatorOptions *options) {
+ instance.GetOptions(options);
+}
+
+AsanChunkView FindHeapChunkByAddress(uptr addr) {
+ return instance.FindHeapChunkByAddress(addr);
+}
+
+void AsanThreadLocalMallocStorage::CommitBack() {
+ instance.CommitBack(this);
+}
+
+void PrintInternalAllocatorStats() {
+ instance.PrintStats();
+}
+
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ return instance.Allocate(size, alignment, stack, alloc_type, true);
+}
+
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
+ instance.Deallocate(ptr, 0, stack, alloc_type);
+}
+
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ instance.Deallocate(ptr, size, stack, alloc_type);
+}
+
+void *asan_malloc(uptr size, BufferedStackTrace *stack) {
+ return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+}
+
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
+ return instance.Calloc(nmemb, size, stack);
+}
+
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
+ if (!p)
+ return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+ if (size == 0) {
+ instance.Deallocate(p, 0, stack, FROM_MALLOC);
+ return nullptr;
+ }
+ return instance.Reallocate(p, size, stack);
+}
+
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
+ return instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
+}
+
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ return instance.Allocate(size, PageSize, stack, FROM_MALLOC, true);
+}
+
+int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
+ BufferedStackTrace *stack) {
+ void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);
+ CHECK(IsAligned((uptr)ptr, alignment));
+ *memptr = ptr;
+ return 0;
+}
+
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
+ if (!ptr) return 0;
+ uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
+ if (flags()->check_malloc_usable_size && (usable_size == 0)) {
+ GET_STACK_TRACE_FATAL(pc, bp);
+ ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
+ }
+ return usable_size;
+}
+
+uptr asan_mz_size(const void *ptr) {
+ return instance.AllocationSize(reinterpret_cast<uptr>(ptr));
+}
+
+void asan_mz_force_lock() {
+ instance.ForceLock();
+}
+
+void asan_mz_force_unlock() {
+ instance.ForceUnlock();
+}
+
+void AsanSoftRssLimitExceededCallback(bool exceeded) {
+ instance.allocator.SetRssLimitIsExceeded(exceeded);
+}
+
+} // namespace __asan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+void LockAllocator() {
+ __asan::get_allocator().ForceLock();
+}
+
+void UnlockAllocator() {
+ __asan::get_allocator().ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&__asan::get_allocator();
+ *end = *begin + sizeof(__asan::get_allocator());
+}
+
+uptr PointsIntoChunk(void* p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr);
+ if (!m) return 0;
+ uptr chunk = m->Beg();
+ if (m->chunk_state != __asan::CHUNK_ALLOCATED)
+ return 0;
+ if (m->AddrIsInside(addr, /*locked_version=*/true))
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
+ addr))
+ return chunk;
+ return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
+ CHECK(m);
+ return m->Beg();
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
+}
+
+bool LsanMetadata::allocated() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->chunk_state == __asan::CHUNK_ALLOCATED;
+}
+
+ChunkTag LsanMetadata::tag() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return static_cast<ChunkTag>(m->lsan_tag);
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ m->lsan_tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->UsedSize(/*locked_version=*/true);
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+ __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+ return m->alloc_context_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ __asan::get_allocator().ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
+ if (!m) return kIgnoreObjectInvalid;
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) {
+ if (m->lsan_tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->lsan_tag = __lsan::kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
+}
+} // namespace __lsan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// ASan allocator doesn't reserve extra bytes, so normally we would
+// just return "size". We don't want to expose our redzone sizes, etc here.
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
+ return size;
+}
+
+int __sanitizer_get_ownership(const void *p) {
+ uptr ptr = reinterpret_cast<uptr>(p);
+ return instance.AllocationSize(ptr) > 0;
+}
+
+uptr __sanitizer_get_allocated_size(const void *p) {
+ if (!p) return 0;
+ uptr ptr = reinterpret_cast<uptr>(p);
+ uptr allocated_size = instance.AllocationSize(ptr);
+ // Die if p is not malloced or if it is already freed.
+ if (allocated_size == 0) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
+ }
+ return allocated_size;
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+// Provide default (no-op) implementation of malloc hooks.
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
+ (void)ptr;
+ (void)size;
+}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_free_hook(void *ptr) {
+ (void)ptr;
+}
+} // extern "C"
+#endif
diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h
new file mode 100644
index 0000000..e3d5333
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_allocator.h
@@ -0,0 +1,184 @@
+//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_allocator.cc.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ALLOCATOR_H
+#define ASAN_ALLOCATOR_H
+
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_list.h"
+
+namespace __asan {
+
+enum AllocType {
+ FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.
+ FROM_NEW = 2, // Memory block came from operator new.
+ FROM_NEW_BR = 3 // Memory block came from operator new [ ]
+};
+
+struct AsanChunk;
+
+struct AllocatorOptions {
+ u32 quarantine_size_mb;
+ u16 min_redzone;
+ u16 max_redzone;
+ u8 may_return_null;
+ u8 alloc_dealloc_mismatch;
+
+ void SetFrom(const Flags *f, const CommonFlags *cf);
+ void CopyTo(Flags *f, CommonFlags *cf);
+};
+
+void InitializeAllocator(const AllocatorOptions &options);
+void ReInitializeAllocator(const AllocatorOptions &options);
+void GetAllocatorOptions(AllocatorOptions *options);
+
+class AsanChunkView {
+ public:
+ explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
+ uptr AllocTid();
+ uptr FreeTid();
+ bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
+ StackTrace GetAllocStack();
+ StackTrace GetFreeStack();
+ bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
+ if (addr >= Beg() && (addr + access_size) <= End()) {
+ *offset = addr - Beg();
+ return true;
+ }
+ return false;
+ }
+ bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
+ (void)access_size;
+ if (addr < Beg()) {
+ *offset = Beg() - addr;
+ return true;
+ }
+ return false;
+ }
+ bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+ if (addr + access_size > End()) {
+ *offset = addr - End();
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ AsanChunk *const chunk_;
+};
+
+AsanChunkView FindHeapChunkByAddress(uptr address);
+
+// List of AsanChunks with total size.
+class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
+ public:
+ explicit AsanChunkFifoList(LinkerInitialized) { }
+ AsanChunkFifoList() { clear(); }
+ void Push(AsanChunk *n);
+ void PushList(AsanChunkFifoList *q);
+ AsanChunk *Pop();
+ uptr size() { return size_; }
+ void clear() {
+ IntrusiveList<AsanChunk>::clear();
+ size_ = 0;
+ }
+ private:
+ uptr size_;
+};
+
+struct AsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const;
+ void OnUnmap(uptr p, uptr size) const;
+};
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__powerpc64__)
+const uptr kAllocatorSpace = 0xa0000000000ULL;
+const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+# elif defined(__aarch64__)
+// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA
+// so no need to different values for different VMA.
+const uptr kAllocatorSpace = 0x10000000000ULL;
+const uptr kAllocatorSize = 0x10000000000ULL; // 3T.
+# else
+const uptr kAllocatorSpace = 0x600000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+# endif
+typedef DefaultSizeClassMap SizeClassMap;
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
+ SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+#else // Fallback to SizeClassAllocator32.
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+# if SANITIZER_WORDSIZE == 32
+typedef FlatByteMap<kNumRegions> ByteMap;
+# elif SANITIZER_WORDSIZE == 64
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+# endif
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
+ SizeClassMap, kRegionSizeLog,
+ ByteMap,
+ AsanMapUnmapCallback> PrimaryAllocator;
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+
+static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> AsanAllocator;
+
+
+struct AsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ AllocatorCache allocator_cache;
+ void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ AsanThreadLocalMallocStorage() {}
+};
+
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type);
+
+void *asan_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
+
+int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
+ BufferedStackTrace *stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
+
+uptr asan_mz_size(const void *ptr);
+void asan_mz_force_lock();
+void asan_mz_force_unlock();
+
+void PrintInternalAllocatorStats();
+void AsanSoftRssLimitExceededCallback(bool exceeded);
+
+} // namespace __asan
+#endif // ASAN_ALLOCATOR_H
diff --git a/compiler-rt/lib/asan/asan_android_stub.cc b/compiler-rt/lib/asan/asan_android_stub.cc
new file mode 100644
index 0000000..cf68f58
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_android_stub.cc
@@ -0,0 +1,4 @@
+#include "sanitizer/asan_interface.h"
+
+__attribute__((section(".preinit_array")))
+ typeof(__asan_init) *__asan_preinit =__asan_init;
diff --git a/compiler-rt/lib/asan/asan_blacklist.txt b/compiler-rt/lib/asan/asan_blacklist.txt
new file mode 100644
index 0000000..c25921f
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_blacklist.txt
@@ -0,0 +1,13 @@
+# Blacklist for AddressSanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
+# global:*global_with_bad_access_or_initialization*
+# global:*global_with_initialization_issues*=init
+# type:*Namespace::ClassName*=init
+
+# Stack buffer overflow in VC/INCLUDE/xlocnum, see http://goo.gl/L4qqUG
+fun:*_Find_elem@*@std*
diff --git a/compiler-rt/lib/asan/asan_debugging.cc b/compiler-rt/lib/asan/asan_debugging.cc
new file mode 100644
index 0000000..7c3a8a7
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_debugging.cc
@@ -0,0 +1,141 @@
+//===-- asan_debugging.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+ descr->region_kind = "stack";
+
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access))
+ return;
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ return;
+ }
+
+ for (uptr i = 0; i < vars.size(); i++) {
+ if (access.offset <= vars[i].beg + vars[i].size) {
+ internal_strncat(descr->name, vars[i].name_pos,
+ Min(descr->name_size, vars[i].name_len));
+ descr->region_address = addr - (access.offset - vars[i].beg);
+ descr->region_size = vars[i].size;
+ return;
+ }
+ }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+
+ if (!chunk.IsValid()) {
+ descr->region_kind = "heap-invalid";
+ return;
+ }
+
+ descr->region_address = chunk.Beg();
+ descr->region_size = chunk.UsedSize();
+ descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+ if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+ return;
+ }
+ if (GetInfoForAddressIfGlobal(addr, descr)) {
+ return;
+ }
+ asanThreadRegistry().Lock();
+ AsanThread *thread = FindThreadByStackAddress(addr);
+ asanThreadRegistry().Unlock();
+ if (thread) {
+ GetInfoForStackVar(addr, descr, thread);
+ return;
+ }
+ GetInfoForHeapAddress(addr, descr);
+}
+
+static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
+ bool alloc_stack) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) return 0;
+
+ StackTrace stack(nullptr, 0);
+ if (alloc_stack) {
+ if (chunk.AllocTid() == kInvalidTid) return 0;
+ stack = chunk.GetAllocStack();
+ if (thread_id) *thread_id = chunk.AllocTid();
+ } else {
+ if (chunk.FreeTid() == kInvalidTid) return 0;
+ stack = chunk.GetFreeStack();
+ if (thread_id) *thread_id = chunk.FreeTid();
+ }
+
+ if (trace && size) {
+ size = Min(size, Min(stack.size, kStackTraceMax));
+ for (uptr i = 0; i < size; i++)
+ trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+} // namespace __asan
+
+using namespace __asan;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size) {
+ AddressDescription descr = { name, name_size, 0, 0, nullptr };
+ AsanLocateAddress(addr, &descr);
+ if (region_address) *region_address = descr.region_address;
+ if (region_size) *region_size = descr.region_size;
+ return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+ if (shadow_scale)
+ *shadow_scale = SHADOW_SCALE;
+ if (shadow_offset)
+ *shadow_offset = SHADOW_OFFSET;
+}
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cc b/compiler-rt/lib/asan/asan_fake_stack.cc
new file mode 100644
index 0000000..91fdf0a
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_fake_stack.cc
@@ -0,0 +1,283 @@
+//===-- asan_fake_stack.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// FakeStack is used to detect use-after-return bugs.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_poisoning.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+static const u64 kMagic1 = kAsanStackAfterReturnMagic;
+static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
+static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
+static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;
+
+static const u64 kAllocaRedzoneSize = 32UL;
+static const u64 kAllocaRedzoneMask = 31UL;
+
+// For small size classes inline PoisonShadow for better performance.
+ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
+ CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
+ u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
+ if (class_id <= 6) {
+ for (uptr i = 0; i < (1U << class_id); i++) {
+ shadow[i] = magic;
+ // Make sure this does not become memset.
+ SanitizerBreakOptimization(nullptr);
+ }
+ } else {
+ // The size class is too big, it's cheaper to poison only size bytes.
+ PoisonShadow(ptr, size, static_cast<u8>(magic));
+ }
+}
+
+FakeStack *FakeStack::Create(uptr stack_size_log) {
+ static uptr kMinStackSizeLog = 16;
+ static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28);
+ if (stack_size_log < kMinStackSizeLog)
+ stack_size_log = kMinStackSizeLog;
+ if (stack_size_log > kMaxStackSizeLog)
+ stack_size_log = kMaxStackSizeLog;
+ uptr size = RequiredSize(stack_size_log);
+ FakeStack *res = reinterpret_cast<FakeStack *>(
+ flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
+ : MmapOrDie(size, "FakeStack"));
+ res->stack_size_log_ = stack_size_log;
+ u8 *p = reinterpret_cast<u8 *>(res);
+ VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
+ "mmapped %zdK, noreserve=%d \n",
+ GetCurrentTidOrInvalid(), p,
+ p + FakeStack::RequiredSize(stack_size_log), stack_size_log,
+ size >> 10, flags()->uar_noreserve);
+ return res;
+}
+
+void FakeStack::Destroy(int tid) {
+ PoisonAll(0);
+ if (Verbosity() >= 2) {
+ InternalScopedString str(kNumberOfSizeClasses * 50);
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
+ str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
+ NumberOfFrames(stack_size_log(), class_id));
+ Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
+ }
+ uptr size = RequiredSize(stack_size_log_);
+ FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
+ UnmapOrDie(this, size);
+}
+
+void FakeStack::PoisonAll(u8 magic) {
+ PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
+ magic);
+}
+
+#if !defined(_MSC_VER) || defined(__clang__)
+ALWAYS_INLINE USED
+#endif
+FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
+ uptr real_stack) {
+ CHECK_LT(class_id, kNumberOfSizeClasses);
+ if (needs_gc_)
+ GC(real_stack);
+ uptr &hint_position = hint_position_[class_id];
+ const int num_iter = NumberOfFrames(stack_size_log, class_id);
+ u8 *flags = GetFlags(stack_size_log, class_id);
+ for (int i = 0; i < num_iter; i++) {
+ uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
+ // This part is tricky. On one hand, checking and setting flags[pos]
+ // should be atomic to ensure async-signal safety. But on the other hand,
+ // if the signal arrives between checking and setting flags[pos], the
+ // signal handler's fake stack will start from a different hint_position
+ // and so will not touch this particular byte. So, it is safe to do this
+ // with regular non-atimic load and store (at least I was not able to make
+ // this code crash).
+ if (flags[pos]) continue;
+ flags[pos] = 1;
+ FakeFrame *res = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log, class_id, pos));
+ res->real_stack = real_stack;
+ *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
+ return res;
+ }
+ return nullptr; // We are out of fake stack.
+}
+
+uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
+ uptr stack_size_log = this->stack_size_log();
+ uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
+ uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
+ if (ptr < beg || ptr >= end) return 0;
+ uptr class_id = (ptr - beg) >> stack_size_log;
+ uptr base = beg + (class_id << stack_size_log);
+ CHECK_LE(base, ptr);
+ CHECK_LT(ptr, base + (1UL << stack_size_log));
+ uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
+ uptr res = base + pos * BytesInSizeClass(class_id);
+ *frame_end = res + BytesInSizeClass(class_id);
+ *frame_beg = res + sizeof(FakeFrame);
+ return res;
+}
+
+void FakeStack::HandleNoReturn() {
+ needs_gc_ = true;
+}
+
+// When throw, longjmp or some such happens we don't call OnFree() and
+// as the result may leak one or more fake frames, but the good news is that
+// we are notified about all such events by HandleNoReturn().
+// If we recently had such no-return event we need to collect garbage frames.
+// We do it based on their 'real_stack' values -- everything that is lower
+// than the current real_stack is garbage.
+NOINLINE void FakeStack::GC(uptr real_stack) {
+ uptr collected = 0;
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ if (ff->real_stack < real_stack) {
+ flags[i] = 0;
+ collected++;
+ }
+ }
+ }
+ needs_gc_ = false;
+}
+
+void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ uptr begin = reinterpret_cast<uptr>(ff);
+ callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
+ }
+ }
+}
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+static THREADLOCAL FakeStack *fake_stack_tls;
+
+FakeStack *GetTLSFakeStack() {
+ return fake_stack_tls;
+}
+void SetTLSFakeStack(FakeStack *fs) {
+ fake_stack_tls = fs;
+}
+#else
+FakeStack *GetTLSFakeStack() { return 0; }
+void SetTLSFakeStack(FakeStack *fs) { }
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+static FakeStack *GetFakeStack() {
+ AsanThread *t = GetCurrentThread();
+ if (!t) return nullptr;
+ return t->fake_stack();
+}
+
+static FakeStack *GetFakeStackFast() {
+ if (FakeStack *fs = GetTLSFakeStack())
+ return fs;
+ if (!__asan_option_detect_stack_use_after_return)
+ return nullptr;
+ return GetFakeStack();
+}
+
+ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
+ FakeStack *fs = GetFakeStackFast();
+ if (!fs) return 0;
+ uptr local_stack;
+ uptr real_stack = reinterpret_cast<uptr>(&local_stack);
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
+ if (!ff) return 0; // Out of fake stack.
+ uptr ptr = reinterpret_cast<uptr>(ff);
+ SetShadow(ptr, size, class_id, 0);
+ return ptr;
+}
+
+ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
+ FakeStack::Deallocate(ptr, class_id);
+ SetShadow(ptr, size, class_id, kMagic8);
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;
+#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
+ __asan_stack_malloc_##class_id(uptr size) { \
+ return OnMalloc(class_id, size); \
+ } \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
+ uptr ptr, uptr size) { \
+ OnFree(ptr, class_id, size); \
+ }
+
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
+ void **end) {
+ FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
+ if (!fs) return nullptr;
+ uptr frame_beg, frame_end;
+ FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
+ reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
+ if (!frame) return nullptr;
+ if (frame->magic != kCurrentStackFrameMagic)
+ return nullptr;
+ if (beg) *beg = reinterpret_cast<void*>(frame_beg);
+ if (end) *end = reinterpret_cast<void*>(frame_end);
+ return reinterpret_cast<void*>(frame->real_stack);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_alloca_poison(uptr addr, uptr size) {
+ uptr LeftRedzoneAddr = addr - kAllocaRedzoneSize;
+ uptr PartialRzAddr = addr + size;
+ uptr RightRzAddr = (PartialRzAddr + kAllocaRedzoneMask) & ~kAllocaRedzoneMask;
+ uptr PartialRzAligned = PartialRzAddr & ~(SHADOW_GRANULARITY - 1);
+ FastPoisonShadow(LeftRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaLeftMagic);
+ FastPoisonShadowPartialRightRedzone(
+ PartialRzAligned, PartialRzAddr % SHADOW_GRANULARITY,
+ RightRzAddr - PartialRzAligned, kAsanAllocaRightMagic);
+ FastPoisonShadow(RightRzAddr, kAllocaRedzoneSize, kAsanAllocaRightMagic);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_allocas_unpoison(uptr top, uptr bottom) {
+ if ((!top) || (top > bottom)) return;
+ REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0,
+ (bottom - top) / SHADOW_GRANULARITY);
+}
+} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h
new file mode 100644
index 0000000..3b1d9eb
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_fake_stack.h
@@ -0,0 +1,175 @@
+//===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_fake_stack.cc, implements FakeStack.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_FAKE_STACK_H
+#define ASAN_FAKE_STACK_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __asan {
+
+// Fake stack frame contains local variables of one function.
+struct FakeFrame {
+ uptr magic; // Modified by the instrumented code.
+ uptr descr; // Modified by the instrumented code.
+ uptr pc; // Modified by the instrumented code.
+ uptr real_stack;
+};
+
+// For each thread we create a fake stack and place stack objects on this fake
+// stack instead of the real stack. The fake stack is not really a stack but
+// a fast malloc-like allocator so that when a function exits the fake stack
+// is not popped but remains there for quite some time until gets used again.
+// So, we poison the objects on the fake stack when function returns.
+// It helps us find use-after-return bugs.
+//
+// The FakeStack objects is allocated by a single mmap call and has no other
+// pointers. The size of the fake stack depends on the actual thread stack size
+// and thus can not be a constant.
+// stack_size is a power of two greater or equal to the thread's stack size;
+// we store it as its logarithm (stack_size_log).
+// FakeStack has kNumberOfSizeClasses (11) size classes, each size class
+// is a power of two, starting from 64 bytes. Each size class occupies
+// stack_size bytes and thus can allocate
+// NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2).
+// For each size class we have NumberOfFrames allocation flags,
+// each flag indicates whether the given frame is currently allocated.
+// All flags for size classes 0 .. 10 are stored in a single contiguous region
+// followed by another contiguous region which contains the actual memory for
+// size classes. The addresses are computed by GetFlags and GetFrame without
+// any memory accesses solely based on 'this' and stack_size_log.
+// Allocate() flips the appropriate allocation flag atomically, thus achieving
+// async-signal safety.
+// This allocator does not have quarantine per se, but it tries to allocate the
+// frames in round robin fasion to maximize the delay between a deallocation
+// and the next allocation.
+class FakeStack {
+ static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B.
+ static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
+
+ public:
+ static const uptr kNumberOfSizeClasses =
+ kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
+
+ // CTOR: create the FakeStack as a single mmap-ed object.
+ static FakeStack *Create(uptr stack_size_log);
+
+ void Destroy(int tid);
+
+ // stack_size_log is at least 15 (stack_size >= 32K).
+ static uptr SizeRequiredForFlags(uptr stack_size_log) {
+ return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog);
+ }
+
+ // Each size class occupies stack_size bytes.
+ static uptr SizeRequiredForFrames(uptr stack_size_log) {
+ return (1ULL << stack_size_log) * kNumberOfSizeClasses;
+ }
+
+ // Number of bytes requires for the whole object.
+ static uptr RequiredSize(uptr stack_size_log) {
+ return kFlagsOffset + SizeRequiredForFlags(stack_size_log) +
+ SizeRequiredForFrames(stack_size_log);
+ }
+
+ // Offset of the given flag from the first flag.
+ // The flags for class 0 begin at offset 000000000
+ // The flags for class 1 begin at offset 100000000
+ // ....................2................ 110000000
+ // ....................3................ 111000000
+ // and so on.
+ static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
+ uptr t = kNumberOfSizeClasses - 1 - class_id;
+ const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1;
+ return ((all_ones >> t) << t) << (stack_size_log - 15);
+ }
+
+ static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
+ return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id);
+ }
+
+ // Divide n by the numbe of frames in size class.
+ static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) {
+ return n & (NumberOfFrames(stack_size_log, class_id) - 1);
+ }
+
+ // The the pointer to the flags of the given class_id.
+ u8 *GetFlags(uptr stack_size_log, uptr class_id) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ FlagsOffset(stack_size_log, class_id);
+ }
+
+ // Get frame by class_id and pos.
+ u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ SizeRequiredForFlags(stack_size_log) +
+ (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos;
+ }
+
+ // Allocate the fake frame.
+ FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack);
+
+ // Deallocate the fake frame: read the saved flag address and write 0 there.
+ static void Deallocate(uptr x, uptr class_id) {
+ **SavedFlagPtr(x, class_id) = 0;
+ }
+
+ // Poison the entire FakeStack's shadow with the magic value.
+ void PoisonAll(u8 magic);
+
+ // Return the beginning of the FakeFrame or 0 if the address is not ours.
+ uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
+ USED uptr AddrIsInFakeStack(uptr addr) {
+ uptr t1, t2;
+ return AddrIsInFakeStack(addr, &t1, &t2);
+ }
+
+ // Number of bytes in a fake frame of this size class.
+ static uptr BytesInSizeClass(uptr class_id) {
+ return 1UL << (class_id + kMinStackFrameSizeLog);
+ }
+
+ // The fake frame is guaranteed to have a right redzone.
+ // We use the last word of that redzone to store the address of the flag
+ // that corresponds to the current frame to make faster deallocation.
+ static u8 **SavedFlagPtr(uptr x, uptr class_id) {
+ return reinterpret_cast<u8 **>(x + BytesInSizeClass(class_id) - sizeof(x));
+ }
+
+ uptr stack_size_log() const { return stack_size_log_; }
+
+ void HandleNoReturn();
+ void GC(uptr real_stack);
+
+ void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
+
+ private:
+ FakeStack() { }
+ static const uptr kFlagsOffset = 4096; // This is were the flags begin.
+ // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
+ COMPILER_CHECK(kNumberOfSizeClasses == 11);
+ static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+
+ uptr hint_position_[kNumberOfSizeClasses];
+ uptr stack_size_log_;
+ // a bit is set if something was allocated from the corresponding size class.
+ bool needs_gc_;
+};
+
+FakeStack *GetTLSFakeStack();
+void SetTLSFakeStack(FakeStack *fs);
+
+} // namespace __asan
+
+#endif // ASAN_FAKE_STACK_H
diff --git a/compiler-rt/lib/asan/asan_flags.cc b/compiler-rt/lib/asan/asan_flags.cc
new file mode 100644
index 0000000..363ee67
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_flags.cc
@@ -0,0 +1,171 @@
+//===-- asan_flags.cc -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan flag parsing logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_flags.h"
+#include "asan_interface_internal.h"
+#include "asan_stack.h"
+#include "lsan/lsan_common.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "ubsan/ubsan_flags.h"
+#include "ubsan/ubsan_platform.h"
+
+namespace __asan {
+
+Flags asan_flags_dont_use_directly; // use via flags().
+
+static const char *MaybeCallAsanDefaultOptions() {
+ return (&__asan_default_options) ? __asan_default_options() : "";
+}
+
+static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
+#ifdef ASAN_DEFAULT_OPTIONS
+// Stringize the macro value.
+# define ASAN_STRINGIZE(x) #x
+# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options)
+ return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS);
+#else
+ return "";
+#endif
+}
+
+void Flags::SetDefaults() {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+}
+
+static void RegisterAsanFlags(FlagParser *parser, Flags *f) {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+}
+
+void InitializeFlags() {
+ // Set the default values and prepare for parsing ASan and common flags.
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.detect_leaks = CAN_SANITIZE_LEAKS;
+ cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = kDefaultMallocContextSize;
+ cf.intercept_tls_get_addr = true;
+ cf.exitcode = 1;
+ OverrideCommonFlags(cf);
+ }
+ Flags *f = flags();
+ f->SetDefaults();
+
+ FlagParser asan_parser;
+ RegisterAsanFlags(&asan_parser, f);
+ RegisterCommonFlags(&asan_parser);
+
+ // Set the default values and prepare for parsing LSan and UBSan flags
+ // (which can also overwrite common flags).
+#if CAN_SANITIZE_LEAKS
+ __lsan::Flags *lf = __lsan::flags();
+ lf->SetDefaults();
+
+ FlagParser lsan_parser;
+ __lsan::RegisterLsanFlags(&lsan_parser, lf);
+ RegisterCommonFlags(&lsan_parser);
+#endif
+
+#if CAN_SANITIZE_UB
+ __ubsan::Flags *uf = __ubsan::flags();
+ uf->SetDefaults();
+
+ FlagParser ubsan_parser;
+ __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+ RegisterCommonFlags(&ubsan_parser);
+#endif
+
+ // Override from ASan compile definition.
+ const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
+ asan_parser.ParseString(asan_compile_def);
+
+ // Override from user-specified string.
+ const char *asan_default_options = MaybeCallAsanDefaultOptions();
+ asan_parser.ParseString(asan_default_options);
+#if CAN_SANITIZE_UB
+ const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+ ubsan_parser.ParseString(ubsan_default_options);
+#endif
+
+ // Override from command line.
+ asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
+#if CAN_SANITIZE_LEAKS
+ lsan_parser.ParseString(GetEnv("LSAN_OPTIONS"));
+#endif
+#if CAN_SANITIZE_UB
+ ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
+
+ SetVerbosity(common_flags()->verbosity);
+
+ // TODO(eugenis): dump all flags at verbosity>=2?
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) {
+ // TODO(samsonov): print all of the flags (ASan, LSan, common).
+ asan_parser.PrintFlagDescriptions();
+ }
+
+ // Flag validation:
+ if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
+ Report("%s: detect_leaks is not supported on this platform.\n",
+ SanitizerToolName);
+ Die();
+ }
+ // Make "strict_init_order" imply "check_initialization_order".
+ // TODO(samsonov): Use a single runtime flag for an init-order checker.
+ if (f->strict_init_order) {
+ f->check_initialization_order = true;
+ }
+ CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax);
+ CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log);
+ CHECK_GE(f->redzone, 16);
+ CHECK_GE(f->max_redzone, f->redzone);
+ CHECK_LE(f->max_redzone, 2048);
+ CHECK(IsPowerOfTwo(f->redzone));
+ CHECK(IsPowerOfTwo(f->max_redzone));
+
+ // quarantine_size is deprecated but we still honor it.
+ // quarantine_size can not be used together with quarantine_size_mb.
+ if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) {
+ Report("%s: please use either 'quarantine_size' (deprecated) or "
+ "quarantine_size_mb, but not both\n", SanitizerToolName);
+ Die();
+ }
+ if (f->quarantine_size >= 0)
+ f->quarantine_size_mb = f->quarantine_size >> 20;
+ if (f->quarantine_size_mb < 0) {
+ const int kDefaultQuarantineSizeMb =
+ (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8;
+ f->quarantine_size_mb = kDefaultQuarantineSizeMb;
+ }
+}
+
+} // namespace __asan
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __asan_default_options() { return ""; }
+} // extern "C"
+#endif
diff --git a/compiler-rt/lib/asan/asan_flags.h b/compiler-rt/lib/asan/asan_flags.h
new file mode 100644
index 0000000..4935161
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_flags.h
@@ -0,0 +1,49 @@
+//===-- asan_flags.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan runtime flags.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_FLAGS_H
+#define ASAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+
+// ASan flag values can be defined in four ways:
+// 1) initialized with default values at startup.
+// 2) overriden during compilation of ASan runtime by providing
+// compile definition ASAN_DEFAULT_OPTIONS.
+// 3) overriden from string returned by user-specified function
+// __asan_default_options().
+// 4) overriden from env variable ASAN_OPTIONS.
+// 5) overriden during ASan activation (for now used on Android only).
+
+namespace __asan {
+
+struct Flags {
+#define ASAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "asan_flags.inc"
+#undef ASAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags asan_flags_dont_use_directly;
+inline Flags *flags() {
+ return &asan_flags_dont_use_directly;
+}
+
+void InitializeFlags();
+
+} // namespace __asan
+
+#endif // ASAN_FLAGS_H
diff --git a/compiler-rt/lib/asan/asan_flags.inc b/compiler-rt/lib/asan/asan_flags.inc
new file mode 100644
index 0000000..5e69242
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_flags.inc
@@ -0,0 +1,137 @@
+//===-- asan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ASan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_FLAG
+# error "Define ASAN_FLAG prior to including this file!"
+#endif
+
+// ASAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+ASAN_FLAG(int, quarantine_size, -1,
+ "Deprecated, please use quarantine_size_mb.")
+ASAN_FLAG(int, quarantine_size_mb, -1,
+ "Size (in Mb) of quarantine used to detect use-after-free "
+ "errors. Lower value may reduce memory usage but increase the "
+ "chance of false negatives.")
+ASAN_FLAG(int, redzone, 16,
+ "Minimal size (in bytes) of redzones around heap objects. "
+ "Requirement: redzone >= 16, is a power of two.")
+ASAN_FLAG(int, max_redzone, 2048,
+ "Maximal size (in bytes) of redzones around heap objects.")
+ASAN_FLAG(
+ bool, debug, false,
+ "If set, prints some debugging information and does additional checks.")
+ASAN_FLAG(
+ int, report_globals, 1,
+ "Controls the way to handle globals (0 - don't detect buffer overflow on "
+ "globals, 1 - detect buffer overflow, 2 - print data about registered "
+ "globals).")
+ASAN_FLAG(bool, check_initialization_order, false,
+ "If set, attempts to catch initialization order issues.")
+ASAN_FLAG(
+ bool, replace_str, true,
+ "If set, uses custom wrappers and replacements for libc string functions "
+ "to find more errors.")
+ASAN_FLAG(bool, replace_intrin, true,
+ "If set, uses custom wrappers for memset/memcpy/memmove intinsics.")
+ASAN_FLAG(bool, detect_stack_use_after_return, false,
+ "Enables stack-use-after-return checking at run-time.")
+ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway.
+ "Minimum fake stack size log.")
+ASAN_FLAG(int, max_uar_stack_size_log,
+ 20, // 1Mb per size class, i.e. ~11Mb per thread
+ "Maximum fake stack size log.")
+ASAN_FLAG(bool, uar_noreserve, false,
+ "Use mmap with 'noreserve' flag to allocate fake stack.")
+ASAN_FLAG(
+ int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
+ "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
+ "bytes that will be filled with malloc_fill_byte on malloc.")
+ASAN_FLAG(int, malloc_fill_byte, 0xbe,
+ "Value used to fill the newly allocated memory.")
+ASAN_FLAG(bool, allow_user_poisoning, true,
+ "If set, user may manually mark memory regions as poisoned or "
+ "unpoisoned.")
+ASAN_FLAG(
+ int, sleep_before_dying, 0,
+ "Number of seconds to sleep between printing an error report and "
+ "terminating the program. Useful for debugging purposes (e.g. when one "
+ "needs to attach gdb).")
+ASAN_FLAG(bool, check_malloc_usable_size, true,
+ "Allows the users to work around the bug in Nvidia drivers prior to "
+ "295.*.")
+ASAN_FLAG(bool, unmap_shadow_on_exit, false,
+ "If set, explicitly unmaps the (huge) shadow at exit.")
+ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap")
+ASAN_FLAG(bool, print_stats, false,
+ "Print various statistics after printing an error message or if "
+ "atexit=1.")
+ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.")
+ASAN_FLAG(bool, atexit, false,
+ "If set, prints ASan exit stats even after program terminates "
+ "successfully.")
+ASAN_FLAG(
+ bool, print_full_thread_history, true,
+ "If set, prints thread creation stacks for the threads involved in the "
+ "report and their ancestors up to the main thread.")
+ASAN_FLAG(
+ bool, poison_heap, true,
+ "Poison (or not) the heap memory on [de]allocation. Zero value is useful "
+ "for benchmarking the allocator or instrumentator.")
+ASAN_FLAG(bool, poison_partial, true,
+ "If true, poison partially addressable 8-byte aligned words "
+ "(default=true). This flag affects heap and global buffers, but not "
+ "stack buffers.")
+ASAN_FLAG(bool, poison_array_cookie, true,
+ "Poison (or not) the array cookie after operator new[].")
+
+// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
+// https://github.com/google/sanitizers/issues/131
+// https://github.com/google/sanitizers/issues/309
+// TODO(glider,timurrrr): Fix known issues and enable this back.
+ASAN_FLAG(bool, alloc_dealloc_mismatch,
+ (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0),
+ "Report errors on malloc/delete, new/free, new/delete[], etc.")
+
+ASAN_FLAG(bool, new_delete_type_mismatch, true,
+ "Report errors on mismatch betwen size of new and delete.")
+ASAN_FLAG(
+ bool, strict_init_order, false,
+ "If true, assume that dynamic initializers can never access globals from "
+ "other modules, even if the latter are already initialized.")
+ASAN_FLAG(
+ bool, start_deactivated, false,
+ "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap "
+ "poisoning) to reduce memory consumption as much as possible, and "
+ "restores them to original values when the first instrumented module is "
+ "loaded into the process. This is mainly intended to be used on "
+ "Android. ")
+ASAN_FLAG(
+ int, detect_invalid_pointer_pairs, 0,
+ "If non-zero, try to detect operations like <, <=, >, >= and - on "
+ "invalid pointer pairs (e.g. when pointers belong to different objects). "
+ "The bigger the value the harder we try.")
+ASAN_FLAG(
+ bool, detect_container_overflow, true,
+ "If true, honor the container overflow annotations. See "
+ "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow")
+ASAN_FLAG(int, detect_odr_violation, 2,
+ "If >=2, detect violation of One-Definition-Rule (ODR); "
+ "If ==1, detect ODR-violation only if the two variables "
+ "have different sizes")
+ASAN_FLAG(bool, dump_instruction_bytes, false,
+ "If true, dump 16 bytes starting at the instruction that caused SEGV")
+ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
+ASAN_FLAG(bool, halt_on_error, true,
+ "Crash the program after printing the first error report "
+ "(WARNING: USE AT YOUR OWN RISK!)")
diff --git a/compiler-rt/lib/asan/asan_globals.cc b/compiler-rt/lib/asan/asan_globals.cc
new file mode 100644
index 0000000..eb9f1bf
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_globals.cc
@@ -0,0 +1,292 @@
+//===-- asan_globals.cc ---------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Handle globals.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_suppressions.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+typedef __asan_global Global;
+
+struct ListOfGlobals {
+ const Global *g;
+ ListOfGlobals *next;
+};
+
+static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_globals;
+static ListOfGlobals *list_of_all_globals;
+
+static const int kDynamicInitGlobalsInitialCapacity = 512;
+struct DynInitGlobal {
+ Global g;
+ bool initialized;
+};
+typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
+// Lazy-initialized and never deleted.
+static VectorOfGlobals *dynamic_init_globals;
+
+// We want to remember where a certain range of globals was registered.
+struct GlobalRegistrationSite {
+ u32 stack_id;
+ Global *g_first, *g_last;
+};
+typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
+static GlobalRegistrationSiteVector *global_registration_site_vector;
+
+ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
+ FastPoisonShadow(g->beg, g->size_with_redzone, value);
+}
+
+ALWAYS_INLINE void PoisonRedZones(const Global &g) {
+ uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
+ FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+ kAsanGlobalRedzoneMagic);
+ if (g.size != aligned_size) {
+ FastPoisonShadowPartialRightRedzone(
+ g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
+ g.size % SHADOW_GRANULARITY,
+ SHADOW_GRANULARITY,
+ kAsanGlobalRedzoneMagic);
+ }
+}
+
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+ if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+ if (addr >= g.beg + g.size_with_redzone) return false;
+ return true;
+}
+
+static void ReportGlobal(const Global &g, const char *prefix) {
+ Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+ prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
+ g.module_name, g.has_dynamic_init);
+ if (g.location) {
+ Report(" location (%p): name=%s[%p], %d %d\n", g.location,
+ g.location->filename, g.location->filename, g.location->line_no,
+ g.location->column_no);
+ }
+}
+
+static u32 FindRegistrationSite(const Global *g) {
+ mu_for_globals.CheckLocked();
+ CHECK(global_registration_site_vector);
+ for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
+ GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
+ if (g >= grs.g_first && g <= grs.g_last)
+ return grs.stack_id;
+ }
+ return 0;
+}
+
+int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites,
+ int max_globals) {
+ if (!flags()->report_globals) return 0;
+ BlockingMutexLock lock(&mu_for_globals);
+ int res = 0;
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ const Global &g = *l->g;
+ if (flags()->report_globals >= 2)
+ ReportGlobal(g, "Search");
+ if (IsAddressNearGlobal(addr, g)) {
+ globals[res] = g;
+ if (reg_sites)
+ reg_sites[res] = FindRegistrationSite(&g);
+ res++;
+ if (res == max_globals) break;
+ }
+ }
+ return res;
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+ Global g = {};
+ if (GetGlobalsForAddress(addr, &g, nullptr, 1)) {
+ internal_strncpy(descr->name, g.name, descr->name_size);
+ descr->region_address = g.beg;
+ descr->region_size = g.size;
+ descr->region_kind = "global";
+ return true;
+ }
+ return false;
+}
+
+// Register a global variable.
+// This function may be called more than once for every global
+// so we store the globals in a map.
+static void RegisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ if (flags()->report_globals >= 2)
+ ReportGlobal(*g, "Added");
+ CHECK(flags()->report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (flags()->detect_odr_violation) {
+ // Try detecting ODR (One Definition Rule) violation, i.e. the situation
+ // where two globals with the same name are defined in different modules.
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
+ !IsODRViolationSuppressed(g->name))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+ }
+ if (CanPoisonMemory())
+ PoisonRedZones(*g);
+ ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
+ l->g = g;
+ l->next = list_of_all_globals;
+ list_of_all_globals = l;
+ if (g->has_dynamic_init) {
+ if (!dynamic_init_globals) {
+ dynamic_init_globals = new(allocator_for_globals)
+ VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
+ }
+ DynInitGlobal dyn_global = { *g, false };
+ dynamic_init_globals->push_back(dyn_global);
+ }
+}
+
+static void UnregisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ if (flags()->report_globals >= 2)
+ ReportGlobal(*g, "Removed");
+ CHECK(flags()->report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (CanPoisonMemory())
+ PoisonShadowForGlobal(g, 0);
+ // We unpoison the shadow memory for the global but we do not remove it from
+ // the list because that would require O(n^2) time with the current list
+ // implementation. It might not be worth doing anyway.
+}
+
+void StopInitOrderChecking() {
+ BlockingMutexLock lock(&mu_for_globals);
+ if (!flags()->check_initialization_order || !dynamic_init_globals)
+ return;
+ flags()->check_initialization_order = false;
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ // Unpoison the whole global.
+ PoisonShadowForGlobal(g, 0);
+ // Poison redzones back.
+ PoisonRedZones(*g);
+ }
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// Register an array of globals.
+void __asan_register_globals(__asan_global *globals, uptr n) {
+ if (!flags()->report_globals) return;
+ GET_STACK_TRACE_MALLOC;
+ u32 stack_id = StackDepotPut(stack);
+ BlockingMutexLock lock(&mu_for_globals);
+ if (!global_registration_site_vector)
+ global_registration_site_vector =
+ new(allocator_for_globals) GlobalRegistrationSiteVector(128);
+ GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
+ global_registration_site_vector->push_back(site);
+ if (flags()->report_globals >= 2) {
+ PRINT_CURRENT_STACK();
+ Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
+ }
+ for (uptr i = 0; i < n; i++) {
+ RegisterGlobal(&globals[i]);
+ }
+}
+
+// Unregister an array of globals.
+// We must do this when a shared objects gets dlclosed.
+void __asan_unregister_globals(__asan_global *globals, uptr n) {
+ if (!flags()->report_globals) return;
+ BlockingMutexLock lock(&mu_for_globals);
+ for (uptr i = 0; i < n; i++) {
+ UnregisterGlobal(&globals[i]);
+ }
+}
+
+// This method runs immediately prior to dynamic initialization in each TU,
+// when all dynamically initialized globals are unpoisoned. This method
+// poisons all global variables not defined in this TU, so that a dynamic
+// initializer can only touch global variables in the same TU.
+void __asan_before_dynamic_init(const char *module_name) {
+ if (!flags()->check_initialization_order ||
+ !CanPoisonMemory())
+ return;
+ bool strict_init_order = flags()->strict_init_order;
+ CHECK(dynamic_init_globals);
+ CHECK(module_name);
+ CHECK(asan_inited);
+ BlockingMutexLock lock(&mu_for_globals);
+ if (flags()->report_globals >= 3)
+ Printf("DynInitPoison module: %s\n", module_name);
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ if (dyn_g.initialized)
+ continue;
+ if (g->module_name != module_name)
+ PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
+ else if (!strict_init_order)
+ dyn_g.initialized = true;
+ }
+}
+
+// This method runs immediately after dynamic initialization in each TU, when
+// all dynamically initialized globals except for those defined in the current
+// TU are poisoned. It simply unpoisons all dynamically initialized globals.
+void __asan_after_dynamic_init() {
+ if (!flags()->check_initialization_order ||
+ !CanPoisonMemory())
+ return;
+ CHECK(asan_inited);
+ BlockingMutexLock lock(&mu_for_globals);
+ // FIXME: Optionally report that we're unpoisoning globals from a module.
+ for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+ DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+ const Global *g = &dyn_g.g;
+ if (!dyn_g.initialized) {
+ // Unpoison the whole global.
+ PoisonShadowForGlobal(g, 0);
+ // Poison redzones back.
+ PoisonRedZones(*g);
+ }
+ }
+}
diff --git a/compiler-rt/lib/asan/asan_init_version.h b/compiler-rt/lib/asan/asan_init_version.h
new file mode 100644
index 0000000..bc8a622
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_init_version.h
@@ -0,0 +1,34 @@
+//===-- asan_init_version.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This header defines a versioned __asan_init function to be called at the
+// startup of the instrumented program.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INIT_VERSION_H
+#define ASAN_INIT_VERSION_H
+
+extern "C" {
+ // Every time the ASan ABI changes we also change the version number in the
+ // __asan_init function name. Objects built with incompatible ASan ABI
+ // versions will not link with run-time.
+ // Changes between ABI versions:
+ // v1=>v2: added 'module_name' to __asan_global
+ // v2=>v3: stack frame description (created by the compiler)
+ // contains the function PC as the 3-rd field (see
+ // DescribeAddressIfStack).
+ // v3=>v4: added '__asan_global_source_location' to __asan_global.
+ // v4=>v5: changed the semantics and format of __asan_stack_malloc_ and
+ // __asan_stack_free_ functions.
+ // v5=>v6: changed the name of the version check symbol
+ #define __asan_version_mismatch_check __asan_version_mismatch_check_v6
+}
+
+#endif // ASAN_INIT_VERSION_H
diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc
new file mode 100644
index 0000000..d9a0c71
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_interceptors.cc
@@ -0,0 +1,822 @@
+//===-- asan_interceptors.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Intercept various libc functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_suppressions.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#if SANITIZER_POSIX
+#include "sanitizer_common/sanitizer_posix.h"
+#endif
+
+#if defined(__i386) && SANITIZER_LINUX
+#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
+#elif defined(__mips__) && SANITIZER_LINUX
+#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
+#endif
+
+namespace __asan {
+
+// Return true if we can quickly decide that the region is unpoisoned.
+static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
+ if (size == 0) return true;
+ if (size <= 32)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + size / 2);
+ return false;
+}
+
+struct AsanInterceptorContext {
+ const char *interceptor_name;
+};
+
+// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
+// and ASAN_WRITE_RANGE as macro instead of function so
+// that no extra frames are created, and stack trace contains
+// relevant information only.
+// We check all shadow bytes.
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
+ uptr __offset = (uptr)(offset); \
+ uptr __size = (uptr)(size); \
+ uptr __bad = 0; \
+ if (__offset > __offset + __size) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
+ } \
+ if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
+ (__bad = __asan_region_is_poisoned(__offset, __size))) { \
+ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
+ } \
+ } \
+ } while (0)
+
+#define ASAN_READ_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, false)
+#define ASAN_WRITE_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, true)
+
+#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
+ ASAN_READ_RANGE((ctx), (s), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n))
+
+#define ASAN_READ_STRING(ctx, s, n) \
+ ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
+// Behavior of functions like "memcpy" or "strcpy" is undefined
+// if memory intervals overlap. We report error in this case.
+// Macro is used to avoid creation of new frames.
+static inline bool RangesOverlap(const char *offset1, uptr length1,
+ const char *offset2, uptr length2) {
+ return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
+}
+#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
+ const char *offset1 = (const char*)_offset1; \
+ const char *offset2 = (const char*)_offset2; \
+ if (RangesOverlap(offset1, length1, offset2, length2)) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
+ offset2, length2, &stack); \
+ } \
+} while (0)
+
+static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
+#if ASAN_INTERCEPT_STRNLEN
+ if (REAL(strnlen)) {
+ return REAL(strnlen)(s, maxlen);
+ }
+#endif
+ return internal_strnlen(s, maxlen);
+}
+
+void SetThreadName(const char *name) {
+ AsanThread *t = GetCurrentThread();
+ if (t)
+ asanThreadRegistry().SetThreadName(t->tid(), name);
+}
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // namespace __asan
+
+// ---------------------- Wrappers ---------------- {{{1
+using namespace __asan; // NOLINT
+
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+
+#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
+ AsanInterceptorContext _ctx = {#func}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx; \
+
+#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ ASAN_WRITE_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ ASAN_READ_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ ASAN_INTERCEPTOR_ENTER(ctx, func); \
+ do { \
+ if (asan_init_is_running) \
+ return REAL(func)(__VA_ARGS__); \
+ if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
+ return REAL(func)(__VA_ARGS__); \
+ ENSURE_ASAN_INITED(); \
+ } while (false)
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
+// But asan does not remember UserId's for threads (pthread_t);
+// and remembers all ever existed threads, so the linear search by UserId
+// can be slow.
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+// Strict init-order checking is dlopen-hostile:
+// https://github.com/google/sanitizers/issues/178
+#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
+ if (flags()->strict_init_order) { \
+ StopInitOrderChecking(); \
+ }
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ CoverageUpdateMapping()
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
+#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
+ if (AsanThread *t = GetCurrentThread()) { \
+ *begin = t->tls_begin(); \
+ *end = t->tls_end(); \
+ } else { \
+ *begin = *end = 0; \
+ }
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+// Syscall interceptors don't have contexts, we don't support suppressions
+// for them.
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+struct ThreadStartParam {
+ atomic_uintptr_t t;
+ atomic_uintptr_t is_registered;
+};
+
+static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
+ ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
+ AsanThread *t = nullptr;
+ while ((t = reinterpret_cast<AsanThread *>(
+ atomic_load(¶m->t, memory_order_acquire))) == nullptr)
+ internal_sched_yield();
+ SetCurrentThread(t);
+ return t->ThreadStart(GetTid(), ¶m->is_registered);
+}
+
+#if ASAN_INTERCEPT_PTHREAD_CREATE
+INTERCEPTOR(int, pthread_create, void *thread,
+ void *attr, void *(*start_routine)(void*), void *arg) {
+ EnsureMainThreadIDIsCorrect();
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order)
+ StopInitOrderChecking();
+ GET_STACK_TRACE_THREAD;
+ int detached = 0;
+ if (attr)
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
+ ThreadStartParam param;
+ atomic_store(¶m.t, 0, memory_order_relaxed);
+ atomic_store(¶m.is_registered, 0, memory_order_relaxed);
+ int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
+ if (result == 0) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // Wait until the AsanThread object is initialized and the ThreadRegistry
+ // entry is in "started" state. One reason for this is that after this
+ // interceptor exits, the child thread's stack may be the only thing holding
+ // the |arg| pointer. This may cause LSan to report a leak if leak checking
+ // happens at a point when the interceptor has already exited, but the stack
+ // range for the child thread is not yet known.
+ while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
+}
+
+INTERCEPTOR(int, pthread_join, void *t, void **arg) {
+ return real_pthread_join(t, arg);
+}
+
+DEFINE_REAL_PTHREAD_FUNCTIONS
+#endif // ASAN_INTERCEPT_PTHREAD_CREATE
+
+#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
+
+#if SANITIZER_ANDROID
+INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
+ if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ return REAL(bsd_signal)(signum, handler);
+ }
+ return 0;
+}
+#endif
+
+INTERCEPTOR(void*, signal, int signum, void *handler) {
+ if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ return REAL(signal)(signum, handler);
+ }
+ return nullptr;
+}
+
+INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact) {
+ if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ return REAL(sigaction)(signum, act, oldact);
+ }
+ return 0;
+}
+
+namespace __sanitizer {
+int real_sigaction(int signum, const void *act, void *oldact) {
+ return REAL(sigaction)(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+} // namespace __sanitizer
+
+#elif SANITIZER_POSIX
+// We need to have defined REAL(sigaction) on posix systems.
+DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
+
+#if ASAN_INTERCEPT_SWAPCONTEXT
+static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
+ // Align to page size.
+ uptr PageSize = GetPageSizeCached();
+ uptr bottom = stack & ~(PageSize - 1);
+ ssize += stack - bottom;
+ ssize = RoundUpTo(ssize, PageSize);
+ static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb
+ if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) {
+ PoisonShadow(bottom, ssize, 0);
+ }
+}
+
+INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
+ struct ucontext_t *ucp) {
+ static bool reported_warning = false;
+ if (!reported_warning) {
+ Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
+ "functions and may produce false positives in some cases!\n");
+ reported_warning = true;
+ }
+ // Clear shadow memory for new context (it may share stack
+ // with current context).
+ uptr stack, ssize;
+ ReadContextStack(ucp, &stack, &ssize);
+ ClearShadowMemoryForContextStack(stack, ssize);
+ int res = REAL(swapcontext)(oucp, ucp);
+ // swapcontext technically does not return, but program may swap context to
+ // "oucp" later, that would look as if swapcontext() returned 0.
+ // We need to clear shadow for ucp once again, as it may be in arbitrary
+ // state.
+ ClearShadowMemoryForContextStack(stack, ssize);
+ return res;
+}
+#endif // ASAN_INTERCEPT_SWAPCONTEXT
+
+INTERCEPTOR(void, longjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(longjmp)(env, val);
+}
+
+#if ASAN_INTERCEPT__LONGJMP
+INTERCEPTOR(void, _longjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(_longjmp)(env, val);
+}
+#endif
+
+#if ASAN_INTERCEPT_SIGLONGJMP
+INTERCEPTOR(void, siglongjmp, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(siglongjmp)(env, val);
+}
+#endif
+
+#if ASAN_INTERCEPT___CXA_THROW
+INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
+ CHECK(REAL(__cxa_throw));
+ __asan_handle_no_return();
+ REAL(__cxa_throw)(a, b, c);
+}
+#endif
+
+// memcpy is called during __asan_init() from the internals of printf(...).
+// We do not treat memcpy with to==from as a bug.
+// See http://llvm.org/bugs/show_bug.cgi?id=11763.
+#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
+ if (asan_init_is_running) { \
+ return REAL(memcpy)(to, from, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ if (to != from) { \
+ CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
+ } \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return REAL(memcpy)(to, from, size); \
+ } while (0)
+
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+// memset is called inside Printf.
+#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
+ if (asan_init_is_running) { \
+ return REAL(memset)(block, c, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_WRITE_RANGE(ctx, block, size); \
+ } \
+ return REAL(memset)(block, c, size); \
+ } while (0)
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) \
+ return internal_memmove(to, from, size); \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return internal_memmove(to, from, size); \
+ } while (0)
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
+}
+
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memmove);
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+}
+
+INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
+#if !SANITIZER_MAC
+ ASAN_MEMCPY_IMPL(ctx, to, from, size);
+#else
+ // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
+ // with WRAP(memcpy). As a result, false positives are reported for memmove()
+ // calls. If we just disable error reporting with
+ // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
+ // internal_memcpy(), which may lead to crashes, see
+ // http://llvm.org/bugs/show_bug.cgi?id=16362.
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+#endif // !SANITIZER_MAC
+}
+
+INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memset);
+ ASAN_MEMSET_IMPL(ctx, block, c, size);
+}
+
+INTERCEPTOR(char*, strchr, const char *str, int c) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strchr);
+ if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
+ // strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
+ // used.
+ if (asan_init_is_running) {
+ return REAL(strchr)(str, c);
+ }
+ ENSURE_ASAN_INITED();
+ char *result = REAL(strchr)(str, c);
+ if (flags()->replace_str) {
+ uptr len = REAL(strlen)(str);
+ uptr bytes_read = (result ? result - str : len) + 1;
+ ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
+ }
+ return result;
+}
+
+#if ASAN_INTERCEPT_INDEX
+# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+INTERCEPTOR(char*, index, const char *string, int c)
+ ALIAS(WRAPPER_NAME(strchr));
+# else
+# if SANITIZER_MAC
+DECLARE_REAL(char*, index, const char *string, int c)
+OVERRIDE_FUNCTION(index, strchr);
+# else
+DEFINE_REAL(char*, index, const char *string, int c)
+# endif
+# endif
+#endif // ASAN_INTERCEPT_INDEX
+
+// For both strcat() and strncat() we need to check the validity of |to|
+// argument irrespective of the |from| length.
+INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_length = REAL(strlen)(from);
+ ASAN_READ_RANGE(ctx, from, from_length + 1);
+ uptr to_length = REAL(strlen)(to);
+ ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+ // If the copying actually happens, the |from| string should not overlap
+ // with the resulting string starting at |to|, which has a length of
+ // to_length + from_length + 1.
+ if (from_length > 0) {
+ CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1,
+ from, from_length + 1);
+ }
+ }
+ return REAL(strcat)(to, from); // NOLINT
+}
+
+INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncat);
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_length = MaybeRealStrnlen(from, size);
+ uptr copy_length = Min(size, from_length + 1);
+ ASAN_READ_RANGE(ctx, from, copy_length);
+ uptr to_length = REAL(strlen)(to);
+ ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+ if (from_length > 0) {
+ CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
+ from, copy_length);
+ }
+ }
+ return REAL(strncat)(to, from, size);
+}
+
+INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
+#endif
+ // strcpy is called from malloc_default_purgeable_zone()
+ // in __asan::ReplaceSystemAlloc() on Mac.
+ if (asan_init_is_running) {
+ return REAL(strcpy)(to, from); // NOLINT
+ }
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_size = REAL(strlen)(from) + 1;
+ CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, from_size);
+ }
+ return REAL(strcpy)(to, from); // NOLINT
+}
+
+#if ASAN_INTERCEPT_STRDUP
+INTERCEPTOR(char*, strdup, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strdup);
+ if (UNLIKELY(!asan_inited)) return internal_strdup(s);
+ ENSURE_ASAN_INITED();
+ uptr length = REAL(strlen)(s);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, length + 1);
+ }
+ GET_STACK_TRACE_MALLOC;
+ void *new_mem = asan_malloc(length + 1, &stack);
+ REAL(memcpy)(new_mem, s, length + 1);
+ return reinterpret_cast<char*>(new_mem);
+}
+#endif
+
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strlen);
+ if (UNLIKELY(!asan_inited)) return internal_strlen(s);
+ // strlen is called from malloc_default_purgeable_zone()
+ // in __asan::ReplaceSystemAlloc() on Mac.
+ if (asan_init_is_running) {
+ return REAL(strlen)(s);
+ }
+ ENSURE_ASAN_INITED();
+ SIZE_T length = REAL(strlen)(s);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, length + 1);
+ }
+ return length;
+}
+
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
+ SIZE_T length = REAL(wcslen)(s);
+ if (!asan_init_is_running) {
+ ENSURE_ASAN_INITED();
+ ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
+ }
+ return length;
+}
+
+INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
+ ENSURE_ASAN_INITED();
+ if (flags()->replace_str) {
+ uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
+ CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, size);
+ }
+ return REAL(strncpy)(to, from, size);
+}
+
+#if ASAN_INTERCEPT_STRNLEN
+INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
+ ENSURE_ASAN_INITED();
+ uptr length = REAL(strnlen)(s, maxlen);
+ if (flags()->replace_str) {
+ ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
+ }
+ return length;
+}
+#endif // ASAN_INTERCEPT_STRNLEN
+
+INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
+ char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtol);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(strtol)(nptr, endptr, base);
+ }
+ char *real_endptr;
+ long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ return result;
+}
+
+INTERCEPTOR(int, atoi, const char *nptr) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoi);
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
+#endif
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atoi)(nptr);
+ }
+ char *real_endptr;
+ // "man atoi" tells that behavior of atoi(nptr) is the same as
+ // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
+ // parsed integer can't be stored in *long* type (even if it's
+ // different from int). So, we just imitate this behavior.
+ int result = REAL(strtol)(nptr, &real_endptr, 10);
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+
+INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atol);
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
+#endif
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atol)(nptr);
+ }
+ char *real_endptr;
+ long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+
+#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
+ char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(strtoll)(nptr, endptr, base);
+ }
+ char *real_endptr;
+ long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ return result;
+}
+
+INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoll);
+ ENSURE_ASAN_INITED();
+ if (!flags()->replace_str) {
+ return REAL(atoll)(nptr);
+ }
+ char *real_endptr;
+ long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
+ return result;
+}
+#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+
+static void AtCxaAtexit(void *unused) {
+ (void)unused;
+ StopInitOrderChecking();
+}
+
+#if ASAN_INTERCEPT___CXA_ATEXIT
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+#if SANITIZER_MAC
+ if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
+#endif
+ ENSURE_ASAN_INITED();
+ int res = REAL(__cxa_atexit)(func, arg, dso_handle);
+ REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
+ return res;
+}
+#endif // ASAN_INTERCEPT___CXA_ATEXIT
+
+#if ASAN_INTERCEPT_FORK
+INTERCEPTOR(int, fork, void) {
+ ENSURE_ASAN_INITED();
+ if (common_flags()->coverage) CovBeforeFork();
+ int pid = REAL(fork)();
+ if (common_flags()->coverage) CovAfterFork(pid);
+ return pid;
+}
+#endif // ASAN_INTERCEPT_FORK
+
+// ---------------------- InitializeAsanInterceptors ---------------- {{{1
+namespace __asan {
+void InitializeAsanInterceptors() {
+ static bool was_called_once;
+ CHECK(was_called_once == false);
+ was_called_once = true;
+ InitializeCommonInterceptors();
+
+ // Intercept mem* functions.
+ ASAN_INTERCEPT_FUNC(memmove);
+ ASAN_INTERCEPT_FUNC(memset);
+ if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
+ ASAN_INTERCEPT_FUNC(memcpy);
+ }
+
+ // Intercept str* functions.
+ ASAN_INTERCEPT_FUNC(strcat); // NOLINT
+ ASAN_INTERCEPT_FUNC(strchr);
+ ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
+ ASAN_INTERCEPT_FUNC(strlen);
+ ASAN_INTERCEPT_FUNC(wcslen);
+ ASAN_INTERCEPT_FUNC(strncat);
+ ASAN_INTERCEPT_FUNC(strncpy);
+#if ASAN_INTERCEPT_STRDUP
+ ASAN_INTERCEPT_FUNC(strdup);
+#endif
+#if ASAN_INTERCEPT_STRNLEN
+ ASAN_INTERCEPT_FUNC(strnlen);
+#endif
+#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+ ASAN_INTERCEPT_FUNC(index);
+#endif
+
+ ASAN_INTERCEPT_FUNC(atoi);
+ ASAN_INTERCEPT_FUNC(atol);
+ ASAN_INTERCEPT_FUNC(strtol);
+#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+ ASAN_INTERCEPT_FUNC(atoll);
+ ASAN_INTERCEPT_FUNC(strtoll);
+#endif
+
+ // Intecept signal- and jump-related functions.
+ ASAN_INTERCEPT_FUNC(longjmp);
+#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
+ ASAN_INTERCEPT_FUNC(sigaction);
+#if SANITIZER_ANDROID
+ ASAN_INTERCEPT_FUNC(bsd_signal);
+#endif
+ ASAN_INTERCEPT_FUNC(signal);
+#endif
+#if ASAN_INTERCEPT_SWAPCONTEXT
+ ASAN_INTERCEPT_FUNC(swapcontext);
+#endif
+#if ASAN_INTERCEPT__LONGJMP
+ ASAN_INTERCEPT_FUNC(_longjmp);
+#endif
+#if ASAN_INTERCEPT_SIGLONGJMP
+ ASAN_INTERCEPT_FUNC(siglongjmp);
+#endif
+
+ // Intercept exception handling functions.
+#if ASAN_INTERCEPT___CXA_THROW
+ ASAN_INTERCEPT_FUNC(__cxa_throw);
+#endif
+
+ // Intercept threading-related functions
+#if ASAN_INTERCEPT_PTHREAD_CREATE
+#if defined(ASAN_PTHREAD_CREATE_VERSION)
+ ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
+#else
+ ASAN_INTERCEPT_FUNC(pthread_create);
+#endif
+ ASAN_INTERCEPT_FUNC(pthread_join);
+#endif
+
+ // Intercept atexit function.
+#if ASAN_INTERCEPT___CXA_ATEXIT
+ ASAN_INTERCEPT_FUNC(__cxa_atexit);
+#endif
+
+#if ASAN_INTERCEPT_FORK
+ ASAN_INTERCEPT_FUNC(fork);
+#endif
+
+ InitializePlatformInterceptors();
+
+ VReport(1, "AddressSanitizer: libc interceptors initialized\n");
+}
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h
new file mode 100644
index 0000000..279c5f3
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_interceptors.h
@@ -0,0 +1,126 @@
+//===-- asan_interceptors.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_interceptors.cc
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERCEPTORS_H
+#define ASAN_INTERCEPTORS_H
+
+#include "asan_internal.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+// Use macro to describe if specific function should be
+// intercepted on a given platform.
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
+# define ASAN_INTERCEPT__LONGJMP 1
+# define ASAN_INTERCEPT_STRDUP 1
+# define ASAN_INTERCEPT_INDEX 1
+# define ASAN_INTERCEPT_PTHREAD_CREATE 1
+# define ASAN_INTERCEPT_FORK 1
+#else
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
+# define ASAN_INTERCEPT__LONGJMP 0
+# define ASAN_INTERCEPT_STRDUP 0
+# define ASAN_INTERCEPT_INDEX 0
+# define ASAN_INTERCEPT_PTHREAD_CREATE 0
+# define ASAN_INTERCEPT_FORK 0
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
+#else
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
+#endif
+
+#if !SANITIZER_MAC
+# define ASAN_INTERCEPT_STRNLEN 1
+#else
+# define ASAN_INTERCEPT_STRNLEN 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT_SWAPCONTEXT 1
+#else
+# define ASAN_INTERCEPT_SWAPCONTEXT 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
+#else
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGLONGJMP 1
+#else
+# define ASAN_INTERCEPT_SIGLONGJMP 0
+#endif
+
+// Android bug: https://code.google.com/p/android/issues/detail?id=61799
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
+ !(SANITIZER_ANDROID && defined(__i386))
+# define ASAN_INTERCEPT___CXA_THROW 1
+#else
+# define ASAN_INTERCEPT___CXA_THROW 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
+#endif
+
+DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
+DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
+DECLARE_REAL(void*, memset, void *block, int c, uptr size)
+DECLARE_REAL(char*, strchr, const char *str, int c)
+DECLARE_REAL(SIZE_T, strlen, const char *s)
+DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
+DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
+DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
+struct sigaction;
+DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+
+#if !SANITIZER_MAC
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+#define ASAN_INTERCEPT_FUNC_VER(name, ver) \
+ do { \
+ if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \
+ VReport( \
+ 1, "AddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \
+ } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif // SANITIZER_MAC
+
+namespace __asan {
+
+void InitializeAsanInterceptors();
+void InitializePlatformInterceptors();
+
+#define ENSURE_ASAN_INITED() do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+} while (0)
+
+} // namespace __asan
+
+#endif // ASAN_INTERCEPTORS_H
diff --git a/compiler-rt/lib/asan/asan_interface_internal.h b/compiler-rt/lib/asan/asan_interface_internal.h
new file mode 100644
index 0000000..9efddcb
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_interface_internal.h
@@ -0,0 +1,219 @@
+//===-- asan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This header declares the AddressSanitizer runtime interface functions.
+// The runtime library has to define these functions so the instrumented program
+// could call them.
+//
+// See also include/sanitizer/asan_interface.h
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_INTERNAL_H
+#define ASAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+#include "asan_init_version.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+ // This function should be called at the very beginning of the process,
+ // before any instrumented code is executed and before any call to malloc.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
+
+ // This function exists purely to get a linker/loader error when using
+ // incompatible versions of instrumentation and runtime library. Please note
+ // that __asan_version_mismatch_check is a macro that is replaced with
+ // __asan_version_mismatch_check_vXXX at compile-time.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_version_mismatch_check();
+
+ // This structure is used to describe the source location of a place where
+ // global was defined.
+ struct __asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+ };
+
+ // This structure describes an instrumented global variable.
+ struct __asan_global {
+ uptr beg; // The address of the global.
+ uptr size; // The original size of the global.
+ uptr size_with_redzone; // The size with the redzone.
+ const char *name; // Name as a C string.
+ const char *module_name; // Module name as a C string. This pointer is a
+ // unique identifier of a module.
+ uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
+ __asan_global_source_location *location; // Source location of a global,
+ // or NULL if it is unknown.
+ };
+
+ // These two functions should be called by the instrumented code.
+ // 'globals' is an array of structures describing 'n' globals.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_globals(__asan_global *globals, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_globals(__asan_global *globals, uptr n);
+
+ // These two functions should be called before and after dynamic initializers
+ // of a single module run, respectively.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_before_dynamic_init(const char *module_name);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_after_dynamic_init();
+
+ // These two functions are used by instrumented code in the
+ // use-after-scope mode. They mark memory for local variables as
+ // unaddressable when they leave scope and addressable before the
+ // function exits.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_stack_memory(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_stack_memory(uptr addr, uptr size);
+
+ // Performs cleanup before a NoReturn function. Must be called before things
+ // like _exit and execl to avoid false positives on stack.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_memory_region(void const volatile *addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_address_is_poisoned(void const volatile *addr);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_region_is_poisoned(uptr beg, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_describe_address(uptr addr);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_report_present();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_pc();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_bp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_sp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_address();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_get_report_access_type();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_access_size();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_get_report_description();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_report_error(uptr pc, uptr bp, uptr sp,
+ uptr addr, int is_write, uptr access_size, u32 exp);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_death_callback(void (*callback)(void));
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_error_report_callback(void (*callback)(const char*));
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __asan_on_error();
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ const char* __asan_default_options();
+
+ // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern int __asan_option_detect_stack_use_after_return;
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern uptr *__asan_test_only_reported_buggy_pointer;
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load8(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load16(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store1(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store2(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store4(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store8(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store16(uptr p, u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr p, uptr size,
+ u32 exp);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr p, uptr size,
+ u32 exp);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memcpy(void *dst, const void *src, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memset(void *s, int c, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memmove(void* dest, const void* src, uptr n);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_cxx_array_cookie(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_load_cxx_array_cookie(uptr *p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_intra_object_redzone(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_alloca_poison(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_allocas_unpoison(uptr top, uptr bottom);
+} // extern "C"
+
+#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
new file mode 100644
index 0000000..0ef0d0e
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -0,0 +1,141 @@
+//===-- asan_internal.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header which defines various general utilities.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERNAL_H
+#define ASAN_INTERNAL_H
+
+#include "asan_flags.h"
+#include "asan_interface_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# error "The AddressSanitizer run-time should not be"
+ " instrumented by AddressSanitizer"
+#endif
+
+// Build-time configuration options.
+
+// If set, asan will intercept C++ exception api call(s).
+#ifndef ASAN_HAS_EXCEPTIONS
+# define ASAN_HAS_EXCEPTIONS 1
+#endif
+
+// If set, values like allocator chunk size, as well as defaults for some flags
+// will be changed towards less memory overhead.
+#ifndef ASAN_LOW_MEMORY
+#if SANITIZER_WORDSIZE == 32
+# define ASAN_LOW_MEMORY 1
+#else
+# define ASAN_LOW_MEMORY 0
+# endif
+#endif
+
+#ifndef ASAN_DYNAMIC
+# ifdef PIC
+# define ASAN_DYNAMIC 1
+# else
+# define ASAN_DYNAMIC 0
+# endif
+#endif
+
+// All internal functions in asan reside inside the __asan namespace
+// to avoid namespace collisions with the user programs.
+// Separate namespace also makes it simpler to distinguish the asan run-time
+// functions from the instrumented user code in a profile.
+namespace __asan {
+
+class AsanThread;
+using __sanitizer::StackTrace;
+
+void AsanInitFromRtl();
+
+// asan_rtl.cc
+void NORETURN ShowStatsAndAbort();
+
+// asan_malloc_linux.cc / asan_malloc_mac.cc
+void ReplaceSystemMalloc();
+
+// asan_linux.cc / asan_mac.cc / asan_win.cc
+void *AsanDoesNotSupportStaticLinkage();
+void AsanCheckDynamicRTPrereqs();
+void AsanCheckIncompatibleRT();
+
+void AsanOnDeadlySignal(int, void *siginfo, void *context);
+
+void ReadContextStack(void *context, uptr *stack, uptr *ssize);
+void StopInitOrderChecking();
+
+// Wrapper for TLS/TSD.
+void AsanTSDInit(void (*destructor)(void *tsd));
+void *AsanTSDGet();
+void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
+
+void AppendToErrorMessageBuffer(const char *buffer);
+
+void *AsanDlSymNext(const char *sym);
+
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
+
+// Platform-specific options.
+#if SANITIZER_MAC
+bool PlatformHasDifferentMemcpyAndMemmove();
+# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
+ (PlatformHasDifferentMemcpyAndMemmove())
+#else
+# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
+#endif // SANITIZER_MAC
+
+// Add convenient macro for interface functions that may be represented as
+// weak hooks.
+#define ASAN_MALLOC_HOOK(ptr, size) \
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
+#define ASAN_FREE_HOOK(ptr) \
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
+#define ASAN_ON_ERROR() \
+ if (&__asan_on_error) __asan_on_error()
+
+extern int asan_inited;
+// Used to avoid infinite recursion in __asan_init().
+extern bool asan_init_is_running;
+extern void (*death_callback)(void);
+
+// These magic values are written to shadow for better error reporting.
+const int kAsanHeapLeftRedzoneMagic = 0xfa;
+const int kAsanHeapRightRedzoneMagic = 0xfb;
+const int kAsanHeapFreeMagic = 0xfd;
+const int kAsanStackLeftRedzoneMagic = 0xf1;
+const int kAsanStackMidRedzoneMagic = 0xf2;
+const int kAsanStackRightRedzoneMagic = 0xf3;
+const int kAsanStackPartialRedzoneMagic = 0xf4;
+const int kAsanStackAfterReturnMagic = 0xf5;
+const int kAsanInitializationOrderMagic = 0xf6;
+const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
+const int kAsanStackUseAfterScopeMagic = 0xf8;
+const int kAsanGlobalRedzoneMagic = 0xf9;
+const int kAsanInternalHeapMagic = 0xfe;
+const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
+const int kAsanAllocaLeftMagic = 0xca;
+const int kAsanAllocaRightMagic = 0xcb;
+
+static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
+static const uptr kRetiredStackFrameMagic = 0x45E0360E;
+
+} // namespace __asan
+
+#endif // ASAN_INTERNAL_H
diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc
new file mode 100644
index 0000000..e26b400
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_linux.cc
@@ -0,0 +1,171 @@
+//===-- asan_linux.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_freebsd.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <unwind.h>
+
+#if SANITIZER_FREEBSD
+#include <sys/link_elf.h>
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <ucontext.h>
+extern "C" void* _DYNAMIC;
+#else
+#include <sys/ucontext.h>
+#include <link.h>
+#endif
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+ __FreeBSD_version <= 902001 // v9.2
+#define ucontext_t xucontext_t
+#endif
+
+typedef enum {
+ ASAN_RT_VERSION_UNDEFINED = 0,
+ ASAN_RT_VERSION_DYNAMIC,
+ ASAN_RT_VERSION_STATIC,
+} asan_rt_version_t;
+
+// FIXME: perhaps also store abi version here?
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+asan_rt_version_t __asan_rt_version;
+}
+
+namespace __asan {
+
+void InitializePlatformInterceptors() {}
+
+void *AsanDoesNotSupportStaticLinkage() {
+ // This will fail to link with -static.
+ return &_DYNAMIC; // defined in link.h
+}
+
+#if SANITIZER_ANDROID
+// FIXME: should we do anything for Android?
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+#else
+static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ // Continue until the first dynamic library is found
+ if (!info->dlpi_name || info->dlpi_name[0] == 0)
+ return 0;
+
+ // Ignore vDSO
+ if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
+ return 0;
+
+ *(const char **)data = info->dlpi_name;
+ return 1;
+}
+
+static bool IsDynamicRTName(const char *libname) {
+ return internal_strstr(libname, "libclang_rt.asan") ||
+ internal_strstr(libname, "libasan.so");
+}
+
+static void ReportIncompatibleRT() {
+ Report("Your application is linked against incompatible ASan runtimes.\n");
+ Die();
+}
+
+void AsanCheckDynamicRTPrereqs() {
+ if (!ASAN_DYNAMIC)
+ return;
+
+ // Ensure that dynamic RT is the first DSO in the list
+ const char *first_dso_name = nullptr;
+ dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
+ if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
+ Report("ASan runtime does not come first in initial library list; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
+ Die();
+ }
+}
+
+void AsanCheckIncompatibleRT() {
+ if (ASAN_DYNAMIC) {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
+ ReportIncompatibleRT();
+ }
+ } else {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ // Ensure that dynamic runtime is not present. We should detect it
+ // as early as possible, otherwise ASan interceptors could bind to
+ // the functions in dynamic ASan runtime instead of the functions in
+ // system libraries, causing crashes later in ASan initialization.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ char filename[128];
+ while (proc_maps.Next(nullptr, nullptr, nullptr, filename,
+ sizeof(filename), nullptr)) {
+ if (IsDynamicRTName(filename)) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ }
+ __asan_rt_version = ASAN_RT_VERSION_STATIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
+ ReportIncompatibleRT();
+ }
+ }
+}
+#endif // SANITIZER_ANDROID
+
+#if !SANITIZER_ANDROID
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ ucontext_t *ucp = (ucontext_t*)context;
+ *stack = (uptr)ucp->uc_stack.ss_sp;
+ *ssize = ucp->uc_stack.ss_size;
+}
+#else
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+#endif
+
+void *AsanDlSymNext(const char *sym) {
+ return dlsym(RTLD_NEXT, sym);
+}
+
+} // namespace __asan
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/compiler-rt/lib/asan/asan_lock.h b/compiler-rt/lib/asan/asan_lock.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_lock.h
diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc
new file mode 100644
index 0000000..f00d98f
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_mac.cc
@@ -0,0 +1,263 @@
+//===-- asan_mac.cc -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mac.h"
+
+#include <fcntl.h>
+#include <libkern/OSAtomic.h>
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+#include <pthread.h>
+#include <stdlib.h> // for free()
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+
+namespace __asan {
+
+void InitializePlatformInterceptors() {}
+
+bool PlatformHasDifferentMemcpyAndMemmove() {
+ // On OS X 10.7 memcpy() and memmove() are both resolved
+ // into memmove$VARIANT$sse42.
+ // See also https://github.com/google/sanitizers/issues/34.
+ // TODO(glider): need to check dynamically that memcpy() and memmove() are
+ // actually the same function.
+ return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
+}
+
+// No-op. Mac does not support static linkage anyway.
+void *AsanDoesNotSupportStaticLinkage() {
+ return 0;
+}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckDynamicRTPrereqs() {}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckIncompatibleRT() {}
+
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+
+// Support for the following functions from libdispatch on Mac OS:
+// dispatch_async_f()
+// dispatch_async()
+// dispatch_sync_f()
+// dispatch_sync()
+// dispatch_after_f()
+// dispatch_after()
+// dispatch_group_async_f()
+// dispatch_group_async()
+// TODO(glider): libdispatch API contains other functions that we don't support
+// yet.
+//
+// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
+// they can cause jobs to run on a thread different from the current one.
+// TODO(glider): if so, we need a test for this (otherwise we should remove
+// them).
+//
+// The following functions use dispatch_barrier_async_f() (which isn't a library
+// function but is exported) and are thus supported:
+// dispatch_source_set_cancel_handler_f()
+// dispatch_source_set_cancel_handler()
+// dispatch_source_set_event_handler_f()
+// dispatch_source_set_event_handler()
+//
+// The reference manual for Grand Central Dispatch is available at
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// The implementation details are at
+// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
+
+typedef void* dispatch_group_t;
+typedef void* dispatch_queue_t;
+typedef void* dispatch_source_t;
+typedef u64 dispatch_time_t;
+typedef void (*dispatch_function_t)(void *block);
+typedef void* (*worker_t)(void *block);
+
+// A wrapper for the ObjC blocks used to support libdispatch.
+typedef struct {
+ void *block;
+ dispatch_function_t func;
+ u32 parent_tid;
+} asan_block_context_t;
+
+ALWAYS_INLINE
+void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
+ AsanThread *t = GetCurrentThread();
+ if (!t) {
+ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
+ parent_tid, stack, /* detached */ true);
+ t->Init();
+ asanThreadRegistry().StartThread(t->tid(), 0, 0);
+ SetCurrentThread(t);
+ }
+}
+
+// For use by only those functions that allocated the context via
+// alloc_asan_context().
+extern "C"
+void asan_dispatch_call_block_and_release(void *block) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *context = (asan_block_context_t*)block;
+ VReport(2,
+ "asan_dispatch_call_block_and_release(): "
+ "context: %p, pthread_self: %p\n",
+ block, pthread_self());
+ asan_register_worker_thread(context->parent_tid, &stack);
+ // Call the original dispatcher for the block.
+ context->func(context->block);
+ asan_free(context, &stack, FROM_MALLOC);
+}
+
+} // namespace __asan
+
+using namespace __asan; // NOLINT
+
+// Wrap |ctxt| and |func| into an asan_block_context_t.
+// The caller retains control of the allocated context.
+extern "C"
+asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
+ BufferedStackTrace *stack) {
+ asan_block_context_t *asan_ctxt =
+ (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
+ asan_ctxt->block = ctxt;
+ asan_ctxt->func = func;
+ asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
+ return asan_ctxt;
+}
+
+// Define interceptor for dispatch_*_f function with the three most common
+// parameters: dispatch_queue_t, context, dispatch_function_t.
+#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
+ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
+ dispatch_function_t func) { \
+ GET_STACK_TRACE_THREAD; \
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
+ if (Verbosity() >= 2) { \
+ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
+ asan_ctxt, pthread_self()); \
+ PRINT_CURRENT_STACK(); \
+ } \
+ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
+ asan_dispatch_call_block_and_release); \
+ }
+
+INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
+
+INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
+ dispatch_queue_t dq, void *ctxt,
+ dispatch_function_t func) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+ if (Verbosity() >= 2) {
+ Report("dispatch_after_f: %p\n", asan_ctxt);
+ PRINT_CURRENT_STACK();
+ }
+ return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
+ asan_dispatch_call_block_and_release);
+}
+
+INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+ dispatch_queue_t dq, void *ctxt,
+ dispatch_function_t func) {
+ GET_STACK_TRACE_THREAD;
+ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+ if (Verbosity() >= 2) {
+ Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
+ asan_ctxt, pthread_self());
+ PRINT_CURRENT_STACK();
+ }
+ REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
+ asan_dispatch_call_block_and_release);
+}
+
+#if !defined(MISSING_BLOCKS_SUPPORT)
+extern "C" {
+void dispatch_async(dispatch_queue_t dq, void(^work)(void));
+void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
+ void(^work)(void));
+void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
+ void(^work)(void));
+void dispatch_source_set_cancel_handler(dispatch_source_t ds,
+ void(^work)(void));
+void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
+}
+
+#define GET_ASAN_BLOCK(work) \
+ void (^asan_block)(void); \
+ int parent_tid = GetCurrentTidOrInvalid(); \
+ asan_block = ^(void) { \
+ GET_STACK_TRACE_THREAD; \
+ asan_register_worker_thread(parent_tid, &stack); \
+ work(); \
+ }
+
+INTERCEPTOR(void, dispatch_async,
+ dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_async)(dq, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_group_async,
+ dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_group_async)(dg, dq, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_after,
+ dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_after)(when, queue, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_cancel_handler,
+ dispatch_source_t ds, void(^work)(void)) {
+ if (!work) {
+ REAL(dispatch_source_set_cancel_handler)(ds, work);
+ return;
+ }
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_event_handler,
+ dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
+ GET_ASAN_BLOCK(work);
+ REAL(dispatch_source_set_event_handler)(ds, asan_block);
+}
+#endif
+
+#endif // SANITIZER_MAC
diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cc b/compiler-rt/lib/asan/asan_malloc_linux.cc
new file mode 100644
index 0000000..d5089f9
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cc
@@ -0,0 +1,203 @@
+//===-- asan_malloc_linux.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific malloc interception.
+// We simply define functions like malloc, free, realloc, etc.
+// They will replace the corresponding libc functions automagically.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __asan; // NOLINT
+
+static const uptr kCallocPoolSize = 1024;
+static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+
+static bool IsInCallocPool(const void *ptr) {
+ sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
+ return 0 <= off && off < (sptr)kCallocPoolSize;
+}
+
+INTERCEPTOR(void, free, void *ptr) {
+ GET_STACK_TRACE_FREE;
+ if (UNLIKELY(IsInCallocPool(ptr)))
+ return;
+ asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_STACK_TRACE_FREE;
+ if (UNLIKELY(IsInCallocPool(ptr)))
+ return;
+ asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (UNLIKELY(!asan_inited)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ if (UNLIKELY(IsInCallocPool(ptr))) {
+ uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
+ uptr copy_size = Min(size, kCallocPoolSize - offset);
+ void *new_ptr = asan_malloc(size, &stack);
+ internal_memcpy(new_ptr, ptr, copy_size);
+ return new_ptr;
+ }
+ return asan_realloc(ptr, size, &stack);
+}
+
+INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
+ DTLS_on_libc_memalign(res, size * boundary);
+ return res;
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
+}
+
+// We avoid including malloc.h for portability reasons.
+// man mallinfo says the fields are "long", but the implementation uses int.
+// It doesn't matter much -- we just need to make sure that the libc's mallinfo
+// is not called.
+struct fake_mallinfo {
+ int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+ struct fake_mallinfo res;
+ REAL(memset)(&res, 0, sizeof(res));
+ return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ // Printf("posix_memalign: %zx %zu\n", alignment, size);
+ return asan_posix_memalign(memptr, alignment, size, &stack);
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_valloc(size, &stack);
+}
+
+INTERCEPTOR(void*, pvalloc, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_pvalloc(size, &stack);
+}
+
+INTERCEPTOR(void, malloc_stats, void) {
+ __asan_print_accumulated_stats();
+}
+
+#if SANITIZER_ANDROID
+// Format of __libc_malloc_dispatch has changed in Android L.
+// While we are moving towards a solution that does not depend on bionic
+// internals, here is something to support both K* and L releases.
+struct MallocDebugK {
+ void *(*malloc)(uptr bytes);
+ void (*free)(void *mem);
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+};
+
+struct MallocDebugL {
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void (*free)(void *mem);
+ fake_mallinfo (*mallinfo)(void);
+ void *(*malloc)(uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
+ void* (*pvalloc)(uptr size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void* (*valloc)(uptr size);
+};
+
+ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+ WRAP(malloc), WRAP(free), WRAP(calloc),
+ WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
+
+ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+ WRAP(calloc), WRAP(free), WRAP(mallinfo),
+ WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
+ WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
+ WRAP(valloc)};
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+ void **__libc_malloc_dispatch_p =
+ (void **)AsanDlSymNext("__libc_malloc_dispatch");
+ if (__libc_malloc_dispatch_p) {
+ // Decide on K vs L dispatch format by the presence of
+ // __libc_malloc_default_dispatch export in libc.
+ void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
+ if (default_dispatch_p)
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
+ else
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
+ }
+}
+} // namespace __asan
+
+#else // SANITIZER_ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+} // namespace __asan
+#endif // SANITIZER_ANDROID
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cc b/compiler-rt/lib/asan/asan_malloc_mac.cc
new file mode 100644
index 0000000..744728d
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_malloc_mac.cc
@@ -0,0 +1,61 @@
+//===-- asan_malloc_mac.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "asan_interceptors.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+
+using namespace __asan;
+#define COMMON_MALLOC_ZONE_NAME "asan"
+#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
+#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
+#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
+#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
+#define COMMON_MALLOC_MEMALIGN(alignment, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC)
+#define COMMON_MALLOC_MALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_malloc(size, &stack)
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_realloc(ptr, size, &stack);
+#define COMMON_MALLOC_CALLOC(count, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_calloc(count, size, &stack);
+#define COMMON_MALLOC_VALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
+#define COMMON_MALLOC_FREE(ptr) \
+ GET_STACK_TRACE_FREE; \
+ asan_free(ptr, &stack, FROM_MALLOC);
+#define COMMON_MALLOC_SIZE(ptr) \
+ uptr size = asan_mz_size(ptr);
+#define COMMON_MALLOC_FILL_STATS(zone, stats) \
+ AsanMallocStats malloc_stats; \
+ FillMallocStatistics(&malloc_stats); \
+ CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \
+ internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
+#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
+ GET_STACK_TRACE_FREE; \
+ ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
+#define COMMON_MALLOC_NAMESPACE __asan
+
+#include "sanitizer_common/sanitizer_malloc_mac.inc"
+
+#endif
diff --git a/compiler-rt/lib/asan/asan_malloc_win.cc b/compiler-rt/lib/asan/asan_malloc_win.cc
new file mode 100644
index 0000000..c99e312
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_malloc_win.cc
@@ -0,0 +1,178 @@
+//===-- asan_malloc_win.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Windows-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "interception/interception.h"
+
+#include <stddef.h>
+
+using namespace __asan; // NOLINT
+
+// MT: Simply defining functions with the same signature in *.obj
+// files overrides the standard functions in the CRT.
+// MD: Memory allocation functions are defined in the CRT .dll,
+// so we have to intercept them before they are called for the first time.
+
+#if ASAN_DYNAMIC
+# define ALLOCATION_FUNCTION_ATTRIBUTE
+#else
+# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#endif
+
+extern "C" {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void free(void *ptr) {
+ GET_STACK_TRACE_FREE;
+ return asan_free(ptr, &stack, FROM_MALLOC);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_dbg(void *ptr, int) {
+ free(ptr);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void cfree(void *ptr) {
+ CHECK(!"cfree() should not be used on Windows");
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *malloc(size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_malloc(size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_dbg(size_t size, int, const char *, int) {
+ return malloc(size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *calloc(size_t nmemb, size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_calloc(nmemb, size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+ return calloc(nmemb, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
+ return calloc(nmemb, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *realloc(void *ptr, size_t size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_realloc(ptr, size, &stack);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_realloc_dbg(void *ptr, size_t size, int) {
+ CHECK(!"_realloc_dbg should not exist!");
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_recalloc(void *p, size_t n, size_t elem_size) {
+ if (!p)
+ return calloc(n, elem_size);
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n)
+ return 0;
+ return realloc(p, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+size_t _msize(void *ptr) {
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand(void *memblock, size_t size) {
+ // _expand is used in realloc-like functions to resize the buffer if possible.
+ // We don't want memory to stand still while resizing buffers, so return 0.
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand_dbg(void *memblock, size_t size) {
+ return _expand(memblock, size);
+}
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+int _CrtDbgReport(int, const char*, int,
+ const char*, const char*, ...) {
+ ShowStatsAndAbort();
+}
+
+int _CrtDbgReportW(int reportType, const wchar_t*, int,
+ const wchar_t*, const wchar_t*, ...) {
+ ShowStatsAndAbort();
+}
+
+int _CrtSetReportMode(int, int) {
+ return 0;
+}
+} // extern "C"
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+#if defined(ASAN_DYNAMIC)
+ // We don't check the result because CRT might not be used in the process.
+ __interception::OverrideFunction("free", (uptr)free);
+ __interception::OverrideFunction("malloc", (uptr)malloc);
+ __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
+ __interception::OverrideFunction("calloc", (uptr)calloc);
+ __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
+ __interception::OverrideFunction("realloc", (uptr)realloc);
+ __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
+ __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
+ __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
+ __interception::OverrideFunction("_msize", (uptr)_msize);
+ __interception::OverrideFunction("_expand", (uptr)_expand);
+
+ // Override different versions of 'operator new' and 'operator delete'.
+ // No need to override the nothrow versions as they just wrap the throw
+ // versions.
+ // FIXME: Unfortunately, MSVC miscompiles the statements that take the
+ // addresses of the array versions of these operators,
+ // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
+ // We might want to try to work around this by [inline] assembly or compiling
+ // parts of the RTL with Clang.
+ void *(*op_new)(size_t sz) = operator new;
+ void (*op_delete)(void *p) = operator delete;
+ void *(*op_array_new)(size_t sz) = operator new[];
+ void (*op_array_delete)(void *p) = operator delete[];
+ __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
+ __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
+ __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
+ __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
+#endif
+}
+} // namespace __asan
+
+#endif // _WIN32
diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h
new file mode 100644
index 0000000..8fe347c
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_mapping.h
@@ -0,0 +1,312 @@
+//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Defines ASan memory mapping.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_MAPPING_H
+#define ASAN_MAPPING_H
+
+#include "asan_internal.h"
+
+// The full explanation of the memory mapping could be found here:
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
+//
+// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
+//
+// When SHADOW_OFFSET is zero (-pie):
+// || `[0x100000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x020000000000, 0x0fffffffffff]` || HighShadow ||
+// || `[0x000000040000, 0x01ffffffffff]` || ShadowGap ||
+//
+// Special case when something is already mapped between
+// 0x003000000000 and 0x005000000000 (e.g. when prelink is installed):
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
+// || `[0x003000000000, 0x004fffffffff]` || MidMem ||
+// || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
+// || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow ||
+// || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
+//
+// Default Linux/i386 mapping on x86_64 machine:
+// || `[0x40000000, 0xffffffff]` || HighMem ||
+// || `[0x28000000, 0x3fffffff]` || HighShadow ||
+// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
+// Default Linux/i386 mapping on i386 machine
+// (addresses starting with 0xc0000000 are reserved
+// for kernel and thus not sanitized):
+// || `[0x38000000, 0xbfffffff]` || HighMem ||
+// || `[0x27000000, 0x37ffffff]` || HighShadow ||
+// || `[0x24000000, 0x26ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
+// Default Linux/MIPS32 mapping:
+// || `[0x2aaa0000, 0xffffffff]` || HighMem ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem ||
+//
+// Default Linux/MIPS64 mapping:
+// || `[0x4000000000, 0xffffffffff]` || HighMem ||
+// || `[0x2800000000, 0x3fffffffff]` || HighShadow ||
+// || `[0x2400000000, 0x27ffffffff]` || ShadowGap ||
+// || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
+// || `[0x0000000000, 0x1fffffffff]` || LowMem ||
+//
+// Default Linux/AArch64 (39-bit VMA) mapping:
+// || `[0x2000000000, 0x7fffffffff]` || highmem ||
+// || `[0x1400000000, 0x1fffffffff]` || highshadow ||
+// || `[0x1200000000, 0x13ffffffff]` || shadowgap ||
+// || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
+// || `[0x0000000000, 0x0fffffffff]` || lowmem ||
+//
+// Default Linux/AArch64 (42-bit VMA) mapping:
+// || `[0x10000000000, 0x3ffffffffff]` || highmem ||
+// || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
+// || `[0x09000000000, 0x09fffffffff]` || shadowgap ||
+// || `[0x08000000000, 0x08fffffffff]` || lowshadow ||
+// || `[0x00000000000, 0x07fffffffff]` || lowmem ||
+//
+// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
+// || `[0x480000000000, 0x49ffffffffff]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000:
+// || `[0x60000000, 0xffffffff]` || HighMem ||
+// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
+// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
+// || `[0x40000000, 0x47ffffff]` || LowShadow ||
+// || `[0x00000000, 0x3fffffff]` || LowMem ||
+//
+// Default Windows/i386 mapping:
+// (the exact location of HighShadow/HighMem may vary depending
+// on WoW64, /LARGEADDRESSAWARE, etc).
+// || `[0x50000000, 0xffffffff]` || HighMem ||
+// || `[0x3a000000, 0x4fffffff]` || HighShadow ||
+// || `[0x36000000, 0x39ffffff]` || ShadowGap ||
+// || `[0x30000000, 0x35ffffff]` || LowShadow ||
+// || `[0x00000000, 0x2fffffff]` || LowMem ||
+
+static const u64 kDefaultShadowScale = 3;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
+static const u64 kDefaultShadowOffset64 = 1ULL << 44;
+static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kIosShadowOffset64 = 0x130000000;
+static const u64 kIosSimShadowOffset32 = 1ULL << 30;
+static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64;
+static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
+static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
+static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
+
+#define SHADOW_SCALE kDefaultShadowScale
+
+
+#if SANITIZER_WORDSIZE == 32
+# if SANITIZER_ANDROID
+# define SHADOW_OFFSET (0)
+# elif defined(__mips__)
+# define SHADOW_OFFSET kMIPS32_ShadowOffset32
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
+# elif SANITIZER_WINDOWS
+# define SHADOW_OFFSET kWindowsShadowOffset32
+# elif SANITIZER_IOSSIM
+# define SHADOW_OFFSET kIosSimShadowOffset32
+# elif SANITIZER_IOS
+# define SHADOW_OFFSET kIosShadowOffset32
+# else
+# define SHADOW_OFFSET kDefaultShadowOffset32
+# endif
+#else
+# if defined(__aarch64__)
+# define SHADOW_OFFSET kAArch64_ShadowOffset64
+# elif defined(__powerpc64__)
+# define SHADOW_OFFSET kPPC64_ShadowOffset64
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_MAC
+# define SHADOW_OFFSET kDefaultShadowOffset64
+# elif defined(__mips64)
+# define SHADOW_OFFSET kMIPS64_ShadowOffset64
+# elif SANITIZER_IOSSIM
+# define SHADOW_OFFSET kIosSimShadowOffset64
+# elif SANITIZER_IOS
+# define SHADOW_OFFSET kIosShadowOffset64
+# else
+# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
+# endif
+#endif
+
+#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
+#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
+
+#define kLowMemBeg 0
+#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
+
+#define kLowShadowBeg SHADOW_OFFSET
+#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd)
+
+#define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1)
+
+#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
+#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd)
+
+# define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg)
+# define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd)
+
+// With the zero shadow base we can not actually map pages starting from 0.
+// This constant is somewhat arbitrary.
+#define kZeroBaseShadowStart 0
+#define kZeroBaseMaxShadowStart (1 << 18)
+
+#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \
+ : kZeroBaseShadowStart)
+#define kShadowGapEnd ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1)
+
+#define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0)
+#define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0)
+
+#define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0)
+#define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0)
+
+#define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below.
+
+#if DO_ASAN_MAPPING_PROFILE
+# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++;
+#else
+# define PROFILE_ASAN_MAPPING()
+#endif
+
+// If 1, all shadow boundaries are constants.
+// Don't set to 1 other than for testing.
+#define ASAN_FIXED_MAPPING 0
+
+namespace __asan {
+
+extern uptr AsanMappingProfile[];
+
+#if ASAN_FIXED_MAPPING
+// Fixed mapping for 64-bit Linux. Mostly used for performance comparison
+// with non-fixed mapping. As of r175253 (Feb 2013) the performance
+// difference between fixed and non-fixed mapping is below the noise level.
+static uptr kHighMemEnd = 0x7fffffffffffULL;
+static uptr kMidMemBeg = 0x3000000000ULL;
+static uptr kMidMemEnd = 0x4fffffffffULL;
+#else
+extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.
+#endif
+
+static inline bool AddrIsInLowMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a < kLowMemEnd;
+}
+
+static inline bool AddrIsInLowShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kLowShadowBeg && a <= kLowShadowEnd;
+}
+
+static inline bool AddrIsInHighMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kHighMemBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMidMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
+}
+
+static inline bool AddrIsInMem(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
+}
+
+static inline uptr MemToShadow(uptr p) {
+ PROFILE_ASAN_MAPPING();
+ CHECK(AddrIsInMem(p));
+ return MEM_TO_SHADOW(p);
+}
+
+static inline bool AddrIsInHighShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return a >= kHighShadowBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMidShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
+}
+
+static inline bool AddrIsInShadow(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
+}
+
+static inline bool AddrIsInShadowGap(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ if (kMidMemBeg) {
+ if (a <= kShadowGapEnd)
+ return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
+ return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
+ (a >= kShadowGap3Beg && a <= kShadowGap3End);
+ }
+ // In zero-based shadow mode we treat addresses near zero as addresses
+ // in shadow gap as well.
+ if (SHADOW_OFFSET == 0)
+ return a <= kShadowGapEnd;
+ return a >= kShadowGapBeg && a <= kShadowGapEnd;
+}
+
+static inline bool AddrIsAlignedByGranularity(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ return (a & (SHADOW_GRANULARITY - 1)) == 0;
+}
+
+static inline bool AddressIsPoisoned(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ const uptr kAccessSize = 1;
+ u8 *shadow_address = (u8*)MEM_TO_SHADOW(a);
+ s8 shadow_value = *shadow_address;
+ if (shadow_value) {
+ u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1))
+ + kAccessSize - 1;
+ return (last_accessed_byte >= shadow_value);
+ }
+ return false;
+}
+
+// Must be after all calls to PROFILE_ASAN_MAPPING().
+static const uptr kAsanMappingProfileSize = __LINE__;
+
+} // namespace __asan
+
+#endif // ASAN_MAPPING_H
diff --git a/compiler-rt/lib/asan/asan_new_delete.cc b/compiler-rt/lib/asan/asan_new_delete.cc
new file mode 100644
index 0000000..b5ba13e
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_new_delete.cc
@@ -0,0 +1,132 @@
+//===-- asan_interceptors.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Interceptors for operators new and delete.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+#include "interception/interception.h"
+
+#include <stddef.h>
+
+// C++ operators can't have visibility attributes on Windows.
+#if SANITIZER_WINDOWS
+# define CXX_OPERATOR_ATTRIBUTE
+#else
+# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+#endif
+
+using namespace __asan; // NOLINT
+
+// This code has issues on OSX.
+// See https://github.com/google/sanitizers/issues/131.
+
+// Fake std::nothrow_t to avoid including <new>.
+namespace std {
+struct nothrow_t {};
+} // namespace std
+
+#define OPERATOR_NEW_BODY(type) \
+ GET_STACK_TRACE_MALLOC;\
+ return asan_memalign(0, size, &stack, type);
+
+// On OS X it's not enough to just provide our own 'operator new' and
+// 'operator delete' implementations, because they're going to be in the
+// runtime dylib, and the main executable will depend on both the runtime
+// dylib and libstdc++, each of those'll have its implementation of new and
+// delete.
+// To make sure that C++ allocation/deallocation operators are overridden on
+// OS X we need to intercept them using their mangled names.
+#if !SANITIZER_MAC
+// FreeBSD prior v9.2 have wrong definition of 'size_t'.
+// http://svnweb.freebsd.org/base?view=revision&revision=232261
+#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+#include <sys/param.h>
+#if __FreeBSD_version <= 902001 // v9.2
+#define size_t unsigned
+#endif // __FreeBSD_version
+#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new(size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FROM_NEW); }
+CXX_OPERATOR_ATTRIBUTE
+void *operator new[](size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
+
+#else // SANITIZER_MAC
+INTERCEPTOR(void *, _Znwm, size_t size) {
+ OPERATOR_NEW_BODY(FROM_NEW);
+}
+INTERCEPTOR(void *, _Znam, size_t size) {
+ OPERATOR_NEW_BODY(FROM_NEW_BR);
+}
+INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(FROM_NEW);
+}
+INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
+ OPERATOR_NEW_BODY(FROM_NEW_BR);
+}
+#endif
+
+#define OPERATOR_DELETE_BODY(type) \
+ GET_STACK_TRACE_FREE;\
+ asan_free(ptr, &stack, type);
+
+#if !SANITIZER_MAC
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr) NOEXCEPT {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr) NOEXCEPT {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) NOEXCEPT {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) NOEXCEPT {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
+}
+
+#else // SANITIZER_MAC
+INTERCEPTOR(void, _ZdlPv, void *ptr) {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+INTERCEPTOR(void, _ZdaPv, void *ptr) {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+#endif
diff --git a/compiler-rt/lib/asan/asan_poisoning.cc b/compiler-rt/lib/asan/asan_poisoning.cc
new file mode 100644
index 0000000..f77ab87
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_poisoning.cc
@@ -0,0 +1,434 @@
+//===-- asan_poisoning.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Shadow memory poisoning by ASan RTL and by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static atomic_uint8_t can_poison_memory;
+
+void SetCanPoisonMemory(bool value) {
+ atomic_store(&can_poison_memory, value, memory_order_release);
+}
+
+bool CanPoisonMemory() {
+ return atomic_load(&can_poison_memory, memory_order_acquire);
+}
+
+void PoisonShadow(uptr addr, uptr size, u8 value) {
+ if (!CanPoisonMemory()) return;
+ CHECK(AddrIsAlignedByGranularity(addr));
+ CHECK(AddrIsInMem(addr));
+ CHECK(AddrIsAlignedByGranularity(addr + size));
+ CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
+ CHECK(REAL(memset));
+ FastPoisonShadow(addr, size, value);
+}
+
+void PoisonShadowPartialRightRedzone(uptr addr,
+ uptr size,
+ uptr redzone_size,
+ u8 value) {
+ if (!CanPoisonMemory()) return;
+ CHECK(AddrIsAlignedByGranularity(addr));
+ CHECK(AddrIsInMem(addr));
+ FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
+}
+
+struct ShadowSegmentEndpoint {
+ u8 *chunk;
+ s8 offset; // in [0, SHADOW_GRANULARITY)
+ s8 value; // = *chunk;
+
+ explicit ShadowSegmentEndpoint(uptr address) {
+ chunk = (u8*)MemToShadow(address);
+ offset = address & (SHADOW_GRANULARITY - 1);
+ value = *chunk;
+ }
+};
+
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+ // Since asan's mapping is compacting, the shadow chunk may be
+ // not page-aligned, so we only flush the page-aligned portion.
+ uptr page_size = GetPageSizeCached();
+ uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
+ uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
+ FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+}
+
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+ uptr end = ptr + size;
+ if (Verbosity()) {
+ Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+ poison ? "" : "un", ptr, end, size);
+ if (Verbosity() >= 2)
+ PRINT_CURRENT_STACK();
+ }
+ CHECK(size);
+ CHECK_LE(size, 4096);
+ CHECK(IsAligned(end, SHADOW_GRANULARITY));
+ if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+ *(u8 *)MemToShadow(ptr) =
+ poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+ ptr |= SHADOW_GRANULARITY - 1;
+ ptr++;
+ }
+ for (; ptr < end; ptr += SHADOW_GRANULARITY)
+ *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// Current implementation of __asan_(un)poison_memory_region doesn't check
+// that user program (un)poisons the memory it owns. It poisons memory
+// conservatively, and unpoisons progressively to make sure asan shadow
+// mapping invariant is preserved (see detailed mapping description here:
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm).
+//
+// * if user asks to poison region [left, right), the program poisons
+// at least [left, AlignDown(right)).
+// * if user asks to unpoison region [left, right), the program unpoisons
+// at most [AlignDown(left), right).
+void __asan_poison_memory_region(void const volatile *addr, uptr size) {
+ if (!flags()->allow_user_poisoning || size == 0) return;
+ uptr beg_addr = (uptr)addr;
+ uptr end_addr = beg_addr + size;
+ VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
+ ShadowSegmentEndpoint beg(beg_addr);
+ ShadowSegmentEndpoint end(end_addr);
+ if (beg.chunk == end.chunk) {
+ CHECK(beg.offset < end.offset);
+ s8 value = beg.value;
+ CHECK(value == end.value);
+ // We can only poison memory if the byte in end.offset is unaddressable.
+ // No need to re-poison memory if it is poisoned already.
+ if (value > 0 && value <= end.offset) {
+ if (beg.offset > 0) {
+ *beg.chunk = Min(value, beg.offset);
+ } else {
+ *beg.chunk = kAsanUserPoisonedMemoryMagic;
+ }
+ }
+ return;
+ }
+ CHECK(beg.chunk < end.chunk);
+ if (beg.offset > 0) {
+ // Mark bytes from beg.offset as unaddressable.
+ if (beg.value == 0) {
+ *beg.chunk = beg.offset;
+ } else {
+ *beg.chunk = Min(beg.value, beg.offset);
+ }
+ beg.chunk++;
+ }
+ REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk);
+ // Poison if byte in end.offset is unaddressable.
+ if (end.value > 0 && end.value <= end.offset) {
+ *end.chunk = kAsanUserPoisonedMemoryMagic;
+ }
+}
+
+void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
+ if (!flags()->allow_user_poisoning || size == 0) return;
+ uptr beg_addr = (uptr)addr;
+ uptr end_addr = beg_addr + size;
+ VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
+ ShadowSegmentEndpoint beg(beg_addr);
+ ShadowSegmentEndpoint end(end_addr);
+ if (beg.chunk == end.chunk) {
+ CHECK(beg.offset < end.offset);
+ s8 value = beg.value;
+ CHECK(value == end.value);
+ // We unpoison memory bytes up to enbytes up to end.offset if it is not
+ // unpoisoned already.
+ if (value != 0) {
+ *beg.chunk = Max(value, end.offset);
+ }
+ return;
+ }
+ CHECK(beg.chunk < end.chunk);
+ if (beg.offset > 0) {
+ *beg.chunk = 0;
+ beg.chunk++;
+ }
+ REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk);
+ if (end.offset > 0 && end.value != 0) {
+ *end.chunk = Max(end.value, end.offset);
+ }
+}
+
+int __asan_address_is_poisoned(void const volatile *addr) {
+ return __asan::AddressIsPoisoned((uptr)addr);
+}
+
+uptr __asan_region_is_poisoned(uptr beg, uptr size) {
+ if (!size) return 0;
+ uptr end = beg + size;
+ if (!AddrIsInMem(beg)) return beg;
+ if (!AddrIsInMem(end)) return end;
+ CHECK_LT(beg, end);
+ uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
+ uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
+ uptr shadow_beg = MemToShadow(aligned_b);
+ uptr shadow_end = MemToShadow(aligned_e);
+ // First check the first and the last application bytes,
+ // then check the SHADOW_GRANULARITY-aligned region by calling
+ // mem_is_zero on the corresponding shadow.
+ if (!__asan::AddressIsPoisoned(beg) &&
+ !__asan::AddressIsPoisoned(end - 1) &&
+ (shadow_end <= shadow_beg ||
+ __sanitizer::mem_is_zero((const char *)shadow_beg,
+ shadow_end - shadow_beg)))
+ return 0;
+ // The fast check failed, so we have a poisoned byte somewhere.
+ // Find it slowly.
+ for (; beg < end; beg++)
+ if (__asan::AddressIsPoisoned(beg))
+ return beg;
+ UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found");
+ return 0;
+}
+
+#define CHECK_SMALL_REGION(p, size, isWrite) \
+ do { \
+ uptr __p = reinterpret_cast<uptr>(p); \
+ uptr __size = size; \
+ if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \
+ __asan::AddressIsPoisoned(__p + __size - 1))) { \
+ GET_CURRENT_PC_BP_SP; \
+ uptr __bad = __asan_region_is_poisoned(__p, __size); \
+ __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\
+ } \
+ } while (false); \
+
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+ CHECK_SMALL_REGION(p, sizeof(*p), false);
+ return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+ CHECK_SMALL_REGION(p, sizeof(*p), true);
+ *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_cxx_array_cookie(uptr p) {
+ if (SANITIZER_WORDSIZE != 64) return;
+ if (!flags()->poison_array_cookie) return;
+ uptr s = MEM_TO_SHADOW(p);
+ *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_load_cxx_array_cookie(uptr *p) {
+ if (SANITIZER_WORDSIZE != 64) return *p;
+ if (!flags()->poison_array_cookie) return *p;
+ uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
+ u8 sval = *reinterpret_cast<u8*>(s);
+ if (sval == kAsanArrayCookieMagic) return *p;
+ // If sval is not kAsanArrayCookieMagic it can only be freed memory,
+ // which means that we are going to get double-free. So, return 0 to avoid
+ // infinite loop of destructors. We don't want to report a double-free here
+ // though, so print a warning just in case.
+ // CHECK_EQ(sval, kAsanHeapFreeMagic);
+ if (sval == kAsanHeapFreeMagic) {
+ Report("AddressSanitizer: loaded array cookie from free-d memory; "
+ "expect a double-free report\n");
+ return 0;
+ }
+ // The cookie may remain unpoisoned if e.g. it comes from a custom
+ // operator new defined inside a class.
+ return *p;
+}
+
+// This is a simplified version of __asan_(un)poison_memory_region, which
+// assumes that left border of region to be poisoned is properly aligned.
+static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
+ if (size == 0) return;
+ uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1);
+ PoisonShadow(addr, aligned_size,
+ do_poison ? kAsanStackUseAfterScopeMagic : 0);
+ if (size == aligned_size)
+ return;
+ s8 end_offset = (s8)(size - aligned_size);
+ s8* shadow_end = (s8*)MemToShadow(addr + aligned_size);
+ s8 end_value = *shadow_end;
+ if (do_poison) {
+ // If possible, mark all the bytes mapping to last shadow byte as
+ // unaddressable.
+ if (end_value > 0 && end_value <= end_offset)
+ *shadow_end = (s8)kAsanStackUseAfterScopeMagic;
+ } else {
+ // If necessary, mark few first bytes mapping to last shadow byte
+ // as addressable
+ if (end_value != 0)
+ *shadow_end = Max(end_value, end_offset);
+ }
+}
+
+void __asan_poison_stack_memory(uptr addr, uptr size) {
+ VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
+ PoisonAlignedStackMemory(addr, size, true);
+}
+
+void __asan_unpoison_stack_memory(uptr addr, uptr size) {
+ VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
+ PoisonAlignedStackMemory(addr, size, false);
+}
+
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (!flags()->detect_container_overflow) return;
+ VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
+ uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+ uptr granularity = SHADOW_GRANULARITY;
+ if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity))) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
+ &stack);
+ }
+ CHECK_LE(end - beg,
+ FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
+
+ uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
+ uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ // uptr d2 = RoundUpTo(old_mid, granularity);
+ // Currently we should be in this state:
+ // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
+ // Make a quick sanity check that we are indeed in this state.
+ //
+ // FIXME: Two of these three checks are disabled until we fix
+ // https://github.com/google/sanitizers/issues/258.
+ // if (d1 != d2)
+ // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
+ if (a + granularity <= d1)
+ CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ // if (d2 + granularity <= c && c <= end)
+ // CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ // kAsanContiguousContainerOOBMagic);
+
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
+ // New state:
+ // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
+ PoisonShadow(a, b1 - a, 0);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+ if (b1 != b2) {
+ CHECK_EQ(b2 - b1, granularity);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+ }
+}
+
+const void *__sanitizer_contiguous_container_find_bad_address(
+ const void *beg_p, const void *mid_p, const void *end_p) {
+ if (!flags()->detect_container_overflow)
+ return nullptr;
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr mid = reinterpret_cast<uptr>(mid_p);
+ CHECK_LE(beg, mid);
+ CHECK_LE(mid, end);
+ // Check some bytes starting from beg, some bytes around mid, and some bytes
+ // ending with end.
+ uptr kMaxRangeToCheck = 32;
+ uptr r1_beg = beg;
+ uptr r1_end = Min(end + kMaxRangeToCheck, mid);
+ uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
+ uptr r2_end = Min(end, mid + kMaxRangeToCheck);
+ uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
+ uptr r3_end = end;
+ for (uptr i = r1_beg; i < r1_end; i++)
+ if (AddressIsPoisoned(i))
+ return reinterpret_cast<const void *>(i);
+ for (uptr i = r2_beg; i < mid; i++)
+ if (AddressIsPoisoned(i))
+ return reinterpret_cast<const void *>(i);
+ for (uptr i = mid; i < r2_end; i++)
+ if (!AddressIsPoisoned(i))
+ return reinterpret_cast<const void *>(i);
+ for (uptr i = r3_beg; i < r3_end; i++)
+ if (!AddressIsPoisoned(i))
+ return reinterpret_cast<const void *>(i);
+ return nullptr;
+}
+
+int __sanitizer_verify_contiguous_container(const void *beg_p,
+ const void *mid_p,
+ const void *end_p) {
+ return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p,
+ end_p) == nullptr;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool WordIsPoisoned(uptr addr) {
+ return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
+}
+}
+
diff --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h
new file mode 100644
index 0000000..6344225
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_poisoning.h
@@ -0,0 +1,93 @@
+//===-- asan_poisoning.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Shadow memory poisoning by ASan RTL and by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+// Enable/disable memory poisoning.
+void SetCanPoisonMemory(bool value);
+bool CanPoisonMemory();
+
+// Poisons the shadow memory for "size" bytes starting from "addr".
+void PoisonShadow(uptr addr, uptr size, u8 value);
+
+// Poisons the shadow memory for "redzone_size" bytes starting from
+// "addr + size".
+void PoisonShadowPartialRightRedzone(uptr addr,
+ uptr size,
+ uptr redzone_size,
+ u8 value);
+
+// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that
+// assume that memory addresses are properly aligned. Use in
+// performance-critical code with care.
+ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
+ u8 value) {
+ DCHECK(CanPoisonMemory());
+ uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
+ uptr shadow_end = MEM_TO_SHADOW(
+ aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
+ // FIXME: Page states are different on Windows, so using the same interface
+ // for mapping shadow and zeroing out pages doesn't "just work", so we should
+ // probably provide higher-level interface for these operations.
+ // For now, just memset on Windows.
+ if (value ||
+ SANITIZER_WINDOWS == 1 ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_size = GetPageSizeCached();
+ uptr page_beg = RoundUpTo(shadow_beg, page_size);
+ uptr page_end = RoundDownTo(shadow_end, page_size);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr);
+ }
+ }
+}
+
+ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
+ uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
+ DCHECK(CanPoisonMemory());
+ bool poison_partial = flags()->poison_partial;
+ u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
+ for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
+ if (i + SHADOW_GRANULARITY <= size) {
+ *shadow = 0; // fully addressable
+ } else if (i >= size) {
+ *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
+ } else {
+ // first size-i bytes are addressable
+ *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
+ }
+ }
+}
+
+// Calls __sanitizer::FlushUnneededShadowMemory() on
+// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
+void FlushUnneededASanShadowMemory(uptr p, uptr size);
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_posix.cc b/compiler-rt/lib/asan/asan_posix.cc
new file mode 100644
index 0000000..9e01bcd
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_posix.cc
@@ -0,0 +1,117 @@
+//===-- asan_posix.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Posix-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+namespace __asan {
+
+void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ ScopedDeadlySignal signal_scope(GetCurrentThread());
+ int code = (int)((siginfo_t*)siginfo)->si_code;
+ // Write the first message using the bullet-proof write.
+ if (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die();
+ SignalContext sig = SignalContext::Create(siginfo, context);
+
+ // Access at a reasonable offset above SP, or slightly below it (to account
+ // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+ // probably a stack overflow.
+ bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
+
+#if __powerpc__
+ // Large stack frames can be allocated with e.g.
+ // lis r0,-10000
+ // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
+ // If the store faults then sp will not have been updated, so test above
+ // will not work, becase the fault address will be more than just "slightly"
+ // below sp.
+ if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
+ u32 inst = *(unsigned *)sig.pc;
+ u32 ra = (inst >> 16) & 0x1F;
+ u32 opcd = inst >> 26;
+ u32 xo = (inst >> 1) & 0x3FF;
+ // Check for store-with-update to sp. The instructions we accept are:
+ // stbu rs,d(ra) stbux rs,ra,rb
+ // sthu rs,d(ra) sthux rs,ra,rb
+ // stwu rs,d(ra) stwux rs,ra,rb
+ // stdu rs,ds(ra) stdux rs,ra,rb
+ // where ra is r1 (the stack pointer).
+ if (ra == 1 &&
+ (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
+ (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
+ IsStackAccess = true;
+ }
+#endif // __powerpc__
+
+ // We also check si_code to filter out SEGV caused by something else other
+ // then hitting the guard page or unmapped memory, like, for example,
+ // unaligned memory access.
+ if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
+ ReportStackOverflow(sig);
+ else if (signo == SIGFPE)
+ ReportDeadlySignal("FPE", sig);
+ else if (signo == SIGILL)
+ ReportDeadlySignal("ILL", sig);
+ else
+ ReportDeadlySignal("SEGV", sig);
+}
+
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+void *AsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return pthread_getspecific(tsd_key);
+}
+
+void AsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, tsd);
+}
+
+void PlatformTSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ if (context->destructor_iterations > 1) {
+ context->destructor_iterations--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ AsanThread::TSDDtor(tsd);
+}
+} // namespace __asan
+
+#endif // SANITIZER_POSIX
diff --git a/compiler-rt/lib/asan/asan_preinit.cc b/compiler-rt/lib/asan/asan_preinit.cc
new file mode 100644
index 0000000..a3986d2
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_preinit.cc
@@ -0,0 +1,25 @@
+//===-- asan_preinit.cc ---------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Call __asan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+#include "asan_internal.h"
+
+using namespace __asan;
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+ // The symbol is called __local_asan_preinit, because it's not intended to be
+ // exported.
+ // This code linked into the main executable when -fsanitize=address is in
+ // the link flags. It can only use exported interface functions.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_asan_preinit)(void) = __asan_init;
+#endif
diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc
new file mode 100644
index 0000000..0fb6084
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_report.cc
@@ -0,0 +1,1188 @@
+//===-- asan_report.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file contains error reporting code.
+//===----------------------------------------------------------------------===//
+
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+// -------------------- User-specified callbacks ----------------- {{{1
+static void (*error_report_callback)(const char*);
+static char *error_message_buffer = nullptr;
+static uptr error_message_buffer_pos = 0;
+static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
+static const unsigned kAsanBuggyPcPoolSize = 25;
+static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
+
+struct ReportData {
+ uptr pc;
+ uptr sp;
+ uptr bp;
+ uptr addr;
+ bool is_write;
+ uptr access_size;
+ const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
+void AppendToErrorMessageBuffer(const char *buffer) {
+ BlockingMutexLock l(&error_message_buf_mutex);
+ if (!error_message_buffer) {
+ error_message_buffer =
+ (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
+ error_message_buffer_pos = 0;
+ }
+ uptr length = internal_strlen(buffer);
+ RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
+ uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
+ internal_strncpy(error_message_buffer + error_message_buffer_pos,
+ buffer, remaining);
+ error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
+ // FIXME: reallocate the buffer instead of truncating the message.
+ error_message_buffer_pos += Min(remaining, length);
+}
+
+// ---------------------- Decorator ------------------------------ {{{1
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Access() { return Blue(); }
+ const char *EndAccess() { return Default(); }
+ const char *Location() { return Green(); }
+ const char *EndLocation() { return Default(); }
+ const char *Allocation() { return Magenta(); }
+ const char *EndAllocation() { return Default(); }
+
+ const char *ShadowByte(u8 byte) {
+ switch (byte) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ return Red();
+ case kAsanHeapFreeMagic:
+ return Magenta();
+ case kAsanStackLeftRedzoneMagic:
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ case kAsanStackPartialRedzoneMagic:
+ return Red();
+ case kAsanStackAfterReturnMagic:
+ return Magenta();
+ case kAsanInitializationOrderMagic:
+ return Cyan();
+ case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ return Blue();
+ case kAsanStackUseAfterScopeMagic:
+ return Magenta();
+ case kAsanGlobalRedzoneMagic:
+ return Red();
+ case kAsanInternalHeapMagic:
+ return Yellow();
+ case kAsanIntraObjectRedzone:
+ return Yellow();
+ default:
+ return Default();
+ }
+ }
+ const char *EndShadowByte() { return Default(); }
+ const char *MemoryByte() { return Magenta(); }
+ const char *EndMemoryByte() { return Default(); }
+};
+
+// ---------------------- Helper functions ----------------------- {{{1
+
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+ u8 byte, bool in_shadow, const char *after = "\n") {
+ Decorator d;
+ str->append("%s%s%x%x%s%s", before,
+ in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
+ byte >> 4, byte & 15,
+ in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+ u8 byte, const char *after = "\n") {
+ PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
+}
+
+static void PrintShadowBytes(InternalScopedString *str, const char *before,
+ u8 *bytes, u8 *guilty, uptr n) {
+ Decorator d;
+ if (before) str->append("%s%p:", before, bytes);
+ for (uptr i = 0; i < n; i++) {
+ u8 *p = bytes + i;
+ const char *before =
+ p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
+ const char *after = p == guilty ? "]" : "";
+ PrintShadowByte(str, before, *p, after);
+ }
+ str->append("\n");
+}
+
+static void PrintLegend(InternalScopedString *str) {
+ str->append(
+ "Shadow byte legend (one shadow byte represents %d "
+ "application bytes):\n",
+ (int)SHADOW_GRANULARITY);
+ PrintShadowByte(str, " Addressable: ", 0);
+ str->append(" Partially addressable: ");
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
+ str->append("\n");
+ PrintShadowByte(str, " Heap left redzone: ",
+ kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(str, " Heap right redzone: ",
+ kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(str, " Stack left redzone: ",
+ kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(str, " Stack mid redzone: ",
+ kAsanStackMidRedzoneMagic);
+ PrintShadowByte(str, " Stack right redzone: ",
+ kAsanStackRightRedzoneMagic);
+ PrintShadowByte(str, " Stack partial redzone: ",
+ kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(str, " Stack after return: ",
+ kAsanStackAfterReturnMagic);
+ PrintShadowByte(str, " Stack use after scope: ",
+ kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(str, " Global init order: ",
+ kAsanInitializationOrderMagic);
+ PrintShadowByte(str, " Poisoned by user: ",
+ kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(str, " Container overflow: ",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(str, " Array cookie: ",
+ kAsanArrayCookieMagic);
+ PrintShadowByte(str, " Intra object redzone: ",
+ kAsanIntraObjectRedzone);
+ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
+ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
+}
+
+void MaybeDumpInstructionBytes(uptr pc) {
+ if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
+ return;
+ InternalScopedString str(1024);
+ str.append("First 16 instruction bytes at pc: ");
+ if (IsAccessibleMemoryRange(pc, 16)) {
+ for (int i = 0; i < 16; ++i) {
+ PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
+ }
+ str.append("\n");
+ } else {
+ str.append("unaccessible\n");
+ }
+ Report("%s", str.data());
+}
+
+static void PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr)) return;
+ uptr shadow_addr = MemToShadow(addr);
+ const uptr n_bytes_per_row = 16;
+ uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+ InternalScopedString str(4096 * 8);
+ str.append("Shadow bytes around the buggy address:\n");
+ for (int i = -5; i <= 5; i++) {
+ const char *prefix = (i == 0) ? "=>" : " ";
+ PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
+ (u8 *)shadow_addr, n_bytes_per_row);
+ }
+ if (flags()->print_legend) PrintLegend(&str);
+ Printf("%s", str.data());
+}
+
+static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
+ const char *zone_name) {
+ if (zone_ptr) {
+ if (zone_name) {
+ Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
+ ptr, zone_ptr, zone_name);
+ } else {
+ Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
+ ptr, zone_ptr);
+ }
+ } else {
+ Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
+ }
+}
+
+static void DescribeThread(AsanThread *t) {
+ if (t)
+ DescribeThread(t->context());
+}
+
+// ---------------------- Address Descriptions ------------------- {{{1
+
+static bool IsASCII(unsigned char c) {
+ return /*0x00 <= c &&*/ c <= 0x7F;
+}
+
+static const char *MaybeDemangleGlobalName(const char *name) {
+ // We can spoil names of globals with C linkage, so use an heuristic
+ // approach to check if the name should be demangled.
+ bool should_demangle = false;
+ if (name[0] == '_' && name[1] == 'Z')
+ should_demangle = true;
+ else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
+ should_demangle = true;
+
+ return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
+}
+
+// Check if the global is a zero-terminated ASCII string. If so, print it.
+static void PrintGlobalNameIfASCII(InternalScopedString *str,
+ const __asan_global &g) {
+ for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
+ unsigned char c = *(unsigned char*)p;
+ if (c == '\0' || !IsASCII(c)) return;
+ }
+ if (*(char*)(g.beg + g.size - 1) != '\0') return;
+ str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
+ (char *)g.beg);
+}
+
+static const char *GlobalFilename(const __asan_global &g) {
+ const char *res = g.module_name;
+ // Prefer the filename from source location, if is available.
+ if (g.location)
+ res = g.location->filename;
+ CHECK(res);
+ return res;
+}
+
+static void PrintGlobalLocation(InternalScopedString *str,
+ const __asan_global &g) {
+ str->append("%s", GlobalFilename(g));
+ if (!g.location)
+ return;
+ if (g.location->line_no)
+ str->append(":%d", g.location->line_no);
+ if (g.location->column_no)
+ str->append(":%d", g.location->column_no);
+}
+
+static void DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+ const __asan_global &g) {
+ InternalScopedString str(4096);
+ Decorator d;
+ str.append("%s", d.Location());
+ if (addr < g.beg) {
+ str.append("%p is located %zd bytes to the left", (void *)addr,
+ g.beg - addr);
+ } else if (addr + size > g.beg + g.size) {
+ if (addr < g.beg + g.size)
+ addr = g.beg + g.size;
+ str.append("%p is located %zd bytes to the right", (void *)addr,
+ addr - (g.beg + g.size));
+ } else {
+ // Can it happen?
+ str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
+ }
+ str.append(" of global variable '%s' defined in '",
+ MaybeDemangleGlobalName(g.name));
+ PrintGlobalLocation(&str, g);
+ str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
+ str.append("%s", d.EndLocation());
+ PrintGlobalNameIfASCII(&str, g);
+ Printf("%s", str.data());
+}
+
+static bool DescribeAddressIfGlobal(uptr addr, uptr size,
+ const char *bug_type) {
+ // Assume address is close to at most four globals.
+ const int kMaxGlobalsInReport = 4;
+ __asan_global globals[kMaxGlobalsInReport];
+ u32 reg_sites[kMaxGlobalsInReport];
+ int globals_num =
+ GetGlobalsForAddress(addr, globals, reg_sites, ARRAY_SIZE(globals));
+ if (globals_num == 0)
+ return false;
+ for (int i = 0; i < globals_num; i++) {
+ DescribeAddressRelativeToGlobal(addr, size, globals[i]);
+ if (0 == internal_strcmp(bug_type, "initialization-order-fiasco") &&
+ reg_sites[i]) {
+ Printf(" registered at:\n");
+ StackDepotGet(reg_sites[i]).Print();
+ }
+ }
+ return true;
+}
+
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
+ if (AddrIsInMem(addr))
+ return false;
+ const char *area_type = nullptr;
+ if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+ else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+ else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+ if (area_type != nullptr) {
+ if (print) {
+ Printf("Address %p is located in the %s area.\n", addr, area_type);
+ } else {
+ CHECK(descr);
+ descr->region_kind = area_type;
+ }
+ return true;
+ }
+ CHECK(0 && "Address is not in memory and not in shadow?");
+ return false;
+}
+
+// Return " (thread_name) " or an empty string if the name is empty.
+const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
+ uptr buff_len) {
+ const char *name = t->name;
+ if (name[0] == '\0') return "";
+ buff[0] = 0;
+ internal_strncat(buff, " (", 3);
+ internal_strncat(buff, name, buff_len - 4);
+ internal_strncat(buff, ")", 2);
+ return buff;
+}
+
+const char *ThreadNameWithParenthesis(u32 tid, char buff[],
+ uptr buff_len) {
+ if (tid == kInvalidTid) return "";
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *t = GetThreadContextByTidLocked(tid);
+ return ThreadNameWithParenthesis(t, buff, buff_len);
+}
+
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+ uptr access_size, uptr prev_var_end,
+ uptr next_var_beg) {
+ uptr var_end = var.beg + var.size;
+ uptr addr_end = addr + access_size;
+ const char *pos_descr = nullptr;
+ // If the variable [var.beg, var_end) is the nearest variable to the
+ // current memory access, indicate it in the log.
+ if (addr >= var.beg) {
+ if (addr_end <= var_end)
+ pos_descr = "is inside"; // May happen if this is a use-after-return.
+ else if (addr < var_end)
+ pos_descr = "partially overflows";
+ else if (addr_end <= next_var_beg &&
+ next_var_beg - addr_end >= addr - var_end)
+ pos_descr = "overflows";
+ } else {
+ if (addr_end > var.beg)
+ pos_descr = "partially underflows";
+ else if (addr >= prev_var_end &&
+ addr - prev_var_end >= var.beg - addr_end)
+ pos_descr = "underflows";
+ }
+ InternalScopedString str(1024);
+ str.append(" [%zd, %zd)", var.beg, var_end);
+ // Render variable name.
+ str.append(" '");
+ for (uptr i = 0; i < var.name_len; ++i) {
+ str.append("%c", var.name_pos[i]);
+ }
+ str.append("'");
+ if (pos_descr) {
+ Decorator d;
+ // FIXME: we may want to also print the size of the access here,
+ // but in case of accesses generated by memset it may be confusing.
+ str.append("%s <== Memory access at offset %zd %s this variable%s\n",
+ d.Location(), addr, pos_descr, d.EndLocation());
+ } else {
+ str.append("\n");
+ }
+ Printf("%s", str.data());
+}
+
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars) {
+ CHECK(frame_descr);
+ char *p;
+ // This string is created by the compiler and has the following form:
+ // "n alloc_1 alloc_2 ... alloc_n"
+ // where alloc_i looks like "offset size len ObjectName".
+ uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+ if (n_objects == 0)
+ return false;
+
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr len = (uptr)internal_simple_strtoll(p, &p, 10);
+ if (beg == 0 || size == 0 || *p != ' ') {
+ return false;
+ }
+ p++;
+ StackVarDescr var = {beg, size, p, len};
+ vars->push_back(var);
+ p += len;
+ }
+
+ return true;
+}
+
+bool DescribeAddressIfStack(uptr addr, uptr access_size) {
+ AsanThread *t = FindThreadByStackAddress(addr);
+ if (!t) return false;
+
+ Decorator d;
+ char tname[128];
+ Printf("%s", d.Location());
+ Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+ ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+ // Try to fetch precise stack frame for this access.
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+ Printf("%s\n", d.EndLocation());
+ return true;
+ }
+ Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
+ // Now we print the frame where the alloca has happened.
+ // We print this frame as a stack trace with one element.
+ // The symbolizer may print more than one frame if inlining was involved.
+ // The frame numbers may be different than those in the stack trace printed
+ // previously. That's unfortunate, but I have no better solution,
+ // especially given that the alloca may be from entirely different place
+ // (e.g. use-after-scope, or different thread's stack).
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ // On PowerPC64 ELFv1, the address of a function actually points to a
+ // three-doubleword data structure with the first field containing
+ // the address of the function's code.
+ access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+ access.frame_pc += 16;
+ Printf("%s", d.EndLocation());
+ StackTrace alloca_stack(&access.frame_pc, 1);
+ alloca_stack.Print();
+
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ Printf("AddressSanitizer can't parse the stack frame "
+ "descriptor: |%s|\n", access.frame_descr);
+ // 'addr' is a stack address, so return true even if we can't parse frame
+ return true;
+ }
+ uptr n_objects = vars.size();
+ // Report the number of stack objects.
+ Printf(" This frame has %zu object(s):\n", n_objects);
+
+ // Report all objects in this frame.
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
+ uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
+ PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
+ prev_var_end, next_var_beg);
+ }
+ Printf("HINT: this may be a false positive if your program uses "
+ "some custom stack unwind mechanism or swapcontext\n");
+ if (SANITIZER_WINDOWS)
+ Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
+ else
+ Printf(" (longjmp and C++ exceptions *are* supported)\n");
+
+ DescribeThread(t);
+ return true;
+}
+
+static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
+ uptr access_size) {
+ sptr offset;
+ Decorator d;
+ InternalScopedString str(4096);
+ str.append("%s", d.Location());
+ if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+ str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
+ } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
+ if (offset < 0) {
+ addr -= offset;
+ offset = 0;
+ }
+ str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
+ } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
+ str.append("%p is located %zd bytes inside of", (void*)addr, offset);
+ } else {
+ str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void *)addr);
+ }
+ str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
+ (void *)(chunk.Beg()), (void *)(chunk.End()));
+ str.append("%s", d.EndLocation());
+ Printf("%s", str.data());
+}
+
+void DescribeHeapAddress(uptr addr, uptr access_size) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) {
+ Printf("AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return;
+ }
+ DescribeAccessToHeapChunk(chunk, addr, access_size);
+ CHECK(chunk.AllocTid() != kInvalidTid);
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *alloc_thread =
+ GetThreadContextByTidLocked(chunk.AllocTid());
+ StackTrace alloc_stack = chunk.GetAllocStack();
+ char tname[128];
+ Decorator d;
+ AsanThreadContext *free_thread = nullptr;
+ if (chunk.FreeTid() != kInvalidTid) {
+ free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
+ Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
+ free_thread->tid,
+ ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ StackTrace free_stack = chunk.GetFreeStack();
+ free_stack.Print();
+ Printf("%spreviously allocated by thread T%d%s here:%s\n",
+ d.Allocation(), alloc_thread->tid,
+ ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ } else {
+ Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
+ alloc_thread->tid,
+ ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ }
+ alloc_stack.Print();
+ DescribeThread(GetCurrentThread());
+ if (free_thread)
+ DescribeThread(free_thread);
+ DescribeThread(alloc_thread);
+}
+
+static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) {
+ // Check if this is shadow or shadow gap.
+ if (DescribeAddressIfShadow(addr))
+ return;
+ CHECK(AddrIsInMem(addr));
+ if (DescribeAddressIfGlobal(addr, access_size, bug_type))
+ return;
+ if (DescribeAddressIfStack(addr, access_size))
+ return;
+ // Assume it is a heap address.
+ DescribeHeapAddress(addr, access_size);
+}
+
+// ------------------- Thread description -------------------- {{{1
+
+void DescribeThread(AsanThreadContext *context) {
+ CHECK(context);
+ asanThreadRegistry().CheckLocked();
+ // No need to announce the main thread.
+ if (context->tid == 0 || context->announced) {
+ return;
+ }
+ context->announced = true;
+ char tname[128];
+ InternalScopedString str(1024);
+ str.append("Thread T%d%s", context->tid,
+ ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ if (context->parent_tid == kInvalidTid) {
+ str.append(" created by unknown thread\n");
+ Printf("%s", str.data());
+ return;
+ }
+ str.append(
+ " created by T%d%s here:\n", context->parent_tid,
+ ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
+ Printf("%s", str.data());
+ StackDepotGet(context->stack_id).Print();
+ // Recursively described parent thread if needed.
+ if (flags()->print_full_thread_history) {
+ AsanThreadContext *parent_context =
+ GetThreadContextByTidLocked(context->parent_tid);
+ DescribeThread(parent_context);
+ }
+}
+
+// -------------------- Different kinds of reports ----------------- {{{1
+
+// Use ScopedInErrorReport to run common actions just before and
+// immediately after printing error report.
+class ScopedInErrorReport {
+ public:
+ explicit ScopedInErrorReport(ReportData *report = nullptr,
+ bool fatal = false) {
+ halt_on_error_ = fatal || flags()->halt_on_error;
+
+ if (lock_.TryLock()) {
+ StartReporting(report);
+ return;
+ }
+
+ // ASan found two bugs in different threads simultaneously.
+
+ u32 current_tid = GetCurrentTidOrInvalid();
+ if (reporting_thread_tid_ == current_tid ||
+ reporting_thread_tid_ == kInvalidTid) {
+ // This is either asynch signal or nested error during error reporting.
+ // Fail simple to avoid deadlocks in Report().
+
+ // Can't use Report() here because of potential deadlocks
+ // in nested signal handlers.
+ const char msg[] = "AddressSanitizer: nested bug in the same thread, "
+ "aborting.\n";
+ WriteToFile(kStderrFd, msg, sizeof(msg));
+
+ internal__exit(common_flags()->exitcode);
+ }
+
+ if (halt_on_error_) {
+ // Do not print more than one report, otherwise they will mix up.
+ // Error reporting functions shouldn't return at this situation, as
+ // they are effectively no-returns.
+
+ Report("AddressSanitizer: while reporting a bug found another one. "
+ "Ignoring.\n");
+
+ // Sleep long enough to make sure that the thread which started
+ // to print an error report will finish doing it.
+ SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
+
+ // If we're still not dead for some reason, use raw _exit() instead of
+ // Die() to bypass any additional checks.
+ internal__exit(common_flags()->exitcode);
+ } else {
+ // The other thread will eventually finish reporting
+ // so it's safe to wait
+ lock_.Lock();
+ }
+
+ StartReporting(report);
+ }
+
+ ~ScopedInErrorReport() {
+ // Make sure the current thread is announced.
+ DescribeThread(GetCurrentThread());
+ // We may want to grab this lock again when printing stats.
+ asanThreadRegistry().Unlock();
+ // Print memory stats.
+ if (flags()->print_stats)
+ __asan_print_accumulated_stats();
+
+ // Copy the message buffer so that we could start logging without holding a
+ // lock that gets aquired during printing.
+ InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
+ {
+ BlockingMutexLock l(&error_message_buf_mutex);
+ internal_memcpy(buffer_copy.data(),
+ error_message_buffer, kErrorMessageBufferSize);
+ }
+
+ // Remove color sequences since logs cannot print them.
+ RemoveANSIEscapeSequencesFromString(buffer_copy.data());
+
+ LogFullErrorReport(buffer_copy.data());
+
+ if (error_report_callback) {
+ error_report_callback(buffer_copy.data());
+ }
+ CommonSanitizerReportMutex.Unlock();
+ reporting_thread_tid_ = kInvalidTid;
+ lock_.Unlock();
+ if (halt_on_error_) {
+ Report("ABORTING\n");
+ Die();
+ }
+ }
+
+ private:
+ void StartReporting(ReportData *report) {
+ if (report) report_data = *report;
+ report_happened = true;
+ ASAN_ON_ERROR();
+ // Make sure the registry and sanitizer report mutexes are locked while
+ // we're printing an error report.
+ // We can lock them only here to avoid self-deadlock in case of
+ // recursive reports.
+ asanThreadRegistry().Lock();
+ CommonSanitizerReportMutex.Lock();
+ reporting_thread_tid_ = GetCurrentTidOrInvalid();
+ Printf("===================================================="
+ "=============\n");
+ }
+
+ static StaticSpinMutex lock_;
+ static u32 reporting_thread_tid_;
+ bool halt_on_error_;
+};
+
+StaticSpinMutex ScopedInErrorReport::lock_;
+u32 ScopedInErrorReport::reporting_thread_tid_;
+
+void ReportStackOverflow(const SignalContext &sig) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: stack-overflow on address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
+ GetCurrentTidOrInvalid());
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ ReportErrorSummary("stack-overflow", &stack);
+}
+
+void ReportDeadlySignal(const char *description, const SignalContext &sig) {
+ ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: %s on unknown address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
+ (void *)sig.sp, GetCurrentTidOrInvalid());
+ if (sig.pc < GetPageSizeCached()) {
+ Report("Hint: pc points to the zero page.\n");
+ }
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ MaybeDumpInstructionBytes(sig.pc);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary(description, &stack);
+}
+
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: attempting double-free on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("double-free", &stack);
+}
+
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
+ Printf(" size of the allocated type: %zd bytes;\n"
+ " size of the deallocated type: %zd bytes.\n",
+ asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("new-delete-type-mismatch", &stack);
+ Report("HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: attempting free on address "
+ "which was not malloc()-ed: %p in thread T%d%s\n", addr,
+ curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-free", &stack);
+}
+
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
+ AllocType alloc_type,
+ AllocType dealloc_type) {
+ static const char *alloc_names[] =
+ {"INVALID", "malloc", "operator new", "operator new []"};
+ static const char *dealloc_names[] =
+ {"INVALID", "free", "operator delete", "operator delete []"};
+ CHECK_NE(alloc_type, dealloc_type);
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
+ alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("alloc-dealloc-mismatch", &stack);
+ Report("HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
+}
+
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: attempting to call "
+ "malloc_usable_size() for pointer which is "
+ "not owned: %p\n", addr);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-malloc_usable_size", stack);
+}
+
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: attempting to call "
+ "__sanitizer_get_allocated_size() for pointer which is "
+ "not owned: %p\n", addr);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
+}
+
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ char bug_type[100];
+ internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: "
+ "memory ranges [%p,%p) and [%p, %p) overlap\n", \
+ bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress((uptr)offset1, length1, bug_type);
+ DescribeAddress((uptr)offset2, length2, bug_type);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ const char *bug_type = "negative-size-param";
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress(offset, size, bug_type);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Report("ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_contiguous_container:\n"
+ " beg : %p\n"
+ " end : %p\n"
+ " old_mid : %p\n"
+ " new_mid : %p\n",
+ beg, end, old_mid, new_mid);
+ uptr granularity = SHADOW_GRANULARITY;
+ if (!IsAligned(beg, granularity))
+ Report("ERROR: beg is not aligned by %d\n", granularity);
+ stack->Print();
+ ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+}
+
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
+ Printf("%s", d.EndWarning());
+ InternalScopedString g1_loc(256), g2_loc(256);
+ PrintGlobalLocation(&g1_loc, *g1);
+ PrintGlobalLocation(&g2_loc, *g2);
+ Printf(" [1] size=%zd '%s' %s\n", g1->size,
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ Printf(" [2] size=%zd '%s' %s\n", g2->size,
+ MaybeDemangleGlobalName(g2->name), g2_loc.data());
+ if (stack_id1 && stack_id2) {
+ Printf("These globals were registered at these points:\n");
+ Printf(" [1]:\n");
+ StackDepotGet(stack_id1).Print();
+ Printf(" [2]:\n");
+ StackDepotGet(stack_id2).Print();
+ }
+ Report("HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=detect_odr_violation=0\n");
+ InternalScopedString error_msg(256);
+ error_msg.append("odr-violation: global '%s' at %s",
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ ReportErrorSummary(error_msg.data());
+}
+
+// ----------------------- CheckForInvalidPointerPair ----------- {{{1
+static NOINLINE void
+ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
+ ScopedInErrorReport in_report;
+ const char *bug_type = "invalid-pointer-pair";
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+ DescribeAddress(a1, 1, bug_type);
+ DescribeAddress(a2, 1, bug_type);
+ ReportErrorSummary(bug_type, &stack);
+}
+
+static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
+ if (!flags()->detect_invalid_pointer_pairs) return;
+ uptr a1 = reinterpret_cast<uptr>(p1);
+ uptr a2 = reinterpret_cast<uptr>(p2);
+ AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
+ AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
+ bool valid1 = chunk1.IsValid();
+ bool valid2 = chunk2.IsValid();
+ if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
+ GET_CALLER_PC_BP_SP; \
+ return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+ }
+}
+// ----------------------- Mac-specific reports ----------------- {{{1
+
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
+ "This is an unrecoverable problem, exiting now.\n",
+ addr);
+ PrintZoneForPointer(addr, zone_ptr, zone_name);
+ stack->Print();
+ DescribeHeapAddress(addr, 1);
+}
+
+// -------------- SuppressErrorReport -------------- {{{1
+// Avoid error reports duplicating for ASan recover mode.
+static bool SuppressErrorReport(uptr pc) {
+ if (!common_flags()->suppress_equal_pcs) return false;
+ for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
+ uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
+ if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
+ pc, memory_order_relaxed))
+ return false;
+ if (cmp == pc) return true;
+ }
+ Die();
+}
+
+void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
+ uptr access_size, u32 exp, bool fatal) {
+ if (!fatal && SuppressErrorReport(pc)) return;
+ ENABLE_FRAME_POINTER;
+
+ // Optimization experiments.
+ // The experiments can be used to evaluate potential optimizations that remove
+ // instrumentation (assess false negatives). Instead of completely removing
+ // some instrumentation, compiler can emit special calls into runtime
+ // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
+ // mask of experiments (exp).
+ // The reaction to a non-zero value of exp is to be defined.
+ (void)exp;
+
+ // Determine the error type.
+ const char *bug_descr = "unknown-crash";
+ if (AddrIsInMem(addr)) {
+ u8 *shadow_addr = (u8*)MemToShadow(addr);
+ // If we are accessing 16 bytes, look at the second shadow byte.
+ if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
+ shadow_addr++;
+ // If we are in the partial right redzone, look at the next shadow byte.
+ if (*shadow_addr > 0 && *shadow_addr < 128)
+ shadow_addr++;
+ switch (*shadow_addr) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ bug_descr = "heap-buffer-overflow";
+ break;
+ case kAsanHeapFreeMagic:
+ bug_descr = "heap-use-after-free";
+ break;
+ case kAsanStackLeftRedzoneMagic:
+ bug_descr = "stack-buffer-underflow";
+ break;
+ case kAsanInitializationOrderMagic:
+ bug_descr = "initialization-order-fiasco";
+ break;
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ case kAsanStackPartialRedzoneMagic:
+ bug_descr = "stack-buffer-overflow";
+ break;
+ case kAsanStackAfterReturnMagic:
+ bug_descr = "stack-use-after-return";
+ break;
+ case kAsanUserPoisonedMemoryMagic:
+ bug_descr = "use-after-poison";
+ break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
+ case kAsanStackUseAfterScopeMagic:
+ bug_descr = "stack-use-after-scope";
+ break;
+ case kAsanGlobalRedzoneMagic:
+ bug_descr = "global-buffer-overflow";
+ break;
+ case kAsanIntraObjectRedzone:
+ bug_descr = "intra-object-overflow";
+ break;
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ bug_descr = "dynamic-stack-buffer-overflow";
+ break;
+ }
+ }
+
+ ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+ bug_descr };
+ ScopedInErrorReport in_report(&report, fatal);
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s on address "
+ "%p at pc %p bp %p sp %p\n",
+ bug_descr, (void*)addr, pc, bp, sp);
+ Printf("%s", d.EndWarning());
+
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ char tname[128];
+ Printf("%s%s of size %zu at %p thread T%d%s%s\n",
+ d.Access(),
+ access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
+ access_size, (void*)addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
+ d.EndAccess());
+
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+
+ DescribeAddress(addr, access_size, bug_descr);
+ ReportErrorSummary(bug_descr, &stack);
+ PrintShadowMemoryForAddress(addr);
+}
+
+} // namespace __asan
+
+// --------------------------- Interface --------------------- {{{1
+using namespace __asan; // NOLINT
+
+void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
+ uptr access_size, u32 exp) {
+ ENABLE_FRAME_POINTER;
+ bool fatal = flags()->halt_on_error;
+ ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
+}
+
+void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
+ BlockingMutexLock l(&error_message_buf_mutex);
+ error_report_callback = callback;
+}
+
+void __asan_describe_address(uptr addr) {
+ // Thread registry must be locked while we're describing an address.
+ asanThreadRegistry().Lock();
+ DescribeAddress(addr, 1, "");
+ asanThreadRegistry().Unlock();
+}
+
+int __asan_report_present() {
+ return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+ return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+ return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+ return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+ return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+ return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+ return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+ return report_data.description;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_sub(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_cmp(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+} // extern "C"
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+// Provide default implementation of __asan_on_error that does nothing
+// and may be overriden by user.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
+void __asan_on_error() {}
+#endif
diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h
new file mode 100644
index 0000000..559b8ad
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_report.h
@@ -0,0 +1,87 @@
+//===-- asan_report.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for error reporting functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+struct StackVarDescr {
+ uptr beg;
+ uptr size;
+ const char *name_pos;
+ uptr name_len;
+};
+
+struct AddressDescription {
+ char *name;
+ uptr name_size;
+ uptr region_address;
+ uptr region_size;
+ const char *region_kind;
+};
+
+// Returns the number of globals close to the provided address and copies
+// them to "globals" array.
+int GetGlobalsForAddress(uptr addr, __asan_global *globals, u32 *reg_sites,
+ int max_globals);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+// The following functions prints address description depending
+// on the memory type (shadow/heap/stack/global).
+void DescribeHeapAddress(uptr addr, uptr access_size);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+ bool print = true);
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars);
+bool DescribeAddressIfStack(uptr addr, uptr access_size);
+void DescribeThread(AsanThreadContext *context);
+
+// Different kinds of error reports.
+void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
+ uptr access_size, u32 exp, bool fatal);
+void ReportStackOverflow(const SignalContext &sig);
+void ReportDeadlySignal(const char *description, const SignalContext &sig);
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack);
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
+ AllocType alloc_type,
+ AllocType dealloc_type);
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack);
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack);
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack);
+
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2);
+
+// Mac-specific errors and warnings.
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc
new file mode 100644
index 0000000..7b8b5dd
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_rtl.cc
@@ -0,0 +1,630 @@
+//===-- asan_rtl.cc -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Main file of the ASan run-time library.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_interface_internal.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_suppressions.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "lsan/lsan_common.h"
+#include "ubsan/ubsan_init.h"
+#include "ubsan/ubsan_platform.h"
+
+int __asan_option_detect_stack_use_after_return; // Global interface symbol.
+uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
+
+namespace __asan {
+
+uptr AsanMappingProfile[kAsanMappingProfileSize];
+
+static void AsanDie() {
+ static atomic_uint32_t num_calls;
+ if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+ // Don't die twice - run a busy loop.
+ while (1) { }
+ }
+ if (flags()->sleep_before_dying) {
+ Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
+ SleepForSeconds(flags()->sleep_before_dying);
+ }
+ if (flags()->unmap_shadow_on_exit) {
+ if (kMidMemBeg) {
+ UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
+ UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
+ } else {
+ UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
+ }
+ }
+}
+
+static void AsanCheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
+ line, cond, (uptr)v1, (uptr)v2);
+ // FIXME: check for infinite recursion without a thread-local counter here.
+ PRINT_CURRENT_STACK_CHECK();
+ Die();
+}
+
+// -------------------------- Globals --------------------- {{{1
+int asan_inited;
+bool asan_init_is_running;
+
+#if !ASAN_FIXED_MAPPING
+uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;
+#endif
+
+// -------------------------- Misc ---------------- {{{1
+void ShowStatsAndAbort() {
+ __asan_print_accumulated_stats();
+ Die();
+}
+
+// ---------------------- mmap -------------------- {{{1
+// Reserve memory range [beg, end].
+// We need to use inclusive range because end+1 may not be representable.
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
+ CHECK_EQ((beg % GetPageSizeCached()), 0);
+ CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
+ uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
+ void *res = MmapFixedNoReserve(beg, size, name);
+ if (res != (void*)beg) {
+ Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
+ "Perhaps you're using ulimit -v\n", size);
+ Abort();
+ }
+ if (common_flags()->no_huge_pages_for_shadow)
+ NoHugePagesInRegion(beg, size);
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(beg, size);
+}
+
+// --------------- LowLevelAllocateCallbac ---------- {{{1
+static void OnLowLevelAllocate(uptr ptr, uptr size) {
+ PoisonShadow(ptr, size, kAsanInternalHeapMagic);
+}
+
+// -------------------------- Run-time entry ------------------- {{{1
+// exported functions
+#define ASAN_REPORT_ERROR(type, is_write, size) \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## size(uptr addr) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## size ## _noabort(uptr addr) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
+} \
+
+ASAN_REPORT_ERROR(load, false, 1)
+ASAN_REPORT_ERROR(load, false, 2)
+ASAN_REPORT_ERROR(load, false, 4)
+ASAN_REPORT_ERROR(load, false, 8)
+ASAN_REPORT_ERROR(load, false, 16)
+ASAN_REPORT_ERROR(store, true, 1)
+ASAN_REPORT_ERROR(store, true, 2)
+ASAN_REPORT_ERROR(store, true, 4)
+ASAN_REPORT_ERROR(store, true, 8)
+ASAN_REPORT_ERROR(store, true, 16)
+
+#define ASAN_REPORT_ERROR_N(type, is_write) \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
+} \
+
+ASAN_REPORT_ERROR_N(load, false)
+ASAN_REPORT_ERROR_N(store, true)
+
+#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \
+ uptr sp = MEM_TO_SHADOW(addr); \
+ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
+ : *reinterpret_cast<u16 *>(sp); \
+ if (UNLIKELY(s)) { \
+ if (UNLIKELY(size >= SHADOW_GRANULARITY || \
+ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \
+ (s8)s)) { \
+ if (__asan_test_only_reported_buggy_pointer) { \
+ *__asan_test_only_reported_buggy_pointer = addr; \
+ } else { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \
+ fatal); \
+ } \
+ } \
+ }
+
+#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+ void __asan_##type##size(uptr addr) { \
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \
+ } \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+ void __asan_exp_##type##size(uptr addr, u32 exp) { \
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \
+ } \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+ void __asan_##type##size ## _noabort(uptr addr) { \
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \
+ } \
+
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_loadN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, false, size, 0, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_exp_loadN(uptr addr, uptr size, u32 exp) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, false, size, exp, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_loadN_noabort(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, false, size, 0, false);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_storeN(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, true, size, 0, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_exp_storeN(uptr addr, uptr size, u32 exp) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, true, size, exp, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_storeN_noabort(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, true, size, 0, false);
+ }
+}
+
+// Force the linker to keep the symbols for various ASan interface functions.
+// We want to keep those in the executable in order to let the instrumented
+// dynamic libraries access the symbol even if it is not used by the executable
+// itself. This should help if the build system is removing dead code at link
+// time.
+static NOINLINE void force_interface_symbols() {
+ volatile int fake_condition = 0; // prevent dead condition elimination.
+ // __asan_report_* functions are noreturn, so we need a switch to prevent
+ // the compiler from removing any of them.
+ switch (fake_condition) {
+ case 1: __asan_report_load1(0); break;
+ case 2: __asan_report_load2(0); break;
+ case 3: __asan_report_load4(0); break;
+ case 4: __asan_report_load8(0); break;
+ case 5: __asan_report_load16(0); break;
+ case 6: __asan_report_load_n(0, 0); break;
+ case 7: __asan_report_store1(0); break;
+ case 8: __asan_report_store2(0); break;
+ case 9: __asan_report_store4(0); break;
+ case 10: __asan_report_store8(0); break;
+ case 11: __asan_report_store16(0); break;
+ case 12: __asan_report_store_n(0, 0); break;
+ case 13: __asan_report_exp_load1(0, 0); break;
+ case 14: __asan_report_exp_load2(0, 0); break;
+ case 15: __asan_report_exp_load4(0, 0); break;
+ case 16: __asan_report_exp_load8(0, 0); break;
+ case 17: __asan_report_exp_load16(0, 0); break;
+ case 18: __asan_report_exp_load_n(0, 0, 0); break;
+ case 19: __asan_report_exp_store1(0, 0); break;
+ case 20: __asan_report_exp_store2(0, 0); break;
+ case 21: __asan_report_exp_store4(0, 0); break;
+ case 22: __asan_report_exp_store8(0, 0); break;
+ case 23: __asan_report_exp_store16(0, 0); break;
+ case 24: __asan_report_exp_store_n(0, 0, 0); break;
+ case 25: __asan_register_globals(nullptr, 0); break;
+ case 26: __asan_unregister_globals(nullptr, 0); break;
+ case 27: __asan_set_death_callback(nullptr); break;
+ case 28: __asan_set_error_report_callback(nullptr); break;
+ case 29: __asan_handle_no_return(); break;
+ case 30: __asan_address_is_poisoned(nullptr); break;
+ case 31: __asan_poison_memory_region(nullptr, 0); break;
+ case 32: __asan_unpoison_memory_region(nullptr, 0); break;
+ case 34: __asan_before_dynamic_init(nullptr); break;
+ case 35: __asan_after_dynamic_init(); break;
+ case 36: __asan_poison_stack_memory(0, 0); break;
+ case 37: __asan_unpoison_stack_memory(0, 0); break;
+ case 38: __asan_region_is_poisoned(0, 0); break;
+ case 39: __asan_describe_address(0); break;
+ }
+}
+
+static void asan_atexit() {
+ Printf("AddressSanitizer exit stats:\n");
+ __asan_print_accumulated_stats();
+ // Print AsanMappingProfile.
+ for (uptr i = 0; i < kAsanMappingProfileSize; i++) {
+ if (AsanMappingProfile[i] == 0) continue;
+ Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]);
+ }
+}
+
+static void InitializeHighMemEnd() {
+#if !ASAN_FIXED_MAPPING
+ kHighMemEnd = GetMaxVirtualAddress();
+ // Increase kHighMemEnd to make sure it's properly
+ // aligned together with kHighMemBeg:
+ kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
+#endif // !ASAN_FIXED_MAPPING
+ CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
+}
+
+static void ProtectGap(uptr addr, uptr size) {
+ if (!flags()->protect_shadow_gap)
+ return;
+ void *res = MmapNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res)
+ return;
+ // A few pages at the start of the address space can not be protected.
+ // But we really want to protect as much as possible, to prevent this memory
+ // being returned as a result of a non-FIXED mmap().
+ if (addr == kZeroBaseShadowStart) {
+ uptr step = GetPageSizeCached();
+ while (size > step && addr < kZeroBaseMaxShadowStart) {
+ addr += step;
+ size -= step;
+ void *res = MmapNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res)
+ return;
+ }
+ }
+
+ Report("ERROR: Failed to protect the shadow gap. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ DumpProcessMap();
+ Die();
+}
+
+static void PrintAddressSpaceLayout() {
+ Printf("|| `[%p, %p]` || HighMem ||\n",
+ (void*)kHighMemBeg, (void*)kHighMemEnd);
+ Printf("|| `[%p, %p]` || HighShadow ||\n",
+ (void*)kHighShadowBeg, (void*)kHighShadowEnd);
+ if (kMidMemBeg) {
+ Printf("|| `[%p, %p]` || ShadowGap3 ||\n",
+ (void*)kShadowGap3Beg, (void*)kShadowGap3End);
+ Printf("|| `[%p, %p]` || MidMem ||\n",
+ (void*)kMidMemBeg, (void*)kMidMemEnd);
+ Printf("|| `[%p, %p]` || ShadowGap2 ||\n",
+ (void*)kShadowGap2Beg, (void*)kShadowGap2End);
+ Printf("|| `[%p, %p]` || MidShadow ||\n",
+ (void*)kMidShadowBeg, (void*)kMidShadowEnd);
+ }
+ Printf("|| `[%p, %p]` || ShadowGap ||\n",
+ (void*)kShadowGapBeg, (void*)kShadowGapEnd);
+ if (kLowShadowBeg) {
+ Printf("|| `[%p, %p]` || LowShadow ||\n",
+ (void*)kLowShadowBeg, (void*)kLowShadowEnd);
+ Printf("|| `[%p, %p]` || LowMem ||\n",
+ (void*)kLowMemBeg, (void*)kLowMemEnd);
+ }
+ Printf("MemToShadow(shadow): %p %p %p %p",
+ (void*)MEM_TO_SHADOW(kLowShadowBeg),
+ (void*)MEM_TO_SHADOW(kLowShadowEnd),
+ (void*)MEM_TO_SHADOW(kHighShadowBeg),
+ (void*)MEM_TO_SHADOW(kHighShadowEnd));
+ if (kMidMemBeg) {
+ Printf(" %p %p",
+ (void*)MEM_TO_SHADOW(kMidShadowBeg),
+ (void*)MEM_TO_SHADOW(kMidShadowEnd));
+ }
+ Printf("\n");
+ Printf("redzone=%zu\n", (uptr)flags()->redzone);
+ Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
+ Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
+ Printf("malloc_context_size=%zu\n",
+ (uptr)common_flags()->malloc_context_size);
+
+ Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE);
+ Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY);
+ Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)SHADOW_OFFSET);
+ CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
+ if (kMidMemBeg)
+ CHECK(kMidShadowBeg > kLowShadowEnd &&
+ kMidMemBeg > kMidShadowEnd &&
+ kHighShadowBeg > kMidMemEnd);
+}
+
+static void AsanInitInternal() {
+ if (LIKELY(asan_inited)) return;
+ SanitizerToolName = "AddressSanitizer";
+ CHECK(!asan_init_is_running && "ASan init calls itself!");
+ asan_init_is_running = true;
+
+ CacheBinaryName();
+
+ // Initialize flags. This must be done early, because most of the
+ // initialization steps look at flags().
+ InitializeFlags();
+
+ AsanCheckIncompatibleRT();
+ AsanCheckDynamicRTPrereqs();
+
+ SetCanPoisonMemory(flags()->poison_heap);
+ SetMallocContextSize(common_flags()->malloc_context_size);
+
+ InitializeHighMemEnd();
+
+ // Make sure we are not statically linked.
+ AsanDoesNotSupportStaticLinkage();
+
+ // Install tool-specific callbacks in sanitizer_common.
+ AddDieCallback(AsanDie);
+ SetCheckFailedCallback(AsanCheckFailed);
+ SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
+
+ __sanitizer_set_report_path(common_flags()->log_path);
+
+ // Enable UAR detection, if required.
+ __asan_option_detect_stack_use_after_return =
+ flags()->detect_stack_use_after_return;
+
+ // Re-exec ourselves if we need to set additional env or command line args.
+ MaybeReexec();
+
+ // Setup internal allocator callback.
+ SetLowLevelAllocateCallback(OnLowLevelAllocate);
+
+ InitializeAsanInterceptors();
+
+ // Enable system log ("adb logcat") on Android.
+ // Doing this before interceptors are initialized crashes in:
+ // AsanInitInternal -> android_log_write -> __interceptor_strcmp
+ AndroidLogInit();
+
+ ReplaceSystemMalloc();
+
+ uptr shadow_start = kLowShadowBeg;
+ if (kLowShadowBeg)
+ shadow_start -= GetMmapGranularity();
+ bool full_shadow_is_available =
+ MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
+
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
+ !ASAN_FIXED_MAPPING
+ if (!full_shadow_is_available) {
+ kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
+ kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
+ }
+#endif
+
+ if (Verbosity()) PrintAddressSpaceLayout();
+
+ DisableCoreDumperIfNecessary();
+
+ if (full_shadow_is_available) {
+ // mmap the low shadow plus at least one page at the left.
+ if (kLowShadowBeg)
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gap.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
+ } else if (kMidMemBeg &&
+ MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
+ MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
+ CHECK(kLowShadowBeg != kLowShadowEnd);
+ // mmap the low shadow plus at least one page at the left.
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the mid shadow.
+ ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gaps.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
+ ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
+ } else {
+ Report("Shadow memory range interleaves with an existing memory mapping. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
+ shadow_start, kHighShadowEnd);
+ DumpProcessMap();
+ Die();
+ }
+
+ AsanTSDInit(PlatformTSDDtor);
+ InstallDeadlySignalHandlers(AsanOnDeadlySignal);
+
+ AllocatorOptions allocator_options;
+ allocator_options.SetFrom(flags(), common_flags());
+ InitializeAllocator(allocator_options);
+
+ MaybeStartBackgroudThread();
+ SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
+
+ // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
+ // should be set to 1 prior to initializing the threads.
+ asan_inited = 1;
+ asan_init_is_running = false;
+
+ if (flags()->atexit)
+ Atexit(asan_atexit);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ // Now that ASan runtime is (mostly) initialized, deactivate it if
+ // necessary, so that it can be re-activated when requested.
+ if (flags()->start_deactivated)
+ AsanDeactivate();
+
+ // interceptors
+ InitTlsSize();
+
+ // Create main thread.
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ CHECK_EQ(0, main_thread->tid());
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart(internal_getpid(),
+ /* signal_thread_is_registered */ nullptr);
+ force_interface_symbols(); // no-op.
+ SanitizerInitializeUnwinder();
+
+#if CAN_SANITIZE_LEAKS
+ __lsan::InitCommonLsan();
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
+ Atexit(__lsan::DoLeakCheck);
+ }
+#endif // CAN_SANITIZE_LEAKS
+
+#if CAN_SANITIZE_UB
+ __ubsan::InitAsPlugin();
+#endif
+
+ InitializeSuppressions();
+
+ VReport(1, "AddressSanitizer Init done\n");
+}
+
+// Initialize as requested from some part of ASan runtime library (interceptors,
+// allocator, etc).
+void AsanInitFromRtl() {
+ AsanInitInternal();
+}
+
+#if ASAN_DYNAMIC
+// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
+// (and thus normal initializers from .preinit_array or modules haven't run).
+
+class AsanInitializer {
+public: // NOLINT
+ AsanInitializer() {
+ AsanInitFromRtl();
+ }
+};
+
+static AsanInitializer asan_initializer;
+#endif // ASAN_DYNAMIC
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+void NOINLINE __asan_handle_no_return() {
+ int local_stack;
+ AsanThread *curr_thread = GetCurrentThread();
+ uptr PageSize = GetPageSizeCached();
+ uptr top, bottom;
+ if (curr_thread) {
+ top = curr_thread->stack_top();
+ bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
+ } else {
+ // If we haven't seen this thread, try asking the OS for stack bounds.
+ uptr tls_addr, tls_size, stack_size;
+ GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
+ &tls_size);
+ top = bottom + stack_size;
+ }
+ static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
+ if (top - bottom > kMaxExpectedCleanupSize) {
+ static bool reported_warning = false;
+ if (reported_warning)
+ return;
+ reported_warning = true;
+ Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
+ "stack top: %p; bottom %p; size: %p (%zd)\n"
+ "False positive error reports may follow\n"
+ "For details see "
+ "https://github.com/google/sanitizers/issues/189\n",
+ top, bottom, top - bottom, top - bottom);
+ return;
+ }
+ PoisonShadow(bottom, top - bottom, 0);
+ if (curr_thread && curr_thread->has_fake_stack())
+ curr_thread->fake_stack()->HandleNoReturn();
+}
+
+void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
+ SetUserDieCallback(callback);
+}
+
+// Initialize as requested from instrumented application code.
+// We use this call as a trigger to wake up ASan from deactivated state.
+void __asan_init() {
+ AsanActivate();
+ AsanInitInternal();
+}
+
+void __asan_version_mismatch_check() {
+ // Do nothing.
+}
diff --git a/compiler-rt/lib/asan/asan_stack.cc b/compiler-rt/lib/asan/asan_stack.cc
new file mode 100644
index 0000000..cf7a587
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_stack.cc
@@ -0,0 +1,40 @@
+//===-- asan_stack.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Code for ASan stack trace.
+//===----------------------------------------------------------------------===//
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+
+namespace __asan {
+
+static atomic_uint32_t malloc_context_size;
+
+void SetMallocContextSize(u32 size) {
+ atomic_store(&malloc_context_size, size, memory_order_release);
+}
+
+u32 GetMallocContextSize() {
+ return atomic_load(&malloc_context_size, memory_order_acquire);
+}
+
+} // namespace __asan
+
+// ------------------ Interface -------------- {{{1
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ using namespace __asan;
+ PRINT_CURRENT_STACK();
+}
+} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_stack.h b/compiler-rt/lib/asan/asan_stack.h
new file mode 100644
index 0000000..5c51815
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_stack.h
@@ -0,0 +1,119 @@
+//===-- asan_stack.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_stack.cc.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_STACK_H
+#define ASAN_STACK_H
+
+#include "asan_flags.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+static const u32 kDefaultMallocContextSize = 30;
+
+void SetMallocContextSize(u32 size);
+u32 GetMallocContextSize();
+
+// Get the stack trace with the given pc and bp.
+// The pc will be in the position 0 of the resulting stack trace.
+// The bp may refer to the current frame or to the caller's frame.
+ALWAYS_INLINE
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+ uptr pc, uptr bp, void *context,
+ bool fast) {
+#if SANITIZER_WINDOWS
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
+#else
+ AsanThread *t;
+ stack->size = 0;
+ if (LIKELY(asan_inited)) {
+ if ((t = GetCurrentThread()) && !t->isUnwinding()) {
+ // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+ // yields the call stack of the signal's handler and not of the code
+ // that raised the signal (as it does on Linux).
+ if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
+ uptr stack_top = t->stack_top();
+ uptr stack_bottom = t->stack_bottom();
+ ScopedUnwinding unwind_scope(t);
+ stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
+ } else if (!t && !fast) {
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
+ }
+ }
+#endif // SANITIZER_WINDOWS
+}
+
+} // namespace __asan
+
+// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
+// as early as possible (in functions exposed to the user), as we generally
+// don't want stack trace to contain functions from ASan internals.
+
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ if (max_size <= 2) { \
+ stack.size = max_size; \
+ if (max_size > 0) { \
+ stack.top_frame_bp = GET_CURRENT_FRAME(); \
+ stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
+ if (max_size > 1) \
+ stack.trace_buffer[1] = GET_CALLER_PC(); \
+ } \
+ } else { \
+ GetStackTraceWithPcBpAndContext(&stack, max_size, \
+ StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), 0, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_SIGNAL(sig) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
+ (sig).pc, (sig).bp, (sig).context, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_FATAL_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_CHECK_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
+#define GET_STACK_TRACE_THREAD \
+ GET_STACK_TRACE(kStackTraceMax, true)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(GetMallocContextSize(), common_flags()->fast_unwind_on_malloc)
+
+#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
+
+#define PRINT_CURRENT_STACK() \
+ { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ stack.Print(); \
+ }
+
+#define PRINT_CURRENT_STACK_CHECK() \
+ { \
+ GET_STACK_TRACE_CHECK_HERE; \
+ stack.Print(); \
+ }
+
+#endif // ASAN_STACK_H
diff --git a/compiler-rt/lib/asan/asan_stats.cc b/compiler-rt/lib/asan/asan_stats.cc
new file mode 100644
index 0000000..b8c68c3
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_stats.cc
@@ -0,0 +1,174 @@
+//===-- asan_stats.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Code related to statistics collected by AddressSanitizer.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+AsanStats::AsanStats() {
+ Clear();
+}
+
+void AsanStats::Clear() {
+ CHECK(REAL(memset));
+ REAL(memset)(this, 0, sizeof(AsanStats));
+}
+
+static void PrintMallocStatsArray(const char *prefix,
+ uptr (&array)[kNumberOfSizeClasses]) {
+ Printf("%s", prefix);
+ for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
+ if (!array[i]) continue;
+ Printf("%zu:%zu; ", i, array[i]);
+ }
+ Printf("\n");
+}
+
+void AsanStats::Print() {
+ Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
+ malloced>>20, malloced_redzones>>20, mallocs);
+ Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
+ Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
+ Printf("Stats: %zuM really freed by %zu calls\n",
+ really_freed>>20, real_frees);
+ Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n",
+ (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
+ mmaps, munmaps);
+
+ PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
+ Printf("Stats: malloc large: %zu\n", malloc_large);
+}
+
+void AsanStats::MergeFrom(const AsanStats *stats) {
+ uptr *dst_ptr = reinterpret_cast<uptr*>(this);
+ const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
+ uptr num_fields = sizeof(*this) / sizeof(uptr);
+ for (uptr i = 0; i < num_fields; i++)
+ dst_ptr[i] += src_ptr[i];
+}
+
+static BlockingMutex print_lock(LINKER_INITIALIZED);
+
+static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
+static AsanStats dead_threads_stats(LINKER_INITIALIZED);
+static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED);
+// Required for malloc_zone_statistics() on OS X. This can't be stored in
+// per-thread AsanStats.
+static uptr max_malloced_memory;
+
+static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
+ AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
+ AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+ if (AsanThread *t = tctx->thread)
+ accumulated_stats->MergeFrom(&t->stats());
+}
+
+static void GetAccumulatedStats(AsanStats *stats) {
+ stats->Clear();
+ {
+ ThreadRegistryLock l(&asanThreadRegistry());
+ asanThreadRegistry()
+ .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
+ }
+ stats->MergeFrom(&unknown_thread_stats);
+ {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ stats->MergeFrom(&dead_threads_stats);
+ }
+ // This is not very accurate: we may miss allocation peaks that happen
+ // between two updates of accumulated_stats_. For more accurate bookkeeping
+ // the maximum should be updated on every malloc(), which is unacceptable.
+ if (max_malloced_memory < stats->malloced) {
+ max_malloced_memory = stats->malloced;
+ }
+}
+
+void FlushToDeadThreadStats(AsanStats *stats) {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ dead_threads_stats.MergeFrom(stats);
+ stats->Clear();
+}
+
+void FillMallocStatistics(AsanMallocStats *malloc_stats) {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ malloc_stats->blocks_in_use = stats.mallocs;
+ malloc_stats->size_in_use = stats.malloced;
+ malloc_stats->max_size_in_use = max_malloced_memory;
+ malloc_stats->size_allocated = stats.mmaped;
+}
+
+AsanStats &GetCurrentThreadStats() {
+ AsanThread *t = GetCurrentThread();
+ return (t) ? t->stats() : unknown_thread_stats;
+}
+
+static void PrintAccumulatedStats() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ // Use lock to keep reports from mixing up.
+ BlockingMutexLock lock(&print_lock);
+ stats.Print();
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
+ stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
+ PrintInternalAllocatorStats();
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+uptr __sanitizer_get_current_allocated_bytes() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr malloced = stats.malloced;
+ uptr freed = stats.freed;
+ // Return sane value if malloced < freed due to racy
+ // way we update accumulated stats.
+ return (malloced > freed) ? malloced - freed : 1;
+}
+
+uptr __sanitizer_get_heap_size() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ return stats.mmaped - stats.munmaped;
+}
+
+uptr __sanitizer_get_free_bytes() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr total_free = stats.mmaped
+ - stats.munmaped
+ + stats.really_freed;
+ uptr total_used = stats.malloced
+ + stats.malloced_redzones;
+ // Return sane value if total_free < total_used due to racy
+ // way we update accumulated stats.
+ return (total_free > total_used) ? total_free - total_used : 1;
+}
+
+uptr __sanitizer_get_unmapped_bytes() {
+ return 0;
+}
+
+void __asan_print_accumulated_stats() {
+ PrintAccumulatedStats();
+}
diff --git a/compiler-rt/lib/asan/asan_stats.h b/compiler-rt/lib/asan/asan_stats.h
new file mode 100644
index 0000000..4605135
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_stats.h
@@ -0,0 +1,72 @@
+//===-- asan_stats.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for statistics.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_STATS_H
+#define ASAN_STATS_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+
+namespace __asan {
+
+// AsanStats struct is NOT thread-safe.
+// Each AsanThread has its own AsanStats, which are sometimes flushed
+// to the accumulated AsanStats.
+struct AsanStats {
+ // AsanStats must be a struct consisting of uptr fields only.
+ // When merging two AsanStats structs, we treat them as arrays of uptr.
+ uptr mallocs;
+ uptr malloced;
+ uptr malloced_redzones;
+ uptr frees;
+ uptr freed;
+ uptr real_frees;
+ uptr really_freed;
+ uptr reallocs;
+ uptr realloced;
+ uptr mmaps;
+ uptr mmaped;
+ uptr munmaps;
+ uptr munmaped;
+ uptr malloc_large;
+ uptr malloced_by_size[kNumberOfSizeClasses];
+
+ // Ctor for global AsanStats (accumulated stats for dead threads).
+ explicit AsanStats(LinkerInitialized) { }
+ // Creates empty stats.
+ AsanStats();
+
+ void Print(); // Prints formatted stats to stderr.
+ void Clear();
+ void MergeFrom(const AsanStats *stats);
+};
+
+// Returns stats for GetCurrentThread(), or stats for fake "unknown thread"
+// if GetCurrentThread() returns 0.
+AsanStats &GetCurrentThreadStats();
+// Flushes a given stats into accumulated stats of dead threads.
+void FlushToDeadThreadStats(AsanStats *stats);
+
+// A cross-platform equivalent of malloc_statistics_t on Mac OS.
+struct AsanMallocStats {
+ uptr blocks_in_use;
+ uptr size_in_use;
+ uptr max_size_in_use;
+ uptr size_allocated;
+};
+
+void FillMallocStatistics(AsanMallocStats *malloc_stats);
+
+} // namespace __asan
+
+#endif // ASAN_STATS_H
diff --git a/compiler-rt/lib/asan/asan_suppressions.cc b/compiler-rt/lib/asan/asan_suppressions.cc
new file mode 100644
index 0000000..41887b5
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_suppressions.cc
@@ -0,0 +1,110 @@
+//===-- asan_suppressions.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Issue suppression and suppression-related functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_suppressions.h"
+
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kInterceptorName[] = "interceptor_name";
+static const char kInterceptorViaFunction[] = "interceptor_via_fun";
+static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
+static const char kODRViolation[] = "odr_violation";
+static const char *kSuppressionTypes[] = {
+ kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
+ kODRViolation};
+
+extern "C" {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__asan_default_suppressions();
+#else
+// No week hooks, provide empty implementation.
+const char *__asan_default_suppressions() { return ""; }
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+} // extern "C"
+
+void InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+ if (&__asan_default_suppressions)
+ suppression_ctx->Parse(__asan_default_suppressions());
+}
+
+bool IsInterceptorSuppressed(const char *interceptor_name) {
+ CHECK(suppression_ctx);
+ Suppression *s;
+ // Match "interceptor_name" suppressions.
+ return suppression_ctx->Match(interceptor_name, kInterceptorName, &s);
+}
+
+bool HaveStackTraceBasedSuppressions() {
+ CHECK(suppression_ctx);
+ return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) ||
+ suppression_ctx->HasSuppressionType(kInterceptorViaLibrary);
+}
+
+bool IsODRViolationSuppressed(const char *global_var_name) {
+ CHECK(suppression_ctx);
+ Suppression *s;
+ // Match "odr_violation" suppressions.
+ return suppression_ctx->Match(global_var_name, kODRViolation, &s);
+}
+
+bool IsStackTraceSuppressed(const StackTrace *stack) {
+ if (!HaveStackTraceBasedSuppressions())
+ return false;
+
+ CHECK(suppression_ctx);
+ Symbolizer *symbolizer = Symbolizer::GetOrInit();
+ Suppression *s;
+ for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
+ uptr addr = stack->trace[i];
+
+ if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
+ // Match "interceptor_via_lib" suppressions.
+ if (const char *module_name = symbolizer->GetModuleNameForPc(addr))
+ if (suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s))
+ return true;
+ }
+
+ if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
+ SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ const char *function_name = cur->info.function;
+ if (!function_name) {
+ continue;
+ }
+ // Match "interceptor_via_fun" suppressions.
+ if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
+ &s)) {
+ frames->ClearAll();
+ return true;
+ }
+ }
+ frames->ClearAll();
+ }
+ }
+ return false;
+}
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_suppressions.h b/compiler-rt/lib/asan/asan_suppressions.h
new file mode 100644
index 0000000..5246b4b
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_suppressions.h
@@ -0,0 +1,30 @@
+//===-- asan_suppressions.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_suppressions.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_SUPPRESSIONS_H
+#define ASAN_SUPPRESSIONS_H
+
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+void InitializeSuppressions();
+bool IsInterceptorSuppressed(const char *interceptor_name);
+bool HaveStackTraceBasedSuppressions();
+bool IsStackTraceSuppressed(const StackTrace *stack);
+bool IsODRViolationSuppressed(const char *global_var_name);
+
+} // namespace __asan
+
+#endif // ASAN_SUPPRESSIONS_H
diff --git a/compiler-rt/lib/asan/asan_thread.cc b/compiler-rt/lib/asan/asan_thread.cc
new file mode 100644
index 0000000..6981354
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_thread.cc
@@ -0,0 +1,357 @@
+//===-- asan_thread.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Thread-related code.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_poisoning.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "lsan/lsan_common.h"
+
+namespace __asan {
+
+// AsanThreadContext implementation.
+
+struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+};
+
+void AsanThreadContext::OnCreated(void *arg) {
+ CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
+ if (args->stack)
+ stack_id = StackDepotPut(*args->stack);
+ thread = args->thread;
+ thread->set_context(this);
+}
+
+void AsanThreadContext::OnFinished() {
+ // Drop the link to the AsanThread object.
+ thread = nullptr;
+}
+
+// MIPS requires aligned address
+static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
+static ThreadRegistry *asan_thread_registry;
+
+static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_thread_context;
+
+static ThreadContextBase *GetAsanThreadContext(u32 tid) {
+ BlockingMutexLock lock(&mu_for_thread_context);
+ return new(allocator_for_thread_context) AsanThreadContext(tid);
+}
+
+ThreadRegistry &asanThreadRegistry() {
+ static bool initialized;
+ // Don't worry about thread_safety - this should be called when there is
+ // a single thread.
+ if (!initialized) {
+ // Never reuse ASan threads: we store pointer to AsanThreadContext
+ // in TSD and can't reliably tell when no more TSD destructors will
+ // be called. It would be wrong to reuse AsanThreadContext for another
+ // thread before all TSD destructors will be called for it.
+ asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
+ GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
+ initialized = true;
+ }
+ return *asan_thread_registry;
+}
+
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
+ return static_cast<AsanThreadContext *>(
+ asanThreadRegistry().GetThreadLocked(tid));
+}
+
+// AsanThread implementation.
+
+AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack,
+ bool detached) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
+ AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ CreateThreadContextArgs args = { thread, stack };
+ asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
+ parent_tid, &args);
+
+ return thread;
+}
+
+void AsanThread::TSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ VReport(1, "T%d TSDDtor\n", context->tid);
+ if (context->thread)
+ context->thread->Destroy();
+}
+
+void AsanThread::Destroy() {
+ int tid = this->tid();
+ VReport(1, "T%d exited\n", tid);
+
+ malloc_storage().CommitBack();
+ if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
+ asanThreadRegistry().FinishThread(tid);
+ FlushToDeadThreadStats(&stats_);
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ DeleteFakeStack(tid);
+ uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+// We want to create the FakeStack lazyly on the first use, but not eralier
+// than the stack size is known and the procedure has to be async-signal safe.
+FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
+ uptr stack_size = this->stack_size();
+ if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
+ return nullptr;
+ uptr old_val = 0;
+ // fake_stack_ has 3 states:
+ // 0 -- not initialized
+ // 1 -- being initialized
+ // ptr -- initialized
+ // This CAS checks if the state was 0 and if so changes it to state 1,
+ // if that was successful, it initializes the pointer.
+ if (atomic_compare_exchange_strong(
+ reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
+ memory_order_relaxed)) {
+ uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
+ stack_size_log =
+ Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
+ stack_size_log =
+ Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
+ fake_stack_ = FakeStack::Create(stack_size_log);
+ SetTLSFakeStack(fake_stack_);
+ return fake_stack_;
+ }
+ return nullptr;
+}
+
+void AsanThread::Init() {
+ fake_stack_ = nullptr; // Will be initialized lazily if needed.
+ CHECK_EQ(this->stack_size(), 0U);
+ SetThreadStackAndTls();
+ CHECK_GT(this->stack_size(), 0U);
+ CHECK(AddrIsInMem(stack_bottom_));
+ CHECK(AddrIsInMem(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+ int local = 0;
+ VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
+ (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
+ &local);
+}
+
+thread_return_t AsanThread::ThreadStart(
+ uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
+ Init();
+ asanThreadRegistry().StartThread(tid(), os_id, nullptr);
+ if (signal_thread_is_registered)
+ atomic_store(signal_thread_is_registered, 1, memory_order_release);
+
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ CHECK_EQ(tid(), 0);
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ // On POSIX systems we defer this to the TSD destructor. LSan will consider
+ // the thread's memory as non-live from the moment we call Destroy(), even
+ // though that memory might contain pointers to heap objects which will be
+ // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+ // the TSD destructors have run might cause false positives in LSan.
+ if (!SANITIZER_POSIX)
+ this->Destroy();
+
+ return res;
+}
+
+void AsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_,
+ &tls_size);
+ stack_top_ = stack_bottom_ + stack_size_;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void AsanThread::ClearShadowForThreadStackAndTLS() {
+ PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+ if (tls_begin_ != tls_end_)
+ PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
+}
+
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+ StackFrameAccess *access) {
+ uptr bottom = 0;
+ if (AddrIsInStack(addr)) {
+ bottom = stack_bottom();
+ } else if (has_fake_stack()) {
+ bottom = fake_stack()->AddrIsInFakeStack(addr);
+ CHECK(bottom);
+ access->offset = addr - bottom;
+ access->frame_pc = ((uptr*)bottom)[2];
+ access->frame_descr = (const char *)((uptr*)bottom)[1];
+ return true;
+ }
+ uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
+ u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
+ u8 *shadow_bottom = (u8*)MemToShadow(bottom);
+
+ while (shadow_ptr >= shadow_bottom &&
+ *shadow_ptr != kAsanStackLeftRedzoneMagic) {
+ shadow_ptr--;
+ }
+
+ while (shadow_ptr >= shadow_bottom &&
+ *shadow_ptr == kAsanStackLeftRedzoneMagic) {
+ shadow_ptr--;
+ }
+
+ if (shadow_ptr < shadow_bottom) {
+ return false;
+ }
+
+ uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
+ CHECK(ptr[0] == kCurrentStackFrameMagic);
+ access->offset = addr - (uptr)ptr;
+ access->frame_pc = ptr[2];
+ access->frame_descr = (const char*)ptr[1];
+ return true;
+}
+
+static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
+ void *addr) {
+ AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+ AsanThread *t = tctx->thread;
+ if (!t) return false;
+ if (t->AddrIsInStack((uptr)addr)) return true;
+ if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
+ return true;
+ return false;
+}
+
+AsanThread *GetCurrentThread() {
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+ if (!context) {
+ if (SANITIZER_ANDROID) {
+ // On Android, libc constructor is called _after_ asan_init, and cleans up
+ // TSD. Try to figure out if this is still the main thread by the stack
+ // address. We are not entirely sure that we have correct main thread
+ // limits, so only do this magic on Android, and only if the found thread
+ // is the main thread.
+ AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
+ if (ThreadStackContainsAddress(tctx, &context)) {
+ SetCurrentThread(tctx->thread);
+ return tctx->thread;
+ }
+ }
+ return nullptr;
+ }
+ return context->thread;
+}
+
+void SetCurrentThread(AsanThread *t) {
+ CHECK(t->context());
+ VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
+ (void *)GetThreadSelf());
+ // Make sure we do not reset the current AsanThread.
+ CHECK_EQ(0, AsanTSDGet());
+ AsanTSDSet(t->context());
+ CHECK_EQ(t->context(), AsanTSDGet());
+}
+
+u32 GetCurrentTidOrInvalid() {
+ AsanThread *t = GetCurrentThread();
+ return t ? t->tid() : kInvalidTid;
+}
+
+AsanThread *FindThreadByStackAddress(uptr addr) {
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
+ asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
+ (void *)addr));
+ return tctx ? tctx->thread : nullptr;
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+ if (context && (context->tid == 0))
+ context->os_id = GetTid();
+}
+
+__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+ __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+ __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+ if (!context) return nullptr;
+ return context->thread;
+}
+} // namespace __asan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (!t) return false;
+ *stack_begin = t->stack_bottom();
+ *stack_end = t->stack_top();
+ *tls_begin = t->tls_begin();
+ *tls_end = t->tls_end();
+ // ASan doesn't keep allocator caches in TLS, so these are unused.
+ *cache_begin = 0;
+ *cache_end = 0;
+ return true;
+}
+
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (t && t->has_fake_stack())
+ t->fake_stack()->ForEachFakeFrame(callback, arg);
+}
+
+void LockThreadRegistry() {
+ __asan::asanThreadRegistry().Lock();
+}
+
+void UnlockThreadRegistry() {
+ __asan::asanThreadRegistry().Unlock();
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ __asan::EnsureMainThreadIDIsCorrect();
+}
+} // namespace __lsan
diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
new file mode 100644
index 0000000..ac35711
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -0,0 +1,185 @@
+//===-- asan_thread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_thread.cc.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_THREAD_H
+#define ASAN_THREAD_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_fake_stack.h"
+#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+namespace __asan {
+
+const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
+const u32 kMaxNumberOfThreads = (1 << 22); // 4M
+
+class AsanThread;
+
+// These objects are created for every thread and are never deleted,
+// so we can find them by tid even if the thread is long dead.
+class AsanThreadContext : public ThreadContextBase {
+ public:
+ explicit AsanThreadContext(int tid)
+ : ThreadContextBase(tid), announced(false),
+ destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
+ thread(nullptr) {}
+ bool announced;
+ u8 destructor_iterations;
+ u32 stack_id;
+ AsanThread *thread;
+
+ void OnCreated(void *arg) override;
+ void OnFinished() override;
+};
+
+// AsanThreadContext objects are never freed, so we need many of them.
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
+
+// AsanThread are stored in TSD and destroyed when the thread dies.
+class AsanThread {
+ public:
+ static AsanThread *Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack, bool detached);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart(uptr os_id,
+ atomic_uintptr_t *signal_thread_is_registered);
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr stack_size() { return stack_size_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ u32 tid() { return context_->tid; }
+ AsanThreadContext *context() { return context_; }
+ void set_context(AsanThreadContext *context) { context_ = context; }
+
+ struct StackFrameAccess {
+ uptr offset;
+ uptr frame_pc;
+ const char *frame_descr;
+ };
+ bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ void DeleteFakeStack(int tid) {
+ if (!fake_stack_) return;
+ FakeStack *t = fake_stack_;
+ fake_stack_ = nullptr;
+ SetTLSFakeStack(nullptr);
+ t->Destroy(tid);
+ }
+
+ bool has_fake_stack() {
+ return (reinterpret_cast<uptr>(fake_stack_) > 1);
+ }
+
+ FakeStack *fake_stack() {
+ if (!__asan_option_detect_stack_use_after_return)
+ return nullptr;
+ if (!has_fake_stack())
+ return AsyncSignalSafeLazyInitFakeStack();
+ return fake_stack_;
+ }
+
+ // True is this thread is currently unwinding stack (i.e. collecting a stack
+ // trace). Used to prevent deadlocks on platforms where libc unwinder calls
+ // malloc internally. See PR17116 for more details.
+ bool isUnwinding() const { return unwinding_; }
+ void setUnwinding(bool b) { unwinding_ = b; }
+
+ // True if we are in a deadly signal handler.
+ bool isInDeadlySignal() const { return in_deadly_signal_; }
+ void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
+
+ AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+ AsanStats &stats() { return stats_; }
+
+ private:
+ // NOTE: There is no AsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ FakeStack *AsyncSignalSafeLazyInitFakeStack();
+
+ AsanThreadContext *context_;
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ // stack_size_ == stack_top_ - stack_bottom_;
+ // It needs to be set in a async-signal-safe manner.
+ uptr stack_size_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ FakeStack *fake_stack_;
+ AsanThreadLocalMallocStorage malloc_storage_;
+ AsanStats stats_;
+ bool unwinding_;
+ bool in_deadly_signal_;
+};
+
+// ScopedUnwinding is a scope for stacktracing member of a context
+class ScopedUnwinding {
+ public:
+ explicit ScopedUnwinding(AsanThread *t) : thread(t) {
+ t->setUnwinding(true);
+ }
+ ~ScopedUnwinding() { thread->setUnwinding(false); }
+
+ private:
+ AsanThread *thread;
+};
+
+// ScopedDeadlySignal is a scope for handling deadly signals.
+class ScopedDeadlySignal {
+ public:
+ explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
+ if (thread) thread->setInDeadlySignal(true);
+ }
+ ~ScopedDeadlySignal() {
+ if (thread) thread->setInDeadlySignal(false);
+ }
+
+ private:
+ AsanThread *thread;
+};
+
+// Returns a single instance of registry.
+ThreadRegistry &asanThreadRegistry();
+
+// Must be called under ThreadRegistryLock.
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
+
+// Get the current thread. May return 0.
+AsanThread *GetCurrentThread();
+void SetCurrentThread(AsanThread *t);
+u32 GetCurrentTidOrInvalid();
+AsanThread *FindThreadByStackAddress(uptr addr);
+
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
+} // namespace __asan
+
+#endif // ASAN_THREAD_H
diff --git a/compiler-rt/lib/asan/asan_win.cc b/compiler-rt/lib/asan/asan_win.cc
new file mode 100644
index 0000000..92bd893
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_win.cc
@@ -0,0 +1,254 @@
+//===-- asan_win.cc -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Windows-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <stdlib.h>
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+
+using namespace __asan; // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_should_detect_stack_use_after_return() {
+ __asan_init();
+ return __asan_option_detect_stack_use_after_return;
+}
+
+// -------------------- A workaround for the abscence of weak symbols ----- {{{
+// We don't have a direct equivalent of weak symbols when using MSVC, but we can
+// use the /alternatename directive to tell the linker to default a specific
+// symbol to a specific value, which works nicely for allocator hooks and
+// __asan_default_options().
+void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
+void __sanitizer_default_free_hook(void *ptr) { }
+const char* __asan_default_default_options() { return ""; }
+const char* __asan_default_default_suppressions() { return ""; }
+void __asan_default_on_error() {}
+#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
+#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
+#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
+#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
+#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
+// }}}
+} // extern "C"
+
+// ---------------------- Windows-specific inteceptors ---------------- {{{
+INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(RaiseException));
+ __asan_handle_no_return();
+ REAL(RaiseException)(a, b, c, d);
+}
+
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler3));
+ __asan_handle_no_return();
+ return REAL(_except_handler3)(a, b, c, d);
+}
+
+#if ASAN_DYNAMIC
+// This handler is named differently in -MT and -MD CRTs.
+#define _except_handler4 _except_handler4_common
+#endif
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler4));
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+
+static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
+ AsanThread *t = (AsanThread*)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
+}
+
+INTERCEPTOR_WINAPI(DWORD, CreateThread,
+ void* security, uptr stack_size,
+ DWORD (__stdcall *start_routine)(void*), void* arg,
+ DWORD thr_flags, void* tid) {
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order)
+ StopInitOrderChecking();
+ GET_STACK_TRACE_THREAD;
+ // FIXME: The CreateThread interceptor is not the same as a pthread_create
+ // one. This is a bandaid fix for PR22025.
+ bool detached = false; // FIXME: how can we determine it on Windows?
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ return REAL(CreateThread)(security, stack_size,
+ asan_thread_start, t, thr_flags, tid);
+}
+
+namespace {
+BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
+
+void EnsureWorkerThreadRegistered() {
+ // FIXME: GetCurrentThread relies on TSD, which might not play well with
+ // system thread pools. We might want to use something like reference
+ // counting to zero out GetCurrentThread() underlying storage when the last
+ // work item finishes? Or can we disable reclaiming of threads in the pool?
+ BlockingMutexLock l(&mu_for_thread_tracking);
+ if (__asan::GetCurrentThread())
+ return;
+
+ AsanThread *t = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr,
+ /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true);
+ t->Init();
+ asanThreadRegistry().StartThread(t->tid(), 0, 0);
+ SetCurrentThread(t);
+}
+} // namespace
+
+INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) {
+ // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to
+ // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc.
+ // System worker pool threads are created at arbitraty point in time and
+ // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory
+ // instead and don't register a specific parent_tid/stack.
+ EnsureWorkerThreadRegistered();
+ return REAL(NtWaitForWorkViaWorkerFactory)(a, b);
+}
+
+// }}}
+
+namespace __asan {
+
+void InitializePlatformInterceptors() {
+ ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(RaiseException);
+ ASAN_INTERCEPT_FUNC(_except_handler3);
+ ASAN_INTERCEPT_FUNC(_except_handler4);
+
+ // NtWaitForWorkViaWorkerFactory is always linked dynamically.
+ CHECK(::__interception::OverrideFunction(
+ "NtWaitForWorkViaWorkerFactory",
+ (uptr)WRAP(NtWaitForWorkViaWorkerFactory),
+ (uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
+}
+
+// ---------------------- TSD ---------------- {{{
+static bool tsd_key_inited = false;
+
+static __declspec(thread) void *fake_tsd = 0;
+
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ // FIXME: we're ignoring the destructor for now.
+ tsd_key_inited = true;
+}
+
+void *AsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return fake_tsd;
+}
+
+void AsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ fake_tsd = tsd;
+}
+
+void PlatformTSDDtor(void *tsd) {
+ AsanThread::TSDDtor(tsd);
+}
+// }}}
+
+// ---------------------- Various stuff ---------------- {{{
+void *AsanDoesNotSupportStaticLinkage() {
+#if defined(_DEBUG)
+#error Please build the runtime with a non-debug CRT: /MD or /MT
+#endif
+ return 0;
+}
+
+void AsanCheckDynamicRTPrereqs() {}
+
+void AsanCheckIncompatibleRT() {}
+
+void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
+ UNIMPLEMENTED();
+}
+
+void AsanOnDeadlySignal(int, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
+
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ SignalContext sig = SignalContext::Create(exception_record, context);
+ ReportDeadlySignal(description, sig);
+ }
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ return default_seh_handler(info);
+}
+
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot. Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module. This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+ // We should only store the previous handler if it's not our own handler in
+ // order to avoid loops in the EH chain.
+ auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ if (prev_seh_handler != &SEHHandler)
+ default_seh_handler = prev_seh_handler;
+ return 0;
+}
+
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+__declspec(allocate(".CRT$XIZ"))
+ int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+// }}}
+} // namespace __asan
+
+#endif // _WIN32
diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc
new file mode 100644
index 0000000..308196d
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc
@@ -0,0 +1,426 @@
+//===-- asan_win_dll_thunk.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have ASan instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://github.com/google/sanitizers/issues/209 for the details.
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dll_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DLL_THUNK
+#include "asan_init_version.h"
+#include "interception/interception.h"
+
+// ---------- Function interception helper functions and macros ----------- {{{1
+extern "C" {
+void *__stdcall GetModuleHandleA(const char *module_name);
+void *__stdcall GetProcAddress(void *module, const char *proc_name);
+void abort();
+}
+
+static uptr getRealProcAddressOrDie(const char *name) {
+ uptr ret =
+ __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
+ if (!ret)
+ abort();
+ return ret;
+}
+
+// We need to intercept some functions (e.g. ASan interface, memory allocator --
+// let's call them "hooks") exported by the DLL thunk and forward the hooks to
+// the runtime in the main module.
+// However, we don't want to keep two lists of these hooks.
+// To avoid that, the list of hooks should be defined using the
+// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
+// at once by calling INTERCEPT_HOOKS().
+
+// Use macro+template magic to automatically generate the list of hooks.
+// Each hook at line LINE defines a template class with a static
+// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
+// The default implementation of FunctionInterceptor<LINE> is to call
+// the Execute() method corresponding to the previous line.
+template<int LINE>
+struct FunctionInterceptor {
+ static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
+};
+
+// There shouldn't be any hooks with negative definition line number.
+template<>
+struct FunctionInterceptor<0> {
+ static void Execute() {}
+};
+
+#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
+ template <> struct FunctionInterceptor<__LINE__> { \
+ static void Execute() { \
+ uptr wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
+ abort(); \
+ FunctionInterceptor<__LINE__ - 1>::Execute(); \
+ } \
+ };
+
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERFACE_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name)
+
+// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
+#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
+
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors. Instead, we can declare a function
+// just to be able to get its address. Me may miss the first few calls to the
+// functions since it can be called before __asan_init, but that would lead to
+// false negatives in the startup code before user's global initializers, which
+// isn't a big deal.
+#define INTERCEPT_LIBRARY_FUNCTION(name) \
+ extern "C" void name(); \
+ INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
+
+// Disable compiler warnings that show up if we declare our own version
+// of a compiler intrinsic (e.g. strlen).
+#pragma warning(disable: 4391)
+#pragma warning(disable: 4392)
+
+static void InterceptHooks();
+// }}}
+
+// ---------- Function wrapping helpers ----------------------------------- {{{1
+#define WRAP_V_V(name) \
+ extern "C" void name() { \
+ typedef void (*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_W(name) \
+ extern "C" void name(void *arg) { \
+ typedef void (*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WW(name) \
+ extern "C" void name(void *arg1, void *arg2) { \
+ typedef void (*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WWW(name) \
+ extern "C" void name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_V(name) \
+ extern "C" void *name() { \
+ typedef void *(*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_W(name) \
+ extern "C" void *name(void *arg) { \
+ typedef void *(*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WW(name) \
+ extern "C" void *name(void *arg1, void *arg2) { \
+ typedef void *(*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
+ typedef void *(*fntype)(void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5, void *arg6) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+// }}}
+
+// ----------------- ASan own interface functions --------------------
+// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
+// want to call it in the __asan_init interceptor.
+WRAP_W_V(__asan_should_detect_stack_use_after_return)
+
+extern "C" {
+ int __asan_option_detect_stack_use_after_return;
+
+ // Manually wrap __asan_init as we need to initialize
+ // __asan_option_detect_stack_use_after_return afterwards.
+ void __asan_init() {
+ typedef void (*fntype)();
+ static fntype fn = 0;
+ // __asan_init is expected to be called by only one thread.
+ if (fn) return;
+
+ fn = (fntype)getRealProcAddressOrDie("__asan_init");
+ fn();
+ __asan_option_detect_stack_use_after_return =
+ (__asan_should_detect_stack_use_after_return() != 0);
+
+ InterceptHooks();
+ }
+}
+
+extern "C" void __asan_version_mismatch_check() {
+ // Do nothing.
+}
+
+INTERFACE_FUNCTION(__asan_handle_no_return)
+
+INTERFACE_FUNCTION(__asan_report_store1)
+INTERFACE_FUNCTION(__asan_report_store2)
+INTERFACE_FUNCTION(__asan_report_store4)
+INTERFACE_FUNCTION(__asan_report_store8)
+INTERFACE_FUNCTION(__asan_report_store16)
+INTERFACE_FUNCTION(__asan_report_store_n)
+
+INTERFACE_FUNCTION(__asan_report_load1)
+INTERFACE_FUNCTION(__asan_report_load2)
+INTERFACE_FUNCTION(__asan_report_load4)
+INTERFACE_FUNCTION(__asan_report_load8)
+INTERFACE_FUNCTION(__asan_report_load16)
+INTERFACE_FUNCTION(__asan_report_load_n)
+
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+
+INTERFACE_FUNCTION(__asan_memcpy);
+INTERFACE_FUNCTION(__asan_memset);
+INTERFACE_FUNCTION(__asan_memmove);
+
+INTERFACE_FUNCTION(__asan_alloca_poison);
+INTERFACE_FUNCTION(__asan_allocas_unpoison);
+
+INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_unregister_globals)
+
+INTERFACE_FUNCTION(__asan_before_dynamic_init)
+INTERFACE_FUNCTION(__asan_after_dynamic_init)
+
+INTERFACE_FUNCTION(__asan_poison_stack_memory)
+INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+
+INTERFACE_FUNCTION(__asan_poison_memory_region)
+INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+
+INTERFACE_FUNCTION(__asan_get_current_fake_stack)
+INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+
+INTERFACE_FUNCTION(__asan_stack_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_malloc_10)
+
+INTERFACE_FUNCTION(__asan_stack_free_0)
+INTERFACE_FUNCTION(__asan_stack_free_1)
+INTERFACE_FUNCTION(__asan_stack_free_2)
+INTERFACE_FUNCTION(__asan_stack_free_4)
+INTERFACE_FUNCTION(__asan_stack_free_5)
+INTERFACE_FUNCTION(__asan_stack_free_6)
+INTERFACE_FUNCTION(__asan_stack_free_7)
+INTERFACE_FUNCTION(__asan_stack_free_8)
+INTERFACE_FUNCTION(__asan_stack_free_9)
+INTERFACE_FUNCTION(__asan_stack_free_10)
+
+// FIXME: we might want to have a sanitizer_win_dll_thunk?
+INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
+INTERFACE_FUNCTION(__sanitizer_cov)
+INTERFACE_FUNCTION(__sanitizer_cov_dump)
+INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
+INTERFACE_FUNCTION(__sanitizer_cov_init)
+INTERFACE_FUNCTION(__sanitizer_cov_module_init)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_switch)
+INTERFACE_FUNCTION(__sanitizer_cov_with_check)
+INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
+INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_heap_size)
+INTERFACE_FUNCTION(__sanitizer_get_ownership)
+INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
+INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
+INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
+INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
+INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
+INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
+INTERFACE_FUNCTION(__sanitizer_ptr_sub)
+INTERFACE_FUNCTION(__sanitizer_report_error_summary)
+INTERFACE_FUNCTION(__sanitizer_reset_coverage)
+INTERFACE_FUNCTION(__sanitizer_get_number_of_counters)
+INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
+INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
+INTERFACE_FUNCTION(__sanitizer_set_death_callback)
+INTERFACE_FUNCTION(__sanitizer_set_report_path)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
+INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
+
+// TODO(timurrrr): Add more interface functions on the as-needed basis.
+
+// ----------------- Memory allocation functions ---------------------
+WRAP_V_W(free)
+WRAP_V_WW(_free_dbg)
+
+WRAP_W_W(malloc)
+WRAP_W_WWWW(_malloc_dbg)
+
+WRAP_W_WW(calloc)
+WRAP_W_WWWWW(_calloc_dbg)
+WRAP_W_WWW(_calloc_impl)
+
+WRAP_W_WW(realloc)
+WRAP_W_WWW(_realloc_dbg)
+WRAP_W_WWW(_recalloc)
+
+WRAP_W_W(_msize)
+WRAP_W_W(_expand)
+WRAP_W_W(_expand_dbg)
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
+
+INTERCEPT_LIBRARY_FUNCTION(atoi);
+INTERCEPT_LIBRARY_FUNCTION(atol);
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+
+INTERCEPT_LIBRARY_FUNCTION(frexp);
+INTERCEPT_LIBRARY_FUNCTION(longjmp);
+INTERCEPT_LIBRARY_FUNCTION(memchr);
+INTERCEPT_LIBRARY_FUNCTION(memcmp);
+INTERCEPT_LIBRARY_FUNCTION(memcpy);
+INTERCEPT_LIBRARY_FUNCTION(memmove);
+INTERCEPT_LIBRARY_FUNCTION(memset);
+INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strchr);
+INTERCEPT_LIBRARY_FUNCTION(strcmp);
+INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strcspn);
+INTERCEPT_LIBRARY_FUNCTION(strlen);
+INTERCEPT_LIBRARY_FUNCTION(strncat);
+INTERCEPT_LIBRARY_FUNCTION(strncmp);
+INTERCEPT_LIBRARY_FUNCTION(strncpy);
+INTERCEPT_LIBRARY_FUNCTION(strnlen);
+INTERCEPT_LIBRARY_FUNCTION(strpbrk);
+INTERCEPT_LIBRARY_FUNCTION(strspn);
+INTERCEPT_LIBRARY_FUNCTION(strstr);
+INTERCEPT_LIBRARY_FUNCTION(strtol);
+INTERCEPT_LIBRARY_FUNCTION(wcslen);
+
+// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
+// is defined.
+void InterceptHooks() {
+ INTERCEPT_HOOKS();
+ INTERCEPT_FUNCTION(_except_handler4);
+}
+
+// We want to call __asan_init before C/C++ initializers/constructors are
+// executed, otherwise functions like memset might be invoked.
+// For some strange reason, merely linking in asan_preinit.cc doesn't work
+// as the callback is never called... Is link.exe doing something too smart?
+
+// In DLLs, the callbacks are expected to return 0,
+// otherwise CRT initialization fails.
+static int call_asan_init() {
+ __asan_init();
+ return 0;
+}
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
+
+#endif // ASAN_DLL_THUNK
diff --git a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 0000000..73e5207
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,99 @@
+//===-- asan_win_uar_thunk.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL RTL.
+//
+// This includes:
+// - forwarding the detect_stack_use_after_return runtime option
+// - working around deficiencies of the MD runtime
+// - installing a custom SEH handlerx
+//
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+// First, declare CRT sections we'll be using in this file
+#pragma section(".CRT$XID", long, read) // NOLINT
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+#pragma section(".CRT$XTW", long, read) // NOLINT
+#pragma section(".CRT$XTY", long, read) // NOLINT
+
+////////////////////////////////////////////////////////////////////////////////
+// Define a copy of __asan_option_detect_stack_use_after_return that should be
+// used when linking an MD runtime with a set of object files on Windows.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it. Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
+// just to work around this issue, let's clone the a variable that is
+// constant after initialization anyways.
+extern "C" {
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+int __asan_option_detect_stack_use_after_return =
+ __asan_should_detect_stack_use_after_return();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
+// unload or on exit. ASan relies on LLVM global_dtors to call
+// __asan_unregister_globals on these events, which unfortunately doesn't work
+// with the MD runtime, see PR22545 for the details.
+// To work around this, for each DLL we schedule a call to UnregisterGlobals
+// using atexit() that calls a small subset of C terminators
+// where LLVM global_dtors is placed. Fingers crossed, no other C terminators
+// are there.
+extern "C" int __cdecl atexit(void (__cdecl *f)(void));
+extern "C" void __cdecl _initterm(void *a, void *b);
+
+namespace {
+__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0;
+__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0;
+
+void UnregisterGlobals() {
+ _initterm(&before_global_dtors, &after_global_dtors);
+}
+
+int ScheduleUnregisterGlobals() {
+ return atexit(UnregisterGlobals);
+}
+
+// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after
+// atexit() is initialized (.CRT$XIC). As this is executed before C++
+// initializers (think ctors for globals), UnregisterGlobals gets executed after
+// dtors for C++ globals.
+__declspec(allocate(".CRT$XID"))
+int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ASan SEH handling.
+// We need to set the ASan-specific SEH handler at the end of CRT initialization
+// of each module (see also asan_win.cc).
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
+
+#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/compiler-rt/lib/asan/asanwrapper.cc b/compiler-rt/lib/asan/asanwrapper.cc
new file mode 100644
index 0000000..f4da969
--- /dev/null
+++ b/compiler-rt/lib/asan/asanwrapper.cc
@@ -0,0 +1,85 @@
+#include <elf.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+void usage(const char* me) {
+ static const char* usage_s = "Usage:\n"
+ " %s /system/bin/app_process <args>\n"
+ "or, better:\n"
+ " setprop wrap.<nicename> %s\n";
+ fprintf(stderr, usage_s, me, me);
+ exit(1);
+}
+
+void env_prepend(const char* name, const char* value, const char* delim) {
+ const char* value_old = getenv(name);
+ std::string value_new = value;
+ if (value_old) {
+ value_new += delim;
+ value_new += value_old;
+ }
+ setenv(name, value_new.c_str(), 1);
+}
+
+bool elf_is_64bit(const char* path) {
+ int fd = open(path, O_RDONLY);
+ if (fd == -1) return false;
+
+ const size_t kBufSize = EI_CLASS + 1;
+ char buf[kBufSize];
+ ssize_t sz = read(fd, buf, kBufSize);
+ if (sz != kBufSize) {
+ close(fd);
+ return false;
+ }
+
+ if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 ||
+ buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
+ return false;
+
+ bool is_64bit = buf[EI_CLASS] == ELFCLASS64;
+ close(fd);
+ return is_64bit;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ usage(argv[0]);
+ }
+ char** args = new char*[argc];
+ // If we are wrapping app_process, replace it with app_process_asan.
+ // TODO(eugenis): rewrite to <dirname>/asan/<basename>, if exists?
+ if (strcmp(argv[1], "/system/bin/app_process") == 0) {
+ args[0] = (char*)"/system/bin/asan/app_process";
+ } else if (strcmp(argv[1], "/system/bin/app_process32") == 0) {
+ args[0] = (char*)"/system/bin/asan/app_process32";
+ } else if (strcmp(argv[1], "/system/bin/app_process64") == 0) {
+ args[0] = (char*)"/system/bin/asan/app_process64";
+ } else {
+ args[0] = argv[1];
+ }
+
+ for (int i = 1; i < argc - 1; ++i)
+ args[i] = argv[i + 1];
+ args[argc - 1] = 0;
+
+ if (elf_is_64bit(args[0])) {
+ env_prepend("LD_LIBRARY_PATH", "/system/lib64/asan:/system/lib64", ":");
+ } else {
+ env_prepend("LD_LIBRARY_PATH", "/system/lib/asan:/system/lib", ":");
+ }
+ env_prepend("ASAN_OPTIONS", "allow_user_segv_handler=1", ",");
+
+ printf("ASAN_OPTIONS: %s\n", getenv("ASAN_OPTIONS"));
+ printf("LD_LIBRARY_PATH: %s\n", getenv("LD_LIBRARY_PATH"));
+ for (int i = 0; i < argc - 1; ++i)
+ printf("argv[%d] = %s\n", i, args[i]);
+
+ execv(args[0], args);
+}
diff --git a/compiler-rt/lib/asan/scripts/CMakeLists.txt b/compiler-rt/lib/asan/scripts/CMakeLists.txt
new file mode 100644
index 0000000..e5ab8eb
--- /dev/null
+++ b/compiler-rt/lib/asan/scripts/CMakeLists.txt
@@ -0,0 +1,4 @@
+if(ANDROID)
+ add_compiler_rt_script(asan_device_setup)
+ add_dependencies(asan asan_device_setup)
+endif()
diff --git a/compiler-rt/lib/asan/scripts/asan_device_setup b/compiler-rt/lib/asan/scripts/asan_device_setup
new file mode 100755
index 0000000..6cb7b94
--- /dev/null
+++ b/compiler-rt/lib/asan/scripts/asan_device_setup
@@ -0,0 +1,434 @@
+#!/bin/bash
+#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+# Prepare Android device to run ASan applications.
+#
+#===------------------------------------------------------------------------===#
+
+set -e
+
+HERE="$(cd "$(dirname "$0")" && pwd)"
+
+revert=no
+extra_options=
+device=
+lib=
+use_su=0
+
+function usage {
+ echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
+ echo " --revert: Uninstall ASan from the device."
+ echo " --lib: Path to ASan runtime library."
+ echo " --extra-options: Extra ASAN_OPTIONS."
+ echo " --device: Install to the given device. Use 'adb devices' to find"
+ echo " device-id."
+ echo " --use-su: Use 'su -c' prefix for every adb command instead of using"
+ echo " 'adb root' once."
+ echo
+ exit 1
+}
+
+function adb_push {
+ if [ $use_su -eq 0 ]; then
+ $ADB push "$1" "$2"
+ else
+ local FILENAME=$(basename $1)
+ $ADB push "$1" "/data/local/tmp/$FILENAME"
+ $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null
+ $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""
+ $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""
+ fi
+}
+
+function adb_remount {
+ if [ $use_su -eq 0 ]; then
+ $ADB remount
+ else
+ local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`
+ if [ "$STORAGE" != "" ]; then
+ echo Remounting $STORAGE at /system
+ $ADB shell su -c "mount -o remount,rw $STORAGE /system"
+ else
+ echo Failed to get storage device name for "/system" mount point
+ fi
+ fi
+}
+
+function adb_shell {
+ if [ $use_su -eq 0 ]; then
+ $ADB shell $@
+ else
+ $ADB shell su -c "$*"
+ fi
+}
+
+function adb_root {
+ if [ $use_su -eq 0 ]; then
+ $ADB root
+ fi
+}
+
+function adb_wait_for_device {
+ $ADB wait-for-device
+}
+
+function adb_pull {
+ if [ $use_su -eq 0 ]; then
+ $ADB pull "$1" "$2"
+ else
+ local FILENAME=$(basename $1)
+ $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null
+ $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" &&
+ $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\""
+ fi
+}
+
+function get_device_arch { # OUT OUT64
+ local _outvar=$1
+ local _outvar64=$2
+ local _ABI=$(adb_shell getprop ro.product.cpu.abi)
+ local _ARCH=
+ local _ARCH64=
+ if [[ $_ABI == x86* ]]; then
+ _ARCH=i686
+ elif [[ $_ABI == armeabi* ]]; then
+ _ARCH=arm
+ elif [[ $_ABI == arm64-v8a* ]]; then
+ _ARCH=arm
+ _ARCH64=aarch64
+ else
+ echo "Unrecognized device ABI: $_ABI"
+ exit 1
+ fi
+ eval $_outvar=\$_ARCH
+ eval $_outvar64=\$_ARCH64
+}
+
+while [[ $# > 0 ]]; do
+ case $1 in
+ --revert)
+ revert=yes
+ ;;
+ --extra-options)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--extra-options requires an argument."
+ exit 1
+ fi
+ extra_options="$1"
+ ;;
+ --lib)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--lib requires an argument."
+ exit 1
+ fi
+ lib="$1"
+ ;;
+ --device)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--device requires an argument."
+ exit 1
+ fi
+ device="$1"
+ ;;
+ --use-su)
+ use_su=1
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+ADB=${ADB:-adb}
+if [[ x$device != x ]]; then
+ ADB="$ADB -s $device"
+fi
+
+if [ $use_su -eq 1 ]; then
+ # Test if 'su' is present on the device
+ SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`
+ if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then
+ echo "ERROR: Cannot use 'su -c':"
+ echo "$ adb shell su -c \"echo foo\""
+ echo $SU_TEST_OUT
+ echo "Check that 'su' binary is correctly installed on the device or omit"
+ echo " --use-su flag"
+ exit 1
+ fi
+fi
+
+echo '>> Remounting /system rw'
+adb_wait_for_device
+adb_root
+adb_wait_for_device
+adb_remount
+adb_wait_for_device
+
+get_device_arch ARCH ARCH64
+echo "Target architecture: $ARCH"
+ASAN_RT="libclang_rt.asan-$ARCH-android.so"
+if [[ -n $ARCH64 ]]; then
+ echo "Target architecture: $ARCH64"
+ ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"
+fi
+
+if [[ x$revert == xyes ]]; then
+ echo '>> Uninstalling ASan'
+
+ if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
+ echo '>> Pre-L device detected.'
+ adb_shell mv /system/bin/app_process.real /system/bin/app_process
+ adb_shell rm /system/bin/asanwrapper
+ elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then
+ # 64-bit installation.
+ adb_shell mv /system/bin/app_process32.real /system/bin/app_process32
+ adb_shell mv /system/bin/app_process64.real /system/bin/app_process64
+ adb_shell rm /system/bin/asanwrapper
+ adb_shell rm /system/bin/asanwrapper64
+ else
+ # 32-bit installation.
+ adb_shell rm /system/bin/app_process.wrap
+ adb_shell rm /system/bin/asanwrapper
+ adb_shell rm /system/bin/app_process
+ adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
+ fi
+
+ echo '>> Restarting shell'
+ adb_shell stop
+ adb_shell start
+
+ # Remove the library on the last step to give a chance to the 'su' binary to
+ # be executed without problem.
+ adb_shell rm /system/lib/$ASAN_RT
+
+ echo '>> Done'
+ exit 0
+fi
+
+if [[ -d "$lib" ]]; then
+ ASAN_RT_PATH="$lib"
+elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
+ ASAN_RT_PATH=$(dirname "$lib")
+elif [[ -f "$HERE/$ASAN_RT" ]]; then
+ ASAN_RT_PATH="$HERE"
+elif [[ $(basename "$HERE") == "bin" ]]; then
+ # We could be in the toolchain's base directory.
+ # Consider ../lib, ../lib/asan, ../lib/linux,
+ # ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux.
+ P=$(ls "$HERE"/../lib/"$ASAN_RT" \
+ "$HERE"/../lib/asan/"$ASAN_RT" \
+ "$HERE"/../lib/linux/"$ASAN_RT" \
+ "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \
+ "$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
+ if [[ -n "$P" ]]; then
+ ASAN_RT_PATH="$(dirname "$P")"
+ fi
+fi
+
+if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+fi
+
+if [[ -n "$ASAN_RT64" ]]; then
+ if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+ fi
+fi
+
+TMPDIRBASE=$(mktemp -d)
+TMPDIROLD="$TMPDIRBASE/old"
+TMPDIR="$TMPDIRBASE/new"
+mkdir "$TMPDIROLD"
+
+RELEASE=$(adb_shell getprop ro.build.version.release)
+PRE_L=0
+if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
+ PRE_L=1
+fi
+
+if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
+
+ if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then
+ echo '>> Old-style ASan installation detected. Reverting.'
+ adb_shell mv /system/bin/app_process.real /system/bin/app_process
+ fi
+
+ echo '>> Pre-L device detected. Setting up app_process symlink.'
+ adb_shell mv /system/bin/app_process /system/bin/app_process32
+ adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
+fi
+
+echo '>> Copying files from the device'
+if [[ -n "$ASAN_RT64" ]]; then
+ adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+ adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process64 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true
+else
+ adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
+fi
+cp -r "$TMPDIROLD" "$TMPDIR"
+
+if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then
+ echo ">> Previous installation detected"
+else
+ echo ">> New installation"
+fi
+
+echo '>> Generating wrappers'
+
+cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
+if [[ -n "$ASAN_RT64" ]]; then
+ cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"
+fi
+
+# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
+# which may or may not be a real bug (probably not).
+ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0
+
+function generate_zygote_wrapper { # from, to, asan_rt
+ local _from=$1
+ local _to=$2
+ local _asan_rt=$3
+ cat <<EOF >"$TMPDIR/$_from"
+#!/system/bin/sh-from-zygote
+ASAN_OPTIONS=$ASAN_OPTIONS \\
+ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
+LD_PRELOAD=\$LD_PRELOAD:$_asan_rt \\
+exec $_to \$@
+
+EOF
+}
+
+# On Android-L not allowing user segv handler breaks some applications.
+if [[ PRE_L -eq 0 ]]; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
+fi
+
+if [[ x$extra_options != x ]] ; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
+fi
+
+# Zygote wrapper.
+if [[ -f "$TMPDIR/app_process64" ]]; then
+ # A 64-bit device.
+ if [[ ! -f "$TMPDIR/app_process64.real" ]]; then
+ # New installation.
+ mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real"
+ mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real"
+ fi
+ generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT"
+ generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64"
+else
+ # A 32-bit device.
+ generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT"
+fi
+
+# General command-line tool wrapper (use for anything that's not started as
+# zygote).
+cat <<EOF >"$TMPDIR/asanwrapper"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT \\
+exec \$@
+
+EOF
+
+if [[ -n "$ASAN_RT64" ]]; then
+ cat <<EOF >"$TMPDIR/asanwrapper64"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT64 \\
+exec \$@
+
+EOF
+fi
+
+function install { # from, to, chmod, chcon
+ local _from=$1
+ local _to=$2
+ local _mode=$3
+ local _context=$4
+ local _basename="$(basename "$_from")"
+ echo "Installing $_to/$_basename $_mode $_context"
+ adb_push "$_from" "$_to/$_basename"
+ adb_shell chown root.shell "$_to/$_basename"
+ if [[ -n "$_mode" ]]; then
+ adb_shell chmod "$_mode" "$_to/$_basename"
+ fi
+ if [[ -n "$_context" ]]; then
+ adb_shell chcon "$_context" "$_to/$_basename"
+ fi
+}
+
+if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
+ # Make SELinux happy by keeping app_process wrapper and the shell
+ # it runs on in zygote domain.
+ ENFORCING=0
+ if adb_shell getenforce | grep Enforcing >/dev/null; then
+ # Sometimes shell is not allowed to change file contexts.
+ # Temporarily switch to permissive.
+ ENFORCING=1
+ adb_shell setenforce 0
+ fi
+
+ if [[ PRE_L -eq 1 ]]; then
+ CTX=u:object_r:system_file:s0
+ else
+ CTX=u:object_r:zygote_exec:s0
+ fi
+
+ echo '>> Pushing files to the device'
+
+ if [[ -n "$ASAN_RT64" ]]; then
+ install "$TMPDIR/$ASAN_RT" /system/lib 644
+ install "$TMPDIR/$ASAN_RT64" /system/lib64 644
+ install "$TMPDIR/app_process32" /system/bin 755 $CTX
+ install "$TMPDIR/app_process32.real" /system/bin 755 $CTX
+ install "$TMPDIR/app_process64" /system/bin 755 $CTX
+ install "$TMPDIR/app_process64.real" /system/bin 755 $CTX
+ install "$TMPDIR/asanwrapper" /system/bin 755
+ install "$TMPDIR/asanwrapper64" /system/bin 755
+ else
+ install "$TMPDIR/$ASAN_RT" /system/lib 644
+ install "$TMPDIR/app_process32" /system/bin 755 $CTX
+ install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
+ install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
+
+ adb_shell rm /system/bin/app_process
+ adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+ fi
+
+ adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
+ adb_shell chcon $CTX /system/bin/sh-from-zygote
+
+ if [ $ENFORCING == 1 ]; then
+ adb_shell setenforce 1
+ fi
+
+ echo '>> Restarting shell (asynchronous)'
+ adb_shell stop
+ adb_shell start
+
+ echo '>> Please wait until the device restarts'
+else
+ echo '>> Device is up to date'
+fi
+
+rm -r "$TMPDIRBASE"
diff --git a/compiler-rt/lib/asan/scripts/asan_symbolize.py b/compiler-rt/lib/asan/scripts/asan_symbolize.py
new file mode 100755
index 0000000..e6d43cd
--- /dev/null
+++ b/compiler-rt/lib/asan/scripts/asan_symbolize.py
@@ -0,0 +1,490 @@
+#!/usr/bin/env python
+#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+import argparse
+import bisect
+import getopt
+import os
+import re
+import subprocess
+import sys
+
+symbolizers = {}
+DEBUG = False
+demangle = False
+binutils_prefix = None
+sysroot_path = None
+binary_name_filter = None
+fix_filename_patterns = None
+logfile = sys.stdin
+allow_system_symbolizer = True
+
+# FIXME: merge the code that calls fix_filename().
+def fix_filename(file_name):
+ if fix_filename_patterns:
+ for path_to_cut in fix_filename_patterns:
+ file_name = re.sub('.*' + path_to_cut, '', file_name)
+ file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
+ file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
+ return file_name
+
+def sysroot_path_filter(binary_name):
+ return sysroot_path + binary_name
+
+def guess_arch(addr):
+ # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
+ if len(addr) > 10:
+ return 'x86_64'
+ else:
+ return 'i386'
+
+class Symbolizer(object):
+ def __init__(self):
+ pass
+
+ def symbolize(self, addr, binary, offset):
+ """Symbolize the given address (pair of binary and offset).
+
+ Overriden in subclasses.
+ Args:
+ addr: virtual address of an instruction.
+ binary: path to executable/shared object containing this instruction.
+ offset: instruction offset in the @binary.
+ Returns:
+ list of strings (one string for each inlined frame) describing
+ the code locations for this instruction (that is, function name, file
+ name, line and column numbers).
+ """
+ return None
+
+
+class LLVMSymbolizer(Symbolizer):
+ def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
+ super(LLVMSymbolizer, self).__init__()
+ self.symbolizer_path = symbolizer_path
+ self.default_arch = default_arch
+ self.system = system
+ self.dsym_hints = dsym_hints
+ self.pipe = self.open_llvm_symbolizer()
+
+ def open_llvm_symbolizer(self):
+ cmd = [self.symbolizer_path,
+ '--use-symbol-table=true',
+ '--demangle=%s' % demangle,
+ '--functions=linkage',
+ '--inlining=true',
+ '--default-arch=%s' % self.default_arch]
+ if self.system == 'Darwin':
+ for hint in self.dsym_hints:
+ cmd.append('--dsym-hint=%s' % hint)
+ if DEBUG:
+ print ' '.join(cmd)
+ try:
+ result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ except OSError:
+ result = None
+ return result
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if not self.pipe:
+ return None
+ result = []
+ try:
+ symbolizer_input = '"%s" %s' % (binary, offset)
+ if DEBUG:
+ print symbolizer_input
+ print >> self.pipe.stdin, symbolizer_input
+ while True:
+ function_name = self.pipe.stdout.readline().rstrip()
+ if not function_name:
+ break
+ file_name = self.pipe.stdout.readline().rstrip()
+ file_name = fix_filename(file_name)
+ if (not function_name.startswith('??') or
+ not file_name.startswith('??')):
+ # Append only non-trivial frames.
+ result.append('%s in %s %s' % (addr, function_name,
+ file_name))
+ except Exception:
+ result = []
+ if not result:
+ result = None
+ return result
+
+
+def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
+ symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
+ if not symbolizer_path:
+ symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
+ if not symbolizer_path:
+ # Assume llvm-symbolizer is in PATH.
+ symbolizer_path = 'llvm-symbolizer'
+ return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
+
+
+class Addr2LineSymbolizer(Symbolizer):
+ def __init__(self, binary):
+ super(Addr2LineSymbolizer, self).__init__()
+ self.binary = binary
+ self.pipe = self.open_addr2line()
+ self.output_terminator = -1
+
+ def open_addr2line(self):
+ addr2line_tool = 'addr2line'
+ if binutils_prefix:
+ addr2line_tool = binutils_prefix + addr2line_tool
+ cmd = [addr2line_tool, '-fi']
+ if demangle:
+ cmd += ['--demangle']
+ cmd += ['-e', self.binary]
+ if DEBUG:
+ print ' '.join(cmd)
+ return subprocess.Popen(cmd,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if self.binary != binary:
+ return None
+ lines = []
+ try:
+ print >> self.pipe.stdin, offset
+ print >> self.pipe.stdin, self.output_terminator
+ is_first_frame = True
+ while True:
+ function_name = self.pipe.stdout.readline().rstrip()
+ file_name = self.pipe.stdout.readline().rstrip()
+ if is_first_frame:
+ is_first_frame = False
+ elif function_name in ['', '??']:
+ assert file_name == function_name
+ break
+ lines.append((function_name, file_name));
+ except Exception:
+ lines.append(('??', '??:0'))
+ return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
+
+class UnbufferedLineConverter(object):
+ """
+ Wrap a child process that responds to each line of input with one line of
+ output. Uses pty to trick the child into providing unbuffered output.
+ """
+ def __init__(self, args, close_stderr=False):
+ # Local imports so that the script can start on Windows.
+ import pty
+ import termios
+ pid, fd = pty.fork()
+ if pid == 0:
+ # We're the child. Transfer control to command.
+ if close_stderr:
+ dev_null = os.open('/dev/null', 0)
+ os.dup2(dev_null, 2)
+ os.execvp(args[0], args)
+ else:
+ # Disable echoing.
+ attr = termios.tcgetattr(fd)
+ attr[3] = attr[3] & ~termios.ECHO
+ termios.tcsetattr(fd, termios.TCSANOW, attr)
+ # Set up a file()-like interface to the child process
+ self.r = os.fdopen(fd, "r", 1)
+ self.w = os.fdopen(os.dup(fd), "w", 1)
+
+ def convert(self, line):
+ self.w.write(line + "\n")
+ return self.readline()
+
+ def readline(self):
+ return self.r.readline().rstrip()
+
+
+class DarwinSymbolizer(Symbolizer):
+ def __init__(self, addr, binary):
+ super(DarwinSymbolizer, self).__init__()
+ self.binary = binary
+ self.arch = guess_arch(addr)
+ self.open_atos()
+
+ def open_atos(self):
+ if DEBUG:
+ print 'atos -o %s -arch %s' % (self.binary, self.arch)
+ cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
+ self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ if self.binary != binary:
+ return None
+ atos_line = self.atos.convert('0x%x' % int(offset, 16))
+ while "got symbolicator for" in atos_line:
+ atos_line = self.atos.readline()
+ # A well-formed atos response looks like this:
+ # foo(type1, type2) (in object.name) (filename.cc:80)
+ match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
+ if DEBUG:
+ print 'atos_line: ', atos_line
+ if match:
+ function_name = match.group(1)
+ function_name = re.sub('\(.*?\)', '', function_name)
+ file_name = fix_filename(match.group(3))
+ return ['%s in %s %s' % (addr, function_name, file_name)]
+ else:
+ return ['%s in %s' % (addr, atos_line)]
+
+
+# Chain several symbolizers so that if one symbolizer fails, we fall back
+# to the next symbolizer in chain.
+class ChainSymbolizer(Symbolizer):
+ def __init__(self, symbolizer_list):
+ super(ChainSymbolizer, self).__init__()
+ self.symbolizer_list = symbolizer_list
+
+ def symbolize(self, addr, binary, offset):
+ """Overrides Symbolizer.symbolize."""
+ for symbolizer in self.symbolizer_list:
+ if symbolizer:
+ result = symbolizer.symbolize(addr, binary, offset)
+ if result:
+ return result
+ return None
+
+ def append_symbolizer(self, symbolizer):
+ self.symbolizer_list.append(symbolizer)
+
+
+def BreakpadSymbolizerFactory(binary):
+ suffix = os.getenv('BREAKPAD_SUFFIX')
+ if suffix:
+ filename = binary + suffix
+ if os.access(filename, os.F_OK):
+ return BreakpadSymbolizer(filename)
+ return None
+
+
+def SystemSymbolizerFactory(system, addr, binary):
+ if system == 'Darwin':
+ return DarwinSymbolizer(addr, binary)
+ elif system == 'Linux':
+ return Addr2LineSymbolizer(binary)
+
+
+class BreakpadSymbolizer(Symbolizer):
+ def __init__(self, filename):
+ super(BreakpadSymbolizer, self).__init__()
+ self.filename = filename
+ lines = file(filename).readlines()
+ self.files = []
+ self.symbols = {}
+ self.address_list = []
+ self.addresses = {}
+ # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t
+ fragments = lines[0].rstrip().split()
+ self.arch = fragments[2]
+ self.debug_id = fragments[3]
+ self.binary = ' '.join(fragments[4:])
+ self.parse_lines(lines[1:])
+
+ def parse_lines(self, lines):
+ cur_function_addr = ''
+ for line in lines:
+ fragments = line.split()
+ if fragments[0] == 'FILE':
+ assert int(fragments[1]) == len(self.files)
+ self.files.append(' '.join(fragments[2:]))
+ elif fragments[0] == 'PUBLIC':
+ self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:])
+ elif fragments[0] in ['CFI', 'STACK']:
+ pass
+ elif fragments[0] == 'FUNC':
+ cur_function_addr = int(fragments[1], 16)
+ if not cur_function_addr in self.symbols.keys():
+ self.symbols[cur_function_addr] = ' '.join(fragments[4:])
+ else:
+ # Line starting with an address.
+ addr = int(fragments[0], 16)
+ self.address_list.append(addr)
+ # Tuple of symbol address, size, line, file number.
+ self.addresses[addr] = (cur_function_addr,
+ int(fragments[1], 16),
+ int(fragments[2]),
+ int(fragments[3]))
+ self.address_list.sort()
+
+ def get_sym_file_line(self, addr):
+ key = None
+ if addr in self.addresses.keys():
+ key = addr
+ else:
+ index = bisect.bisect_left(self.address_list, addr)
+ if index == 0:
+ return None
+ else:
+ key = self.address_list[index - 1]
+ sym_id, size, line_no, file_no = self.addresses[key]
+ symbol = self.symbols[sym_id]
+ filename = self.files[file_no]
+ if addr < key + size:
+ return symbol, filename, line_no
+ else:
+ return None
+
+ def symbolize(self, addr, binary, offset):
+ if self.binary != binary:
+ return None
+ res = self.get_sym_file_line(int(offset, 16))
+ if res:
+ function_name, file_name, line_no = res
+ result = ['%s in %s %s:%d' % (
+ addr, function_name, file_name, line_no)]
+ print result
+ return result
+ else:
+ return None
+
+
+class SymbolizationLoop(object):
+ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
+ if sys.platform == 'win32':
+ # ASan on Windows uses dbghelp.dll to symbolize in-process, which works
+ # even in sandboxed processes. Nothing needs to be done here.
+ self.process_line = self.process_line_echo
+ else:
+ # Used by clients who may want to supply a different binary name.
+ # E.g. in Chrome several binaries may share a single .dSYM.
+ self.binary_name_filter = binary_name_filter
+ self.dsym_hint_producer = dsym_hint_producer
+ self.system = os.uname()[0]
+ if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
+ raise Exception('Unknown system')
+ self.llvm_symbolizers = {}
+ self.last_llvm_symbolizer = None
+ self.dsym_hints = set([])
+ self.frame_no = 0
+ self.process_line = self.process_line_posix
+
+ def symbolize_address(self, addr, binary, offset):
+ # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
+ # a single symbolizer binary.
+ # On Darwin, if the dsym hint producer is present:
+ # 1. check whether we've seen this binary already; if so,
+ # use |llvm_symbolizers[binary]|, which has already loaded the debug
+ # info for this binary (might not be the case for
+ # |last_llvm_symbolizer|);
+ # 2. otherwise check if we've seen all the hints for this binary already;
+ # if so, reuse |last_llvm_symbolizer| which has the full set of hints;
+ # 3. otherwise create a new symbolizer and pass all currently known
+ # .dSYM hints to it.
+ if not binary in self.llvm_symbolizers:
+ use_new_symbolizer = True
+ if self.system == 'Darwin' and self.dsym_hint_producer:
+ dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
+ use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
+ self.dsym_hints |= dsym_hints_for_binary
+ if self.last_llvm_symbolizer and not use_new_symbolizer:
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ else:
+ self.last_llvm_symbolizer = LLVMSymbolizerFactory(
+ self.system, guess_arch(addr), self.dsym_hints)
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ # Use the chain of symbolizers:
+ # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
+ # (fall back to next symbolizer if the previous one fails).
+ if not binary in symbolizers:
+ symbolizers[binary] = ChainSymbolizer(
+ [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
+ result = symbolizers[binary].symbolize(addr, binary, offset)
+ if result is None:
+ if not allow_system_symbolizer:
+ raise Exception('Failed to launch or use llvm-symbolizer.')
+ # Initialize system symbolizer only if other symbolizers failed.
+ symbolizers[binary].append_symbolizer(
+ SystemSymbolizerFactory(self.system, addr, binary))
+ result = symbolizers[binary].symbolize(addr, binary, offset)
+ # The system symbolizer must produce some result.
+ assert result
+ return result
+
+ def get_symbolized_lines(self, symbolized_lines):
+ if not symbolized_lines:
+ return [self.current_line]
+ else:
+ result = []
+ for symbolized_frame in symbolized_lines:
+ result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
+ self.frame_no += 1
+ return result
+
+ def process_logfile(self):
+ self.frame_no = 0
+ for line in logfile:
+ processed = self.process_line(line)
+ print '\n'.join(processed)
+
+ def process_line_echo(self, line):
+ return [line.rstrip()]
+
+ def process_line_posix(self, line):
+ self.current_line = line.rstrip()
+ #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
+ stack_trace_line_format = (
+ '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
+ match = re.match(stack_trace_line_format, line)
+ if not match:
+ return [self.current_line]
+ if DEBUG:
+ print line
+ _, frameno_str, addr, binary, offset = match.groups()
+ if frameno_str == '0':
+ # Assume that frame #0 is the first frame of new stack trace.
+ self.frame_no = 0
+ original_binary = binary
+ if self.binary_name_filter:
+ binary = self.binary_name_filter(binary)
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ if not symbolized_line:
+ if original_binary != binary:
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ return self.get_symbolized_lines(symbolized_line)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='ASan symbolization script',
+ epilog='Example of use:\n'
+ 'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" '
+ '-s "$HOME/SymbolFiles" < asan.log')
+ parser.add_argument('path_to_cut', nargs='*',
+ help='pattern to be cut from the result file path ')
+ parser.add_argument('-d','--demangle', action='store_true',
+ help='demangle function names')
+ parser.add_argument('-s', metavar='SYSROOT',
+ help='set path to sysroot for sanitized binaries')
+ parser.add_argument('-c', metavar='CROSS_COMPILE',
+ help='set prefix for binutils')
+ parser.add_argument('-l','--logfile', default=sys.stdin,
+ type=argparse.FileType('r'),
+ help='set log file name to parse, default is stdin')
+ args = parser.parse_args()
+ if args.path_to_cut:
+ fix_filename_patterns = args.path_to_cut
+ if args.demangle:
+ demangle = True
+ if args.s:
+ binary_name_filter = sysroot_path_filter
+ sysroot_path = args.s
+ if args.c:
+ binutils_prefix = args.c
+ if args.logfile:
+ logfile = args.logfile
+ else:
+ logfile = sys.stdin
+ loop = SymbolizationLoop(binary_name_filter)
+ loop.process_logfile()
diff --git a/compiler-rt/lib/asan/scripts/symbolize.py b/compiler-rt/lib/asan/scripts/symbolize.py
new file mode 100755
index 0000000..2182fd4
--- /dev/null
+++ b/compiler-rt/lib/asan/scripts/symbolize.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+import glob
+import os
+import re
+import sys
+import string
+import subprocess
+
+pipes = {}
+load_addresses = {}
+next_inline_frameno = 0
+
+def patch_address(frameno, addr_s):
+ ''' Subtracts 1 or 2 from the top frame's address.
+ Top frame is normally the return address from asan_report*
+ call, which is not expected to return at all. Because of that, this
+ address often belongs to the next source code line, or even to a different
+ function. '''
+ if frameno == '0':
+ addr = int(addr_s, 16)
+ if os.uname()[4].startswith('arm'):
+ # Cancel the Thumb bit
+ addr = addr & (~1)
+ addr -= 1
+ return hex(addr)
+ return addr_s
+
+def android_get_load_address(path):
+ if load_addresses.has_key(path):
+ return load_addresses[path]
+ readelf_glob = os.path.join(os.environ['ANDROID_TOOLCHAIN'], '*-readelf')
+ readelf = glob.glob(readelf_glob)[0]
+ readelf_pipe = subprocess.Popen([readelf, "-W", "-l", path], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ for line in readelf_pipe.stdout:
+ if ('LOAD' in line) and (' E ' in line):
+ match = re.match(r'\s*LOAD\s+0x[01-9a-zA-Z]+\s+(0x[01-9a-zA-Z]+)', line, re.UNICODE)
+ if match:
+ load_addr = int(match.group(1), 16)
+ load_addresses[path] = load_addr
+ return load_addr
+ else: break
+ print 'Could not make sense of readelf output!'
+ sys.exit(1)
+
+def postprocess_file_name(file_name, paths_to_cut):
+ for path_to_cut in paths_to_cut:
+ file_name = re.sub(".*" + path_to_cut, "", file_name)
+ file_name = re.sub(".*asan_[a-z_]*.(cc|h):[0-9]*", "[asan_rtl]", file_name)
+ file_name = re.sub(".*crtstuff.c:0", "???:0", file_name)
+ return file_name
+
+# TODO(glider): need some refactoring here
+def symbolize_addr2line(line, binary_prefix, paths_to_cut):
+ global next_inline_frameno
+ # Strip the log prefix ("I/asanwrapper( 1196): ").
+ line = re.sub(r'^.*?: ', '', line)
+ #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
+ match = re.match(r'^(\s*#)([0-9]+) *(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line, re.UNICODE)
+ if match:
+ frameno = match.group(2)
+ binary = match.group(4)
+ addr = match.group(5)
+ addr = patch_address(frameno, addr)
+
+ if binary.startswith('/'):
+ binary = binary[1:]
+ binary = os.path.join(binary_prefix, binary)
+
+ if not os.path.exists(binary):
+ print line.rstrip().encode('utf-8')
+ return
+
+ load_addr = android_get_load_address(binary)
+ addr = hex(int(addr, 16) + load_addr)
+
+ if not pipes.has_key(binary):
+ pipes[binary] = subprocess.Popen(["addr2line", "-i", "-f", "-e", binary],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ p = pipes[binary]
+ frames = []
+ try:
+ print >>p.stdin, addr
+ # This will trigger a "??" response from addr2line so we know when to stop
+ print >>p.stdin
+ while True:
+ function_name = p.stdout.readline().rstrip()
+ file_name = p.stdout.readline().rstrip()
+ if function_name in ['??', '']:
+ break
+ file_name = postprocess_file_name(file_name, paths_to_cut)
+ frames.append((function_name, file_name))
+ except:
+ pass
+ if not frames:
+ frames.append(('', ''))
+ # Consume another pair of "??" lines
+ try:
+ p.stdout.readline()
+ p.stdout.readline()
+ except:
+ pass
+ for frame in frames:
+ inline_frameno = next_inline_frameno
+ next_inline_frameno += 1
+ print "%s%d" % (match.group(1).encode('utf-8'), inline_frameno), \
+ match.group(3).encode('utf-8'), "in", frame[0], frame[1]
+ else:
+ print line.rstrip().encode('utf-8')
+
+
+binary_prefix = os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'symbols')
+paths_to_cut = [os.getcwd() + '/', os.environ['ANDROID_BUILD_TOP'] + '/'] + sys.argv[1:]
+
+for line in sys.stdin:
+ line = line.decode('utf-8')
+ symbolize_addr2line(line, binary_prefix, paths_to_cut)
diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt
new file mode 100644
index 0000000..7a8d8f7
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/CMakeLists.txt
@@ -0,0 +1,306 @@
+# Testing rules for AddressSanitizer.
+#
+# These are broken into two buckets. One set of tests directly interacts with
+# the runtime library and checks its functionality. These are the
+# no-instrumentation tests.
+#
+# Another group of tests relies upon the ability to compile the test with
+# address sanitizer instrumentation pass. These tests form "integration" tests
+# and have some elements of version skew -- they test the *host* compiler's
+# instrumentation against the just-built runtime library.
+
+include(CheckCXXCompilerFlag)
+include(CompilerRTCompile)
+
+include_directories(..)
+include_directories(../..)
+
+set(ASAN_UNITTEST_HEADERS
+ asan_mac_test.h
+ asan_test_config.h
+ asan_test_utils.h)
+
+set(ASAN_UNITTEST_COMMON_CFLAGS
+ ${COMPILER_RT_TEST_CFLAGS}
+ ${COMPILER_RT_GTEST_CFLAGS}
+ -I${COMPILER_RT_SOURCE_DIR}/include
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${COMPILER_RT_SOURCE_DIR}/lib/asan
+ -I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/tests
+ -fno-rtti
+ -O2
+ -Wno-format
+ -Werror=sign-compare
+ -Wno-non-virtual-dtor)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
+
+# -gline-tables-only must be enough for ASan, so use it if possible.
+if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
+else()
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
+endif()
+
+# Use -D instead of definitions to please custom compile command.
+list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
+ -DASAN_HAS_BLACKLIST=1
+ -DASAN_HAS_EXCEPTIONS=1
+ -DASAN_UAR=0)
+
+if(APPLE)
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS ${DARWIN_osx_CFLAGS})
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS ${DARWIN_osx_LINKFLAGS})
+endif()
+
+if(MSVC)
+ # Disable exceptions on Windows until they work reliably.
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -fno-exceptions -DGTEST_HAS_SEH=0)
+endif()
+
+set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
+set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
+ ${ASAN_UNITTEST_COMMON_CFLAGS}
+ -fsanitize=address
+ "-fsanitize-blacklist=${ASAN_BLACKLIST_FILE}"
+)
+if(CAN_TARGET_x86_64 OR CAN_TARGET_i386)
+ list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-instrument-assembly)
+endif()
+
+if(NOT MSVC)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS --driver-mode=g++)
+endif()
+
+# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests.
+if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS "-lc++")
+endif()
+
+# Unit tests on Mac depend on Foundation.
+if(APPLE)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -framework Foundation)
+endif()
+if(ANDROID)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -pie)
+endif()
+
+set(ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_COMMON_LINKFLAGS})
+list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
+
+set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}
+ -shared-libasan)
+
+set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
+
+set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS})
+append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBRT -lrt ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
+ ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS)
+
+# TODO(eugenis): move all -l flags above to _LIBS?
+set(ASAN_UNITTEST_NOINST_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
+
+# Compile source for the given architecture, using compiler
+# options in ${ARGN}, and add it to the object list.
+macro(asan_compile obj_list source arch kind)
+ get_filename_component(basename ${source} NAME)
+ set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
+ get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest asan)
+ endif()
+ clang_compile(${output_obj} ${source}
+ CFLAGS ${ARGN} ${TARGET_CFLAGS}
+ DEPS ${COMPILE_DEPS})
+ list(APPEND ${obj_list} ${output_obj})
+endmacro()
+
+# Link ASan unit test for a given architecture from a set
+# of objects in with given linker flags.
+macro(add_asan_test test_suite test_name arch kind)
+ cmake_parse_arguments(TEST "WITH_TEST_RUNTIME" "" "OBJECTS;LINKFLAGS;SUBDIR" ${ARGN})
+ get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ set(TEST_DEPS ${TEST_OBJECTS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TEST_DEPS asan)
+ endif()
+ if(TEST_WITH_TEST_RUNTIME)
+ list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
+ if(NOT MSVC)
+ list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ else()
+ list(APPEND TEST_OBJECTS ${ASAN_TEST_RUNTIME}.lib)
+ endif()
+ endif()
+ add_compiler_rt_test(${test_suite} ${test_name}
+ SUBDIR ${TEST_SUBDIR}
+ OBJECTS ${TEST_OBJECTS}
+ DEPS ${TEST_DEPS}
+ LINK_FLAGS ${TEST_LINKFLAGS}
+ ${TARGET_LINK_FLAGS})
+endmacro()
+
+# Main AddressSanitizer unit tests.
+add_custom_target(AsanUnitTests)
+set_target_properties(AsanUnitTests PROPERTIES FOLDER "ASan unit tests")
+# AddressSanitizer unit tests with dynamic runtime (on platforms where it's
+# not the default).
+add_custom_target(AsanDynamicUnitTests)
+set_target_properties(AsanDynamicUnitTests
+ PROPERTIES FOLDER "ASan unit tests with dynamic runtime")
+# ASan benchmarks (not actively used now).
+add_custom_target(AsanBenchmarks)
+set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
+
+set(ASAN_NOINST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_fake_stack_test.cc
+ asan_noinst_test.cc
+ asan_test_main.cc)
+
+set(ASAN_INST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_asm_test.cc
+ asan_globals_test.cc
+ asan_interface_test.cc
+ asan_test.cc
+ asan_oob_test.cc
+ asan_mem_test.cc
+ asan_str_test.cc
+ asan_test_main.cc)
+if(APPLE)
+ list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc)
+endif()
+
+set(ASAN_BENCHMARKS_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_benchmarks_test.cc)
+
+# Adds ASan unit tests and benchmarks for architecture.
+macro(add_asan_tests_for_arch_and_kind arch kind)
+ # Instrumented tests.
+ set(ASAN_INST_TEST_OBJECTS)
+ foreach(src ${ASAN_INST_TEST_SOURCES})
+ asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
+ endforeach()
+ if (APPLE)
+ # Add Mac-specific helper.
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
+ endif()
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default")
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test"
+ ${arch} ${kind} SUBDIR "default"
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic")
+ add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test"
+ ${arch} ${kind} SUBDIR "dynamic"
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
+
+ # Add static ASan runtime that will be linked with uninstrumented tests.
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
+ if(APPLE)
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan_dynamic.osx>
+ $<TARGET_OBJECTS:RTInterception.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
+ $<TARGET_OBJECTS:RTLSanCommon.osx>
+ $<TARGET_OBJECTS:RTUbsan.osx>)
+ else()
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
+ endif()
+ add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
+ set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # Uninstrumented tests.
+ set(ASAN_NOINST_TEST_OBJECTS)
+ foreach(src ${ASAN_NOINST_TEST_SOURCES})
+ asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN})
+ endforeach()
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test"
+ ${arch} ${kind} SUBDIR "default"
+ OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS}
+ WITH_TEST_RUNTIME)
+
+ # Benchmarks.
+ set(ASAN_BENCHMARKS_OBJECTS)
+ foreach(src ${ASAN_BENCHMARKS_SOURCES})
+ asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
+ endforeach()
+ add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark"
+ ${arch} ${kind} SUBDIR "default"
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+endmacro()
+
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
+ set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
+ if(APPLE)
+ darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
+ endif()
+ foreach(arch ${ASAN_TEST_ARCH})
+ add_asan_tests_for_arch_and_kind(${arch} "-inline")
+ add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
+ -mllvm -asan-instrumentation-with-call-threshold=0)
+ endforeach()
+endif()
+
+if(ANDROID)
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ # Test w/o ASan instrumentation. Link it with ASan statically.
+ add_executable(AsanNoinstTest # FIXME: .arch?
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_NOINST_TEST_SOURCES})
+ set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
+ set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
+ target_link_libraries(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LIBS})
+
+ # Test with ASan instrumentation. Link with ASan dynamic runtime.
+ add_executable(AsanTest
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_INST_TEST_SOURCES})
+ set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ target_link_libraries(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LIBS})
+
+ # Setup correct output directory and link flags.
+ set_target_properties(AsanNoinstTest AsanTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # Add unit tests to the test suite.
+ add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+ endforeach()
+endif()
diff --git a/compiler-rt/lib/asan/tests/asan_asm_test.cc b/compiler-rt/lib/asan/tests/asan_asm_test.cc
new file mode 100644
index 0000000..09af5c3
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_asm_test.cc
@@ -0,0 +1,271 @@
+//===-- asan_asm_test.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__linux__)
+
+// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
+// library). See https://github.com/google/sanitizers/issues/353
+#if defined(__x86_64__) || \
+ (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
+
+#include <emmintrin.h>
+
+namespace {
+
+template<typename T> void asm_write(T *ptr, T val);
+template<typename T> T asm_read(T *ptr);
+template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#if defined(__x86_64__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "rsi", "rdi", "rcx", "memory"); \
+ }
+
+DECLARE_ASM_WRITE(U8, "8", "movq", "r");
+DECLARE_ASM_READ(U8, "8", "movq", "=r");
+DECLARE_ASM_REP_MOVS(U8, "movsq");
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__)
+
+#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "esi", "edi", "ecx", "memory"); \
+ }
+
+} // End of anonymous namespace
+
+#endif // defined(__i386__) && defined(__SSE2__)
+
+#if defined(__x86_64__) || \
+ (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
+
+namespace {
+
+DECLARE_ASM_WRITE(U1, "1", "movb", "r");
+DECLARE_ASM_WRITE(U2, "2", "movw", "r");
+DECLARE_ASM_WRITE(U4, "4", "movl", "r");
+DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
+
+DECLARE_ASM_READ(U1, "1", "movb", "=r");
+DECLARE_ASM_READ(U2, "2", "movw", "=r");
+DECLARE_ASM_READ(U4, "4", "movl", "=r");
+DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
+
+DECLARE_ASM_REP_MOVS(U1, "movsb");
+DECLARE_ASM_REP_MOVS(U2, "movsw");
+DECLARE_ASM_REP_MOVS(U4, "movsl");
+
+template<typename T> void TestAsmWrite(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
+ T var = 0x12;
+ asm_write(&var, static_cast<T>(0x21));
+ ASSERT_EQ(static_cast<T>(0x21), var);
+ delete buf;
+}
+
+template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ __m128i val = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
+ __m128i var = _mm_set1_epi16(0x4321);
+ asm_write(&var, val);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
+ delete [] buf;
+}
+
+template<typename T> void TestAsmRead(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
+ T var = 0x12;
+ ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
+ delete buf;
+}
+
+template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
+ __m128i val = _mm_set1_epi16(0x1234);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
+ delete [] buf;
+}
+
+U4 AsmLoad(U4 *a) {
+ U4 r;
+ __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
+ return r;
+}
+
+void AsmStore(U4 r, U4 *a) {
+ __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
+}
+
+template <typename T>
+void TestAsmRepMovs(const char *DeathPatternRead,
+ const char *DeathPatternWrite) {
+ T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
+ T dst_good[4] = {};
+ asm_rep_movs(dst_good, src_good, 4);
+ ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
+ ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
+ ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
+ ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
+
+ T dst_bad[3];
+ EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
+
+ T src_bad[3] = { 0x0, 0x1, 0x2 };
+ EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
+
+ T* dp = dst_bad + 4;
+ T* sp = src_bad + 4;
+ asm_rep_movs(dp, sp, 0);
+}
+
+} // End of anonymous namespace
+
+TEST(AddressSanitizer, asm_load_store) {
+ U4* buf = new U4[2];
+ EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
+ EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
+ delete [] buf;
+}
+
+TEST(AddressSanitizer, asm_rw) {
+ TestAsmWrite<U1>("WRITE of size 1");
+ TestAsmWrite<U2>("WRITE of size 2");
+ TestAsmWrite<U4>("WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmWrite<U8>("WRITE of size 8");
+#endif // defined(__x86_64__)
+ TestAsmWrite<__m128i>("WRITE of size 16");
+
+ TestAsmRead<U1>("READ of size 1");
+ TestAsmRead<U2>("READ of size 2");
+ TestAsmRead<U4>("READ of size 4");
+#if defined(__x86_64__)
+ TestAsmRead<U8>("READ of size 8");
+#endif // defined(__x86_64__)
+ TestAsmRead<__m128i>("READ of size 16");
+}
+
+TEST(AddressSanitizer, asm_flags) {
+ long magic = 0x1234;
+ long r = 0x0;
+
+#if defined(__x86_64__) && !defined(__ILP32__)
+ __asm__("xorq %%rax, %%rax \n\t"
+ "movq (%[p]), %%rax \n\t"
+ "sete %%al \n\t"
+ "movzbq %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "rax", "memory");
+#else
+ __asm__("xorl %%eax, %%eax \n\t"
+ "movl (%[p]), %%eax \n\t"
+ "sete %%al \n\t"
+ "movzbl %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "eax", "memory");
+#endif // defined(__x86_64__) && !defined(__ILP32__)
+
+ ASSERT_EQ(0x1, r);
+}
+
+TEST(AddressSanitizer, asm_rep_movs) {
+ TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
+ TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
+ TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
+#endif // defined(__x86_64__)
+}
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#endif // defined(__linux__)
diff --git a/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc b/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
new file mode 100644
index 0000000..fc522de
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
@@ -0,0 +1,85 @@
+//===-- asan_benchmarks_test.cc ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some benchmarks for the instrumented code.
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+template<class T>
+__attribute__((noinline))
+static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(0);
+ // hand unroll the loop to stress the reg alloc.
+ for (size_t i = 0; i <= n_elements - 16; i += 16) {
+ x[i + 0] = i;
+ x[i + 1] = i;
+ x[i + 2] = i;
+ x[i + 3] = i;
+ x[i + 4] = i;
+ x[i + 5] = i;
+ x[i + 6] = i;
+ x[i + 7] = i;
+ x[i + 8] = i;
+ x[i + 9] = i;
+ x[i + 10] = i;
+ x[i + 11] = i;
+ x[i + 12] = i;
+ x[i + 13] = i;
+ x[i + 14] = i;
+ x[i + 15] = i;
+ }
+ }
+}
+
+TEST(AddressSanitizer, ManyAccessBenchmark) {
+ size_t kLen = 1024;
+ int *int_array = new int[kLen];
+ ManyAccessFunc(int_array, kLen, 1 << 24);
+ delete [] int_array;
+}
+
+// access 7 char elements in a 7 byte array (i.e. on the border).
+__attribute__((noinline))
+static void BorderAccessFunc(char *x, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(x);
+ x[0] = 0;
+ x[1] = 0;
+ x[2] = 0;
+ x[3] = 0;
+ x[4] = 0;
+ x[5] = 0;
+ x[6] = 0;
+ }
+}
+
+TEST(AddressSanitizer, BorderAccessBenchmark) {
+ char *char_7_array = new char[7];
+ BorderAccessFunc(char_7_array, 1 << 30);
+ delete [] char_7_array;
+}
+
+static void FunctionWithLargeStack() {
+ int stack[1000];
+ Ident(stack);
+}
+
+TEST(AddressSanitizer, FakeStackBenchmark) {
+ for (int i = 0; i < 10000000; i++)
+ Ident(&FunctionWithLargeStack)();
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/compiler-rt/lib/asan/tests/asan_exceptions_test.cc b/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
new file mode 100644
index 0000000..ecd406d
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
@@ -0,0 +1,27 @@
+// See http://llvm.org/bugs/show_bug.cgi?id=11468
+#include <stdio.h>
+#include <string>
+
+class Action {
+ public:
+ Action() {}
+ void PrintString(const std::string& msg) const {
+ fprintf(stderr, "%s\n", msg.c_str());
+ }
+ void Throw(const char& arg) const {
+ PrintString("PrintString called!"); // this line is important
+ throw arg;
+ }
+};
+
+int main() {
+ const Action a;
+ fprintf(stderr, "&a before = %p\n", &a);
+ try {
+ a.Throw('c');
+ } catch(const char&) {
+ fprintf(stderr, "&a in catch = %p\n", &a);
+ }
+ fprintf(stderr, "&a final = %p\n", &a);
+ return 0;
+}
diff --git a/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc b/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
new file mode 100644
index 0000000..516142f
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
@@ -0,0 +1,152 @@
+//===-- asan_fake_stack_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Tests for FakeStack.
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_fake_stack.h"
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <map>
+
+namespace __asan {
+
+TEST(FakeStack, FlagsSize) {
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
+}
+
+TEST(FakeStack, RequiredSize) {
+ // for (int i = 15; i < 20; i++) {
+ // uptr alloc_size = FakeStack::RequiredSize(i);
+ // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
+ // }
+ EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
+ EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
+ EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
+ EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
+ EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
+}
+
+TEST(FakeStack, FlagsOffset) {
+ for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
+ uptr stack_size = 1UL << stack_size_log;
+ uptr offset = 0;
+ for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
+ class_id++) {
+ uptr frame_size = FakeStack::BytesInSizeClass(class_id);
+ uptr num_flags = stack_size / frame_size;
+ EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
+ // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
+ // FakeStack::FlagsOffset(stack_size_log, class_id));
+ offset += num_flags;
+ }
+ }
+}
+
+#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
+TEST(FakeStack, CreateDestroy) {
+ for (int i = 0; i < 1000; i++) {
+ for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
+ FakeStack *fake_stack = FakeStack::Create(stack_size_log);
+ fake_stack->Destroy(0);
+ }
+ }
+}
+#endif
+
+TEST(FakeStack, ModuloNumberOfFrames) {
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
+}
+
+TEST(FakeStack, GetFrame) {
+ const uptr stack_size_log = 20;
+ const uptr stack_size = 1 << stack_size_log;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ u8 *base = fs->GetFrame(stack_size_log, 0, 0);
+ EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
+ fs->SizeRequiredForFlags(stack_size_log) + 4096);
+ EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
+ EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
+ EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
+ fs->Destroy(0);
+}
+
+TEST(FakeStack, Allocate) {
+ const uptr stack_size_log = 19;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ std::map<FakeFrame *, uptr> s;
+ for (int iter = 0; iter < 2; iter++) {
+ s.clear();
+ for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
+ uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
+ uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
+ for (uptr j = 0; j < n; j++) {
+ FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
+ uptr x = reinterpret_cast<uptr>(ff);
+ EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
+ EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
+ }
+ // We are out of fake stack, so Allocate should return 0.
+ EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
+ }
+ for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
+ ++it) {
+ fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
+ }
+ }
+ fs->Destroy(0);
+}
+
+static void RecursiveFunction(FakeStack *fs, int depth) {
+ uptr class_id = depth / 3;
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
+ if (depth) {
+ RecursiveFunction(fs, depth - 1);
+ RecursiveFunction(fs, depth - 1);
+ }
+ fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
+}
+
+TEST(FakeStack, RecursiveStressTest) {
+ const uptr stack_size_log = 16;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
+ fs->Destroy(0);
+}
+
+} // namespace __asan
diff --git a/compiler-rt/lib/asan/tests/asan_globals_test.cc b/compiler-rt/lib/asan/tests/asan_globals_test.cc
new file mode 100644
index 0000000..5042ef0
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_globals_test.cc
@@ -0,0 +1,45 @@
+//===-- asan_globals_test.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+char glob1[1];
+char glob2[2];
+char glob3[3];
+char glob4[4];
+char glob5[5];
+char glob6[6];
+char glob7[7];
+char glob8[8];
+char glob9[9];
+char glob10[10];
+char glob11[11];
+char glob12[12];
+char glob13[13];
+char glob14[14];
+char glob15[15];
+char glob16[16];
+char glob17[17];
+char glob1000[1000];
+char glob10000[10000];
+char glob100000[100000];
+
+static char static10[10];
+
+int GlobalsTest(int zero) {
+ static char func_static15[15];
+ glob5[zero] = 0;
+ static10[zero] = 0;
+ func_static15[zero] = 0;
+ return glob5[1] + func_static15[2];
+}
diff --git a/compiler-rt/lib/asan/tests/asan_interface_test.cc b/compiler-rt/lib/asan/tests/asan_interface_test.cc
new file mode 100644
index 0000000..f5bfb80
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_interface_test.cc
@@ -0,0 +1,423 @@
+//===-- asan_interface_test.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/asan_interface.h>
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+ EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
+ const size_t sizes[] = { 1, 30, 1<<30 };
+ for (size_t i = 0; i < 3; i++) {
+ EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
+ }
+}
+
+static const char* kGetAllocatedSizeErrorMsg =
+ "attempting to call __sanitizer_get_allocated_size";
+
+TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+
+ // Allocated memory is owned by allocator. Allocated size should be
+ // equal to requested size.
+ EXPECT_EQ(true, __sanitizer_get_ownership(array));
+ EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
+ EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
+
+ // We cannot call GetAllocatedSize from the memory we didn't map,
+ // and from the interior pointers (not returned by previous malloc).
+ void *wild_addr = (void*)0x1;
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
+ kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
+ kGetAllocatedSizeErrorMsg);
+
+ // NULL is not owned, but is a valid argument for
+ // __sanitizer_get_allocated_size().
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
+
+ // When memory is freed, it's not owned, and call to GetAllocatedSize
+ // is forbidden.
+ free(array);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array),
+ kGetAllocatedSizeErrorMsg);
+ delete int_ptr;
+
+ void *zero_alloc = Ident(malloc(0));
+ if (zero_alloc != 0) {
+ // If malloc(0) is not null, this pointer is owned and should have valid
+ // allocated size.
+ EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
+ // Allocated size is 0 or 1 depending on the allocator used.
+ EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
+ }
+ free(zero_alloc);
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+ size_t before_malloc, after_malloc, after_free;
+ char *array;
+ const size_t kMallocSize = 100;
+ before_malloc = __sanitizer_get_current_allocated_bytes();
+
+ array = Ident((char*)malloc(kMallocSize));
+ after_malloc = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
+
+ free(array);
+ after_free = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc, after_free);
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+ // ASan allocator does not keep huge chunks in free list, but unmaps them.
+ // The chunk should be greater than the quarantine size,
+ // otherwise it will be stuck in quarantine instead of being unmaped.
+ static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
+ free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
+ size_t old_heap_size = __sanitizer_get_heap_size();
+ for (int i = 0; i < 3; i++) {
+ // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+ free(Ident(malloc(kLargeMallocSize)));
+ EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
+ }
+}
+
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads =
+ (SANITIZER_WORDSIZE == 32) ? 40 : 200;
+
+static void *ManyThreadsWithStatsWorker(void *arg) {
+ (void)arg;
+ for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
+ for (size_t size_index = 0; size_index < 4; size_index++) {
+ free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
+ }
+ }
+ // Just one large allocation.
+ free(Ident(malloc(1 << 20)));
+ return 0;
+}
+
+TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
+ size_t before_test, after_test, i;
+ pthread_t threads[kManyThreadsNumThreads];
+ before_test = __sanitizer_get_current_allocated_bytes();
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_CREATE(&threads[i], 0,
+ (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
+ }
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_JOIN(threads[i], 0);
+ }
+ after_test = __sanitizer_get_current_allocated_bytes();
+ // ASan stats also reflect memory usage of internal ASan RTL structs,
+ // so we can't check for equality here.
+ EXPECT_LT(after_test, before_test + (1UL<<20));
+}
+
+static void DoDoubleFree() {
+ int *x = Ident(new int);
+ delete Ident(x);
+ delete Ident(x);
+}
+
+static void MyDeathCallback() {
+ fprintf(stderr, "MyDeathCallback\n");
+ fflush(0); // On Windows, stderr doesn't flush on crash.
+}
+
+TEST(AddressSanitizerInterface, DeathCallbackTest) {
+ __asan_set_death_callback(MyDeathCallback);
+ EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
+ __asan_set_death_callback(NULL);
+}
+
+static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
+
+#define GOOD_ACCESS(ptr, offset) \
+ EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
+
+#define BAD_ACCESS(ptr, offset) \
+ EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
+
+TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // poison array[40..80)
+ __asan_poison_memory_region(array + 40, 40);
+ GOOD_ACCESS(array, 39);
+ GOOD_ACCESS(array, 80);
+ BAD_ACCESS(array, 40);
+ BAD_ACCESS(array, 60);
+ BAD_ACCESS(array, 79);
+ char value;
+ EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
+ __asan_unpoison_memory_region(array + 40, 40);
+ // access previously poisoned memory.
+ GOOD_ACCESS(array, 40);
+ GOOD_ACCESS(array, 79);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // Poison [0..40) and [80..120)
+ __asan_poison_memory_region(array, 40);
+ __asan_poison_memory_region(array + 80, 40);
+ BAD_ACCESS(array, 20);
+ GOOD_ACCESS(array, 60);
+ BAD_ACCESS(array, 100);
+ // Poison whole array - [0..120)
+ __asan_poison_memory_region(array, 120);
+ BAD_ACCESS(array, 60);
+ // Unpoison [24..96)
+ __asan_unpoison_memory_region(array + 24, 72);
+ BAD_ACCESS(array, 23);
+ GOOD_ACCESS(array, 24);
+ GOOD_ACCESS(array, 60);
+ GOOD_ACCESS(array, 95);
+ BAD_ACCESS(array, 96);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
+ // Vector of capacity 20
+ char *vec = Ident((char*)malloc(20));
+ __asan_poison_memory_region(vec, 20);
+ for (size_t i = 0; i < 7; i++) {
+ // Simulate push_back.
+ __asan_unpoison_memory_region(vec + i, 1);
+ GOOD_ACCESS(vec, i);
+ BAD_ACCESS(vec, i + 1);
+ }
+ for (size_t i = 7; i > 0; i--) {
+ // Simulate pop_back.
+ __asan_poison_memory_region(vec + i - 1, 1);
+ BAD_ACCESS(vec, i - 1);
+ if (i > 1) GOOD_ACCESS(vec, i - 2);
+ }
+ free(vec);
+}
+
+// Make sure that each aligned block of size "2^granularity" doesn't have
+// "true" value before "false" value.
+static void MakeShadowValid(bool *shadow, int length, int granularity) {
+ bool can_be_poisoned = true;
+ for (int i = length - 1; i >= 0; i--) {
+ if (!shadow[i])
+ can_be_poisoned = false;
+ if (!can_be_poisoned)
+ shadow[i] = false;
+ if (i % (1 << granularity) == 0) {
+ can_be_poisoned = true;
+ }
+ }
+}
+
+TEST(AddressSanitizerInterface, PoisoningStressTest) {
+ const size_t kSize = 24;
+ bool expected[kSize];
+ char *arr = Ident((char*)malloc(kSize));
+ for (size_t l1 = 0; l1 < kSize; l1++) {
+ for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
+ for (size_t l2 = 0; l2 < kSize; l2++) {
+ for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
+ // Poison [l1, l1+s1), [l2, l2+s2) and check result.
+ __asan_unpoison_memory_region(arr, kSize);
+ __asan_poison_memory_region(arr + l1, s1);
+ __asan_poison_memory_region(arr + l2, s2);
+ memset(expected, false, kSize);
+ memset(expected + l1, true, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, true, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
+ __asan_poison_memory_region(arr, kSize);
+ __asan_unpoison_memory_region(arr + l1, s1);
+ __asan_unpoison_memory_region(arr + l2, s2);
+ memset(expected, true, kSize);
+ memset(expected + l1, false, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, false, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ }
+ }
+ }
+ }
+ free(arr);
+}
+
+TEST(AddressSanitizerInterface, GlobalRedzones) {
+ GOOD_ACCESS(glob1, 1 - 1);
+ GOOD_ACCESS(glob2, 2 - 1);
+ GOOD_ACCESS(glob3, 3 - 1);
+ GOOD_ACCESS(glob4, 4 - 1);
+ GOOD_ACCESS(glob5, 5 - 1);
+ GOOD_ACCESS(glob6, 6 - 1);
+ GOOD_ACCESS(glob7, 7 - 1);
+ GOOD_ACCESS(glob8, 8 - 1);
+ GOOD_ACCESS(glob9, 9 - 1);
+ GOOD_ACCESS(glob10, 10 - 1);
+ GOOD_ACCESS(glob11, 11 - 1);
+ GOOD_ACCESS(glob12, 12 - 1);
+ GOOD_ACCESS(glob13, 13 - 1);
+ GOOD_ACCESS(glob14, 14 - 1);
+ GOOD_ACCESS(glob15, 15 - 1);
+ GOOD_ACCESS(glob16, 16 - 1);
+ GOOD_ACCESS(glob17, 17 - 1);
+ GOOD_ACCESS(glob1000, 1000 - 1);
+ GOOD_ACCESS(glob10000, 10000 - 1);
+ GOOD_ACCESS(glob100000, 100000 - 1);
+
+ BAD_ACCESS(glob1, 1);
+ BAD_ACCESS(glob2, 2);
+ BAD_ACCESS(glob3, 3);
+ BAD_ACCESS(glob4, 4);
+ BAD_ACCESS(glob5, 5);
+ BAD_ACCESS(glob6, 6);
+ BAD_ACCESS(glob7, 7);
+ BAD_ACCESS(glob8, 8);
+ BAD_ACCESS(glob9, 9);
+ BAD_ACCESS(glob10, 10);
+ BAD_ACCESS(glob11, 11);
+ BAD_ACCESS(glob12, 12);
+ BAD_ACCESS(glob13, 13);
+ BAD_ACCESS(glob14, 14);
+ BAD_ACCESS(glob15, 15);
+ BAD_ACCESS(glob16, 16);
+ BAD_ACCESS(glob17, 17);
+ BAD_ACCESS(glob1000, 1000);
+ BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
+ BAD_ACCESS(glob10000, 10000);
+ BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
+ BAD_ACCESS(glob100000, 100000);
+ BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
+}
+
+TEST(AddressSanitizerInterface, PoisonedRegion) {
+ size_t rz = 16;
+ for (size_t size = 1; size <= 64; size++) {
+ char *p = new char[size];
+ for (size_t beg = 0; beg < size + rz; beg++) {
+ for (size_t end = beg; end < size + rz; end++) {
+ void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
+ if (beg == end) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg < size && end <= size) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg >= size) {
+ EXPECT_EQ(p + beg, first_poisoned);
+ } else {
+ EXPECT_GT(end, size);
+ EXPECT_EQ(p + size, first_poisoned);
+ }
+ }
+ }
+ delete [] p;
+ }
+}
+
+// This is a performance benchmark for manual runs.
+// asan's memset interceptor calls mem_is_zero for the entire shadow region.
+// the profile should look like this:
+// 89.10% [.] __memset_sse2
+// 10.50% [.] __sanitizer::mem_is_zero
+// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
+// than memset itself.
+TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
+ size_t size = 1 << 20;
+ char *x = new char[size];
+ for (int i = 0; i < 100000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+
+// Same here, but we run memset with small sizes.
+TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
+ size_t size = 32;
+ char *x = new char[size];
+ for (int i = 0; i < 100000000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
+static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
+
+TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
+ char *array = Ident((char*)malloc(120));
+ __asan_unpoison_memory_region(array, 120);
+ // Try to unpoison not owned memory
+ EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
+ kInvalidUnpoisonMessage);
+ EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
+ kInvalidUnpoisonMessage);
+
+ __asan_poison_memory_region(array, 120);
+ // Try to poison not owned memory.
+ EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
+ EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
+ kInvalidPoisonMessage);
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: This should really be a lit test.
+static void ErrorReportCallbackOneToZ(const char *report) {
+ int report_len = strlen(report);
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ ASSERT_EQ(report_len, write(2, report, report_len));
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ _exit(1);
+}
+
+TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
+ __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
+ EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
+ ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
+ __asan_set_error_report_callback(NULL);
+}
+#endif
+
+TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
+ std::vector<char *> pointers;
+ std::vector<size_t> sizes;
+ const size_t kNumMallocs = 1 << 9;
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ size_t size = i * 100 + 1;
+ pointers.push_back((char*)malloc(size));
+ sizes.push_back(size);
+ }
+ for (size_t i = 0; i < 4000000; i++) {
+ EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
+ EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
+ size_t idx = i % kNumMallocs;
+ EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
+ EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
+ }
+ for (size_t i = 0, n = pointers.size(); i < n; i++)
+ free(pointers[i]);
+}
+
diff --git a/compiler-rt/lib/asan/tests/asan_mac_test.cc b/compiler-rt/lib/asan/tests/asan_mac_test.cc
new file mode 100644
index 0000000..dfa6d75
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_mac_test.cc
@@ -0,0 +1,236 @@
+//===-- asan_test_mac.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+#include "asan_mac_test.h"
+
+#include <malloc/malloc.h>
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#include <CoreFoundation/CFString.h>
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorDefaultDoubleFree(NULL),
+ "attempting double-free");
+}
+
+void CFAllocator_DoubleFreeOnPthread() {
+ pthread_t child;
+ PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
+ PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
+}
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
+ EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
+}
+
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+ GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+ return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+ char *p = (char*)GLOB;
+ p[100] = 'A'; // ASan should report an error here.
+ CFAllocatorDeallocate(NULL, GLOB);
+ return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+ pthread_t th1, th2;
+ PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+ PTHREAD_JOIN(th1, NULL);
+ PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+ PTHREAD_JOIN(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+ EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+ "heap-buffer-overflow");
+}
+
+} // namespace
+
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept the non-default CFAllocators?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorSystemDefaultDoubleFree(),
+ "attempting double-free");
+}
+
+// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
+TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+// For libdispatch tests below we check that ASan got to the shadow byte
+// legend, i.e. managed to print the thread stacks (this almost certainly
+// means that the libdispatch task creation has been intercepted correctly).
+TEST(AddressSanitizerMac, GCDDispatchAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
+}
+
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAfter) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceEvent) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceCancel) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDGroupAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+ const int kNumPointers = 100;
+ int i;
+ void *pointers[kNumPointers];
+ for (i = 0; i < kNumPointers; i++) {
+ pointers[i] = malloc(i + 1);
+ }
+ for (i = 0; i < kNumPointers; i++) {
+ free(pointers[i]);
+ }
+
+ return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+ pid_t result = fork();
+ if (result == -1) {
+ perror("fork");
+ }
+ assert(result != -1);
+ if (result == 0) {
+ // Call malloc in the child process to make sure we won't deadlock.
+ void *ptr = malloc(42);
+ free(ptr);
+ exit(0);
+ } else {
+ // Return in the parent process.
+ return NULL;
+ }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+ // Incorrect implementation of force_lock and force_unlock in our malloc zone
+ // will cause forked processes to deadlock.
+ // TODO(glider): need to detect that none of the child processes deadlocked.
+ const int kNumWorkers = 5, kNumIterations = 100;
+ int i, iter;
+ for (iter = 0; iter < kNumIterations; iter++) {
+ pthread_t workers[kNumWorkers], forker;
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+ }
+ PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_JOIN(workers[i], 0);
+ }
+ PTHREAD_JOIN(forker, 0);
+ }
+}
+
+void *TSDAllocWorker(void *test_key) {
+ if (test_key) {
+ void *mem = malloc(10);
+ pthread_setspecific(*(pthread_key_t*)test_key, mem);
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, CallFreeOnWorkqueue);
+ PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+
+// Test that CFStringCreateCopy does not copy constant strings.
+TEST(AddressSanitizerMac, CFStringCreateCopy) {
+ CFStringRef str = CFSTR("Hello world!\n");
+ CFStringRef str2 = CFStringCreateCopy(0, str);
+ EXPECT_EQ(str, str2);
+}
+
+TEST(AddressSanitizerMac, NSObjectOOB) {
+ // Make sure that our allocators are used for NSObjects.
+ EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
+}
+
+// Make sure that correct pointer is passed to free() when deallocating a
+// NSURL object.
+// See https://github.com/google/sanitizers/issues/70.
+TEST(AddressSanitizerMac, NSURLDeallocation) {
+ TestNSURLDeallocation();
+}
+
+// See https://github.com/google/sanitizers/issues/109.
+TEST(AddressSanitizerMac, Mstats) {
+ malloc_statistics_t stats1, stats2;
+ malloc_zone_statistics(/*all zones*/NULL, &stats1);
+ const size_t kMallocSize = 100000;
+ void *alloc = Ident(malloc(kMallocSize));
+ malloc_zone_statistics(/*all zones*/NULL, &stats2);
+ EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
+ EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
+ free(alloc);
+ // Even the default OSX allocator may not change the stats after free().
+}
+
diff --git a/compiler-rt/lib/asan/tests/asan_mac_test.h b/compiler-rt/lib/asan/tests/asan_mac_test.h
new file mode 100644
index 0000000..441547a
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_mac_test.h
@@ -0,0 +1,19 @@
+extern "C" {
+ void *CFAllocatorDefaultDoubleFree(void *unused);
+ void CFAllocatorSystemDefaultDoubleFree();
+ void CFAllocatorMallocDoubleFree();
+ void CFAllocatorMallocZoneDoubleFree();
+ void CallFreeOnWorkqueue(void *mem);
+ void TestGCDDispatchAsync();
+ void TestGCDDispatchSync();
+ void TestGCDReuseWqthreadsAsync();
+ void TestGCDReuseWqthreadsSync();
+ void TestGCDDispatchAfter();
+ void TestGCDInTSDDestructor();
+ void TestGCDSourceEvent();
+ void TestGCDSourceCancel();
+ void TestGCDGroupAsync();
+ void TestOOBNSObjects();
+ void TestNSURLDeallocation();
+ void TestPassCFMemoryToAnotherThread();
+}
diff --git a/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm b/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
new file mode 100644
index 0000000..a7e4b9d
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
@@ -0,0 +1,240 @@
+// Mac OS X 10.6 or higher only.
+#include <dispatch/dispatch.h>
+#include <pthread.h> // for pthread_yield_np()
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#import <CoreFoundation/CFBase.h>
+#import <Foundation/NSObject.h>
+#import <Foundation/NSURL.h>
+
+// This is a (void*)(void*) function so it can be passed to pthread_create.
+void *CFAllocatorDefaultDoubleFree(void *unused) {
+ void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+ CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+ return 0;
+}
+
+void CFAllocatorSystemDefaultDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+ CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+}
+
+void CFAllocatorMallocDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+ CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+}
+
+void CFAllocatorMallocZoneDoubleFree() {
+ void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
+ CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+ CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+}
+
+__attribute__((noinline))
+void access_memory(char *a) {
+ *a = 0;
+}
+
+// Test the +load instrumentation.
+// Because the +load methods are invoked before anything else is initialized,
+// it makes little sense to wrap the code below into a gTest test case.
+// If AddressSanitizer doesn't instrument the +load method below correctly,
+// everything will just crash.
+
+char kStartupStr[] =
+ "If your test didn't crash, AddressSanitizer is instrumenting "
+ "the +load methods correctly.";
+
+@interface LoadSomething : NSObject {
+}
+@end
+
+@implementation LoadSomething
+
++(void) load {
+ for (size_t i = 0; i < strlen(kStartupStr); i++) {
+ access_memory(&kStartupStr[i]); // make sure no optimizations occur.
+ }
+ // Don't print anything here not to interfere with the death tests.
+}
+
+@end
+
+void worker_do_alloc(int size) {
+ char * volatile mem = (char * volatile)malloc(size);
+ mem[0] = 0; // Ok
+ free(mem);
+}
+
+void worker_do_crash(int size) {
+ char * volatile mem = (char * volatile)malloc(size);
+ access_memory(&mem[size]); // BOOM
+ free(mem);
+}
+
+// Used by the GCD tests to avoid a race between the worker thread reporting a
+// memory error and the main thread which may exit with exit code 0 before
+// that.
+void wait_forever() {
+ volatile bool infinite = true;
+ while (infinite) pthread_yield_np();
+}
+
+// Tests for the Grand Central Dispatch. See
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// for the reference.
+void TestGCDDispatchAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block = ^{ worker_do_crash(1024); };
+ // dispatch_async() runs the task on a worker thread that does not go through
+ // pthread_create(). We need to verify that AddressSanitizer notices that the
+ // thread has started.
+ dispatch_async(queue, block);
+ wait_forever();
+}
+
+void TestGCDDispatchSync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
+ dispatch_block_t block = ^{ worker_do_crash(1024); };
+ // dispatch_sync() runs the task on a worker thread that does not go through
+ // pthread_create(). We need to verify that AddressSanitizer notices that the
+ // thread has started.
+ dispatch_sync(queue, block);
+ wait_forever();
+}
+
+// libdispatch spawns a rather small number of threads and reuses them. We need
+// to make sure AddressSanitizer handles the reusing correctly.
+void TestGCDReuseWqthreadsAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ for (int i = 0; i < 100; i++) {
+ dispatch_async(queue, block_alloc);
+ }
+ dispatch_async(queue, block_crash);
+ wait_forever();
+}
+
+// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
+void TestGCDReuseWqthreadsSync() {
+ dispatch_queue_t queue[4];
+ queue[0] = dispatch_get_global_queue(2, 0);
+ queue[1] = dispatch_get_global_queue(0, 0);
+ queue[2] = dispatch_get_global_queue(-2, 0);
+ queue[3] = dispatch_queue_create("my_queue", NULL);
+ dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ for (int i = 0; i < 1000; i++) {
+ dispatch_sync(queue[i % 4], block_alloc);
+ }
+ dispatch_sync(queue[3], block_crash);
+ wait_forever();
+}
+
+void TestGCDDispatchAfter() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+ // Schedule the event one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+ dispatch_after(milestone, queue, block_crash);
+ wait_forever();
+}
+
+void worker_do_deallocate(void *ptr) {
+ free(ptr);
+}
+
+void CallFreeOnWorkqueue(void *tsd) {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
+ dispatch_async(queue, block_dealloc);
+ // Do not wait for the worker to free the memory -- nobody is going to touch
+ // it.
+}
+
+void TestGCDSourceEvent() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_source_t timer =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+ // Schedule the timer one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+ dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+ char * volatile mem = (char * volatile)malloc(10);
+ dispatch_source_set_event_handler(timer, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_resume(timer);
+ wait_forever();
+}
+
+void TestGCDSourceCancel() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_source_t timer =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+ // Schedule the timer one second from the current time.
+ dispatch_time_t milestone =
+ dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+ dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+ char * volatile mem = (char * volatile)malloc(10);
+ // Both dispatch_source_set_cancel_handler() and
+ // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
+ // It's tricky to test dispatch_source_set_cancel_handler() separately,
+ // so we test both here.
+ dispatch_source_set_event_handler(timer, ^{
+ dispatch_source_cancel(timer);
+ });
+ dispatch_source_set_cancel_handler(timer, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_resume(timer);
+ wait_forever();
+}
+
+void TestGCDGroupAsync() {
+ dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+ dispatch_group_t group = dispatch_group_create();
+ char * volatile mem = (char * volatile)malloc(10);
+ dispatch_group_async(group, queue, ^{
+ access_memory(&mem[10]);
+ });
+ dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+ wait_forever();
+}
+
+@interface FixedArray : NSObject {
+ int items[10];
+}
+@end
+
+@implementation FixedArray
+-(int) access: (int)index {
+ return items[index];
+}
+@end
+
+void TestOOBNSObjects() {
+ id anObject = [FixedArray new];
+ [anObject access:1];
+ [anObject access:11];
+ [anObject release];
+}
+
+void TestNSURLDeallocation() {
+ NSURL *base =
+ [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
+ volatile NSURL *u =
+ [[NSURL alloc] initWithString:@"Saved Application State"
+ relativeToURL:base];
+ [u release];
+}
diff --git a/compiler-rt/lib/asan/tests/asan_mem_test.cc b/compiler-rt/lib/asan/tests/asan_mem_test.cc
new file mode 100644
index 0000000..4a941fa
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_mem_test.cc
@@ -0,0 +1,241 @@
+//===-- asan_mem_test.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+template<typename T>
+void MemSetOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *array = Ident((T*)malloc(size));
+ int element = Ident(42);
+ int zero = Ident(0);
+ void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
+ // memset interval inside array
+ MEMSET(array, element, size);
+ MEMSET(array, element, size - 1);
+ MEMSET(array + length - 1, element, sizeof(T));
+ MEMSET(array, element, 1);
+
+ // memset 0 bytes
+ MEMSET(array - 10, element, zero);
+ MEMSET(array - 1, element, zero);
+ MEMSET(array, element, zero);
+ MEMSET(array + length, 0, zero);
+ MEMSET(array + length + 1, 0, zero);
+
+ // try to memset bytes to the right of array
+ EXPECT_DEATH(MEMSET(array, 0, size + 1),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
+ RightOOBWriteMessage(0));
+ // whole interval is to the right
+ EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
+ RightOOBWriteMessage(sizeof(T)));
+
+ // try to memset bytes to the left of array
+ EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
+ LeftOOBWriteMessage(5));
+ if (length >= 100) {
+ // Large OOB, we find it only if the redzone is large enough.
+ EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+ LeftOOBWriteMessage(5 * sizeof(T)));
+ }
+ // whole interval is to the left
+ EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+
+ // try to memset bytes both to the left & to the right
+ EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
+ LeftOOBWriteMessage(2));
+
+ free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+ MemSetOOBTestTemplate<char>(100);
+ MemSetOOBTestTemplate<int>(5);
+ MemSetOOBTestTemplate<double>(256);
+ // We can test arrays of structres/classes here, but what for?
+}
+
+// Try to allocate two arrays of 'size' bytes that are near each other.
+// Strictly speaking we are not guaranteed to find such two pointers,
+// but given the structure of asan's allocator we will.
+static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
+ vector<uintptr_t> v;
+ bool res = false;
+ for (size_t i = 0; i < 1000U && !res; i++) {
+ v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
+ if (i == 0) continue;
+ sort(v.begin(), v.end());
+ for (size_t j = 1; j < v.size(); j++) {
+ assert(v[j] > v[j-1]);
+ if ((size_t)(v[j] - v[j-1]) < size * 2) {
+ *x2 = reinterpret_cast<char*>(v[j]);
+ *x1 = reinterpret_cast<char*>(v[j-1]);
+ res = true;
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < v.size(); i++) {
+ char *p = reinterpret_cast<char *>(v[i]);
+ if (res && p == *x1) continue;
+ if (res && p == *x2) continue;
+ delete [] p;
+ }
+ return res;
+}
+
+TEST(AddressSanitizer, LargeOOBInMemset) {
+ for (size_t size = 200; size < 100000; size += size / 2) {
+ char *x1, *x2;
+ if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
+ continue;
+ // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
+ // Do a memset on x1 with huge out-of-bound access that will end up in x2.
+ EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
+ "is located 0 bytes to the right");
+ delete [] x1;
+ delete [] x2;
+ return;
+ }
+ assert(0 && "Did not find two adjacent malloc-ed pointers");
+}
+
+// Same test for memcpy and memmove functions
+template <typename T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *src = Ident((T*)malloc(size));
+ T *dest = Ident((T*)malloc(size));
+ int zero = Ident(0);
+
+ // valid transfer of bytes between arrays
+ M::transfer(dest, src, size);
+ M::transfer(dest + 1, src, size - sizeof(T));
+ M::transfer(dest, src + length - 1, sizeof(T));
+ M::transfer(dest, src, 1);
+
+ // transfer zero bytes
+ M::transfer(dest - 1, src, 0);
+ M::transfer(dest + length, src, zero);
+ M::transfer(dest, src - 1, zero);
+ M::transfer(dest, src, zero);
+
+ // try to change mem to the right of dest
+ EXPECT_DEATH(M::transfer(dest + 1, src, size),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+ RightOOBWriteMessage(0));
+
+ // try to change mem to the left of dest
+ EXPECT_DEATH(M::transfer(dest - 2, src, size),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+ EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+ LeftOOBWriteMessage(3));
+
+ // try to access mem to the right of src
+ EXPECT_DEATH(M::transfer(dest, src + 2, size),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+ RightOOBReadMessage(0));
+
+ // try to access mem to the left of src
+ EXPECT_DEATH(M::transfer(dest, src - 1, size),
+ LeftOOBReadMessage(sizeof(T)));
+ EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+ LeftOOBReadMessage(6));
+
+ // Generally we don't need to test cases where both accessing src and writing
+ // to dest address to poisoned memory.
+
+ T *big_src = Ident((T*)malloc(size * 2));
+ T *big_dest = Ident((T*)malloc(size * 2));
+ // try to change mem to both sides of dest
+ EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+ LeftOOBWriteMessage(sizeof(T)));
+ // try to access mem to both sides of src
+ EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+ LeftOOBReadMessage(2 * sizeof(T)));
+
+ free(src);
+ free(dest);
+ free(big_src);
+ free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memcpy)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemCpyOOBTest) {
+ MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memmove)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemMoveOOBTest) {
+ MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+
+TEST(AddressSanitizer, MemCmpOOBTest) {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ // Normal memcmp calls.
+ Ident(memcmp(s1, s2, size));
+ Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
+ Ident(memcmp(s1 - 1, s2 - 1, 0));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ // Zero bytes are not terminators and don't prevent from OOB.
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ // Even if the buffers differ in the first byte, we still assume that
+ // memcmp may access the whole buffer and thus reporting the overflow here:
+ s1[0] = 1;
+ s2[0] = 123;
+ EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ free(s1);
+ free(s2);
+}
+
+
+
diff --git a/compiler-rt/lib/asan/tests/asan_noinst_test.cc b/compiler-rt/lib/asan/tests/asan_noinst_test.cc
new file mode 100644
index 0000000..5f5354f
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_noinst_test.cc
@@ -0,0 +1,263 @@
+//===-- asan_noinst_test.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for memset()
+#include <algorithm>
+#include <vector>
+#include <limits>
+
+// ATTENTION!
+// Please don't call intercepted functions (including malloc() and friends)
+// in this test. The static runtime library is linked explicitly (without
+// -fsanitize=address), thus the interceptors do not work correctly on OS X.
+
+// Make sure __asan_init is called before any test case is run.
+struct AsanInitCaller {
+ AsanInitCaller() {
+ DisableReexec();
+ __asan_init();
+ }
+};
+static AsanInitCaller asan_init_caller;
+
+TEST(AddressSanitizer, InternalSimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+static void MallocStress(size_t n) {
+ u32 seed = my_rand();
+ BufferedStackTrace stack1;
+ stack1.trace_buffer[0] = 0xa123;
+ stack1.trace_buffer[1] = 0xa456;
+ stack1.size = 2;
+
+ BufferedStackTrace stack2;
+ stack2.trace_buffer[0] = 0xb123;
+ stack2.trace_buffer[1] = 0xb456;
+ stack2.size = 2;
+
+ BufferedStackTrace stack3;
+ stack3.trace_buffer[0] = 0xc123;
+ stack3.trace_buffer[1] = 0xc456;
+ stack3.size = 2;
+
+ std::vector<void *> vec;
+ for (size_t i = 0; i < n; i++) {
+ if ((i % 3) == 0) {
+ if (vec.empty()) continue;
+ size_t idx = my_rand_r(&seed) % vec.size();
+ void *ptr = vec[idx];
+ vec[idx] = vec.back();
+ vec.pop_back();
+ __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
+ } else {
+ size_t size = my_rand_r(&seed) % 1000 + 1;
+ switch ((my_rand_r(&seed) % 128)) {
+ case 0: size += 1024; break;
+ case 1: size += 2048; break;
+ case 2: size += 4096; break;
+ }
+ size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
+ char *ptr = (char*)__asan::asan_memalign(alignment, size,
+ &stack2, __asan::FROM_MALLOC);
+ EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
+ vec.push_back(ptr);
+ ptr[0] = 0;
+ ptr[size-1] = 0;
+ ptr[size/2] = 0;
+ }
+ }
+ for (size_t i = 0; i < vec.size(); i++)
+ __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
+}
+
+
+TEST(AddressSanitizer, NoInstMallocTest) {
+ MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
+}
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+ const int kNumThreads = 4;
+ const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
+ (void*)kNumIterations);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+static void PrintShadow(const char *tag, uptr ptr, size_t size) {
+ fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
+ uptr prev_shadow = 0;
+ for (sptr i = -32; i < (sptr)size + 32; i++) {
+ uptr shadow = __asan::MemToShadow(ptr + i);
+ if (i == 0 || i == (sptr)size)
+ fprintf(stderr, ".");
+ if (shadow != prev_shadow) {
+ prev_shadow = shadow;
+ fprintf(stderr, "%02x", (int)*(u8*)shadow);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
+ for (size_t size = 1; size <= 513; size++) {
+ char *ptr = new char[size];
+ PrintShadow("m", (uptr)ptr, size);
+ delete [] ptr;
+ PrintShadow("f", (uptr)ptr, size);
+ }
+}
+
+TEST(AddressSanitizer, QuarantineTest) {
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ const int size = 1024;
+ void *p = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ size_t i;
+ size_t max_i = 1 << 30;
+ for (i = 0; i < max_i; i++) {
+ void *p1 = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
+ if (p1 == p) break;
+ }
+ EXPECT_GE(i, 10000U);
+ EXPECT_LT(i, max_i);
+}
+
+void *ThreadedQuarantineTestWorker(void *unused) {
+ (void)unused;
+ u32 seed = my_rand();
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (size_t i = 0; i < 1000; i++) {
+ void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ }
+ return NULL;
+}
+
+// Check that the thread local allocators are flushed when threads are
+// destroyed.
+TEST(AddressSanitizer, ThreadedQuarantineTest) {
+ const int n_threads = 3000;
+ size_t mmaped1 = __sanitizer_get_heap_size();
+ for (int i = 0; i < n_threads; i++) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
+ PTHREAD_JOIN(t, 0);
+ size_t mmaped2 = __sanitizer_get_heap_size();
+ EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
+ }
+}
+
+void *ThreadedOneSizeMallocStress(void *unused) {
+ (void)unused;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+ const size_t kNumMallocs = 1000;
+ for (int iter = 0; iter < 1000; iter++) {
+ void *p[kNumMallocs];
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ p[i] = __asan::asan_malloc(32, &stack);
+ }
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
+ }
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
+ const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
+ using __asan::kHighMemEnd;
+ // Check that __asan_region_is_poisoned works for shadow regions.
+ uptr ptr = kLowShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kShadowGapBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kHighShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+}
+
+// Test __asan_load1 & friends.
+TEST(AddressSanitizer, LoadStoreCallbacks) {
+ typedef void (*CB)(uptr p);
+ CB cb[2][5] = {
+ {
+ __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
+ }, {
+ __asan_store1, __asan_store2, __asan_store4, __asan_store8,
+ __asan_store16,
+ }
+ };
+
+ uptr buggy_ptr;
+
+ __asan_test_only_reported_buggy_pointer = &buggy_ptr;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (uptr len = 16; len <= 32; len++) {
+ char *ptr = (char*) __asan::asan_malloc(len, &stack);
+ uptr p = reinterpret_cast<uptr>(ptr);
+ for (uptr is_write = 0; is_write <= 1; is_write++) {
+ for (uptr size_log = 0; size_log <= 4; size_log++) {
+ uptr size = 1 << size_log;
+ CB call = cb[is_write][size_log];
+ // Iterate only size-aligned offsets.
+ for (uptr offset = 0; offset <= len; offset += size) {
+ buggy_ptr = 0;
+ call(p + offset);
+ if (offset + size <= len)
+ EXPECT_EQ(buggy_ptr, 0U);
+ else
+ EXPECT_EQ(buggy_ptr, p + offset);
+ }
+ }
+ }
+ __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
+ }
+ __asan_test_only_reported_buggy_pointer = 0;
+}
diff --git a/compiler-rt/lib/asan/tests/asan_oob_test.cc b/compiler-rt/lib/asan/tests/asan_oob_test.cc
new file mode 100644
index 0000000..0c6bea2
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_oob_test.cc
@@ -0,0 +1,128 @@
+//===-- asan_oob_test.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
+ EXPECT_EQ(0U, ((uintptr_t)p % size));
+ if (size == 1) asan_write((uint8_t*)p);
+ else if (size == 2) asan_write((uint16_t*)p);
+ else if (size == 4) asan_write((uint32_t*)p);
+ else if (size == 8) asan_write((uint64_t*)p);
+}
+
+template<typename T>
+NOINLINE void oob_test(int size, int off) {
+ char *p = (char*)malloc_aaa(size);
+ // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
+ // sizeof(T), p, p + size, off);
+ asan_write((T*)(p + off));
+ free_aaa(p);
+}
+
+template<typename T>
+void OOBTest() {
+ char expected_str[100];
+ for (int size = sizeof(T); size < 20; size += 5) {
+ for (int i = -5; i < 0; i++) {
+ const char *str =
+ "is located.*%d byte.*to the left";
+ sprintf(expected_str, str, abs(i));
+ EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+ }
+
+ for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
+ oob_test<T>(size, i);
+
+ for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
+ const char *str =
+ "is located.*%d byte.*to the right";
+ int off = i >= size ? (i - size) : 0;
+ // we don't catch unaligned partially OOB accesses.
+ if (i % sizeof(T)) continue;
+ sprintf(expected_str, str, off);
+ EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+ }
+ }
+
+ EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
+ "is located.*1 byte.*to the left");
+ EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
+ "is located.*0 byte.*to the right");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+// AddressSanitizer.OOB_char (125503 ms)
+// AddressSanitizer.OOB_int (126890 ms)
+// AddressSanitizer.OOBRightTest (315605 ms)
+// AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+ OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+ OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
+ for (size_t access_size = 1; access_size <= max_access_size;
+ access_size *= 2) {
+ for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+ for (size_t offset = 0; offset <= 8; offset += access_size) {
+ void *p = malloc(alloc_size);
+ // allocated: [p, p + alloc_size)
+ // accessed: [p + offset, p + offset + access_size)
+ uint8_t *addr = (uint8_t*)p + offset;
+ if (offset + access_size <= alloc_size) {
+ asan_write_sized_aligned(addr, access_size);
+ } else {
+ int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+ const char *str =
+ "is located.%d *byte.*to the right";
+ char expected_str[100];
+ sprintf(expected_str, str, outside_bytes);
+ EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+ expected_str);
+ }
+ free(p);
+ }
+ }
+ }
+}
+
+TEST(AddressSanitizer, LargeOOBRightTest) {
+ size_t large_power_of_two = 1 << 19;
+ for (size_t i = 16; i <= 256; i *= 2) {
+ size_t size = large_power_of_two - i;
+ char *p = Ident(new char[size]);
+ EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
+ delete [] p;
+ }
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+ oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+ oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+ oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+ oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
diff --git a/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc b/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
new file mode 100644
index 0000000..23240e7
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
@@ -0,0 +1,32 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+const int N = 1000;
+void *x[N];
+
+void *Thread1(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+void *Thread2(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+int main() {
+ for (int i = 0; i < N; i++)
+ x[i] = malloc(128);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+}
diff --git a/compiler-rt/lib/asan/tests/asan_str_test.cc b/compiler-rt/lib/asan/tests/asan_str_test.cc
new file mode 100644
index 0000000..89b0d3d
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_str_test.cc
@@ -0,0 +1,573 @@
+//=-- asan_str_test.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__APPLE__)
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#endif
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
+ // Normal strlen calls
+ EXPECT_EQ(strlen(str), length);
+ if (length > 0) {
+ EXPECT_EQ(length - 1, strlen(str + 1));
+ EXPECT_EQ(0U, strlen(str + length));
+ }
+ // Arg of strlen is not malloced, OOB access
+ if (!is_global) {
+ // We don't insert RedZones to the left of global variables
+ EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5));
+ }
+ EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBReadMessage(0));
+ // Overwrite terminator
+ str[length] = 'a';
+ // String is not zero-terminated, strlen will lead to OOB access
+ EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0));
+ // Restore terminator
+ str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+ // Check heap-allocated string
+ size_t length = Ident(10);
+ char *heap_string = Ident((char*)malloc(length + 1));
+ char stack_string[10 + 1];
+ break_optimization(&stack_string);
+ for (size_t i = 0; i < length; i++) {
+ heap_string[i] = 'a';
+ stack_string[i] = 'b';
+ }
+ heap_string[length] = 0;
+ stack_string[length] = 0;
+ StrLenOOBTestTemplate(heap_string, length, false);
+ // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
+ // make test for stack_string work. Or move it to output tests.
+ // StrLenOOBTestTemplate(stack_string, length, false);
+ StrLenOOBTestTemplate(global_string, global_string_length, true);
+ free(heap_string);
+}
+
+TEST(AddressSanitizer, WcsLenTest) {
+ EXPECT_EQ(0U, wcslen(Ident(L"")));
+ size_t hello_len = 13;
+ size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
+ EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
+ wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
+ memcpy(heap_string, L"Hello, World!", hello_size);
+ EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
+ EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
+ free(heap_string);
+}
+
+#if SANITIZER_TEST_HAS_STRNLEN
+TEST(AddressSanitizer, StrNLenOOBTest) {
+ size_t size = Ident(123);
+ char *str = MallocAndMemsetString(size);
+ // Normal strnlen calls.
+ Ident(strnlen(str - 1, 0));
+ Ident(strnlen(str, size));
+ Ident(strnlen(str + size - 1, 1));
+ str[size - 1] = '\0';
+ Ident(strnlen(str, 2 * size));
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
+ free(str);
+}
+#endif // SANITIZER_TEST_HAS_STRNLEN
+
+TEST(AddressSanitizer, StrDupOOBTest) {
+ size_t size = Ident(42);
+ char *str = MallocAndMemsetString(size);
+ char *new_str;
+ // Normal strdup calls.
+ str[size - 1] = '\0';
+ new_str = strdup(str);
+ free(new_str);
+ new_str = strdup(str + size - 1);
+ free(new_str);
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
+ free(str);
+}
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+ size_t to_size = Ident(30);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ char *from = Ident((char*)malloc(from_size));
+ // Normal strcpy calls.
+ strcpy(from, "hello");
+ strcpy(to, from);
+ strcpy(to + to_size - from_size, from);
+ // Length of "from" is too small.
+ EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
+ // "to" or "from" points to not allocated memory.
+ EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
+ // Overwrite the terminating '\0' character and hit unallocated memory.
+ from[from_size - 1] = '!';
+ EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+ size_t to_size = Ident(20);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ // From is a zero-terminated string "hello\0" of length 6
+ char *from = Ident((char*)malloc(from_size));
+ strcpy(from, "hello");
+ // copy 0 bytes
+ strncpy(to, from, 0);
+ strncpy(to - 1, from - 1, 0);
+ // normal strncpy calls
+ strncpy(to, from, from_size);
+ strncpy(to, from, to_size);
+ strncpy(to, from + from_size - 1, to_size);
+ strncpy(to + to_size - 1, from, 1);
+ // One of {to, from} points to not allocated memory
+ EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+ LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+ RightOOBWriteMessage(0));
+ // Length of "to" is too small
+ EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+ RightOOBWriteMessage(0));
+ // Overwrite terminator in from
+ from[from_size - 1] = '!';
+ // normal strncpy call
+ strncpy(to, from, from_size);
+ // Length of "from" is too small
+ EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+ RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+// Users may have different definitions of "strchr" and "index", so provide
+// function pointer typedefs and overload RunStrChrTest implementation.
+// We can't use macro for RunStrChrTest body here, as this macro would
+// confuse EXPECT_DEATH gtest macro.
+typedef char*(*PointerToStrChr1)(const char*, int);
+typedef char*(*PointerToStrChr2)(char*, int);
+
+UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+ size_t size = Ident(100);
+ char *str = MallocAndMemsetString(size);
+ str[10] = 'q';
+ str[11] = '\0';
+ EXPECT_EQ(str, StrChr(str, 'z'));
+ EXPECT_EQ(str + 10, StrChr(str, 'q'));
+ EXPECT_EQ(NULL, StrChr(str, 'a'));
+ // StrChr argument points to not allocated memory.
+ EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
+ // Overwrite the terminator and hit not allocated memory.
+ str[11] = 'z';
+ EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
+ free(str);
+}
+UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+ size_t size = Ident(100);
+ char *str = MallocAndMemsetString(size);
+ str[10] = 'q';
+ str[11] = '\0';
+ EXPECT_EQ(str, StrChr(str, 'z'));
+ EXPECT_EQ(str + 10, StrChr(str, 'q'));
+ EXPECT_EQ(NULL, StrChr(str, 'a'));
+ // StrChr argument points to not allocated memory.
+ EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
+ // Overwrite the terminator and hit not allocated memory.
+ str[11] = 'z';
+ EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
+ free(str);
+}
+
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+ RunStrChrTest(&strchr);
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+ RunStrChrTest(&index);
+#endif
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+ // strcmp
+ EXPECT_EQ(0, strcmp("", ""));
+ EXPECT_EQ(0, strcmp("abcd", "abcd"));
+ EXPECT_GT(0, strcmp("ab", "ac"));
+ EXPECT_GT(0, strcmp("abc", "abcd"));
+ EXPECT_LT(0, strcmp("acc", "abc"));
+ EXPECT_LT(0, strcmp("abcd", "abc"));
+
+ // strncmp
+ EXPECT_EQ(0, strncmp("a", "b", 0));
+ EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+ EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+ EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
+ EXPECT_GT(0, strncmp("a", "b", 5));
+ EXPECT_GT(0, strncmp("bc", "bcde", 4));
+ EXPECT_LT(0, strncmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncmp("baa", "aaa", 1));
+ EXPECT_LT(0, strncmp("zyx", "", 2));
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+ // strcasecmp
+ EXPECT_EQ(0, strcasecmp("", ""));
+ EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
+ EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
+ EXPECT_GT(0, strcasecmp("aB", "Ac"));
+ EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
+ EXPECT_LT(0, strcasecmp("acc", "abc"));
+ EXPECT_LT(0, strcasecmp("ABCd", "abc"));
+
+ // strncasecmp
+ EXPECT_EQ(0, strncasecmp("a", "b", 0));
+ EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
+ EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
+ EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
+ EXPECT_GT(0, strncasecmp("a", "B", 5));
+ EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
+ EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
+ EXPECT_LT(0, strncasecmp("zyx", "", 2));
+#endif
+
+ // memcmp
+ EXPECT_EQ(0, memcmp("a", "b", 0));
+ EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
+ EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
+ EXPECT_GT(0, memcmp("abb\0", "abba", 4));
+ EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
+ EXPECT_LT(0, memcmp("zza", "zyx", 3));
+}
+
+typedef int(*PointerToStrCmp)(const char*, const char*);
+void RunStrCmpTest(PointerToStrCmp StrCmp) {
+ size_t size = Ident(100);
+ int fill = 'o';
+ char *s1 = MallocAndMemsetString(size, fill);
+ char *s2 = MallocAndMemsetString(size, fill);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrCmp calls
+ Ident(StrCmp(s1, s2));
+ Ident(StrCmp(s1, s2 + size - 1));
+ Ident(StrCmp(s1 + size - 1, s2 + size - 1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ s1[size - 1] = fill;
+ EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+ RunStrCmpTest(&strcmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrCaseCmpOOBTest) {
+ RunStrCmpTest(&strcasecmp);
+}
+#endif
+
+typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
+void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrNCmp calls
+ Ident(StrNCmp(s1, s2, size + 2));
+ s1[size - 1] = 'z';
+ s2[size - 1] = 'x';
+ Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
+ s2[size - 1] = 'z';
+ Ident(StrNCmp(s1 - 1, s2 - 1, 0));
+ Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+ RunStrNCmpTest(&strncmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
+ RunStrNCmpTest(&strncasecmp);
+}
+#endif
+
+TEST(AddressSanitizer, StrCatOOBTest) {
+ // strcat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ from[from_size - 1] = '\0';
+ // Normal strcat calls.
+ strcat(to, from);
+ strcat(to, from);
+ strcat(to + from_size, from + from_size - 2);
+ // Passing an invalid pointer is an error even when concatenating an empty
+ // string.
+ EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
+
+ // "from" is not zero-terminated.
+ from[from_size - 1] = 'z';
+ EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
+ from[from_size - 1] = '\0';
+ // "to" is too short to fit "from".
+ memset(to, 'z', to_size);
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
+ // length of "to" is just enough.
+ strcat(to, from + 1);
+
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCatOOBTest) {
+ // strncat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ // Normal strncat calls.
+ strncat(to, from, 0);
+ strncat(to, from, from_size);
+ from[from_size - 1] = '\0';
+ strncat(to, from, 2 * from_size);
+ // Catenating empty string with an invalid string is still an error.
+ EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
+ strncat(to, from + from_size - 1, 10);
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
+
+ memset(from, 'z', from_size);
+ memset(to, 'z', to_size);
+ to[0] = '\0';
+ // "from" is too short.
+ EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
+ // "to" is too short to fit "from".
+ to[0] = 'z';
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
+ // "to" is just enough.
+ strncat(to, from, from_size - 2);
+
+ free(to);
+ free(from);
+}
+
+static string OverlapErrorMessage(const string &func) {
+ return func + "-param-overlap";
+}
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+ size_t size = Ident(100);
+ char *str = Ident((char*)malloc(size));
+
+// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
+// memmove().
+#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
+ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+ // Check "memcpy". Use Ident() to avoid inlining.
+ memset(str, 'z', size);
+ Ident(memcpy)(str + 1, str + 11, 10);
+ Ident(memcpy)(str, str, 0);
+ EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
+ EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
+#endif
+
+ // We do not treat memcpy with to==from as a bug.
+ // See http://llvm.org/bugs/show_bug.cgi?id=11763.
+ // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
+ // OverlapErrorMessage("memcpy"));
+
+ // Check "strcpy".
+ memset(str, 'z', size);
+ str[9] = '\0';
+ strcpy(str + 10, str);
+ EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
+ EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
+ strcpy(str, str + 5);
+
+ // Check "strncpy".
+ memset(str, 'z', size);
+ strncpy(str, str + 10, 10);
+ EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
+ EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
+ str[10] = '\0';
+ strncpy(str + 11, str, 20);
+ EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
+
+ // Check "strcat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ str[20] = '\0';
+ strcat(str, str + 10);
+ EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
+ str[10] = '\0';
+ strcat(str + 11, str);
+ EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
+
+ // Check "strncat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ strncat(str, str + 10, 10); // from is empty
+ EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
+ str[10] = '\0';
+ str[20] = '\0';
+ strncat(str + 5, str, 5);
+ str[10] = '\0';
+ EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
+ EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
+
+ free(str);
+}
+
+typedef void(*PointerToCallAtoi)(const char*);
+
+void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
+ char *array = MallocAndMemsetString(10, '1');
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
+ EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
+ // Die if a buffer doesn't have terminating NULL.
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ // Make last symbol a terminating NULL
+ array[9] = '\0';
+ Atoi(array);
+ // Sometimes we need to detect overflow if no digits are found.
+ memset(array, ' ', 10);
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ array[9] = '-';
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+ Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+ Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+ Ident(atoll(nptr));
+}
+TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
+ RunAtoiOOBTest(&CallAtoi);
+ RunAtoiOOBTest(&CallAtol);
+ RunAtoiOOBTest(&CallAtoll);
+}
+#endif
+
+typedef void(*PointerToCallStrtol)(const char*, char**, int);
+
+void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
+ char *array = MallocAndMemsetString(3);
+ array[0] = '1';
+ array[1] = '2';
+ array[2] = '3';
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
+ EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
+ // Buffer overflow if there is no terminating null (depends on base).
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = 'z';
+ EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
+ // Add terminating zero to get rid of overflow.
+ array[2] = '\0';
+ Strtol(array, NULL, 36);
+ // Sometimes we need to detect overflow if no digits are found.
+ array[0] = array[1] = array[2] = ' ';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '+';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '-';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallStrtol(const char *nptr, char **endptr, int base) {
+ Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+ Ident(strtoll(nptr, endptr, base));
+}
+TEST(AddressSanitizer, StrtollOOBTest) {
+ RunStrtolOOBTest(&CallStrtoll);
+}
+TEST(AddressSanitizer, StrtolOOBTest) {
+ RunStrtolOOBTest(&CallStrtol);
+}
+#endif
+
+
diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc
new file mode 100644
index 0000000..71fb27a
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_test.cc
@@ -0,0 +1,1322 @@
+//===-- asan_test.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+NOINLINE void *malloc_fff(size_t size) {
+ void *res = malloc/**/(size); break_optimization(0); return res;}
+NOINLINE void *malloc_eee(size_t size) {
+ void *res = malloc_fff(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ddd(size_t size) {
+ void *res = malloc_eee(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ccc(size_t size) {
+ void *res = malloc_ddd(size); break_optimization(0); return res;}
+NOINLINE void *malloc_bbb(size_t size) {
+ void *res = malloc_ccc(size); break_optimization(0); return res;}
+NOINLINE void *malloc_aaa(size_t size) {
+ void *res = malloc_bbb(size); break_optimization(0); return res;}
+
+NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
+NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
+NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
+
+template<typename T>
+NOINLINE void uaf_test(int size, int off) {
+ void *p = malloc_aaa(size);
+ free_aaa(p);
+ for (int i = 1; i < 100; i++)
+ free_aaa(malloc_aaa(i));
+ fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+ (long)sizeof(T), p, off);
+ asan_write((T *)((char *)p + off));
+}
+
+TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
+#if defined(__has_feature) && __has_feature(address_sanitizer)
+ bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+ bool asan = 1;
+#else
+ bool asan = 0;
+#endif
+ EXPECT_EQ(true, asan);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+ int *a = (int*)malloc(100 * sizeof(int));
+ a[50] = 0;
+ free(a);
+
+ int *r = (int*)malloc(10);
+ r = (int*)realloc(r, 2000 * sizeof(int));
+ r[1000] = 0;
+ free(r);
+
+ int *b = new int[100];
+ b[50] = 0;
+ delete [] b;
+
+ int *c = new int;
+ *c = 0;
+ delete c;
+
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int *pm;
+ int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
+ EXPECT_EQ(0, pm_res);
+ free(pm);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+ int *ma = (int*)memalign(kPageSize, kPageSize);
+ EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
+ ma[123] = 0;
+ free(ma);
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+}
+
+TEST(AddressSanitizer, CallocTest) {
+ int *a = (int*)calloc(100, sizeof(int));
+ EXPECT_EQ(0, a[10]);
+ free(a);
+}
+
+TEST(AddressSanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+#if !defined(_WIN32)
+ // FIXME: OOM on Windows. We should just make this a lit test
+ // with quarantine size set to 1.
+ free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+#endif
+ }
+ }
+}
+
+// No valloc on Windows or Android.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+TEST(AddressSanitizer, VallocTest) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PVALLOC
+TEST(AddressSanitizer, PvallocTest) {
+ char *a = (char*)pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[kPageSize + 101] = 1; // we should not report an error here.
+ free(a);
+
+ a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[101] = 1; // we should not report an error here.
+ free(a);
+}
+#endif // SANITIZER_TEST_HAS_PVALLOC
+
+#if !defined(_WIN32)
+// FIXME: Use an equivalent of pthread_setspecific on Windows.
+void *TSDWorker(void *test_key) {
+ if (test_key) {
+ pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+ }
+ return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+ // Spawning a thread will check that the current thread id is not -1.
+ pthread_t th;
+ PTHREAD_CREATE(&th, NULL, TSDWorker, NULL);
+ PTHREAD_JOIN(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, TSDDestructor);
+ PTHREAD_CREATE(&th, NULL, TSDWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+#endif
+
+TEST(AddressSanitizer, UAF_char) {
+ const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
+ EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+TEST(AddressSanitizer, UAF_long_double) {
+ if (sizeof(long double) == sizeof(double)) return;
+ long double *p = Ident(new long double[10]);
+ EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
+ EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
+ delete [] Ident(p);
+}
+
+#if !defined(_WIN32)
+struct Packed5 {
+ int x;
+ char c;
+} __attribute__((packed));
+#else
+# pragma pack(push, 1)
+struct Packed5 {
+ int x;
+ char c;
+};
+# pragma pack(pop)
+#endif
+
+TEST(AddressSanitizer, UAF_Packed5) {
+ static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
+ Packed5 *p = Ident(new Packed5[2]);
+ EXPECT_DEATH(p[0] = p[3], "READ of size 5");
+ EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
+ delete [] Ident(p);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+ int *x = Ident(new int);
+ delete Ident(x);
+ *x = 0;
+}
+#endif // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+ int bf1:1;
+ int bf2:1;
+ int bf3:1;
+ int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+ StructWithBitField *x = new StructWithBitField;
+ delete Ident(x);
+ EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+}
+
+struct StructWithBitFields_8_24 {
+ int a:8;
+ int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+ StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+ x->a = 0;
+ x->b = 0;
+ delete Ident(x);
+}
+
+#if ASAN_NEEDS_SEGV
+namespace {
+
+const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
+
+TEST(AddressSanitizer, WildAddressTest) {
+ char *c = (char*)0x123;
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
+}
+
+void my_sigaction_sighandler(int, siginfo_t*, void*) {
+ fprintf(stderr, kOverriddenHandler);
+ exit(1);
+}
+
+void my_signal_sighandler(int signum) {
+ fprintf(stderr, kOverriddenHandler);
+ exit(1);
+}
+
+TEST(AddressSanitizer, SignalTest) {
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = my_sigaction_sighandler;
+ sigact.sa_flags = SA_SIGINFO;
+ // ASan should silently ignore sigaction()...
+ EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
+#ifdef __APPLE__
+ EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
+#endif
+ char *c = (char*)0x123;
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
+ // ... and signal().
+ EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
+}
+} // namespace
+#endif
+
+static void TestLargeMalloc(size_t size) {
+ char buff[1024];
+ sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+ EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+ const int max_size = (SANITIZER_WORDSIZE == 32) ? 1 << 26 : 1 << 28;
+ for (int i = 113; i < max_size; i = i * 2 + 13) {
+ TestLargeMalloc(i);
+ }
+}
+
+TEST(AddressSanitizer, HugeMallocTest) {
+ if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
+ size_t n_megs = 4100;
+ EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
+ "is located 1 bytes to the left|"
+ "AddressSanitizer failed to allocate");
+}
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+void MemalignRun(size_t align, size_t size, int idx) {
+ char *p = (char *)memalign(align, size);
+ Ident(p)[idx] = 0;
+ free(p);
+}
+
+TEST(AddressSanitizer, memalign) {
+ for (int align = 16; align <= (1 << 23); align *= 2) {
+ size_t size = align * 5;
+ EXPECT_DEATH(MemalignRun(align, size, -1),
+ "is located 1 bytes to the left");
+ EXPECT_DEATH(MemalignRun(align, size, size + 1),
+ "is located 1 bytes to the right");
+ }
+}
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+
+void *ManyThreadsWorker(void *a) {
+ for (int iter = 0; iter < 100; iter++) {
+ for (size_t size = 100; size < 2000; size *= 2) {
+ free(Ident(malloc(size)));
+ }
+ }
+ return 0;
+}
+
+#if !defined(__aarch64__)
+// FIXME: Infinite loop in AArch64 (PR24389).
+TEST(AddressSanitizer, ManyThreadsTest) {
+ const size_t kNumThreads =
+ (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
+ pthread_t t[kNumThreads];
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ManyThreadsWorker, (void*)i);
+ }
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+#endif
+
+TEST(AddressSanitizer, ReallocTest) {
+ const int kMinElem = 5;
+ int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+ ptr[3] = 3;
+ for (int i = 0; i < 10000; i++) {
+ ptr = (int*)realloc(ptr,
+ (my_rand() % 1000 + kMinElem) * sizeof(int));
+ EXPECT_EQ(3, ptr[3]);
+ }
+ free(ptr);
+ // Realloc pointer returned by malloc(0).
+ int *ptr2 = Ident((int*)malloc(0));
+ ptr2 = Ident((int*)realloc(ptr2, sizeof(*ptr2)));
+ *ptr2 = 42;
+ EXPECT_EQ(42, *ptr2);
+ free(ptr2);
+}
+
+TEST(AddressSanitizer, ReallocFreedPointerTest) {
+ void *ptr = Ident(malloc(42));
+ ASSERT_TRUE(NULL != ptr);
+ free(ptr);
+ EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
+}
+
+TEST(AddressSanitizer, ReallocInvalidPointerTest) {
+ void *ptr = Ident(malloc(42));
+ EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
+ free(ptr);
+}
+
+TEST(AddressSanitizer, ZeroSizeMallocTest) {
+ // Test that malloc(0) and similar functions don't return NULL.
+ void *ptr = Ident(malloc(0));
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int pm_res = posix_memalign(&ptr, 1<<20, 0);
+ EXPECT_EQ(0, pm_res);
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int *int_ptr = new int[0];
+ int *int_ptr2 = new int[0];
+ EXPECT_TRUE(NULL != int_ptr);
+ EXPECT_TRUE(NULL != int_ptr2);
+ EXPECT_NE(int_ptr, int_ptr2);
+ delete[] int_ptr;
+ delete[] int_ptr2;
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+static const char *kMallocUsableSizeErrorMsg =
+ "AddressSanitizer: attempting to call malloc_usable_size()";
+
+TEST(AddressSanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
+ EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
+ kMallocUsableSizeErrorMsg);
+ free(array);
+ EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+
+void WrongFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ // Use the allocated memory, otherwise Clang will optimize it out.
+ Ident(x);
+ free(x + 1);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, WrongFreeTest) {
+ EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting free.*not malloc"
+ ".*is located 4 bytes inside of 400-byte region"
+ ".*allocated by thread");
+}
+#endif
+
+void DoubleFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ fprintf(stderr, "DoubleFree: x=%p\n", (void *)x);
+ free(x);
+ free(x);
+ fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x);
+ abort();
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, DoubleFreeTest) {
+ EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting double-free"
+ ".*is located 0 bytes inside of 400-byte region"
+ ".*freed by thread T0 here"
+ ".*previously allocated by thread T0 here");
+}
+#endif
+
+template<int kSize>
+NOINLINE void SizedStackTest() {
+ char a[kSize];
+ char *A = Ident((char*)&a);
+ const char *expected_death = "AddressSanitizer: stack-buffer-";
+ for (size_t i = 0; i < kSize; i++)
+ A[i] = i;
+ EXPECT_DEATH(A[-1] = 0, expected_death);
+ EXPECT_DEATH(A[-5] = 0, expected_death);
+ EXPECT_DEATH(A[kSize] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
+ if (kSize > 16)
+ EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+ SizedStackTest<1>();
+ SizedStackTest<2>();
+ SizedStackTest<3>();
+ SizedStackTest<4>();
+ SizedStackTest<5>();
+ SizedStackTest<6>();
+ SizedStackTest<7>();
+ SizedStackTest<16>();
+ SizedStackTest<25>();
+ SizedStackTest<34>();
+ SizedStackTest<43>();
+ SizedStackTest<51>();
+ SizedStackTest<62>();
+ SizedStackTest<64>();
+ SizedStackTest<128>();
+}
+
+#if !defined(_WIN32)
+// FIXME: It's a bit hard to write multi-line death test expectations
+// in a portable way. Anyways, this should just be turned into a lit test.
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+ char XXX[10];
+ char YYY[20];
+ char ZZZ[30];
+ Ident(XXX);
+ Ident(YYY);
+ EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+#endif
+
+#if 0 // This test requires online symbolizer.
+// Moved to lit_tests/stack-oob-frames.cc.
+// Reenable here once we have online symbolizer by default.
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+ char d[4] = {0};
+ char *D = Ident(d);
+ switch (frame) {
+ case 3: a[5]++; break;
+ case 2: b[5]++; break;
+ case 1: c[5]++; break;
+ case 0: D[5]++; break;
+ }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+ char c[4] = {0}; Frame0(frame, a, b, c);
+ break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+ char b[4] = {0}; Frame1(frame, a, b);
+ break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+ char a[4] = {0}; Frame2(frame, a);
+ break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+ EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+ EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+ EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+ EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+#endif
+
+NOINLINE void LongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ longjmp(buf, 1);
+}
+
+NOINLINE void TouchStackFunc() {
+ int a[100]; // long array will intersect with redzones from LongJmpFunc1.
+ int *A = Ident(a);
+ for (int i = 0; i < 100; i++)
+ A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report false positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+ static jmp_buf buf;
+ if (!setjmp(buf)) {
+ LongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+#if !defined(_WIN32) // Only basic longjmp is available on Windows.
+NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ _longjmp(buf, 1);
+}
+
+NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ siglongjmp(buf, 1);
+}
+
+#if !defined(__ANDROID__) && !defined(__arm__) && \
+ !defined(__powerpc64__) && !defined(__powerpc__) && \
+ !defined(__aarch64__) && !defined(__mips__) && \
+ !defined(__mips64)
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ __builtin_longjmp((void**)buf, 1);
+}
+
+// Does not work on Power and ARM:
+// https://github.com/google/sanitizers/issues/185
+TEST(AddressSanitizer, BuiltinLongJmpTest) {
+ static jmp_buf buf;
+ if (!__builtin_setjmp((void**)buf)) {
+ BuiltinLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
+ // !defined(__powerpc__) && !defined(__arm__) &&
+ // !defined(__mips__) && !defined(__mips64)
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+ static jmp_buf buf;
+ if (!_setjmp(buf)) {
+ UnderscopeLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+ static sigjmp_buf buf;
+ if (!sigsetjmp(buf, 1)) {
+ SigLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE void ThrowFunc() {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+ if (ASAN_UAR) return;
+ // TODO(kcc): this test crashes on 32-bit for some reason...
+ if (SANITIZER_WORDSIZE == 32) return;
+ try {
+ ThrowFunc();
+ } catch(...) {}
+ TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ pthread_exit(0);
+ return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+ TouchStackFunc();
+ return 0;
+}
+
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if defined(__i686__) || defined(__x86_64__)
+#include <emmintrin.h>
+TEST(AddressSanitizer, Store128Test) {
+ char *a = Ident((char*)malloc(Ident(12)));
+ char *p = a;
+ if (((uintptr_t)a % 16) != 0)
+ p = a + 8;
+ assert(((uintptr_t)p % 16) == 0);
+ __m128i value_wide = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "AddressSanitizer: heap-buffer-overflow");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "WRITE of size 16");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "located 0 bytes to the right of 12-byte");
+ free(a);
+}
+#endif
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string RightOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance >= 0);
+ char expected_str[100];
+ sprintf(expected_str, ASAN_PCRE_DOTALL
+#if !GTEST_USES_SIMPLE_RE
+ "buffer-overflow.*%s.*"
+#endif
+ "located %d bytes to the right",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string RightOOBWriteMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string RightOOBReadMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string LeftOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str,
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL "%s.*"
+#endif
+ "located %d bytes to the left",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string LeftOOBWriteMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string LeftOOBReadMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+string LeftOOBAccessMessage(int oob_distance) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str, "located %d bytes to the left", oob_distance);
+ return string(expected_str);
+}
+
+char* MallocAndMemsetString(size_t size, char ch) {
+ char *s = Ident((char*)malloc(size));
+ memset(s, ch, size);
+ return s;
+}
+
+char* MallocAndMemsetString(size_t size) {
+ return MallocAndMemsetString(size, 'z');
+}
+
+#if defined(__linux__) && !defined(__ANDROID__)
+#define READ_TEST(READ_N_BYTES) \
+ char *x = new char[10]; \
+ int fd = open("/proc/self/stat", O_RDONLY); \
+ ASSERT_GT(fd, 0); \
+ EXPECT_DEATH(READ_N_BYTES, \
+ ASAN_PCRE_DOTALL \
+ "AddressSanitizer: heap-buffer-overflow" \
+ ".* is located 0 bytes to the right of 10-byte region"); \
+ close(fd); \
+ delete [] x; \
+
+TEST(AddressSanitizer, pread) {
+ READ_TEST(pread(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, pread64) {
+ READ_TEST(pread64(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, read) {
+ READ_TEST(read(fd, x, 15));
+}
+#endif // defined(__linux__) && !defined(__ANDROID__)
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+ int size = Ident(4096);
+ char *s = Ident((char*)malloc(size));
+ EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0));
+ free(s);
+}
+
+// TODO(samsonov): Add a test with malloc(0)
+// TODO(samsonov): Add tests for str* and mem* functions.
+
+NOINLINE static int LargeFunction(bool do_bad_access) {
+ int *x = new int[100];
+ x[0]++;
+ x[1]++;
+ x[2]++;
+ x[3]++;
+ x[4]++;
+ x[5]++;
+ x[6]++;
+ x[7]++;
+ x[8]++;
+ x[9]++;
+
+ x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+ x[10]++;
+ x[11]++;
+ x[12]++;
+ x[13]++;
+ x[14]++;
+ x[15]++;
+ x[16]++;
+ x[17]++;
+ x[18]++;
+ x[19]++;
+
+ delete[] x;
+ return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+ int failing_line = LargeFunction(false);
+ char expected_warning[128];
+ sprintf(expected_warning, "LargeFunction.*asan_test.*:%d", failing_line);
+ EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+ int *a = (int*)malloc_aaa(sizeof(int));
+ *a = 1;
+ free_aaa(a);
+ EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+ "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+static bool TryToSetThreadName(const char *name) {
+#if defined(__linux__) && defined(PR_SET_NAME)
+ return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
+#else
+ return false;
+#endif
+}
+
+void *ThreadedTestAlloc(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("AllocThr"));
+ int **p = (int**)a;
+ *p = new int;
+ return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("FreeThr"));
+ int **p = (int**)a;
+ delete *p;
+ return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("UseThr"));
+ int **p = (int**)a;
+ **p = 1;
+ return 0;
+}
+
+void ThreadedTestSpawn() {
+ pthread_t t;
+ int *x;
+ PTHREAD_CREATE(&t, 0, ThreadedTestAlloc, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestFree, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestUse, &x);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, ThreadedTest) {
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "Thread T.*created"
+ ".*Thread T.*created"
+ ".*Thread T.*created");
+}
+#endif
+
+void *ThreadedTestFunc(void *unused) {
+ // Check if prctl(PR_SET_NAME) is supported. Return if not.
+ if (!TryToSetThreadName("TestFunc"))
+ return 0;
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "WRITE .*thread T. .UseThr."
+ ".*freed by thread T. .FreeThr. here:"
+ ".*previously allocated by thread T. .AllocThr. here:"
+ ".*Thread T. .UseThr. created by T.*TestFunc"
+ ".*Thread T. .FreeThr. created by T"
+ ".*Thread T. .AllocThr. created by T"
+ "");
+ return 0;
+}
+
+TEST(AddressSanitizer, ThreadNamesTest) {
+ // Run ThreadedTestFunc in a separate thread because it tries to set a
+ // thread name and we don't want to change the main thread's name.
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if SANITIZER_WORDSIZE == 32
+ char *addr = (char*)0x22000000;
+#else
+# if defined(__powerpc64__)
+ char *addr = (char*)0x024000800000;
+# else
+ char *addr = (char*)0x0000100000080000;
+# endif
+#endif
+ EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
+}
+#endif // ASAN_NEEDS_SEGV
+
+extern "C" {
+NOINLINE static void UseThenFreeThenUse() {
+ char *x = Ident((char*)malloc(8));
+ *x = 1;
+ free_aaa(x);
+ *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+ EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+ free(strdup(Ident("123")));
+}
+
+// Currently we create and poison redzone at right of global variables.
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+
+TEST(AddressSanitizer, GlobalTest) {
+ static char func_static15[15];
+
+ static char fs1[10];
+ static char fs2[10];
+ static char fs3[10];
+
+ glob5[Ident(0)] = 0;
+ glob5[Ident(1)] = 0;
+ glob5[Ident(2)] = 0;
+ glob5[Ident(3)] = 0;
+ glob5[Ident(4)] = 0;
+
+ EXPECT_DEATH(glob5[Ident(5)] = 0,
+ "0 bytes to the right of global variable.*glob5.* size 5");
+ EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+ "6 bytes to the right of global variable.*glob5.* size 5");
+ Ident(static110); // avoid optimizations
+ static110[Ident(0)] = 0;
+ static110[Ident(109)] = 0;
+ EXPECT_DEATH(static110[Ident(110)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(static110[Ident(110+7)] = 0,
+ "7 bytes to the right of global variable");
+
+ Ident(func_static15); // avoid optimizations
+ func_static15[Ident(0)] = 0;
+ EXPECT_DEATH(func_static15[Ident(15)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+ "9 bytes to the right of global variable");
+
+ Ident(fs1);
+ Ident(fs2);
+ Ident(fs3);
+
+ // We don't create left redzones, so this is not 100% guaranteed to fail.
+ // But most likely will.
+ EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+ EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+ "is located 1 bytes to the right of .*ConstGlob");
+ EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+ "is located 2 bytes to the right of .*StaticConstGlob");
+
+ // call stuff from another file.
+ GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+ static const char *zoo = "FOOBAR123";
+ const char *p = Ident(zoo);
+ EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+TEST(AddressSanitizer, FileNameInGlobalReportTest) {
+ static char zoo[10];
+ const char *p = Ident(zoo);
+ // The file name should be present in the report.
+ EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.");
+}
+
+int *ReturnsPointerToALocalObject() {
+ int a = 0;
+ return Ident(&a);
+}
+
+#if ASAN_UAR == 1
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+ int *(*f)() = Ident(ReturnsPointerToALocalObject);
+ int *p = f();
+ // Call 'f' a few more times, 'p' should still be poisoned.
+ for (int i = 0; i < 32; i++)
+ f();
+ EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
+ EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
+}
+#endif
+
+template <int kSize>
+NOINLINE static void FuncWithStack() {
+ char x[kSize];
+ Ident(x)[0] = 0;
+ Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+ int LargeStack[10000];
+ Ident(LargeStack)[0] = 0;
+ for (int i = 0; i < 10000; i++) {
+ FuncWithStack<128 * 1>();
+ FuncWithStack<128 * 2>();
+ FuncWithStack<128 * 4>();
+ FuncWithStack<128 * 8>();
+ FuncWithStack<128 * 16>();
+ FuncWithStack<128 * 32>();
+ FuncWithStack<128 * 64>();
+ FuncWithStack<128 * 128>();
+ FuncWithStack<128 * 256>();
+ FuncWithStack<128 * 512>();
+ Ident(LargeStack)[0] = 0;
+ }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+ LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+ const int kNumThreads = 20;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+static void *PthreadExit(void *a) {
+ pthread_exit(0);
+ return 0;
+}
+
+TEST(AddressSanitizer, PthreadExitTest) {
+ pthread_t t;
+ for (int i = 0; i < 1000; i++) {
+ PTHREAD_CREATE(&t, 0, PthreadExit, 0);
+ PTHREAD_JOIN(t, 0);
+ }
+}
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE static void StackReuseAndException() {
+ int large_stack[1000];
+ Ident(large_stack);
+ ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+ for (int i = 0; i < 10000; i++) {
+ try {
+ StackReuseAndException();
+ } catch(...) {
+ }
+ }
+}
+#endif
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+#endif
+
+struct LargeStruct {
+ int foo[100];
+};
+
+// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
+// Struct copy should not cause asan warning even if lhs == rhs.
+TEST(AddressSanitizer, LargeStructCopyTest) {
+ LargeStruct a;
+ *Ident(&a) = *Ident(&a);
+}
+
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+static void NoSanitizeAddress() {
+ char *foo = new char[10];
+ Ident(foo)[10] = 0;
+ delete [] foo;
+}
+
+TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
+ Ident(NoSanitizeAddress)();
+}
+
+// The new/delete/etc mismatch checks don't work on Android,
+// as calls to new/delete go through malloc/free.
+// OS X support is tracked here:
+// https://github.com/google/sanitizers/issues/131
+// Windows support is tracked here:
+// https://github.com/google/sanitizers/issues/309
+#if !defined(__ANDROID__) && \
+ !defined(__APPLE__) && \
+ !defined(_WIN32)
+static string MismatchStr(const string &str) {
+ return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
+}
+
+TEST(AddressSanitizer, AllocDeallocMismatch) {
+ EXPECT_DEATH(free(Ident(new int)),
+ MismatchStr("operator new vs free"));
+ EXPECT_DEATH(free(Ident(new int[2])),
+ MismatchStr("operator new \\[\\] vs free"));
+ EXPECT_DEATH(delete (Ident(new int[2])),
+ MismatchStr("operator new \\[\\] vs operator delete"));
+ EXPECT_DEATH(delete (Ident((int*)malloc(2 * sizeof(int)))),
+ MismatchStr("malloc vs operator delete"));
+ EXPECT_DEATH(delete [] (Ident(new int)),
+ MismatchStr("operator new vs operator delete \\[\\]"));
+ EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
+ MismatchStr("malloc vs operator delete \\[\\]"));
+}
+#endif
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+ ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+ char a[20];
+ Ident(a)[20] = 0;
+ return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+ SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, SimpleBugOnSTack, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+ uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+ uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+ uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+ uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+ size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+ printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+ DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+ int *a = 0;
+ Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+ static char a[100];
+ static char b[100];
+ static char c[100];
+ Ident(a);
+ Ident(b);
+ Ident(c);
+ Ident(a)[5] = 0;
+ Ident(b)[105] = 0;
+ Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+ const size_t kAllocSize = (1 << 28) - 1024;
+ size_t total_size = 0;
+ while (true) {
+ void *x = malloc(kAllocSize);
+ memset(x, 0, kAllocSize);
+ total_size += kAllocSize;
+ fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
+ }
+}
+
+// https://github.com/google/sanitizers/issues/66
+TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
+ for (int i = 0; i < 1000000; i++) {
+ delete [] (Ident(new char [8644]));
+ }
+ char *x = new char[8192];
+ EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
+ delete [] Ident(x);
+}
+
+
+// Test that instrumentation of stack allocations takes into account
+// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
+// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
+TEST(AddressSanitizer, LongDoubleNegativeTest) {
+ long double a, b;
+ static long double c;
+ memcpy(Ident(&a), Ident(&b), sizeof(long double));
+ memcpy(Ident(&c), Ident(&b), sizeof(long double));
+}
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, pthread_getschedparam) {
+ int policy;
+ struct sched_param param;
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), &policy, Ident(¶m) + 2),
+ "AddressSanitizer: stack-buffer-.*flow");
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), Ident(&policy) - 1, ¶m),
+ "AddressSanitizer: stack-buffer-.*flow");
+ int res = pthread_getschedparam(pthread_self(), &policy, ¶m);
+ ASSERT_EQ(0, res);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PRINTF_L
+static int vsnprintf_l_wrapper(char *s, size_t n,
+ locale_t l, const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int res = vsnprintf_l(s, n , l, format, va);
+ va_end(va);
+ return res;
+}
+
+TEST(AddressSanitizer, snprintf_l) {
+ char buff[5];
+ // Check that snprintf_l() works fine with Asan.
+ int res = snprintf_l(buff, 5,
+ _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()");
+ EXPECT_EQ(12, res);
+ // Check that vsnprintf_l() works fine with Asan.
+ res = vsnprintf_l_wrapper(buff, 5,
+ _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()");
+ EXPECT_EQ(13, res);
+
+ EXPECT_DEATH(snprintf_l(buff, 10,
+ _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
+ EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10,
+ _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
+}
+#endif
diff --git a/compiler-rt/lib/asan/tests/asan_test.ignore b/compiler-rt/lib/asan/tests/asan_test.ignore
new file mode 100644
index 0000000..ea5c260
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_test.ignore
@@ -0,0 +1,3 @@
+# blacklisted functions for instrumented ASan unit test
+fun:*IgnoreTest*
+fun:*SomeOtherFunc*
diff --git a/compiler-rt/lib/asan/tests/asan_test_config.h b/compiler-rt/lib/asan/tests/asan_test_config.h
new file mode 100644
index 0000000..92f2763
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_test_config.h
@@ -0,0 +1,54 @@
+//===-- asan_test_config.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
+# error "This file should be included into asan_test_utils.h only"
+#endif
+
+#ifndef ASAN_TEST_CONFIG_H
+#define ASAN_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+using std::string;
+using std::vector;
+using std::map;
+
+#ifndef ASAN_UAR
+# error "please define ASAN_UAR"
+#endif
+
+#ifndef ASAN_HAS_EXCEPTIONS
+# error "please define ASAN_HAS_EXCEPTIONS"
+#endif
+
+#ifndef ASAN_HAS_BLACKLIST
+# error "please define ASAN_HAS_BLACKLIST"
+#endif
+
+#ifndef ASAN_NEEDS_SEGV
+# if defined(_WIN32)
+# define ASAN_NEEDS_SEGV 0
+# else
+# define ASAN_NEEDS_SEGV 1
+# endif
+#endif
+
+#ifndef ASAN_AVOID_EXPENSIVE_TESTS
+# define ASAN_AVOID_EXPENSIVE_TESTS 0
+#endif
+
+#define ASAN_PCRE_DOTALL ""
+
+#endif // ASAN_TEST_CONFIG_H
diff --git a/compiler-rt/lib/asan/tests/asan_test_main.cc b/compiler-rt/lib/asan/tests/asan_test_main.cc
new file mode 100644
index 0000000..cdaf801
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_test_main.cc
@@ -0,0 +1,33 @@
+//===-- asan_test_main.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+// Default ASAN_OPTIONS for the unit tests. Let's turn symbolication off to
+// speed up testing (unit tests don't use it anyway).
+extern "C" const char* __asan_default_options() {
+#if SANITIZER_MAC
+ // On Darwin, we default to `abort_on_error=1`, which would make tests run
+ // much slower. Let's override this and run lit tests with 'abort_on_error=0'.
+ // Also, make sure we do not overwhelm the syslog while testing.
+ return "symbolize=false:abort_on_error=0:log_to_syslog=0";
+#else
+ return "symbolize=false";
+#endif
+}
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/compiler-rt/lib/asan/tests/asan_test_utils.h b/compiler-rt/lib/asan/tests/asan_test_utils.h
new file mode 100644
index 0000000..03d17cf
--- /dev/null
+++ b/compiler-rt/lib/asan/tests/asan_test_utils.h
@@ -0,0 +1,107 @@
+//===-- asan_test_utils.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_TEST_UTILS_H
+#define ASAN_TEST_UTILS_H
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_ASAN_TEST_UTILS_H
+# include "asan_test_config.h"
+# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
+#endif
+
+#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <algorithm>
+
+#if !defined(_WIN32)
+# include <strings.h>
+# include <sys/mman.h>
+# include <setjmp.h>
+#endif
+
+#ifdef __linux__
+# include <sys/prctl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+
+#if ASAN_HAS_EXCEPTIONS
+# define ASAN_THROW(x) throw (x)
+#else
+# define ASAN_THROW(x)
+#endif
+
+typedef uint8_t U1;
+typedef uint16_t U2;
+typedef uint32_t U4;
+typedef uint64_t U8;
+
+static const int kPageSize = 4096;
+
+const size_t kLargeMalloc = 1 << 24;
+
+extern void free_aaa(void *p);
+extern void *malloc_aaa(size_t size);
+
+template<typename T>
+NOINLINE void asan_write(T *a) {
+ *a = 0;
+}
+
+string RightOOBErrorMessage(int oob_distance, bool is_write);
+string RightOOBWriteMessage(int oob_distance);
+string RightOOBReadMessage(int oob_distance);
+string LeftOOBErrorMessage(int oob_distance, bool is_write);
+string LeftOOBWriteMessage(int oob_distance);
+string LeftOOBReadMessage(int oob_distance);
+string LeftOOBAccessMessage(int oob_distance);
+char* MallocAndMemsetString(size_t size, char ch);
+char* MallocAndMemsetString(size_t size);
+
+extern char glob1[1];
+extern char glob2[2];
+extern char glob3[3];
+extern char glob4[4];
+extern char glob5[5];
+extern char glob6[6];
+extern char glob7[7];
+extern char glob8[8];
+extern char glob9[9];
+extern char glob10[10];
+extern char glob11[11];
+extern char glob12[12];
+extern char glob13[13];
+extern char glob14[14];
+extern char glob15[15];
+extern char glob16[16];
+extern char glob17[17];
+extern char glob1000[1000];
+extern char glob10000[10000];
+extern char glob100000[100000];
+extern int GlobalsTest(int x);
+
+#endif // ASAN_TEST_UTILS_H
diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt
new file mode 100644
index 0000000..5ffad1d
--- /dev/null
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -0,0 +1,388 @@
+# This directory contains a large amount of C code which provides
+# generic implementations of the core runtime library along with optimized
+# architecture-specific code in various subdirectories.
+
+# TODO: Need to add a mechanism for logging errors when builtin source files are
+# added to a sub-directory and not this CMakeLists file.
+
+set(GENERIC_SOURCES
+ absvdi2.c
+ absvsi2.c
+ absvti2.c
+ adddf3.c
+ addsf3.c
+ addtf3.c
+ addvdi3.c
+ addvsi3.c
+ addvti3.c
+ apple_versioning.c
+ ashldi3.c
+ ashlti3.c
+ ashrdi3.c
+ ashrti3.c
+ # FIXME: atomic.c may only be compiled if host compiler understands _Atomic
+ # atomic.c
+ clear_cache.c
+ clzdi2.c
+ clzsi2.c
+ clzti2.c
+ cmpdi2.c
+ cmpti2.c
+ comparedf2.c
+ comparesf2.c
+ ctzdi2.c
+ ctzsi2.c
+ ctzti2.c
+ divdc3.c
+ divdf3.c
+ divdi3.c
+ divmoddi4.c
+ divmodsi4.c
+ divsc3.c
+ divsf3.c
+ divsi3.c
+ divtc3.c
+ divti3.c
+ divtf3.c
+ divxc3.c
+ enable_execute_stack.c
+ eprintf.c
+ extendsfdf2.c
+ extendhfsf2.c
+ ffsdi2.c
+ ffsti2.c
+ fixdfdi.c
+ fixdfsi.c
+ fixdfti.c
+ fixsfdi.c
+ fixsfsi.c
+ fixsfti.c
+ fixunsdfdi.c
+ fixunsdfsi.c
+ fixunsdfti.c
+ fixunssfdi.c
+ fixunssfsi.c
+ fixunssfti.c
+ fixunsxfdi.c
+ fixunsxfsi.c
+ fixunsxfti.c
+ fixxfdi.c
+ fixxfti.c
+ floatdidf.c
+ floatdisf.c
+ floatdixf.c
+ floatsidf.c
+ floatsisf.c
+ floattidf.c
+ floattisf.c
+ floattixf.c
+ floatundidf.c
+ floatundisf.c
+ floatundixf.c
+ floatunsidf.c
+ floatunsisf.c
+ floatuntidf.c
+ floatuntisf.c
+ floatuntixf.c
+ int_util.c
+ lshrdi3.c
+ lshrti3.c
+ moddi3.c
+ modsi3.c
+ modti3.c
+ muldc3.c
+ muldf3.c
+ muldi3.c
+ mulodi4.c
+ mulosi4.c
+ muloti4.c
+ mulsc3.c
+ mulsf3.c
+ multi3.c
+ multf3.c
+ mulvdi3.c
+ mulvsi3.c
+ mulvti3.c
+ mulxc3.c
+ negdf2.c
+ negdi2.c
+ negsf2.c
+ negti2.c
+ negvdi2.c
+ negvsi2.c
+ negvti2.c
+ paritydi2.c
+ paritysi2.c
+ parityti2.c
+ popcountdi2.c
+ popcountsi2.c
+ popcountti2.c
+ powidf2.c
+ powisf2.c
+ powitf2.c
+ powixf2.c
+ subdf3.c
+ subsf3.c
+ subvdi3.c
+ subvsi3.c
+ subvti3.c
+ subtf3.c
+ trampoline_setup.c
+ truncdfhf2.c
+ truncdfsf2.c
+ truncsfhf2.c
+ ucmpdi2.c
+ ucmpti2.c
+ udivdi3.c
+ udivmoddi4.c
+ udivmodsi4.c
+ udivmodti4.c
+ udivsi3.c
+ udivti3.c
+ umoddi3.c
+ umodsi3.c
+ umodti3.c)
+
+if(APPLE)
+ set(GENERIC_SOURCES
+ ${GENERIC_SOURCES}
+ atomic_flag_clear.c
+ atomic_flag_clear_explicit.c
+ atomic_flag_test_and_set.c
+ atomic_flag_test_and_set_explicit.c
+ atomic_signal_fence.c
+ atomic_thread_fence.c)
+endif()
+
+if(NOT WIN32 OR MINGW)
+ set(GENERIC_SOURCES
+ ${GENERIC_SOURCES}
+ emutls.c)
+endif()
+
+if (HAVE_UNWIND_H)
+ set(GENERIC_SOURCES
+ ${GENERIC_SOURCES}
+ gcc_personality_v0.c)
+endif ()
+
+if (NOT MSVC)
+ set(x86_64_SOURCES
+ x86_64/chkstk.S
+ x86_64/chkstk2.S
+ x86_64/floatdidf.c
+ x86_64/floatdisf.c
+ x86_64/floatdixf.c
+ x86_64/floatundidf.S
+ x86_64/floatundisf.S
+ x86_64/floatundixf.S
+ ${GENERIC_SOURCES})
+ set(x86_64h_SOURCES ${x86_64_SOURCES})
+
+ if (WIN32)
+ set(x86_64_SOURCES
+ ${x86_64_SOURCES}
+ x86_64/chkstk.S
+ x86_64/chkstk2.S)
+ endif()
+
+ set(i386_SOURCES
+ i386/ashldi3.S
+ i386/ashrdi3.S
+ i386/chkstk.S
+ i386/chkstk2.S
+ i386/divdi3.S
+ i386/floatdidf.S
+ i386/floatdisf.S
+ i386/floatdixf.S
+ i386/floatundidf.S
+ i386/floatundisf.S
+ i386/floatundixf.S
+ i386/lshrdi3.S
+ i386/moddi3.S
+ i386/muldi3.S
+ i386/udivdi3.S
+ i386/umoddi3.S
+ ${GENERIC_SOURCES})
+
+ if (WIN32)
+ set(i386_SOURCES
+ ${i386_SOURCES}
+ i386/chkstk.S
+ i386/chkstk2.S)
+ endif()
+
+ set(i686_SOURCES
+ ${i386_SOURCES})
+else () # MSVC
+ # Use C versions of functions when building on MSVC
+ # MSVC's assembler takes Intel syntax, not AT&T syntax
+ set(x86_64_SOURCES
+ x86_64/floatdidf.c
+ x86_64/floatdisf.c
+ x86_64/floatdixf.c
+ ${GENERIC_SOURCES})
+ set(x86_64h_SOURCES ${x86_64_SOURCES})
+ set(i386_SOURCES ${GENERIC_SOURCES})
+ set(i686_SOURCES ${i386_SOURCES})
+endif () # if (NOT MSVC)
+
+set(arm_SOURCES
+ arm/adddf3vfp.S
+ arm/addsf3vfp.S
+ arm/aeabi_cdcmp.S
+ arm/aeabi_cdcmpeq_check_nan.c
+ arm/aeabi_cfcmp.S
+ arm/aeabi_cfcmpeq_check_nan.c
+ arm/aeabi_dcmp.S
+ arm/aeabi_div0.c
+ arm/aeabi_drsub.c
+ arm/aeabi_fcmp.S
+ arm/aeabi_frsub.c
+ arm/aeabi_idivmod.S
+ arm/aeabi_ldivmod.S
+ arm/aeabi_memcmp.S
+ arm/aeabi_memcpy.S
+ arm/aeabi_memmove.S
+ arm/aeabi_memset.S
+ arm/aeabi_uidivmod.S
+ arm/aeabi_uldivmod.S
+ arm/bswapdi2.S
+ arm/bswapsi2.S
+ arm/clzdi2.S
+ arm/clzsi2.S
+ arm/comparesf2.S
+ arm/divdf3vfp.S
+ arm/divmodsi4.S
+ arm/divsf3vfp.S
+ arm/divsi3.S
+ arm/eqdf2vfp.S
+ arm/eqsf2vfp.S
+ arm/extendsfdf2vfp.S
+ arm/fixdfsivfp.S
+ arm/fixsfsivfp.S
+ arm/fixunsdfsivfp.S
+ arm/fixunssfsivfp.S
+ arm/floatsidfvfp.S
+ arm/floatsisfvfp.S
+ arm/floatunssidfvfp.S
+ arm/floatunssisfvfp.S
+ arm/gedf2vfp.S
+ arm/gesf2vfp.S
+ arm/gtdf2vfp.S
+ arm/gtsf2vfp.S
+ arm/ledf2vfp.S
+ arm/lesf2vfp.S
+ arm/ltdf2vfp.S
+ arm/ltsf2vfp.S
+ arm/modsi3.S
+ arm/muldf3vfp.S
+ arm/mulsf3vfp.S
+ arm/nedf2vfp.S
+ arm/negdf2vfp.S
+ arm/negsf2vfp.S
+ arm/nesf2vfp.S
+ arm/restore_vfp_d8_d15_regs.S
+ arm/save_vfp_d8_d15_regs.S
+ arm/subdf3vfp.S
+ arm/subsf3vfp.S
+ arm/switch16.S
+ arm/switch32.S
+ arm/switch8.S
+ arm/switchu8.S
+ arm/sync_fetch_and_add_4.S
+ arm/sync_fetch_and_add_8.S
+ arm/sync_fetch_and_and_4.S
+ arm/sync_fetch_and_and_8.S
+ arm/sync_fetch_and_max_4.S
+ arm/sync_fetch_and_max_8.S
+ arm/sync_fetch_and_min_4.S
+ arm/sync_fetch_and_min_8.S
+ arm/sync_fetch_and_nand_4.S
+ arm/sync_fetch_and_nand_8.S
+ arm/sync_fetch_and_or_4.S
+ arm/sync_fetch_and_or_8.S
+ arm/sync_fetch_and_sub_4.S
+ arm/sync_fetch_and_sub_8.S
+ arm/sync_fetch_and_umax_4.S
+ arm/sync_fetch_and_umax_8.S
+ arm/sync_fetch_and_umin_4.S
+ arm/sync_fetch_and_umin_8.S
+ arm/sync_fetch_and_xor_4.S
+ arm/sync_fetch_and_xor_8.S
+ arm/sync_synchronize.S
+ arm/truncdfsf2vfp.S
+ arm/udivmodsi4.S
+ arm/udivsi3.S
+ arm/umodsi3.S
+ arm/unorddf2vfp.S
+ arm/unordsf2vfp.S
+ ${GENERIC_SOURCES})
+
+set(aarch64_SOURCES
+ comparetf2.c
+ extenddftf2.c
+ extendsftf2.c
+ fixtfdi.c
+ fixtfsi.c
+ fixtfti.c
+ fixunstfdi.c
+ fixunstfsi.c
+ fixunstfti.c
+ floatditf.c
+ floatsitf.c
+ floatunditf.c
+ floatunsitf.c
+ multc3.c
+ trunctfdf2.c
+ trunctfsf2.c
+ ${GENERIC_SOURCES})
+
+set(armhf_SOURCES ${arm_SOURCES})
+set(armv7_SOURCES ${arm_SOURCES})
+set(armv7s_SOURCES ${arm_SOURCES})
+set(arm64_SOURCES ${aarch64_SOURCES})
+
+# macho_embedded archs
+set(armv6m_SOURCES ${GENERIC_SOURCES})
+set(armv7m_SOURCES ${arm_SOURCES})
+set(armv7em_SOURCES ${arm_SOURCES})
+
+set(mips_SOURCES ${GENERIC_SOURCES})
+set(mipsel_SOURCES ${mips_SOURCES})
+set(mips64_SOURCES ${mips_SOURCES})
+set(mips64el_SOURCES ${mips_SOURCES})
+
+add_custom_target(builtins)
+
+if (APPLE)
+ add_subdirectory(Darwin-excludes)
+ add_subdirectory(macho_embedded)
+ darwin_add_builtin_libraries(${BUILTIN_SUPPORTED_OS})
+elseif (NOT WIN32 OR MINGW)
+ append_string_if(COMPILER_RT_HAS_STD_C99_FLAG -std=c99 maybe_stdc99)
+
+ foreach (arch ${BUILTIN_SUPPORTED_ARCH})
+ if (CAN_TARGET_${arch})
+ # Filter out generic versions of routines that are re-implemented in
+ # architecture specific manner. This prevents multiple definitions of the
+ # same symbols, making the symbol selection non-deterministic.
+ foreach (_file ${${arch}_SOURCES})
+ if (${_file} MATCHES ${arch}/*)
+ get_filename_component(_name ${_file} NAME)
+ string(REPLACE ".S" ".c" _cname "${_name}")
+ list(REMOVE_ITEM ${arch}_SOURCES ${_cname})
+ endif ()
+ endforeach ()
+
+ add_compiler_rt_runtime(clang_rt.builtins
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${${arch}_SOURCES}
+ CFLAGS ${maybe_stdc99}
+ PARENT_TARGET builtins)
+ endif ()
+ endforeach ()
+endif ()
+
+add_dependencies(compiler-rt builtins)
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/10.4-x86_64.txt b/compiler-rt/lib/builtins/Darwin-excludes/10.4-x86_64.txt
new file mode 100644
index 0000000..f2ee7fe
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/10.4-x86_64.txt
@@ -0,0 +1,35 @@
+absvti2
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+subvti3
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/10.4.txt b/compiler-rt/lib/builtins/Darwin-excludes/10.4.txt
new file mode 100644
index 0000000..70d3644
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/10.4.txt
@@ -0,0 +1,96 @@
+apple_versioning
+absvdi2
+absvsi2
+adddf3
+addsf3
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+clear_cache
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdi3
+divmoddi4
+divmodsi4
+divsc3
+divsf3
+divsi3
+divxc3
+enable_execute_stack
+comparedf2
+comparesf2
+extendhfsf2
+extendsfdf2
+ffsdi2
+fixdfdi
+fixdfsi
+fixsfdi
+fixsfsi
+fixunsdfdi
+fixunsdfsi
+fixunssfdi
+fixunssfsi
+fixunsxfdi
+fixunsxfsi
+fixxfdi
+floatdidf
+floatdisf
+floatdixf
+floatsidf
+floatsisf
+floatunsidf
+floatunsisf
+gcc_personality_v0
+gnu_f2h_ieee
+gnu_h2f_ieee
+lshrdi3
+moddi3
+modsi3
+muldc3
+muldf3
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulvdi3
+mulvsi3
+mulxc3
+negdf2
+negdi2
+negsf2
+negvdi2
+negvsi2
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+powixf2
+subdf3
+subsf3
+subvdi3
+subvsi3
+truncdfhf2
+truncdfsf2
+truncsfhf2
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+atomic_flag_clear
+atomic_flag_clear_explicit
+atomic_flag_test_and_set
+atomic_flag_test_and_set_explicit
+atomic_signal_fence
+atomic_thread_fence
\ No newline at end of file
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/CMakeLists.txt b/compiler-rt/lib/builtins/Darwin-excludes/CMakeLists.txt
new file mode 100644
index 0000000..266e422
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/CMakeLists.txt
@@ -0,0 +1,4 @@
+file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
+foreach(filter_file ${filter_files})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
+endforeach()
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/README.TXT b/compiler-rt/lib/builtins/Darwin-excludes/README.TXT
new file mode 100644
index 0000000..173eccc
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/README.TXT
@@ -0,0 +1,11 @@
+This folder contains list of symbols that should be excluded from the builtin
+libraries for Darwin. There are two reasons symbols are excluded:
+
+(1) They aren't supported on Darwin
+(2) They are contained within the OS on the minimum supported target
+
+The builtin libraries must contain all symbols not provided by the lowest
+supported target OS. Meaning if minimum deployment target is iOS 6, all builtins
+not included in the ios6-<arch>.txt files need to be included. The one catch is
+that this is per-architecture. Since iOS 6 doesn't support arm64, when supporting
+iOS 6, the minimum deployment target for arm64 binaries is iOS 7.
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7.txt
new file mode 100644
index 0000000..6aa542f
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7.txt
@@ -0,0 +1,57 @@
+absvti2
+addtf3
+addvti3
+aeabi_cdcmp
+aeabi_cdcmpeq_check_nan
+aeabi_cfcmp
+aeabi_cfcmpeq_check_nan
+aeabi_dcmp
+aeabi_div0
+aeabi_drsub
+aeabi_fcmp
+aeabi_frsub
+aeabi_idivmod
+aeabi_ldivmod
+aeabi_memcmp
+aeabi_memcpy
+aeabi_memmove
+aeabi_memset
+aeabi_uidivmod
+aeabi_uldivmod
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divtf3
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+multf3
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subtf3
+subvti3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7s.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7s.txt
new file mode 100644
index 0000000..28167aa
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios-armv7s.txt
@@ -0,0 +1,57 @@
+absvti2
+addtf3
+addvti3
+aeabi_cdcmp
+aeabi_cdcmpeq_check_nan
+aeabi_cfcmp
+aeabi_cfcmpeq_check_nan
+aeabi_dcmp
+aeabi_div0
+aeabi_drsub
+aeabi_fcmp
+aeabi_frsub
+aeabi_idivmod
+aeabi_ldivmod
+aeabi_memcmp
+aeabi_memcpy
+aeabi_memmove
+aeabi_memset
+aeabi_uidivmod
+aeabi_uldivmod
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divtf3
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+multf
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subtf3
+subvti3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios.txt
new file mode 100644
index 0000000..5db2400
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7.txt
new file mode 100644
index 0000000..b01fa71
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7.txt
@@ -0,0 +1,120 @@
+absvdi2
+absvsi2
+adddf3
+adddf3vfp
+addsf3
+addsf3vfp
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+bswapdi2
+bswapsi2
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdf3vfp
+divdi3
+divmodsi4
+divsc3
+divsf3
+divsf3vfp
+divsi3
+eqdf2
+eqdf2vfp
+eqsf2
+eqsf2vfp
+extendsfdf2
+extendsfdf2vfp
+ffsdi2
+fixdfdi
+fixdfsi
+fixdfsivfp
+fixsfdi
+fixsfsi
+fixsfsivfp
+fixunsdfdi
+fixunsdfsi
+fixunsdfsivfp
+fixunssfdi
+fixunssfsi
+fixunssfsivfp
+floatdidf
+floatdisf
+floatsidf
+floatsidfvfp
+floatsisf
+floatsisfvfp
+floatundidf
+floatundisf
+floatunsidf
+floatunsisf
+floatunssidfvfp
+floatunssisfvfp
+gcc_personality_sj0
+gedf2
+gedf2vfp
+gesf2
+gesf2vfp
+gtdf2
+gtdf2vfp
+gtsf2
+gtsf2vfp
+ledf2
+ledf2vfp
+lesf2
+lesf2vfp
+lshrdi3
+ltdf2
+ltdf2vfp
+ltsf2
+ltsf2vfp
+moddi3
+modsi3
+muldc3
+muldf3
+muldf3vfp
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulsf3vfp
+mulvdi3
+mulvsi3
+nedf2
+nedf2vfp
+negdi2
+negvdi2
+negvsi2
+nesf2
+nesf2vfp
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subdf3
+subdf3vfp
+subsf3
+subsf3vfp
+subvdi3
+subvsi3
+truncdfsf2
+truncdfsf2vfp
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+unorddf2
+unorddf2vfp
+unordsf2
+unordsf2vfp
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7s.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7s.txt
new file mode 100644
index 0000000..b01fa71
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios6-armv7s.txt
@@ -0,0 +1,120 @@
+absvdi2
+absvsi2
+adddf3
+adddf3vfp
+addsf3
+addsf3vfp
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+bswapdi2
+bswapsi2
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdf3vfp
+divdi3
+divmodsi4
+divsc3
+divsf3
+divsf3vfp
+divsi3
+eqdf2
+eqdf2vfp
+eqsf2
+eqsf2vfp
+extendsfdf2
+extendsfdf2vfp
+ffsdi2
+fixdfdi
+fixdfsi
+fixdfsivfp
+fixsfdi
+fixsfsi
+fixsfsivfp
+fixunsdfdi
+fixunsdfsi
+fixunsdfsivfp
+fixunssfdi
+fixunssfsi
+fixunssfsivfp
+floatdidf
+floatdisf
+floatsidf
+floatsidfvfp
+floatsisf
+floatsisfvfp
+floatundidf
+floatundisf
+floatunsidf
+floatunsisf
+floatunssidfvfp
+floatunssisfvfp
+gcc_personality_sj0
+gedf2
+gedf2vfp
+gesf2
+gesf2vfp
+gtdf2
+gtdf2vfp
+gtsf2
+gtsf2vfp
+ledf2
+ledf2vfp
+lesf2
+lesf2vfp
+lshrdi3
+ltdf2
+ltdf2vfp
+ltsf2
+ltsf2vfp
+moddi3
+modsi3
+muldc3
+muldf3
+muldf3vfp
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulsf3vfp
+mulvdi3
+mulvsi3
+nedf2
+nedf2vfp
+negdi2
+negvdi2
+negvsi2
+nesf2
+nesf2vfp
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subdf3
+subdf3vfp
+subsf3
+subsf3vfp
+subvdi3
+subvsi3
+truncdfsf2
+truncdfsf2vfp
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+unorddf2
+unorddf2vfp
+unordsf2
+unordsf2vfp
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/ios7-arm64.txt b/compiler-rt/lib/builtins/Darwin-excludes/ios7-arm64.txt
new file mode 100644
index 0000000..5e4caf9
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/ios7-arm64.txt
@@ -0,0 +1,16 @@
+clzti2
+divti3
+fixdfti
+fixsfti
+fixunsdfti
+floattidf
+floattisf
+floatuntidf
+floatuntisf
+gcc_personality_v0
+modti3
+powidf2
+powisf2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/iossim-i386.txt b/compiler-rt/lib/builtins/Darwin-excludes/iossim-i386.txt
new file mode 100644
index 0000000..60c0e2d
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/iossim-i386.txt
@@ -0,0 +1,82 @@
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/iossim-x86_64.txt b/compiler-rt/lib/builtins/Darwin-excludes/iossim-x86_64.txt
new file mode 100644
index 0000000..de1574e
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/iossim-x86_64.txt
@@ -0,0 +1,12 @@
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/iossim.txt b/compiler-rt/lib/builtins/Darwin-excludes/iossim.txt
new file mode 100644
index 0000000..5db2400
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/iossim.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/osx-i386.txt b/compiler-rt/lib/builtins/Darwin-excludes/osx-i386.txt
new file mode 100644
index 0000000..60c0e2d
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/osx-i386.txt
@@ -0,0 +1,82 @@
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/osx-x86_64.txt b/compiler-rt/lib/builtins/Darwin-excludes/osx-x86_64.txt
new file mode 100644
index 0000000..de1574e
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/osx-x86_64.txt
@@ -0,0 +1,12 @@
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
diff --git a/compiler-rt/lib/builtins/Darwin-excludes/osx.txt b/compiler-rt/lib/builtins/Darwin-excludes/osx.txt
new file mode 100644
index 0000000..5db2400
--- /dev/null
+++ b/compiler-rt/lib/builtins/Darwin-excludes/osx.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/compiler-rt/lib/builtins/Makefile.mk b/compiler-rt/lib/builtins/Makefile.mk
new file mode 100644
index 0000000..00e2f53
--- /dev/null
+++ b/compiler-rt/lib/builtins/Makefile.mk
@@ -0,0 +1,25 @@
+#===- lib/builtins/Makefile.mk -----------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+
+# Add arch specific optimized implementations.
+SubDirs += i386 ppc x86_64 arm armv6m
+
+# Add ARM64 dir.
+SubDirs += arm64
+
+# Define the variables for this specific directory.
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o)
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/README.txt b/compiler-rt/lib/builtins/README.txt
new file mode 100644
index 0000000..ad36e4e
--- /dev/null
+++ b/compiler-rt/lib/builtins/README.txt
@@ -0,0 +1,345 @@
+Compiler-RT
+================================
+
+This directory and its subdirectories contain source code for the compiler
+support routines.
+
+Compiler-RT is open source software. You may freely distribute it under the
+terms of the license agreement found in LICENSE.txt.
+
+================================
+
+This is a replacement library for libgcc. Each function is contained
+in its own file. Each function has a corresponding unit test under
+test/Unit.
+
+A rudimentary script to test each file is in the file called
+test/Unit/test.
+
+Here is the specification for this library:
+
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
+
+Here is a synopsis of the contents of this library:
+
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+// Integral bit manipulation
+
+di_int __ashldi3(di_int a, si_int b); // a << b
+ti_int __ashlti3(ti_int a, si_int b); // a << b
+
+di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
+ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
+di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
+ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
+
+si_int __clzsi2(si_int a); // count leading zeros
+si_int __clzdi2(di_int a); // count leading zeros
+si_int __clzti2(ti_int a); // count leading zeros
+si_int __ctzsi2(si_int a); // count trailing zeros
+si_int __ctzdi2(di_int a); // count trailing zeros
+si_int __ctzti2(ti_int a); // count trailing zeros
+
+si_int __ffsdi2(di_int a); // find least significant 1 bit
+si_int __ffsti2(ti_int a); // find least significant 1 bit
+
+si_int __paritysi2(si_int a); // bit parity
+si_int __paritydi2(di_int a); // bit parity
+si_int __parityti2(ti_int a); // bit parity
+
+si_int __popcountsi2(si_int a); // bit population
+si_int __popcountdi2(di_int a); // bit population
+si_int __popcountti2(ti_int a); // bit population
+
+uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
+uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
+
+// Integral arithmetic
+
+di_int __negdi2 (di_int a); // -a
+ti_int __negti2 (ti_int a); // -a
+di_int __muldi3 (di_int a, di_int b); // a * b
+ti_int __multi3 (ti_int a, ti_int b); // a * b
+si_int __divsi3 (si_int a, si_int b); // a / b signed
+di_int __divdi3 (di_int a, di_int b); // a / b signed
+ti_int __divti3 (ti_int a, ti_int b); // a / b signed
+su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
+du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
+tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
+si_int __modsi3 (si_int a, si_int b); // a % b signed
+di_int __moddi3 (di_int a, di_int b); // a % b signed
+ti_int __modti3 (ti_int a, ti_int b); // a % b signed
+su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
+du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
+tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
+du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned
+tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
+su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
+si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
+
+
+
+// Integral arithmetic with trapping overflow
+
+si_int __absvsi2(si_int a); // abs(a)
+di_int __absvdi2(di_int a); // abs(a)
+ti_int __absvti2(ti_int a); // abs(a)
+
+si_int __negvsi2(si_int a); // -a
+di_int __negvdi2(di_int a); // -a
+ti_int __negvti2(ti_int a); // -a
+
+si_int __addvsi3(si_int a, si_int b); // a + b
+di_int __addvdi3(di_int a, di_int b); // a + b
+ti_int __addvti3(ti_int a, ti_int b); // a + b
+
+si_int __subvsi3(si_int a, si_int b); // a - b
+di_int __subvdi3(di_int a, di_int b); // a - b
+ti_int __subvti3(ti_int a, ti_int b); // a - b
+
+si_int __mulvsi3(si_int a, si_int b); // a * b
+di_int __mulvdi3(di_int a, di_int b); // a * b
+ti_int __mulvti3(ti_int a, ti_int b); // a * b
+
+
+// Integral arithmetic which returns if overflow
+
+si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
+ one if result not in signed range
+
+
+// Integral comparison: a < b -> 0
+// a == b -> 1
+// a > b -> 2
+
+si_int __cmpdi2 (di_int a, di_int b);
+si_int __cmpti2 (ti_int a, ti_int b);
+si_int __ucmpdi2(du_int a, du_int b);
+si_int __ucmpti2(tu_int a, tu_int b);
+
+// Integral / floating point conversion
+
+di_int __fixsfdi( float a);
+di_int __fixdfdi( double a);
+di_int __fixxfdi(long double a);
+
+ti_int __fixsfti( float a);
+ti_int __fixdfti( double a);
+ti_int __fixxfti(long double a);
+uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
+
+su_int __fixunssfsi( float a);
+su_int __fixunsdfsi( double a);
+su_int __fixunsxfsi(long double a);
+
+du_int __fixunssfdi( float a);
+du_int __fixunsdfdi( double a);
+du_int __fixunsxfdi(long double a);
+
+tu_int __fixunssfti( float a);
+tu_int __fixunsdfti( double a);
+tu_int __fixunsxfti(long double a);
+uint64_t __fixunstfdi(long double input); // ppc only
+
+float __floatdisf(di_int a);
+double __floatdidf(di_int a);
+long double __floatdixf(di_int a);
+long double __floatditf(int64_t a); // ppc only
+
+float __floattisf(ti_int a);
+double __floattidf(ti_int a);
+long double __floattixf(ti_int a);
+
+float __floatundisf(du_int a);
+double __floatundidf(du_int a);
+long double __floatundixf(du_int a);
+long double __floatunditf(uint64_t a); // ppc only
+
+float __floatuntisf(tu_int a);
+double __floatuntidf(tu_int a);
+long double __floatuntixf(tu_int a);
+
+// Floating point raised to integer power
+
+float __powisf2( float a, si_int b); // a ^ b
+double __powidf2( double a, si_int b); // a ^ b
+long double __powixf2(long double a, si_int b); // a ^ b
+long double __powitf2(long double a, si_int b); // ppc only, a ^ b
+
+// Complex arithmetic
+
+// (a + ib) * (c + id)
+
+ float _Complex __mulsc3( float a, float b, float c, float d);
+ double _Complex __muldc3(double a, double b, double c, double d);
+long double _Complex __mulxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __multc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+// (a + ib) / (c + id)
+
+ float _Complex __divsc3( float a, float b, float c, float d);
+ double _Complex __divdc3(double a, double b, double c, double d);
+long double _Complex __divxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __divtc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+
+// Runtime support
+
+// __clear_cache() is used to tell process that new instructions have been
+// written to an address range. Necessary on processors that do not have
+// a unified instruction and data cache.
+void __clear_cache(void* start, void* end);
+
+// __enable_execute_stack() is used with nested functions when a trampoline
+// function is written onto the stack and that page range needs to be made
+// executable.
+void __enable_execute_stack(void* addr);
+
+// __gcc_personality_v0() is normally only called by the system unwinder.
+// C code (as opposed to C++) normally does not need a personality function
+// because there are no catch clauses or destructors to be run. But there
+// is a C language extension __attribute__((cleanup(func))) which marks local
+// variables as needing the cleanup function "func" to be run when the
+// variable goes out of scope. That includes when an exception is thrown,
+// so a personality handler is needed.
+_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ _Unwind_Context_t context);
+
+// for use with some implementations of assert() in <assert.h>
+void __eprintf(const char* format, const char* assertion_expression,
+ const char* line, const char* file);
+
+// for systems with emulated thread local storage
+void* __emutls_get_address(struct __emutls_control*);
+
+
+// Power PC specific functions
+
+// There is no C interface to the saveFP/restFP functions. They are helper
+// functions called by the prolog and epilog of functions that need to save
+// a number of non-volatile float point registers.
+saveFP
+restFP
+
+// PowerPC has a standard template for trampoline functions. This function
+// generates a custom trampoline function with the specific realFunc
+// and localsPtr values.
+void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr);
+
+// adds two 128-bit double-double precision values ( x + y )
+long double __gcc_qadd(long double x, long double y);
+
+// subtracts two 128-bit double-double precision values ( x - y )
+long double __gcc_qsub(long double x, long double y);
+
+// multiples two 128-bit double-double precision values ( x * y )
+long double __gcc_qmul(long double x, long double y);
+
+// divides two 128-bit double-double precision values ( x / y )
+long double __gcc_qdiv(long double a, long double b);
+
+
+// ARM specific functions
+
+// There is no C interface to the switch* functions. These helper functions
+// are only needed by Thumb1 code for efficient switch table generation.
+switch16
+switch32
+switch8
+switchu8
+
+// There is no C interface to the *_vfp_d8_d15_regs functions. There are
+// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
+// SJLJ for exceptions, each function with a catch clause or destuctors needs
+// to save and restore all registers in it prolog and epliog. But there is
+// no way to access vector and high float registers from thumb1 code, so the
+// compiler must add call outs to these helper functions in the prolog and
+// epilog.
+restore_vfp_d8_d15_regs
+save_vfp_d8_d15_regs
+
+
+// Note: long ago ARM processors did not have floating point hardware support.
+// Floating point was done in software and floating point parameters were
+// passed in integer registers. When hardware support was added for floating
+// point, new *vfp functions were added to do the same operations but with
+// floating point parameters in floating point registers.
+
+// Undocumented functions
+
+float __addsf3vfp(float a, float b); // Appears to return a + b
+double __adddf3vfp(double a, double b); // Appears to return a + b
+float __divsf3vfp(float a, float b); // Appears to return a / b
+double __divdf3vfp(double a, double b); // Appears to return a / b
+int __eqsf2vfp(float a, float b); // Appears to return one
+ // iff a == b and neither is NaN.
+int __eqdf2vfp(double a, double b); // Appears to return one
+ // iff a == b and neither is NaN.
+double __extendsfdf2vfp(float a); // Appears to convert from
+ // float to double.
+int __fixdfsivfp(double a); // Appears to convert from
+ // double to int.
+int __fixsfsivfp(float a); // Appears to convert from
+ // float to int.
+unsigned int __fixunssfsivfp(float a); // Appears to convert from
+ // float to unsigned int.
+unsigned int __fixunsdfsivfp(double a); // Appears to convert from
+ // double to unsigned int.
+double __floatsidfvfp(int a); // Appears to convert from
+ // int to double.
+float __floatsisfvfp(int a); // Appears to convert from
+ // int to float.
+double __floatunssidfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to double.
+float __floatunssisfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to float.
+int __gedf2vfp(double a, double b); // Appears to return __gedf2
+ // (a >= b)
+int __gesf2vfp(float a, float b); // Appears to return __gesf2
+ // (a >= b)
+int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
+ // (a > b)
+int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
+ // (a > b)
+int __ledf2vfp(double a, double b); // Appears to return __ledf2
+ // (a <= b)
+int __lesf2vfp(float a, float b); // Appears to return __lesf2
+ // (a <= b)
+int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
+ // (a < b)
+int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
+ // (a < b)
+double __muldf3vfp(double a, double b); // Appears to return a * b
+float __mulsf3vfp(float a, float b); // Appears to return a * b
+int __nedf2vfp(double a, double b); // Appears to return __nedf2
+ // (a != b)
+double __negdf2vfp(double a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+double __subdf3vfp(double a, double b); // Appears to return a - b
+float __subsf3vfp(float a, float b); // Appears to return a - b
+float __truncdfsf2vfp(double a); // Appears to convert from
+ // double to float.
+int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
+int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
+
+
+Preconditions are listed for each function at the definition when there are any.
+Any preconditions reflect the specification at
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
+
+Assumptions are listed in "int_lib.h", and in individual files. Where possible
+assumptions are checked at compile time.
diff --git a/compiler-rt/lib/builtins/absvdi2.c b/compiler-rt/lib/builtins/absvdi2.c
new file mode 100644
index 0000000..682c235
--- /dev/null
+++ b/compiler-rt/lib/builtins/absvdi2.c
@@ -0,0 +1,29 @@
+/*===-- absvdi2.c - Implement __absvdi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * This file implements __absvdi2 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: absolute value */
+
+/* Effects: aborts if abs(x) < 0 */
+
+COMPILER_RT_ABI di_int
+__absvdi2(di_int a)
+{
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ if (a == ((di_int)1 << (N-1)))
+ compilerrt_abort();
+ const di_int t = a >> (N - 1);
+ return (a ^ t) - t;
+}
diff --git a/compiler-rt/lib/builtins/absvsi2.c b/compiler-rt/lib/builtins/absvsi2.c
new file mode 100644
index 0000000..4812af8
--- /dev/null
+++ b/compiler-rt/lib/builtins/absvsi2.c
@@ -0,0 +1,29 @@
+/* ===-- absvsi2.c - Implement __absvsi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __absvsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: absolute value */
+
+/* Effects: aborts if abs(x) < 0 */
+
+COMPILER_RT_ABI si_int
+__absvsi2(si_int a)
+{
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ if (a == (1 << (N-1)))
+ compilerrt_abort();
+ const si_int t = a >> (N - 1);
+ return (a ^ t) - t;
+}
diff --git a/compiler-rt/lib/builtins/absvti2.c b/compiler-rt/lib/builtins/absvti2.c
new file mode 100644
index 0000000..7927770
--- /dev/null
+++ b/compiler-rt/lib/builtins/absvti2.c
@@ -0,0 +1,34 @@
+/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __absvti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: absolute value */
+
+/* Effects: aborts if abs(x) < 0 */
+
+COMPILER_RT_ABI ti_int
+__absvti2(ti_int a)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ if (a == ((ti_int)1 << (N-1)))
+ compilerrt_abort();
+ const ti_int s = a >> (N - 1);
+ return (a ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
+
diff --git a/compiler-rt/lib/builtins/adddf3.c b/compiler-rt/lib/builtins/adddf3.c
new file mode 100644
index 0000000..8b7aae0
--- /dev/null
+++ b/compiler-rt/lib/builtins/adddf3.c
@@ -0,0 +1,22 @@
+//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(dadd, adddf3)
+
+COMPILER_RT_ABI double __adddf3(double a, double b){
+ return __addXf3__(a, b);
+}
diff --git a/compiler-rt/lib/builtins/addsf3.c b/compiler-rt/lib/builtins/addsf3.c
new file mode 100644
index 0000000..0f5d6ea
--- /dev/null
+++ b/compiler-rt/lib/builtins/addsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(fadd, addsf3)
+
+COMPILER_RT_ABI float __addsf3(float a, float b) {
+ return __addXf3__(a, b);
+}
diff --git a/compiler-rt/lib/builtins/addtf3.c b/compiler-rt/lib/builtins/addtf3.c
new file mode 100644
index 0000000..e4bbe02
--- /dev/null
+++ b/compiler-rt/lib/builtins/addtf3.c
@@ -0,0 +1,25 @@
+//===-- lib/addtf3.c - Quad-precision addition --------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_add_impl.inc"
+
+COMPILER_RT_ABI long double __addtf3(long double a, long double b){
+ return __addXf3__(a, b);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/addvdi3.c b/compiler-rt/lib/builtins/addvdi3.c
new file mode 100644
index 0000000..0da3894
--- /dev/null
+++ b/compiler-rt/lib/builtins/addvdi3.c
@@ -0,0 +1,36 @@
+/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __addvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI di_int
+__addvdi3(di_int a, di_int b)
+{
+ di_int s = (du_int) a + (du_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/compiler-rt/lib/builtins/addvsi3.c b/compiler-rt/lib/builtins/addvsi3.c
new file mode 100644
index 0000000..94ca726
--- /dev/null
+++ b/compiler-rt/lib/builtins/addvsi3.c
@@ -0,0 +1,36 @@
+/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __addvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI si_int
+__addvsi3(si_int a, si_int b)
+{
+ si_int s = (su_int) a + (su_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/compiler-rt/lib/builtins/addvti3.c b/compiler-rt/lib/builtins/addvti3.c
new file mode 100644
index 0000000..c224de6
--- /dev/null
+++ b/compiler-rt/lib/builtins/addvti3.c
@@ -0,0 +1,40 @@
+/* ===-- addvti3.c - Implement __addvti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __addvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI ti_int
+__addvti3(ti_int a, ti_int b)
+{
+ ti_int s = (tu_int) a + (tu_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/apple_versioning.c b/compiler-rt/lib/builtins/apple_versioning.c
new file mode 100644
index 0000000..3797a1a
--- /dev/null
+++ b/compiler-rt/lib/builtins/apple_versioning.c
@@ -0,0 +1,350 @@
+/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+
+#if __APPLE__
+ #include <Availability.h>
+
+ #if __IPHONE_OS_VERSION_MIN_REQUIRED
+ #define NOT_HERE_BEFORE_10_6(sym)
+ #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \
+ extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \
+ extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \
+ extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp50 = 0;
+ #else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+ #endif
+
+
+/* Symbols in libSystem.dylib in 10.6 and later,
+ * but are in libgcc_s.dylib in earlier versions
+ */
+
+NOT_HERE_BEFORE_10_6(__absvdi2)
+NOT_HERE_BEFORE_10_6(__absvsi2)
+NOT_HERE_BEFORE_10_6(__absvti2)
+NOT_HERE_BEFORE_10_6(__addvdi3)
+NOT_HERE_BEFORE_10_6(__addvsi3)
+NOT_HERE_BEFORE_10_6(__addvti3)
+NOT_HERE_BEFORE_10_6(__ashldi3)
+NOT_HERE_BEFORE_10_6(__ashlti3)
+NOT_HERE_BEFORE_10_6(__ashrdi3)
+NOT_HERE_BEFORE_10_6(__ashrti3)
+NOT_HERE_BEFORE_10_6(__clear_cache)
+NOT_HERE_BEFORE_10_6(__clzdi2)
+NOT_HERE_BEFORE_10_6(__clzsi2)
+NOT_HERE_BEFORE_10_6(__clzti2)
+NOT_HERE_BEFORE_10_6(__cmpdi2)
+NOT_HERE_BEFORE_10_6(__cmpti2)
+NOT_HERE_BEFORE_10_6(__ctzdi2)
+NOT_HERE_BEFORE_10_6(__ctzsi2)
+NOT_HERE_BEFORE_10_6(__ctzti2)
+NOT_HERE_BEFORE_10_6(__divdc3)
+NOT_HERE_BEFORE_10_6(__divdi3)
+NOT_HERE_BEFORE_10_6(__divsc3)
+NOT_HERE_BEFORE_10_6(__divtc3)
+NOT_HERE_BEFORE_10_6(__divti3)
+NOT_HERE_BEFORE_10_6(__divxc3)
+NOT_HERE_BEFORE_10_6(__enable_execute_stack)
+NOT_HERE_BEFORE_10_6(__ffsdi2)
+NOT_HERE_BEFORE_10_6(__ffsti2)
+NOT_HERE_BEFORE_10_6(__fixdfdi)
+NOT_HERE_BEFORE_10_6(__fixdfti)
+NOT_HERE_BEFORE_10_6(__fixsfdi)
+NOT_HERE_BEFORE_10_6(__fixsfti)
+NOT_HERE_BEFORE_10_6(__fixtfdi)
+NOT_HERE_BEFORE_10_6(__fixunsdfdi)
+NOT_HERE_BEFORE_10_6(__fixunsdfsi)
+NOT_HERE_BEFORE_10_6(__fixunsdfti)
+NOT_HERE_BEFORE_10_6(__fixunssfdi)
+NOT_HERE_BEFORE_10_6(__fixunssfsi)
+NOT_HERE_BEFORE_10_6(__fixunssfti)
+NOT_HERE_BEFORE_10_6(__fixunstfdi)
+NOT_HERE_BEFORE_10_6(__fixunsxfdi)
+NOT_HERE_BEFORE_10_6(__fixunsxfsi)
+NOT_HERE_BEFORE_10_6(__fixunsxfti)
+NOT_HERE_BEFORE_10_6(__fixxfdi)
+NOT_HERE_BEFORE_10_6(__fixxfti)
+NOT_HERE_BEFORE_10_6(__floatdidf)
+NOT_HERE_BEFORE_10_6(__floatdisf)
+NOT_HERE_BEFORE_10_6(__floatditf)
+NOT_HERE_BEFORE_10_6(__floatdixf)
+NOT_HERE_BEFORE_10_6(__floattidf)
+NOT_HERE_BEFORE_10_6(__floattisf)
+NOT_HERE_BEFORE_10_6(__floattixf)
+NOT_HERE_BEFORE_10_6(__floatundidf)
+NOT_HERE_BEFORE_10_6(__floatundisf)
+NOT_HERE_BEFORE_10_6(__floatunditf)
+NOT_HERE_BEFORE_10_6(__floatundixf)
+NOT_HERE_BEFORE_10_6(__floatuntidf)
+NOT_HERE_BEFORE_10_6(__floatuntisf)
+NOT_HERE_BEFORE_10_6(__floatuntixf)
+NOT_HERE_BEFORE_10_6(__gcc_personality_v0)
+NOT_HERE_BEFORE_10_6(__lshrdi3)
+NOT_HERE_BEFORE_10_6(__lshrti3)
+NOT_HERE_BEFORE_10_6(__moddi3)
+NOT_HERE_BEFORE_10_6(__modti3)
+NOT_HERE_BEFORE_10_6(__muldc3)
+NOT_HERE_BEFORE_10_6(__muldi3)
+NOT_HERE_BEFORE_10_6(__mulsc3)
+NOT_HERE_BEFORE_10_6(__multc3)
+NOT_HERE_BEFORE_10_6(__multi3)
+NOT_HERE_BEFORE_10_6(__mulvdi3)
+NOT_HERE_BEFORE_10_6(__mulvsi3)
+NOT_HERE_BEFORE_10_6(__mulvti3)
+NOT_HERE_BEFORE_10_6(__mulxc3)
+NOT_HERE_BEFORE_10_6(__negdi2)
+NOT_HERE_BEFORE_10_6(__negti2)
+NOT_HERE_BEFORE_10_6(__negvdi2)
+NOT_HERE_BEFORE_10_6(__negvsi2)
+NOT_HERE_BEFORE_10_6(__negvti2)
+NOT_HERE_BEFORE_10_6(__paritydi2)
+NOT_HERE_BEFORE_10_6(__paritysi2)
+NOT_HERE_BEFORE_10_6(__parityti2)
+NOT_HERE_BEFORE_10_6(__popcountdi2)
+NOT_HERE_BEFORE_10_6(__popcountsi2)
+NOT_HERE_BEFORE_10_6(__popcountti2)
+NOT_HERE_BEFORE_10_6(__powidf2)
+NOT_HERE_BEFORE_10_6(__powisf2)
+NOT_HERE_BEFORE_10_6(__powitf2)
+NOT_HERE_BEFORE_10_6(__powixf2)
+NOT_HERE_BEFORE_10_6(__subvdi3)
+NOT_HERE_BEFORE_10_6(__subvsi3)
+NOT_HERE_BEFORE_10_6(__subvti3)
+NOT_HERE_BEFORE_10_6(__ucmpdi2)
+NOT_HERE_BEFORE_10_6(__ucmpti2)
+NOT_HERE_BEFORE_10_6(__udivdi3)
+NOT_HERE_BEFORE_10_6(__udivmoddi4)
+NOT_HERE_BEFORE_10_6(__udivmodti4)
+NOT_HERE_BEFORE_10_6(__udivti3)
+NOT_HERE_BEFORE_10_6(__umoddi3)
+NOT_HERE_BEFORE_10_6(__umodti3)
+
+
+#if __ppc__
+NOT_HERE_BEFORE_10_6(__gcc_qadd)
+NOT_HERE_BEFORE_10_6(__gcc_qdiv)
+NOT_HERE_BEFORE_10_6(__gcc_qmul)
+NOT_HERE_BEFORE_10_6(__gcc_qsub)
+NOT_HERE_BEFORE_10_6(__trampoline_setup)
+#endif /* __ppc__ */
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8)
+
+
+#if __arm__ && __DYNAMIC__
+ #define NOT_HERE_UNTIL_AFTER_4_3(sym) \
+ extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp1 = 0; \
+ extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp2 = 0; \
+ extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0;
+
+NOT_HERE_UNTIL_AFTER_4_3(__absvdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__absvsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__adddf3)
+NOT_HERE_UNTIL_AFTER_4_3(__adddf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__addsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__addsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__addvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__addvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ashldi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ashrdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__bswapdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__bswapsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__clzdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__clzsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__cmpdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__ctzdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__ctzsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__divdc3)
+NOT_HERE_UNTIL_AFTER_4_3(__divdf3)
+NOT_HERE_UNTIL_AFTER_4_3(__divdf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__divdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsc3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__divsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__divsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__eqdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__eqdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__eqsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__eqsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ffsdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixdfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixsfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfdi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsi)
+NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsivfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatdidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatdisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsidfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatsisfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatundidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatundisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunsidf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunsisf)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunssidfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__floatunssisfvfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gedf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gedf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gtdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gtdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__gtsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__gtsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ledf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ledf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__lesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__lesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__lshrdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__ltdf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ltdf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ltsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__ltsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__moddi3)
+NOT_HERE_UNTIL_AFTER_4_3(__modsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldc3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldf3)
+NOT_HERE_UNTIL_AFTER_4_3(__muldf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__muldi3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsc3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__mulvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__mulvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__nedf2)
+NOT_HERE_UNTIL_AFTER_4_3(__nedf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__negdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__negvdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__negvsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__nesf2)
+NOT_HERE_UNTIL_AFTER_4_3(__nesf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__paritydi2)
+NOT_HERE_UNTIL_AFTER_4_3(__paritysi2)
+NOT_HERE_UNTIL_AFTER_4_3(__popcountdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__popcountsi2)
+NOT_HERE_UNTIL_AFTER_4_3(__powidf2)
+NOT_HERE_UNTIL_AFTER_4_3(__powisf2)
+NOT_HERE_UNTIL_AFTER_4_3(__subdf3)
+NOT_HERE_UNTIL_AFTER_4_3(__subdf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__subsf3)
+NOT_HERE_UNTIL_AFTER_4_3(__subsf3vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__subvdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__subvsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__ucmpdi2)
+NOT_HERE_UNTIL_AFTER_4_3(__udivdi3)
+NOT_HERE_UNTIL_AFTER_4_3(__udivmoddi4)
+NOT_HERE_UNTIL_AFTER_4_3(__udivsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__umoddi3)
+NOT_HERE_UNTIL_AFTER_4_3(__umodsi3)
+NOT_HERE_UNTIL_AFTER_4_3(__unorddf2)
+NOT_HERE_UNTIL_AFTER_4_3(__unorddf2vfp)
+NOT_HERE_UNTIL_AFTER_4_3(__unordsf2)
+NOT_HERE_UNTIL_AFTER_4_3(__unordsf2vfp)
+
+NOT_HERE_UNTIL_AFTER_4_3(__divmodsi4)
+NOT_HERE_UNTIL_AFTER_4_3(__udivmodsi4)
+#endif // __arm__ && __DYNAMIC__
+
+
+
+
+
+#else /* !__APPLE__ */
+
+extern int avoid_empty_file;
+
+#endif /* !__APPLE__*/
diff --git a/compiler-rt/lib/builtins/arm/Makefile.mk b/compiler-rt/lib/builtins/arm/Makefile.mk
new file mode 100644
index 0000000..ed2e832
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := armv5 armv6 armv7 armv7k armv7m armv7em armv7s
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/arm/adddf3vfp.S b/compiler-rt/lib/builtins/arm/adddf3vfp.S
new file mode 100644
index 0000000..2825ae9
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/adddf3vfp.S
@@ -0,0 +1,26 @@
+//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// double __adddf3vfp(double a, double b) { return a + b; }
+//
+// Adds two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vadd.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__adddf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/addsf3vfp.S b/compiler-rt/lib/builtins/arm/addsf3vfp.S
new file mode 100644
index 0000000..bff5a7e
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/addsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __addsf3vfp(float a, float b);
+//
+// Adds two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed in GPRs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vadd.f32 s14, s14, s15
+ vmov r0, s14 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__addsf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S b/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
new file mode 100644
index 0000000..036a6f5
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
@@ -0,0 +1,96 @@
+//===-- aeabi_cdcmp.S - EABI cdcmp* implementation ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error big endian support not implemented
+#endif
+
+#define APSR_Z (1 << 30)
+#define APSR_C (1 << 29)
+
+// void __aeabi_cdcmpeq(double a, double b) {
+// if (isnan(a) || isnan(b)) {
+// Z = 0; C = 1;
+// } else {
+// __aeabi_cdcmple(a, b);
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
+ push {r0-r3, lr}
+ bl __aeabi_cdcmpeq_check_nan
+ cmp r0, #1
+ pop {r0-r3, lr}
+
+ // NaN has been ruled out, so __aeabi_cdcmple can't trap
+ bne __aeabi_cdcmple
+
+ msr CPSR_f, #APSR_C
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
+
+
+// void __aeabi_cdcmple(double a, double b) {
+// if (__aeabi_dcmplt(a, b)) {
+// Z = 0; C = 0;
+// } else if (__aeabi_dcmpeq(a, b)) {
+// Z = 1; C = 1;
+// } else {
+// Z = 0; C = 1;
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
+ // Per the RTABI, this function must preserve r0-r11.
+ // Save lr in the same instruction for compactness
+ push {r0-r3, lr}
+
+ bl __aeabi_dcmplt
+ cmp r0, #1
+ moveq ip, #0
+ beq 1f
+
+ ldm sp, {r0-r3}
+ bl __aeabi_dcmpeq
+ cmp r0, #1
+ moveq ip, #(APSR_C | APSR_Z)
+ movne ip, #(APSR_C)
+
+1:
+ msr CPSR_f, ip
+ pop {r0-r3}
+ POP_PC()
+END_COMPILERRT_FUNCTION(__aeabi_cdcmple)
+
+// int __aeabi_cdrcmple(double a, double b) {
+// return __aeabi_cdcmple(b, a);
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
+ // Swap r0 and r2
+ mov ip, r0
+ mov r0, r2
+ mov r2, ip
+
+ // Swap r1 and r3
+ mov ip, r1
+ mov r1, r3
+ mov r3, ip
+
+ b __aeabi_cdcmple
+END_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
+
diff --git a/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c b/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c
new file mode 100644
index 0000000..577f6b2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c
@@ -0,0 +1,16 @@
+//===-- lib/arm/aeabi_cdcmpeq_helper.c - Helper for cdcmpeq ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+__attribute__((pcs("aapcs")))
+__attribute__((visibility("hidden")))
+int __aeabi_cdcmpeq_check_nan(double a, double b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
+}
diff --git a/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S b/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S
new file mode 100644
index 0000000..43594e5
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S
@@ -0,0 +1,91 @@
+//===-- aeabi_cfcmp.S - EABI cfcmp* implementation ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error big endian support not implemented
+#endif
+
+#define APSR_Z (1 << 30)
+#define APSR_C (1 << 29)
+
+// void __aeabi_cfcmpeq(float a, float b) {
+// if (isnan(a) || isnan(b)) {
+// Z = 0; C = 1;
+// } else {
+// __aeabi_cfcmple(a, b);
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
+ push {r0-r3, lr}
+ bl __aeabi_cfcmpeq_check_nan
+ cmp r0, #1
+ pop {r0-r3, lr}
+
+ // NaN has been ruled out, so __aeabi_cfcmple can't trap
+ bne __aeabi_cfcmple
+
+ msr CPSR_f, #APSR_C
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
+
+
+// void __aeabi_cfcmple(float a, float b) {
+// if (__aeabi_fcmplt(a, b)) {
+// Z = 0; C = 0;
+// } else if (__aeabi_fcmpeq(a, b)) {
+// Z = 1; C = 1;
+// } else {
+// Z = 0; C = 1;
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
+ // Per the RTABI, this function must preserve r0-r11.
+ // Save lr in the same instruction for compactness
+ push {r0-r3, lr}
+
+ bl __aeabi_fcmplt
+ cmp r0, #1
+ moveq ip, #0
+ beq 1f
+
+ ldm sp, {r0-r3}
+ bl __aeabi_fcmpeq
+ cmp r0, #1
+ moveq ip, #(APSR_C | APSR_Z)
+ movne ip, #(APSR_C)
+
+1:
+ msr CPSR_f, ip
+ pop {r0-r3}
+ POP_PC()
+END_COMPILERRT_FUNCTION(__aeabi_cfcmple)
+
+// int __aeabi_cfrcmple(float a, float b) {
+// return __aeabi_cfcmple(b, a);
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
+ // Swap r0 and r1
+ mov ip, r0
+ mov r0, r1
+ mov r1, ip
+
+ b __aeabi_cfcmple
+END_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
+
diff --git a/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c b/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c
new file mode 100644
index 0000000..992e31f
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c
@@ -0,0 +1,16 @@
+//===-- lib/arm/aeabi_cfcmpeq_helper.c - Helper for cdcmpeq ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+__attribute__((pcs("aapcs")))
+__attribute__((visibility("hidden")))
+int __aeabi_cfcmpeq_check_nan(float a, float b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
+}
diff --git a/compiler-rt/lib/builtins/arm/aeabi_dcmp.S b/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
new file mode 100644
index 0000000..310c35b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_dcmp.S - EABI dcmp* implementation ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) {
+// int result = __{eq,lt,le,ge,gt}df2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_DCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond)
+
+DEFINE_AEABI_DCMP(eq)
+DEFINE_AEABI_DCMP(lt)
+DEFINE_AEABI_DCMP(le)
+DEFINE_AEABI_DCMP(ge)
+DEFINE_AEABI_DCMP(gt)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_div0.c b/compiler-rt/lib/builtins/arm/aeabi_div0.c
new file mode 100644
index 0000000..ccc95fa
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_div0.c
@@ -0,0 +1,43 @@
+/* ===-- aeabi_div0.c - ARM Runtime ABI support routines for compiler-rt ---===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements the division by zero helper routines as specified by the
+ * Run-time ABI for the ARM Architecture.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+/*
+ * RTABI 4.3.2 - Division by zero
+ *
+ * The *div0 functions:
+ * - Return the value passed to them as a parameter
+ * - Or, return a fixed value defined by the execution environment (such as 0)
+ * - Or, raise a signal (often SIGFPE) or throw an exception, and do not return
+ *
+ * An application may provide its own implementations of the *div0 functions to
+ * for a particular behaviour from the *div and *divmod functions called out of
+ * line.
+ */
+
+/* provide an unused declaration to pacify pendantic compilation */
+extern unsigned char declaration;
+
+#if defined(__ARM_EABI__)
+int __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_idiv0(int return_value) {
+ return return_value;
+}
+
+long long __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_ldiv0(long long return_value) {
+ return return_value;
+}
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/aeabi_drsub.c b/compiler-rt/lib/builtins/arm/aeabi_drsub.c
new file mode 100644
index 0000000..fc17d5a
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_drsub.c
@@ -0,0 +1,19 @@
+//===-- lib/arm/aeabi_drsub.c - Double-precision subtraction --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "../fp_lib.h"
+
+COMPILER_RT_ABI fp_t
+__aeabi_dsub(fp_t, fp_t);
+
+COMPILER_RT_ABI fp_t
+__aeabi_drsub(fp_t a, fp_t b) {
+ return __aeabi_dsub(b, a);
+}
diff --git a/compiler-rt/lib/builtins/arm/aeabi_fcmp.S b/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
new file mode 100644
index 0000000..55f49a2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_fcmp.S - EABI fcmp* implementation ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) {
+// int result = __{eq,lt,le,ge,gt}sf2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_FCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond)
+
+DEFINE_AEABI_FCMP(eq)
+DEFINE_AEABI_FCMP(lt)
+DEFINE_AEABI_FCMP(le)
+DEFINE_AEABI_FCMP(ge)
+DEFINE_AEABI_FCMP(gt)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_frsub.c b/compiler-rt/lib/builtins/arm/aeabi_frsub.c
new file mode 100644
index 0000000..64258dc
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_frsub.c
@@ -0,0 +1,19 @@
+//===-- lib/arm/aeabi_frsub.c - Single-precision subtraction --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "../fp_lib.h"
+
+COMPILER_RT_ABI fp_t
+__aeabi_fsub(fp_t, fp_t);
+
+COMPILER_RT_ABI fp_t
+__aeabi_frsub(fp_t a, fp_t b) {
+ return __aeabi_fsub(b, a);
+}
diff --git a/compiler-rt/lib/builtins/arm/aeabi_idivmod.S b/compiler-rt/lib/builtins/arm/aeabi_idivmod.S
new file mode 100644
index 0000000..384add3
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_idivmod.S
@@ -0,0 +1,28 @@
+//===-- aeabi_idivmod.S - EABI idivmod implementation ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) {
+// int rem, quot;
+// quot = __divmodsi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
+ push { lr }
+ sub sp, sp, #4
+ mov r2, sp
+ bl SYMBOL_NAME(__divmodsi4)
+ ldr r1, [sp]
+ add sp, sp, #4
+ pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_idivmod)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S b/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S
new file mode 100644
index 0000000..ad06f1d
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S
@@ -0,0 +1,31 @@
+//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { int64_t quot, int64_t rem}
+// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
+// int64_t rem, quot;
+// quot = __divmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+ push {r11, lr}
+ sub sp, sp, #16
+ add r12, sp, #8
+ str r12, [sp]
+ bl SYMBOL_NAME(__divmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r11, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_memcmp.S b/compiler-rt/lib/builtins/arm/aeabi_memcmp.S
new file mode 100644
index 0000000..051ce43
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_memcmp.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memcmp.S - EABI memcmp implementation -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
+ b memcmp
+END_COMPILERRT_FUNCTION(__aeabi_memcmp)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_memcpy.S b/compiler-rt/lib/builtins/arm/aeabi_memcpy.S
new file mode 100644
index 0000000..cf02332
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_memcpy.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memcpy.S - EABI memcpy implementation -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
+ b memcpy
+END_COMPILERRT_FUNCTION(__aeabi_memcpy)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_memmove.S b/compiler-rt/lib/builtins/arm/aeabi_memmove.S
new file mode 100644
index 0000000..4dda06f
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_memmove.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memmove.S - EABI memmove implementation --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// void __aeabi_memmove(void *dest, void *src, size_t n) { memmove(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
+ b memmove
+END_COMPILERRT_FUNCTION(__aeabi_memmove)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_memset.S b/compiler-rt/lib/builtins/arm/aeabi_memset.S
new file mode 100644
index 0000000..c8b49c7
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_memset.S
@@ -0,0 +1,34 @@
+//===-- aeabi_memset.S - EABI memset implementation -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
+// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
+ mov r3, r1
+ mov r1, r2
+ mov r2, r3
+ b memset
+END_COMPILERRT_FUNCTION(__aeabi_memset)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
+
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
+ mov r2, r1
+ mov r1, #0
+ b memset
+END_COMPILERRT_FUNCTION(__aeabi_memclr)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
+
diff --git a/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S b/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S
new file mode 100644
index 0000000..8ea474d
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S
@@ -0,0 +1,29 @@
+//===-- aeabi_uidivmod.S - EABI uidivmod implementation -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { unsigned quot, unsigned rem}
+// __aeabi_uidivmod(unsigned numerator, unsigned denominator) {
+// unsigned rem, quot;
+// quot = __udivmodsi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
+ push { lr }
+ sub sp, sp, #4
+ mov r2, sp
+ bl SYMBOL_NAME(__udivmodsi4)
+ ldr r1, [sp]
+ add sp, sp, #4
+ pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_uidivmod)
diff --git a/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S b/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S
new file mode 100644
index 0000000..4e1f8e2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S
@@ -0,0 +1,31 @@
+//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { uint64_t quot, uint64_t rem}
+// __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) {
+// uint64_t rem, quot;
+// quot = __udivmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
+ push {r11, lr}
+ sub sp, sp, #16
+ add r12, sp, #8
+ str r12, [sp]
+ bl SYMBOL_NAME(__udivmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r11, pc}
+END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
diff --git a/compiler-rt/lib/builtins/arm/bswapdi2.S b/compiler-rt/lib/builtins/arm/bswapdi2.S
new file mode 100644
index 0000000..86f3bba
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/bswapdi2.S
@@ -0,0 +1,47 @@
+//===------- bswapdi2 - Implement bswapdi2 --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+//
+// extern uint64_t __bswapdi2(uint64_t);
+//
+// Reverse all the bytes in a 64-bit integer.
+//
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
+#endif
+#if __ARM_ARCH < 6
+ // before armv6 does not have "rev" instruction
+ // r2 = rev(r0)
+ eor r2, r0, r0, ror #16
+ bic r2, r2, #0xff0000
+ mov r2, r2, lsr #8
+ eor r2, r2, r0, ror #8
+ // r0 = rev(r1)
+ eor r0, r1, r1, ror #16
+ bic r0, r0, #0xff0000
+ mov r0, r0, lsr #8
+ eor r0, r0, r1, ror #8
+#else
+ rev r2, r0 // r2 = rev(r0)
+ rev r0, r1 // r0 = rev(r1)
+#endif
+ mov r1, r2 // r1 = r2 = rev(r0)
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapdi2)
diff --git a/compiler-rt/lib/builtins/arm/bswapsi2.S b/compiler-rt/lib/builtins/arm/bswapsi2.S
new file mode 100644
index 0000000..59ba815
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/bswapsi2.S
@@ -0,0 +1,39 @@
+//===------- bswapsi2 - Implement bswapsi2 --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+//
+// extern uint32_t __bswapsi2(uint32_t);
+//
+// Reverse all the bytes in a 32-bit integer.
+//
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
+#endif
+#if __ARM_ARCH < 6
+ // before armv6 does not have "rev" instruction
+ eor r1, r0, r0, ror #16
+ bic r1, r1, #0xff0000
+ mov r1, r1, lsr #8
+ eor r0, r1, r0, ror #8
+#else
+ rev r0, r0
+#endif
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapsi2)
diff --git a/compiler-rt/lib/builtins/arm/clzdi2.S b/compiler-rt/lib/builtins/arm/clzdi2.S
new file mode 100644
index 0000000..a55abac
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/clzdi2.S
@@ -0,0 +1,97 @@
+/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements count leading zeros for 64bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__clzdi2)
+#endif
+#ifdef __ARM_FEATURE_CLZ
+#ifdef __ARMEB__
+ cmp r0, 0
+ itee ne
+ clzne r0, r0
+ clzeq r0, r1
+ addeq r0, r0, 32
+#else
+ cmp r1, 0
+ itee ne
+ clzne r0, r1
+ clzeq r0, r0
+ addeq r0, r0, 32
+#endif
+ JMP(lr)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: upper half of n, overwritten after check
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+#ifdef __ARMEB__
+ cmp r0, 0
+ moveq r0, r1
+#else
+ cmp r1, 0
+ movne r0, r1
+#endif
+ movne r1, 1
+ moveq r1, 33
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzdi2)
diff --git a/compiler-rt/lib/builtins/arm/clzsi2.S b/compiler-rt/lib/builtins/arm/clzsi2.S
new file mode 100644
index 0000000..1cd379b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/clzsi2.S
@@ -0,0 +1,76 @@
+/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements count leading zeros for 32bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__clzsi2)
+#endif
+#ifdef __ARM_FEATURE_CLZ
+ clz r0, r0
+ JMP(lr)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+ mov r1, 1
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzsi2)
diff --git a/compiler-rt/lib/builtins/arm/comparesf2.S b/compiler-rt/lib/builtins/arm/comparesf2.S
new file mode 100644
index 0000000..cf71d36
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/comparesf2.S
@@ -0,0 +1,148 @@
+//===-- comparesf2.S - Implement single-precision soft-float comparisons --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the following soft-fp_t comparison routines:
+//
+// __eqsf2 __gesf2 __unordsf2
+// __lesf2 __gtsf2
+// __ltsf2
+// __nesf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, with multiple names.
+//
+// The routines behave as follows:
+//
+// __lesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordsf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+.syntax unified
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqsf2)
+ // Make copies of a and b with the sign bit shifted off the top. These will
+ // be used to detect zeros and NaNs.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+
+ // We do the comparison in three stages (ignoring NaN values for the time
+ // being). First, we orr the absolute values of a and b; this sets the Z
+ // flag if both a and b are zero (of either sign). The shift of r3 doesn't
+ // effect this at all, but it *does* make sure that the C flag is clear for
+ // the subsequent operations.
+ orrs r12, r2, r3, lsr #1
+
+ // Next, we check if a and b have the same or different signs. If they have
+ // opposite signs, this eor will set the N flag.
+ it ne
+ eorsne r12, r0, r1
+
+ // If a and b are equal (either both zeros or bit identical; again, we're
+ // ignoring NaNs for now), this subtract will zero out r0. If they have the
+ // same sign, the flags are updated as they would be for a comparison of the
+ // absolute values of a and b.
+ it pl
+ subspl r0, r2, r3
+
+ // If a is smaller in magnitude than b and both have the same sign, place
+ // the negation of the sign of b in r0. Thus, if both are negative and
+ // a > b, this sets r0 to 0; if both are positive and a < b, this sets
+ // r0 to -1.
+ //
+ // This is also done if a and b have opposite signs and are not both zero,
+ // because in that case the subtract was not performed and the C flag is
+ // still clear from the shift argument in orrs; if a is positive and b
+ // negative, this places 0 in r0; if a is negative and b positive, -1 is
+ // placed in r0.
+ it lo
+ mvnlo r0, r1, asr #31
+
+ // If a is greater in magnitude than b and both have the same sign, place
+ // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
+ // in r0, which is the desired result. Conversely, if both are positive
+ // and a > b, zero is placed in r0.
+ it hi
+ movhi r0, r1, asr #31
+
+ // If you've been keeping track, at this point r0 contains -1 if a < b and
+ // 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
+ // If a == b, then the Z flag is set, so we can get the correct final value
+ // into r0 by simply or'ing with 1 if Z is clear.
+ it ne
+ orrne r0, r0, #1
+
+ // Finally, we need to deal with NaNs. If either argument is NaN, replace
+ // the value in r0 with 1.
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2)
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtsf2)
+ // Identical to the preceding except in that we return -1 for NaN values.
+ // Given that the two paths share so much code, one might be tempted to
+ // unify them; however, the extra code needed to do so makes the code size
+ // to performance tradeoff very hard to justify for such small functions.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ orrs r12, r2, r3, lsr #1
+ it ne
+ eorsne r12, r0, r1
+ it pl
+ subspl r0, r2, r3
+ it lo
+ mvnlo r0, r1, asr #31
+ it hi
+ movhi r0, r1, asr #31
+ it ne
+ orrne r0, r0, #1
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #-1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__gtsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unordsf2)
+ // Return 1 for NaN values, 0 otherwise.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ mov r0, #0
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__unordsf2)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)
diff --git a/compiler-rt/lib/builtins/arm/divdf3vfp.S b/compiler-rt/lib/builtins/arm/divdf3vfp.S
new file mode 100644
index 0000000..6eebef1
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/divdf3vfp.S
@@ -0,0 +1,26 @@
+//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __divdf3vfp(double a, double b);
+//
+// Divides two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vdiv.f64 d5, d6, d7
+ vmov r0, r1, d5 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__divdf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/divmodsi4.S b/compiler-rt/lib/builtins/arm/divmodsi4.S
new file mode 100644
index 0000000..646b9ab
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/divmodsi4.S
@@ -0,0 +1,74 @@
+/*===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __divmodsi4 (32-bit signed integer divide and
+ * modulus) function for the ARM architecture. A naive digit-by-digit
+ * computation is employed for simplicity.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4-r7, lr} ;\
+ add r7, sp, #12
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4-r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ int __divmodsi4(int divident, int divisor, int *remainder)
+@ Calculate the quotient and remainder of the (signed) division. The return
+@ value is the quotient, the remainder is placed in the variable.
+
+ .p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
+#else
+DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divzero)
+ mov r3, r0
+ sdiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
+ ESTABLISH_FRAME
+// Set aside the sign of the quotient and modulus, and the address for the
+// modulus.
+ eor r4, r0, r1
+ mov r5, r0
+ mov r6, r2
+// Take the absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor ip, r0, r0, asr #31
+ eor lr, r1, r1, asr #31
+ sub r0, ip, r0, asr #31
+ sub r1, lr, r1, asr #31
+// Unsigned divmod:
+ bl SYMBOL_NAME(__udivmodsi4)
+// Apply the sign of quotient and modulus
+ ldr r1, [r6]
+ eor r0, r0, r4, asr #31
+ eor r1, r1, r5, asr #31
+ sub r0, r0, r4, asr #31
+ sub r1, r1, r5, asr #31
+ str r1, [r6]
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__divmodsi4)
diff --git a/compiler-rt/lib/builtins/arm/divsf3vfp.S b/compiler-rt/lib/builtins/arm/divsf3vfp.S
new file mode 100644
index 0000000..fdbaebc
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/divsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __divsf3vfp(float a, float b);
+//
+// Divides two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vdiv.f32 s13, s14, s15
+ vmov r0, s13 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__divsf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/divsi3.S b/compiler-rt/lib/builtins/arm/divsi3.S
new file mode 100644
index 0000000..adf8f94
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/divsi3.S
@@ -0,0 +1,65 @@
+/*===-- divsi3.S - 32-bit signed integer divide ---------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __divsi3 (32-bit signed integer divide) function
+ * for the ARM architecture as a wrapper around the unsigned routine.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4, r7, lr} ;\
+ add r7, sp, #4
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4, r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 3
+// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
+
+@ int __divsi3(int divident, int divisor)
+@ Calculate and return the quotient of the (signed) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__divsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1,r1
+ beq LOCAL_LABEL(divzero)
+ sdiv r0, r0, r1
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0,#0
+ bx lr
+#else
+ESTABLISH_FRAME
+// Set aside the sign of the quotient.
+ eor r4, r0, r1
+// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor r2, r0, r0, asr #31
+ eor r3, r1, r1, asr #31
+ sub r0, r2, r0, asr #31
+ sub r1, r3, r1, asr #31
+// abs(a) / abs(b)
+ bl SYMBOL_NAME(__udivsi3)
+// Apply sign of quotient to result and return.
+ eor r0, r0, r4, asr #31
+ sub r0, r0, r4, asr #31
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__divsi3)
diff --git a/compiler-rt/lib/builtins/arm/eqdf2vfp.S b/compiler-rt/lib/builtins/arm/eqdf2vfp.S
new file mode 100644
index 0000000..7f2fbc3
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/eqdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __eqdf2vfp(double a, double b);
+//
+// Returns one iff a == b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ moveq r0, #1 // set result register to 1 if equal
+ movne r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__eqdf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/eqsf2vfp.S b/compiler-rt/lib/builtins/arm/eqsf2vfp.S
new file mode 100644
index 0000000..a318b33
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/eqsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __eqsf2vfp(float a, float b);
+//
+// Returns one iff a == b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ moveq r0, #1 // set result register to 1 if equal
+ movne r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__eqsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S b/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S
new file mode 100644
index 0000000..b998e58
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S
@@ -0,0 +1,26 @@
+//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __extendsfdf2vfp(float a);
+//
+// Converts single precision float to double precision result.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR and a double precision result is returned in R0/R1 pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.f64.f32 d7, s15 // convert single to double
+ vmov r0, r1, d7 // return result in r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__extendsfdf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/fixdfsivfp.S b/compiler-rt/lib/builtins/arm/fixdfsivfp.S
new file mode 100644
index 0000000..e3bd8e0
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/fixdfsivfp.S
@@ -0,0 +1,26 @@
+//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __fixdfsivfp(double a);
+//
+// Converts double precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
+ vmov d7, r0, r1 // load double register from R0/R1
+ vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixdfsivfp)
diff --git a/compiler-rt/lib/builtins/arm/fixsfsivfp.S b/compiler-rt/lib/builtins/arm/fixsfsivfp.S
new file mode 100644
index 0000000..3d0d0f5
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/fixsfsivfp.S
@@ -0,0 +1,26 @@
+//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __fixsfsivfp(float a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixsfsivfp)
diff --git a/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S b/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S
new file mode 100644
index 0000000..35dda5b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S
@@ -0,0 +1,27 @@
+//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern unsigned int __fixunsdfsivfp(double a);
+//
+// Converts double precision float to a 32-bit unsigned int rounding towards
+// zero. All negative values become zero.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
+ vmov d7, r0, r1 // load double register from R0/R1
+ vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixunsdfsivfp)
diff --git a/compiler-rt/lib/builtins/arm/fixunssfsivfp.S b/compiler-rt/lib/builtins/arm/fixunssfsivfp.S
new file mode 100644
index 0000000..5c3a7d9
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/fixunssfsivfp.S
@@ -0,0 +1,27 @@
+//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern unsigned int __fixunssfsivfp(float a);
+//
+// Converts single precision float to a 32-bit unsigned int rounding towards
+// zero. All negative values become zero.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixunssfsivfp)
diff --git a/compiler-rt/lib/builtins/arm/floatsidfvfp.S b/compiler-rt/lib/builtins/arm/floatsidfvfp.S
new file mode 100644
index 0000000..d691849
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/floatsidfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __floatsidfvfp(int a);
+//
+// Converts a 32-bit int to a double precision float.
+// Uses Darwin calling convention where a double precision result is
+// return in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
+ vmov r0, r1, d7 // move d7 to result register pair r0/r1
+ bx lr
+END_COMPILERRT_FUNCTION(__floatsidfvfp)
diff --git a/compiler-rt/lib/builtins/arm/floatsisfvfp.S b/compiler-rt/lib/builtins/arm/floatsisfvfp.S
new file mode 100644
index 0000000..4a0cb39
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/floatsisfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __floatsisfvfp(int a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision result is
+// return in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__floatsisfvfp)
diff --git a/compiler-rt/lib/builtins/arm/floatunssidfvfp.S b/compiler-rt/lib/builtins/arm/floatunssidfvfp.S
new file mode 100644
index 0000000..d92969e
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/floatunssidfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __floatunssidfvfp(unsigned int a);
+//
+// Converts a 32-bit int to a double precision float.
+// Uses Darwin calling convention where a double precision result is
+// return in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
+ vmov r0, r1, d7 // move d7 to result register pair r0/r1
+ bx lr
+END_COMPILERRT_FUNCTION(__floatunssidfvfp)
diff --git a/compiler-rt/lib/builtins/arm/floatunssisfvfp.S b/compiler-rt/lib/builtins/arm/floatunssisfvfp.S
new file mode 100644
index 0000000..f6aeba5
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/floatunssisfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __floatunssisfvfp(unsigned int a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision result is
+// return in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__floatunssisfvfp)
diff --git a/compiler-rt/lib/builtins/arm/gedf2vfp.S b/compiler-rt/lib/builtins/arm/gedf2vfp.S
new file mode 100644
index 0000000..9e23527
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/gedf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __gedf2vfp(double a, double b);
+//
+// Returns one iff a >= b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movge r0, #1 // set result register to 1 if greater than or equal
+ movlt r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gedf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/gesf2vfp.S b/compiler-rt/lib/builtins/arm/gesf2vfp.S
new file mode 100644
index 0000000..0ff6084
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/gesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __gesf2vfp(float a, float b);
+//
+// Returns one iff a >= b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movge r0, #1 // set result register to 1 if greater than or equal
+ movlt r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gesf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/gtdf2vfp.S b/compiler-rt/lib/builtins/arm/gtdf2vfp.S
new file mode 100644
index 0000000..3dc5d5b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/gtdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __gtdf2vfp(double a, double b);
+//
+// Returns one iff a > b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movgt r0, #1 // set result register to 1 if equal
+ movle r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gtdf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/gtsf2vfp.S b/compiler-rt/lib/builtins/arm/gtsf2vfp.S
new file mode 100644
index 0000000..ddd843a
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/gtsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __gtsf2vfp(float a, float b);
+//
+// Returns one iff a > b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movgt r0, #1 // set result register to 1 if equal
+ movle r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gtsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/ledf2vfp.S b/compiler-rt/lib/builtins/arm/ledf2vfp.S
new file mode 100644
index 0000000..b06ff6d
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/ledf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __ledf2vfp(double a, double b);
+//
+// Returns one iff a <= b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movls r0, #1 // set result register to 1 if equal
+ movhi r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ledf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/lesf2vfp.S b/compiler-rt/lib/builtins/arm/lesf2vfp.S
new file mode 100644
index 0000000..9b33c0c
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/lesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __lesf2vfp(float a, float b);
+//
+// Returns one iff a <= b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movls r0, #1 // set result register to 1 if equal
+ movhi r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__lesf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/ltdf2vfp.S b/compiler-rt/lib/builtins/arm/ltdf2vfp.S
new file mode 100644
index 0000000..9f794b0
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/ltdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __ltdf2vfp(double a, double b);
+//
+// Returns one iff a < b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movmi r0, #1 // set result register to 1 if equal
+ movpl r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ltdf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/ltsf2vfp.S b/compiler-rt/lib/builtins/arm/ltsf2vfp.S
new file mode 100644
index 0000000..ba190d9
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/ltsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __ltsf2vfp(float a, float b);
+//
+// Returns one iff a < b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movmi r0, #1 // set result register to 1 if equal
+ movpl r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ltsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/modsi3.S b/compiler-rt/lib/builtins/arm/modsi3.S
new file mode 100644
index 0000000..295a227
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/modsi3.S
@@ -0,0 +1,63 @@
+/*===-- modsi3.S - 32-bit signed integer modulus --------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __modsi3 (32-bit signed integer modulus) function
+ * for the ARM architecture as a wrapper around the unsigned routine.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4, r7, lr} ;\
+ add r7, sp, #4
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4, r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ int __modsi3(int divident, int divisor)
+@ Calculate and return the remainder of the (signed) division.
+
+ .p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__modsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divzero)
+ sdiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
+ ESTABLISH_FRAME
+ // Set aside the sign of the dividend.
+ mov r4, r0
+ // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor r2, r0, r0, asr #31
+ eor r3, r1, r1, asr #31
+ sub r0, r2, r0, asr #31
+ sub r1, r3, r1, asr #31
+ // abs(a) % abs(b)
+ bl SYMBOL_NAME(__umodsi3)
+ // Apply sign of dividend to result and return.
+ eor r0, r0, r4, asr #31
+ sub r0, r0, r4, asr #31
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__modsi3)
diff --git a/compiler-rt/lib/builtins/arm/muldf3vfp.S b/compiler-rt/lib/builtins/arm/muldf3vfp.S
new file mode 100644
index 0000000..636cc71
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/muldf3vfp.S
@@ -0,0 +1,26 @@
+//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __muldf3vfp(double a, double b);
+//
+// Multiplies two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vmul.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__muldf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/mulsf3vfp.S b/compiler-rt/lib/builtins/arm/mulsf3vfp.S
new file mode 100644
index 0000000..7f40082
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/mulsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __mulsf3vfp(float a, float b);
+//
+// Multiplies two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vmul.f32 s13, s14, s15
+ vmov r0, s13 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__mulsf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/nedf2vfp.S b/compiler-rt/lib/builtins/arm/nedf2vfp.S
new file mode 100644
index 0000000..7ab2f55
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/nedf2vfp.S
@@ -0,0 +1,29 @@
+//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __nedf2vfp(double a, double b);
+//
+// Returns zero if a and b are unequal and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movne r0, #1 // set result register to 0 if unequal
+ moveq r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__nedf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/negdf2vfp.S b/compiler-rt/lib/builtins/arm/negdf2vfp.S
new file mode 100644
index 0000000..56d73c6
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/negdf2vfp.S
@@ -0,0 +1,23 @@
+//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __negdf2vfp(double a, double b);
+//
+// Returns the negation a double precision floating point numbers using the
+// Darwin calling convention where double arguments are passsed in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
+ eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__negdf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/negsf2vfp.S b/compiler-rt/lib/builtins/arm/negsf2vfp.S
new file mode 100644
index 0000000..a6e32e1
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/negsf2vfp.S
@@ -0,0 +1,23 @@
+//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __negsf2vfp(float a);
+//
+// Returns the negation of a single precision floating point numbers using the
+// Darwin calling convention where single arguments are passsed like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
+ eor r0, r0, #-2147483648 // flip sign bit on float in r0
+ bx lr
+END_COMPILERRT_FUNCTION(__negsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/nesf2vfp.S b/compiler-rt/lib/builtins/arm/nesf2vfp.S
new file mode 100644
index 0000000..9fe8ecd
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/nesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __nesf2vfp(float a, float b);
+//
+// Returns one iff a != b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movne r0, #1 // set result register to 1 if unequal
+ moveq r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__nesf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S b/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S
new file mode 100644
index 0000000..0f6ea51
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S
@@ -0,0 +1,33 @@
+//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling C++ functions that need to handle thrown exceptions the
+// compiler is required to save all registers and call __Unwind_SjLj_Register
+// in the function prolog. But when compiling for thumb1, there are
+// no instructions to access the floating point registers, so the
+// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
+// written in ARM to save the float registers. In the epilog, the compiler
+// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
+//
+
+ .text
+ .syntax unified
+
+//
+// Restore registers d8-d15 from stack
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs)
+ vldmia sp!, {d8-d15} // pop registers d8-d15 off stack
+ bx lr // return to prolog
+END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs)
+
diff --git a/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S b/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S
new file mode 100644
index 0000000..f1d90e7
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S
@@ -0,0 +1,33 @@
+//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling C++ functions that need to handle thrown exceptions the
+// compiler is required to save all registers and call __Unwind_SjLj_Register
+// in the function prolog. But when compiling for thumb1, there are
+// no instructions to access the floating point registers, so the
+// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
+// written in ARM to save the float registers. In the epilog, the compiler
+// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
+//
+
+ .text
+ .syntax unified
+
+//
+// Save registers d8-d15 onto stack
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs)
+ vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack
+ bx lr // return to prolog
+END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs)
+
diff --git a/compiler-rt/lib/builtins/arm/softfloat-alias.list b/compiler-rt/lib/builtins/arm/softfloat-alias.list
new file mode 100644
index 0000000..cc6a4b3
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/softfloat-alias.list
@@ -0,0 +1,21 @@
+#
+# These are soft float functions which can be
+# aliased to the *vfp functions on arm processors
+# that support floating point instructions.
+#
+___adddf3vfp ___adddf3
+___addsf3vfp ___addsf3
+___divdf3vfp ___divdf3
+___divsf3vfp ___divsf3
+___extendsfdf2vfp ___extendsfdf2
+___fixdfsivfp ___fixdfsi
+___fixsfsivfp ___fixsfsi
+___floatsidfvfp ___floatsidf
+___floatsisfvfp ___floatsisf
+___muldf3vfp ___muldf3
+___mulsf3vfp ___mulsf3
+___subdf3vfp ___subdf3
+___subsf3vfp ___subsf3
+___truncdfsf2vfp ___truncdfsf2
+___floatunssidfvfp ___floatunsidf
+___floatunssisfvfp ___floatunsisf
diff --git a/compiler-rt/lib/builtins/arm/subdf3vfp.S b/compiler-rt/lib/builtins/arm/subdf3vfp.S
new file mode 100644
index 0000000..5f3c0f7
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/subdf3vfp.S
@@ -0,0 +1,26 @@
+//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern double __subdf3vfp(double a, double b);
+//
+// Returns difference between two double precision floating point numbers using
+// the Darwin calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vsub.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__subdf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/subsf3vfp.S b/compiler-rt/lib/builtins/arm/subsf3vfp.S
new file mode 100644
index 0000000..d6e06df
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/subsf3vfp.S
@@ -0,0 +1,27 @@
+//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __subsf3vfp(float a, float b);
+//
+// Returns the difference between two single precision floating point numbers
+// using the Darwin calling convention where single arguments are passsed
+// like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vsub.f32 s14, s14, s15
+ vmov r0, s14 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__subsf3vfp)
diff --git a/compiler-rt/lib/builtins/arm/switch16.S b/compiler-rt/lib/builtins/arm/switch16.S
new file mode 100644
index 0000000..3c3a6b1
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/switch16.S
@@ -0,0 +1,44 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed 2-byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
+ ldrh ip, [lr, #-1] // get first 16-bit word in table
+ cmp r0, ip // compare with index
+ add r0, lr, r0, lsl #1 // compute address of element in table
+ add ip, lr, ip, lsl #1 // compute address of last element in table
+ ite lo
+ ldrshlo r0, [r0, #1] // load 16-bit element if r0 is in range
+ ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch16)
+
diff --git a/compiler-rt/lib/builtins/arm/switch32.S b/compiler-rt/lib/builtins/arm/switch32.S
new file mode 100644
index 0000000..b38cd2b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/switch32.S
@@ -0,0 +1,44 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed 4-byte sized elements which are the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32)
+ ldr ip, [lr, #-1] // get first 32-bit word in table
+ cmp r0, ip // compare with index
+ add r0, lr, r0, lsl #2 // compute address of element in table
+ add ip, lr, ip, lsl #2 // compute address of last element in table
+ ite lo
+ ldrlo r0, [r0, #3] // load 32-bit element if r0 is in range
+ ldrhs r0, [ip, #3] // load 32-bit element if r0 out of range
+ add ip, lr, r0 // compute label = lr + element
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch32)
+
diff --git a/compiler-rt/lib/builtins/arm/switch8.S b/compiler-rt/lib/builtins/arm/switch8.S
new file mode 100644
index 0000000..d7c2042
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/switch8.S
@@ -0,0 +1,42 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
+ ldrb ip, [lr, #-1] // get first byte in table
+ cmp r0, ip // signed compare with index
+ ite lo
+ ldrsblo r0, [lr, r0] // get indexed byte out of table
+ ldrsbhs r0, [lr, ip] // if out of range, use last entry in table
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch8)
+
diff --git a/compiler-rt/lib/builtins/arm/switchu8.S b/compiler-rt/lib/builtins/arm/switchu8.S
new file mode 100644
index 0000000..1844f11
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/switchu8.S
@@ -0,0 +1,42 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains unsigned byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
+ ldrb ip, [lr, #-1] // get first byte in table
+ cmp r0, ip // compare with index
+ ite lo
+ ldrblo r0, [lr, r0] // get indexed byte out of table
+ ldrbhs r0, [lr, ip] // if out of range, use last entry in table
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switchu8)
+
diff --git a/compiler-rt/lib/builtins/arm/sync-ops.h b/compiler-rt/lib/builtins/arm/sync-ops.h
new file mode 100644
index 0000000..ee02c30
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync-ops.h
@@ -0,0 +1,64 @@
+/*===-- sync-ops.h - --===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements outline macros for the __sync_fetch_and_*
+ * operations. Different instantiations will generate appropriate assembly for
+ * ARM and Thumb-2 versions of the functions.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define SYNC_OP_4(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrex r0, [r12] ; \
+ op(r2, r0, r1) ; \
+ strex r3, r2, [r12] ; \
+ cmp r3, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ bx lr
+
+#define SYNC_OP_8(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ push {r4, r5, r6, lr} ; \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrexd r0, r1, [r12] ; \
+ op(r4, r5, r0, r1, r2, r3) ; \
+ strexd r6, r4, r5, [r12] ; \
+ cmp r6, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ pop {r4, r5, r6, pc}
+
+#define MINMAX_4(rD, rN, rM, cmp_kind) \
+ cmp rN, rM ; \
+ mov rD, rM ; \
+ it cmp_kind ; \
+ mov##cmp_kind rD, rN
+
+#define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind) \
+ cmp rN_LO, rM_LO ; \
+ sbcs rN_HI, rM_HI ; \
+ mov rD_LO, rM_LO ; \
+ mov rD_HI, rM_HI ; \
+ itt cmp_kind ; \
+ mov##cmp_kind rD_LO, rN_LO ; \
+ mov##cmp_kind rD_HI, rN_HI
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S
new file mode 100644
index 0000000..54c33e2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_add_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_add_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "adds" is 2 bytes shorter than "add". */
+#define add_4(rD, rN, rM) add rD, rN, rM
+
+SYNC_OP_4(add_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S
new file mode 100644
index 0000000..5724bb1
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_add_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_add_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define add_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ adds rD_LO, rN_LO, rM_LO ; \
+ adc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(add_8)
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S
new file mode 100644
index 0000000..e2b77a1
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S
@@ -0,0 +1,19 @@
+/*===-- sync_fetch_and_and_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_and_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define and_4(rD, rN, rM) and rD, rN, rM
+
+SYNC_OP_4(and_4)
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S
new file mode 100644
index 0000000..a74163a
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S
@@ -0,0 +1,23 @@
+/*===-- sync_fetch_and_and_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_and_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define and_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ and rD_LO, rN_LO, rM_LO ; \
+ and rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(and_8)
+#endif
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S
new file mode 100644
index 0000000..01e4f44
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_max_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_max_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define max_4(rD, rN, rM) MINMAX_4(rD, rN, rM, gt)
+
+SYNC_OP_4(max_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S
new file mode 100644
index 0000000..1eef2b2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_max_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_max_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define max_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, gt)
+
+SYNC_OP_8(max_8)
+#endif
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S
new file mode 100644
index 0000000..015626b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_min_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_min_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define min_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lt)
+
+SYNC_OP_4(min_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S
new file mode 100644
index 0000000..ad5cce0
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_min_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_min_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define min_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lt)
+
+SYNC_OP_8(min_8)
+#endif
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S
new file mode 100644
index 0000000..b32a314
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_nand_4.S - -----------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_nand_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define nand_4(rD, rN, rM) bic rD, rN, rM
+
+SYNC_OP_4(nand_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S
new file mode 100644
index 0000000..a2c17c0
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_nand_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_nand_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define nand_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ bic rD_LO, rN_LO, rM_LO ; \
+ bic rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(nand_8)
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S
new file mode 100644
index 0000000..f2e0857
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_or_4.S - -------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_or_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define or_4(rD, rN, rM) orr rD, rN, rM
+
+SYNC_OP_4(or_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S
new file mode 100644
index 0000000..87b940b
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_or_8.S - -------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_or_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define or_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ orr rD_LO, rN_LO, rM_LO ; \
+ orr rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(or_8)
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S
new file mode 100644
index 0000000..460b2bc
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_sub_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_sub_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "subs" is 2 bytes shorter than "sub". */
+#define sub_4(rD, rN, rM) sub rD, rN, rM
+
+SYNC_OP_4(sub_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S
new file mode 100644
index 0000000..a8035a2
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_sub_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_sub_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define sub_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ subs rD_LO, rN_LO, rM_LO ; \
+ sbc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(sub_8)
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S
new file mode 100644
index 0000000..c591530
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umax_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umax_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umax_4(rD, rN, rM) MINMAX_4(rD, rN, rM, hi)
+
+SYNC_OP_4(umax_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S
new file mode 100644
index 0000000..d9b7965
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umax_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umax_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umax_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, hi)
+
+SYNC_OP_8(umax_8)
+#endif
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S
new file mode 100644
index 0000000..9f3896f
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umin_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umin_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umin_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lo)
+
+SYNC_OP_4(umin_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S
new file mode 100644
index 0000000..7bf5e23
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umin_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_umin_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umin_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lo)
+
+SYNC_OP_8(umin_8)
+#endif
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S
new file mode 100644
index 0000000..7e7c90c
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_xor_4.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_xor_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define xor_4(rD, rN, rM) eor rD, rN, rM
+
+SYNC_OP_4(xor_4)
+
diff --git a/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S b/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S
new file mode 100644
index 0000000..ea9aa6d
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_xor_8.S - ------------------------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __sync_fetch_and_xor_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define xor_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ eor rD_LO, rN_LO, rM_LO ; \
+ eor rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(xor_8)
+#endif
+
diff --git a/compiler-rt/lib/builtins/arm/sync_synchronize.S b/compiler-rt/lib/builtins/arm/sync_synchronize.S
new file mode 100644
index 0000000..178f245
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/sync_synchronize.S
@@ -0,0 +1,35 @@
+//===-- sync_synchronize - Implement memory barrier * ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode
+// the compiler may emit a call to __sync_synchronize.
+// On Darwin the implementation jumps to an OS supplied function named
+// OSMemoryBarrier
+//
+
+ .text
+ .syntax unified
+
+#if __APPLE__
+
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize)
+ stmfd sp!, {r7, lr}
+ add r7, sp, #0
+ bl _OSMemoryBarrier
+ ldmfd sp!, {r7, pc}
+END_COMPILERRT_FUNCTION(__sync_synchronize)
+
+ // tell linker it can break up file at label boundaries
+ .subsections_via_symbols
+
+#endif
diff --git a/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S
new file mode 100644
index 0000000..fa4362c
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S
@@ -0,0 +1,26 @@
+//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern float __truncdfsf2vfp(double a);
+//
+// Converts double precision float to signle precision result.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in a R0/R1 pair and a signle precision result is returned in R0.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
+ vmov d7, r0, r1 // load double from r0/r1 pair
+ vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
+ vmov r0, s15 // return result in r0
+ bx lr
+END_COMPILERRT_FUNCTION(__truncdfsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/udivmodsi4.S b/compiler-rt/lib/builtins/arm/udivmodsi4.S
new file mode 100644
index 0000000..85b8493
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/udivmodsi4.S
@@ -0,0 +1,184 @@
+/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
+ * modulus) function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
+@ unsigned int *remainder)
+@ Calculate the quotient and remainder of the (unsigned) division. The return
+@ value is the quotient, the remainder is placed in the variable.
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
+#else
+DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ mov r3, r0
+ udiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ beq LOCAL_LABEL(divby1)
+ cmp r0, r1
+ bcc LOCAL_LABEL(quotient0)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ str r4, [sp, #-8]!
+
+ mov r4, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r4, #16
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r4, #8
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r4, #4
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r4, #2
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r3 or r4. */
+ cmp r1, r4, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ ldr r4, [sp], #8 /* restore r4, we are done with it. */
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ str r0, [r2]
+ mov r0, r3
+ JMP(lr)
+
+LOCAL_LABEL(quotient0):
+ str r0, [r2]
+ mov r0, #0
+ JMP(lr)
+
+LOCAL_LABEL(divby1):
+ mov r3, #0
+ str r3, [r2]
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivmodsi4)
diff --git a/compiler-rt/lib/builtins/arm/udivsi3.S b/compiler-rt/lib/builtins/arm/udivsi3.S
new file mode 100644
index 0000000..165b2b5
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/udivsi3.S
@@ -0,0 +1,170 @@
+/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __udivsi3 (32-bit unsigned integer divide)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 2
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
+
+@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
+@ Calculate and return the quotient of the (unsigned) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__udivsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ udiv r0, r0, r1
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ IT(eq)
+ JMPc(lr, eq)
+ cmp r0, r1
+ ITT(cc)
+ movcc r0, #0
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ mov r0, r3
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivsi3)
diff --git a/compiler-rt/lib/builtins/arm/umodsi3.S b/compiler-rt/lib/builtins/arm/umodsi3.S
new file mode 100644
index 0000000..9e7a148
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/umodsi3.S
@@ -0,0 +1,161 @@
+/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===//
+ *
+ * This file implements the __umodsi3 (32-bit unsigned integer modulus)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
+@ Calculate and return the remainder of the (unsigned) division.
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__umodsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ udiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ ITT(eq)
+ moveq r0, #0
+ JMPc(lr, eq)
+ cmp r0, r1
+ IT(cc)
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 8 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #3
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 8)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 8)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 8)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 8)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 8)
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ IT(hs); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__umodsi3)
diff --git a/compiler-rt/lib/builtins/arm/unorddf2vfp.S b/compiler-rt/lib/builtins/arm/unorddf2vfp.S
new file mode 100644
index 0000000..c4bea2d
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/unorddf2vfp.S
@@ -0,0 +1,29 @@
+//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __unorddf2vfp(double a, double b);
+//
+// Returns one iff a or b is NaN
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
+ movvc r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__unorddf2vfp)
diff --git a/compiler-rt/lib/builtins/arm/unordsf2vfp.S b/compiler-rt/lib/builtins/arm/unordsf2vfp.S
new file mode 100644
index 0000000..886e965
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm/unordsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// extern int __unordsf2vfp(float a, float b);
+//
+// Returns one iff a or b is NaN
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
+ movvc r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__unordsf2vfp)
diff --git a/compiler-rt/lib/builtins/arm64/Makefile.mk b/compiler-rt/lib/builtins/arm64/Makefile.mk
new file mode 100644
index 0000000..7f7e386
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm64/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm64/Makefile.mk -----------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := arm64
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/arm64/dummy.c b/compiler-rt/lib/builtins/arm64/dummy.c
new file mode 100644
index 0000000..76bec30
--- /dev/null
+++ b/compiler-rt/lib/builtins/arm64/dummy.c
@@ -0,0 +1,13 @@
+/* ===---------- dummy.c - Implements dummy function, for bringup -----------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+static void dummy(void) __attribute__((used));
+
+static void dummy(void) {}
diff --git a/compiler-rt/lib/builtins/armv6m/Makefile.mk b/compiler-rt/lib/builtins/armv6m/Makefile.mk
new file mode 100644
index 0000000..f3c1807
--- /dev/null
+++ b/compiler-rt/lib/builtins/armv6m/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := armv6m
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/ashldi3.c b/compiler-rt/lib/builtins/ashldi3.c
new file mode 100644
index 0000000..eb4698a
--- /dev/null
+++ b/compiler-rt/lib/builtins/ashldi3.c
@@ -0,0 +1,43 @@
+/* ====-- ashldi3.c - Implement __ashldi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ashldi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a << b */
+
+/* Precondition: 0 <= b < bits_in_dword */
+
+ARM_EABI_FNALIAS(llsl, ashldi3)
+
+COMPILER_RT_ABI di_int
+__ashldi3(di_int a, si_int b)
+{
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ dwords input;
+ dwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
+ {
+ result.s.low = 0;
+ result.s.high = input.s.low << (b - bits_in_word);
+ }
+ else /* 0 <= b < bits_in_word */
+ {
+ if (b == 0)
+ return a;
+ result.s.low = input.s.low << b;
+ result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_word - b));
+ }
+ return result.all;
+}
diff --git a/compiler-rt/lib/builtins/ashlti3.c b/compiler-rt/lib/builtins/ashlti3.c
new file mode 100644
index 0000000..638ae84
--- /dev/null
+++ b/compiler-rt/lib/builtins/ashlti3.c
@@ -0,0 +1,45 @@
+/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ashlti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a << b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__ashlti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ result.s.low = 0;
+ result.s.high = input.s.low << (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.low = input.s.low << b;
+ result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b));
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/ashrdi3.c b/compiler-rt/lib/builtins/ashrdi3.c
new file mode 100644
index 0000000..14c878b
--- /dev/null
+++ b/compiler-rt/lib/builtins/ashrdi3.c
@@ -0,0 +1,44 @@
+/*===-- ashrdi3.c - Implement __ashrdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ashrdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: arithmetic a >> b */
+
+/* Precondition: 0 <= b < bits_in_dword */
+
+ARM_EABI_FNALIAS(lasr, ashrdi3)
+
+COMPILER_RT_ABI di_int
+__ashrdi3(di_int a, si_int b)
+{
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ dwords input;
+ dwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
+ {
+ /* result.s.high = input.s.high < 0 ? -1 : 0 */
+ result.s.high = input.s.high >> (bits_in_word - 1);
+ result.s.low = input.s.high >> (b - bits_in_word);
+ }
+ else /* 0 <= b < bits_in_word */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
diff --git a/compiler-rt/lib/builtins/ashrti3.c b/compiler-rt/lib/builtins/ashrti3.c
new file mode 100644
index 0000000..f78205d
--- /dev/null
+++ b/compiler-rt/lib/builtins/ashrti3.c
@@ -0,0 +1,46 @@
+/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ashrti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: arithmetic a >> b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__ashrti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ /* result.s.high = input.s.high < 0 ? -1 : 0 */
+ result.s.high = input.s.high >> (bits_in_dword - 1);
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/assembly.h b/compiler-rt/lib/builtins/assembly.h
new file mode 100644
index 0000000..c289705
--- /dev/null
+++ b/compiler-rt/lib/builtins/assembly.h
@@ -0,0 +1,158 @@
+/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in compiler-rt assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define CONST_SECTION .section .rodata
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#define CONST_SECTION .section .rdata,"rd"
+
+#endif
+
+#if defined(__arm__)
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && \
+ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+// pop {pc} can't switch Thumb mode on ARMv4T
+#if __ARM_ARCH >= 5
+#define POP_PC() pop {pc}
+#else
+#define POP_PC() \
+ pop {ip}; \
+ JMP(ip)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#else
+#define IT(cond)
+#define ITT(cond)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#endif
+
+#define GLUE2(a, b) a##b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .thumb_func SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ name:
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#endif
+
+#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/compiler-rt/lib/builtins/atomic.c b/compiler-rt/lib/builtins/atomic.c
new file mode 100644
index 0000000..f1ddc3e
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic.c
@@ -0,0 +1,331 @@
+/*===-- atomic.c - Implement support functions for atomic operations.------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * atomic.c defines a set of functions for performing atomic accesses on
+ * arbitrary-sized memory locations. This design uses locks that should
+ * be fast in the uncontended case, for two reasons:
+ *
+ * 1) This code must work with C programs that do not link to anything
+ * (including pthreads) and so it should not depend on any pthread
+ * functions.
+ * 2) Atomic operations, rather than explicit mutexes, are most commonly used
+ * on code where contended operations are rate.
+ *
+ * To avoid needing a per-object lock, this code allocates an array of
+ * locks and hashes the object pointers to find the one that it should use.
+ * For operations that must be atomic on two locations, the lower lock is
+ * always acquired first, to avoid deadlock.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "assembly.h"
+
+// Clang objects if you redefine a builtin. This little hack allows us to
+// define a function with the same name as an intrinsic.
+#pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load)
+#pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store)
+#pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange)
+#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(__atomic_compare_exchange)
+
+/// Number of locks. This allocates one page on 32-bit platforms, two on
+/// 64-bit. This can be specified externally if a different trade between
+/// memory usage and contention probability is required for a given platform.
+#ifndef SPINLOCK_COUNT
+#define SPINLOCK_COUNT (1<<10)
+#endif
+static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
+
+////////////////////////////////////////////////////////////////////////////////
+// Platform-specific lock implementation. Falls back to spinlocks if none is
+// defined. Each platform should define the Lock type, and corresponding
+// lock() and unlock() functions.
+////////////////////////////////////////////////////////////////////////////////
+#ifdef __FreeBSD__
+#include <errno.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include <sys/umtx.h>
+typedef struct _usem Lock;
+__inline static void unlock(Lock *l) {
+ __c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE);
+ __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
+ if (l->_has_waiters)
+ _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0);
+}
+__inline static void lock(Lock *l) {
+ uint32_t old = 1;
+ while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old,
+ 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
+ _umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0);
+ old = 1;
+ }
+}
+/// locks for atomic operations
+static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} };
+
+#elif defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+typedef OSSpinLock Lock;
+__inline static void unlock(Lock *l) {
+ OSSpinLockUnlock(l);
+}
+/// Locks a lock. In the current implementation, this is potentially
+/// unbounded in the contended case.
+__inline static void lock(Lock *l) {
+ OSSpinLockLock(l);
+}
+static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
+
+#else
+typedef _Atomic(uintptr_t) Lock;
+/// Unlock a lock. This is a release operation.
+__inline static void unlock(Lock *l) {
+ __c11_atomic_store(l, 0, __ATOMIC_RELEASE);
+}
+/// Locks a lock. In the current implementation, this is potentially
+/// unbounded in the contended case.
+__inline static void lock(Lock *l) {
+ uintptr_t old = 0;
+ while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE,
+ __ATOMIC_RELAXED))
+ old = 0;
+}
+/// locks for atomic operations
+static Lock locks[SPINLOCK_COUNT];
+#endif
+
+
+/// Returns a lock to use for a given pointer.
+static __inline Lock *lock_for_pointer(void *ptr) {
+ intptr_t hash = (intptr_t)ptr;
+ // Disregard the lowest 4 bits. We want all values that may be part of the
+ // same memory operation to hash to the same value and therefore use the same
+ // lock.
+ hash >>= 4;
+ // Use the next bits as the basis for the hash
+ intptr_t low = hash & SPINLOCK_MASK;
+ // Now use the high(er) set of bits to perturb the hash, so that we don't
+ // get collisions from atomic fields in a single object
+ hash >>= 16;
+ hash ^= low;
+ // Return a pointer to the word to use
+ return locks + (hash & SPINLOCK_MASK);
+}
+
+/// Macros for determining whether a size is lock free. Clang can not yet
+/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are
+/// not lock free.
+#define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1)
+#define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2)
+#define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4)
+#define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8)
+#define IS_LOCK_FREE_16 0
+
+/// Macro that calls the compiler-generated lock-free versions of functions
+/// when they exist.
+#define LOCK_FREE_CASES() \
+ do {\
+ switch (size) {\
+ case 2:\
+ if (IS_LOCK_FREE_2) {\
+ LOCK_FREE_ACTION(uint16_t);\
+ }\
+ case 4:\
+ if (IS_LOCK_FREE_4) {\
+ LOCK_FREE_ACTION(uint32_t);\
+ }\
+ case 8:\
+ if (IS_LOCK_FREE_8) {\
+ LOCK_FREE_ACTION(uint64_t);\
+ }\
+ case 16:\
+ if (IS_LOCK_FREE_16) {\
+ /* FIXME: __uint128_t isn't available on 32 bit platforms.
+ LOCK_FREE_ACTION(__uint128_t);*/\
+ }\
+ }\
+ } while (0)
+
+
+/// An atomic load operation. This is atomic with respect to the source
+/// pointer only.
+void __atomic_load_c(int size, void *src, void *dest, int model) {
+#define LOCK_FREE_ACTION(type) \
+ *((type*)dest) = __c11_atomic_load((_Atomic(type)*)src, model);\
+ return;
+ LOCK_FREE_CASES();
+#undef LOCK_FREE_ACTION
+ Lock *l = lock_for_pointer(src);
+ lock(l);
+ memcpy(dest, src, size);
+ unlock(l);
+}
+
+/// An atomic store operation. This is atomic with respect to the destination
+/// pointer only.
+void __atomic_store_c(int size, void *dest, void *src, int model) {
+#define LOCK_FREE_ACTION(type) \
+ __c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\
+ return;
+ LOCK_FREE_CASES();
+#undef LOCK_FREE_ACTION
+ Lock *l = lock_for_pointer(dest);
+ lock(l);
+ memcpy(dest, src, size);
+ unlock(l);
+}
+
+/// Atomic compare and exchange operation. If the value at *ptr is identical
+/// to the value at *expected, then this copies value at *desired to *ptr. If
+/// they are not, then this stores the current value from *ptr in *expected.
+///
+/// This function returns 1 if the exchange takes place or 0 if it fails.
+int __atomic_compare_exchange_c(int size, void *ptr, void *expected,
+ void *desired, int success, int failure) {
+#define LOCK_FREE_ACTION(type) \
+ return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\
+ *(type*)desired, success, failure)
+ LOCK_FREE_CASES();
+#undef LOCK_FREE_ACTION
+ Lock *l = lock_for_pointer(ptr);
+ lock(l);
+ if (memcmp(ptr, expected, size) == 0) {
+ memcpy(ptr, desired, size);
+ unlock(l);
+ return 1;
+ }
+ memcpy(expected, ptr, size);
+ unlock(l);
+ return 0;
+}
+
+/// Performs an atomic exchange operation between two pointers. This is atomic
+/// with respect to the target address.
+void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) {
+#define LOCK_FREE_ACTION(type) \
+ *(type*)old = __c11_atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\
+ model);\
+ return;
+ LOCK_FREE_CASES();
+#undef LOCK_FREE_ACTION
+ Lock *l = lock_for_pointer(ptr);
+ lock(l);
+ memcpy(old, ptr, size);
+ memcpy(ptr, val, size);
+ unlock(l);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Where the size is known at compile time, the compiler may emit calls to
+// specialised versions of the above functions.
+////////////////////////////////////////////////////////////////////////////////
+#define OPTIMISED_CASES\
+ OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\
+ OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\
+ OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\
+ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\
+ /* FIXME: __uint128_t isn't available on 32 bit platforms.
+ OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)*/\
+
+#define OPTIMISED_CASE(n, lockfree, type)\
+type __atomic_load_##n(type *src, int model) {\
+ if (lockfree)\
+ return __c11_atomic_load((_Atomic(type)*)src, model);\
+ Lock *l = lock_for_pointer(src);\
+ lock(l);\
+ type val = *src;\
+ unlock(l);\
+ return val;\
+}
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+
+#define OPTIMISED_CASE(n, lockfree, type)\
+void __atomic_store_##n(type *dest, type val, int model) {\
+ if (lockfree) {\
+ __c11_atomic_store((_Atomic(type)*)dest, val, model);\
+ return;\
+ }\
+ Lock *l = lock_for_pointer(dest);\
+ lock(l);\
+ *dest = val;\
+ unlock(l);\
+ return;\
+}
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+
+#define OPTIMISED_CASE(n, lockfree, type)\
+type __atomic_exchange_##n(type *dest, type val, int model) {\
+ if (lockfree)\
+ return __c11_atomic_exchange((_Atomic(type)*)dest, val, model);\
+ Lock *l = lock_for_pointer(dest);\
+ lock(l);\
+ type tmp = *dest;\
+ *dest = val;\
+ unlock(l);\
+ return tmp;\
+}
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+
+#define OPTIMISED_CASE(n, lockfree, type)\
+int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\
+ int success, int failure) {\
+ if (lockfree)\
+ return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\
+ success, failure);\
+ Lock *l = lock_for_pointer(ptr);\
+ lock(l);\
+ if (*ptr == *expected) {\
+ *ptr = desired;\
+ unlock(l);\
+ return 1;\
+ }\
+ *expected = *ptr;\
+ unlock(l);\
+ return 0;\
+}
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+
+////////////////////////////////////////////////////////////////////////////////
+// Atomic read-modify-write operations for integers of various sizes.
+////////////////////////////////////////////////////////////////////////////////
+#define ATOMIC_RMW(n, lockfree, type, opname, op) \
+type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\
+ if (lockfree) \
+ return __c11_atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\
+ Lock *l = lock_for_pointer(ptr);\
+ lock(l);\
+ type tmp = *ptr;\
+ *ptr = tmp op val;\
+ unlock(l);\
+ return tmp;\
+}
+
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, sub, -)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, and, &)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, or, |)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
diff --git a/compiler-rt/lib/builtins/atomic_flag_clear.c b/compiler-rt/lib/builtins/atomic_flag_clear.c
new file mode 100644
index 0000000..da912af
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_flag_clear.c
@@ -0,0 +1,27 @@
+/*===-- atomic_flag_clear.c -------------------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_flag_clear from C11's stdatomic.h.
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_flag_clear
+void atomic_flag_clear(volatile atomic_flag *object) {
+ __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c b/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c
new file mode 100644
index 0000000..1059b78
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c
@@ -0,0 +1,28 @@
+/*===-- atomic_flag_clear_explicit.c ----------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_flag_clear_explicit from C11's stdatomic.h.
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_flag_clear_explicit
+void atomic_flag_clear_explicit(volatile atomic_flag *object,
+ memory_order order) {
+ __c11_atomic_store(&(object)->_Value, 0, order);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/atomic_flag_test_and_set.c b/compiler-rt/lib/builtins/atomic_flag_test_and_set.c
new file mode 100644
index 0000000..e8811d3
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_flag_test_and_set.c
@@ -0,0 +1,27 @@
+/*===-- atomic_flag_test_and_set.c ------------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_flag_test_and_set from C11's stdatomic.h.
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_flag_test_and_set
+_Bool atomic_flag_test_and_set(volatile atomic_flag *object) {
+ return __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c b/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c
new file mode 100644
index 0000000..5c8c2df
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c
@@ -0,0 +1,28 @@
+/*===-- atomic_flag_test_and_set_explicit.c ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_flag_test_and_set_explicit from C11's stdatomic.h
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_flag_test_and_set_explicit
+_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
+ memory_order order) {
+ return __c11_atomic_exchange(&(object)->_Value, 1, order);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/atomic_signal_fence.c b/compiler-rt/lib/builtins/atomic_signal_fence.c
new file mode 100644
index 0000000..9ccc2ae
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_signal_fence.c
@@ -0,0 +1,27 @@
+/*===-- atomic_signal_fence.c -----------------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_signal_fence from C11's stdatomic.h.
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_signal_fence
+void atomic_signal_fence(memory_order order) {
+ __c11_atomic_signal_fence(order);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/atomic_thread_fence.c b/compiler-rt/lib/builtins/atomic_thread_fence.c
new file mode 100644
index 0000000..d225601
--- /dev/null
+++ b/compiler-rt/lib/builtins/atomic_thread_fence.c
@@ -0,0 +1,27 @@
+/*===-- atomic_thread_fence.c -----------------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------===
+ *
+ * This file implements atomic_thread_fence from C11's stdatomic.h.
+ *
+ *===------------------------------------------------------------------------===
+ */
+
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
+#include <stdatomic.h>
+#undef atomic_thread_fence
+void atomic_thread_fence(memory_order order) {
+ __c11_atomic_thread_fence(order);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/clear_cache.c b/compiler-rt/lib/builtins/clear_cache.c
new file mode 100644
index 0000000..ede7659
--- /dev/null
+++ b/compiler-rt/lib/builtins/clear_cache.c
@@ -0,0 +1,159 @@
+/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include <stddef.h>
+
+#if __APPLE__
+ #include <libkern/OSCacheControl.h>
+#endif
+#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__)
+ #include <sys/types.h>
+ #include <machine/sysarch.h>
+#endif
+
+#if defined(__NetBSD__) && defined(__arm__)
+ #include <machine/sysarch.h>
+#endif
+
+#if defined(__mips__)
+ #include <sys/cachectl.h>
+ #include <sys/syscall.h>
+ #include <unistd.h>
+ #if defined(__ANDROID__) && defined(__LP64__)
+ /*
+ * clear_mips_cache - Invalidates instruction cache for Mips.
+ */
+ static void clear_mips_cache(const void* Addr, size_t Size) {
+ asm volatile (
+ ".set push\n"
+ ".set noreorder\n"
+ ".set noat\n"
+ "beq %[Size], $zero, 20f\n" /* If size == 0, branch around. */
+ "nop\n"
+ "daddu %[Size], %[Addr], %[Size]\n" /* Calculate end address + 1 */
+ "rdhwr $v0, $1\n" /* Get step size for SYNCI.
+ $1 is $HW_SYNCI_Step */
+ "beq $v0, $zero, 20f\n" /* If no caches require
+ synchronization, branch
+ around. */
+ "nop\n"
+ "10:\n"
+ "synci 0(%[Addr])\n" /* Synchronize all caches around
+ address. */
+ "daddu %[Addr], %[Addr], $v0\n" /* Add step size. */
+ "sltu $at, %[Addr], %[Size]\n" /* Compare current with end
+ address. */
+ "bne $at, $zero, 10b\n" /* Branch if more to do. */
+ "nop\n"
+ "sync\n" /* Clear memory hazards. */
+ "20:\n"
+ "bal 30f\n"
+ "nop\n"
+ "30:\n"
+ "daddiu $ra, $ra, 12\n" /* $ra has a value of $pc here.
+ Add offset of 12 to point to the
+ instruction after the last nop.
+ */
+ "jr.hb $ra\n" /* Return, clearing instruction
+ hazards. */
+ "nop\n"
+ ".set pop\n"
+ : [Addr] "+r"(Addr), [Size] "+r"(Size)
+ :: "at", "ra", "v0", "memory"
+ );
+ }
+ #endif
+#endif
+
+#if defined(__ANDROID__) && defined(__arm__)
+ #include <asm/unistd.h>
+#endif
+
+/*
+ * The compiler generates calls to __clear_cache() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * It is expected to invalidate the instruction cache for the
+ * specified range.
+ */
+
+void __clear_cache(void *start, void *end) {
+#if __i386__ || __x86_64__
+/*
+ * Intel processors have a unified instruction and data cache
+ * so there is nothing to do
+ */
+#elif defined(__arm__) && !defined(__APPLE__)
+ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__)
+ struct arm_sync_icache_args arg;
+
+ arg.addr = (uintptr_t)start;
+ arg.len = (uintptr_t)end - (uintptr_t)start;
+
+ sysarch(ARM_SYNC_ICACHE, &arg);
+ #elif defined(__ANDROID__)
+ register int start_reg __asm("r0") = (int) (intptr_t) start;
+ const register int end_reg __asm("r1") = (int) (intptr_t) end;
+ const register int flags __asm("r2") = 0;
+ const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
+ __asm __volatile("svc 0x0" : "=r"(start_reg)
+ : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0");
+ if (start_reg != 0) {
+ compilerrt_abort();
+ }
+ #else
+ compilerrt_abort();
+ #endif
+#elif defined(__mips__)
+ const uintptr_t start_int = (uintptr_t) start;
+ const uintptr_t end_int = (uintptr_t) end;
+ #if defined(__ANDROID__) && defined(__LP64__)
+ // Call synci implementation for short address range.
+ const uintptr_t address_range_limit = 256;
+ if ((end_int - start_int) <= address_range_limit) {
+ clear_mips_cache(start, (end_int - start_int));
+ } else {
+ syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
+ }
+ #else
+ syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
+ #endif
+#elif defined(__aarch64__) && !defined(__APPLE__)
+ uint64_t xstart = (uint64_t)(uintptr_t) start;
+ uint64_t xend = (uint64_t)(uintptr_t) end;
+ uint64_t addr;
+
+ // Get Cache Type Info
+ uint64_t ctr_el0;
+ __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
+
+ /*
+ * dc & ic instructions must use 64bit registers so we don't use
+ * uintptr_t in case this runs in an IPL32 environment.
+ */
+ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
+ for (addr = xstart; addr < xend; addr += dcache_line_size)
+ __asm __volatile("dc cvau, %0" :: "r"(addr));
+ __asm __volatile("dsb ish");
+
+ const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
+ for (addr = xstart; addr < xend; addr += icache_line_size)
+ __asm __volatile("ic ivau, %0" :: "r"(addr));
+ __asm __volatile("isb sy");
+#else
+ #if __APPLE__
+ /* On Darwin, sys_icache_invalidate() provides this functionality */
+ sys_icache_invalidate(start, end-start);
+ #else
+ compilerrt_abort();
+ #endif
+#endif
+}
+
diff --git a/compiler-rt/lib/builtins/clzdi2.c b/compiler-rt/lib/builtins/clzdi2.c
new file mode 100644
index 0000000..b9e64da
--- /dev/null
+++ b/compiler-rt/lib/builtins/clzdi2.c
@@ -0,0 +1,29 @@
+/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __clzdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: the number of leading 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__clzdi2(di_int a)
+{
+ dwords x;
+ x.all = a;
+ const si_int f = -(x.s.high == 0);
+ return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) +
+ (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
+}
diff --git a/compiler-rt/lib/builtins/clzsi2.c b/compiler-rt/lib/builtins/clzsi2.c
new file mode 100644
index 0000000..25b8ed2
--- /dev/null
+++ b/compiler-rt/lib/builtins/clzsi2.c
@@ -0,0 +1,53 @@
+/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __clzsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: the number of leading 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__clzsi2(si_int a)
+{
+ su_int x = (su_int)a;
+ si_int t = ((x & 0xFFFF0000) == 0) << 4; /* if (x is small) t = 16 else 0 */
+ x >>= 16 - t; /* x = [0 - 0xFFFF] */
+ su_int r = t; /* r = [0, 16] */
+ /* return r + clz(x) */
+ t = ((x & 0xFF00) == 0) << 3;
+ x >>= 8 - t; /* x = [0 - 0xFF] */
+ r += t; /* r = [0, 8, 16, 24] */
+ /* return r + clz(x) */
+ t = ((x & 0xF0) == 0) << 2;
+ x >>= 4 - t; /* x = [0 - 0xF] */
+ r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */
+ /* return r + clz(x) */
+ t = ((x & 0xC) == 0) << 1;
+ x >>= 2 - t; /* x = [0 - 3] */
+ r += t; /* r = [0 - 30] and is even */
+ /* return r + clz(x) */
+/* switch (x)
+ * {
+ * case 0:
+ * return r + 2;
+ * case 1:
+ * return r + 1;
+ * case 2:
+ * case 3:
+ * return r;
+ * }
+ */
+ return r + ((2 - x) & -((x & 2) == 0));
+}
diff --git a/compiler-rt/lib/builtins/clzti2.c b/compiler-rt/lib/builtins/clzti2.c
new file mode 100644
index 0000000..15a7b3c
--- /dev/null
+++ b/compiler-rt/lib/builtins/clzti2.c
@@ -0,0 +1,33 @@
+/* ===-- clzti2.c - Implement __clzti2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __clzti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the number of leading 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__clzti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.high == 0);
+ return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/cmpdi2.c b/compiler-rt/lib/builtins/cmpdi2.c
new file mode 100644
index 0000000..52634d9
--- /dev/null
+++ b/compiler-rt/lib/builtins/cmpdi2.c
@@ -0,0 +1,51 @@
+/* ===-- cmpdi2.c - Implement __cmpdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __cmpdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: if (a < b) returns 0
+* if (a == b) returns 1
+* if (a > b) returns 2
+*/
+
+COMPILER_RT_ABI si_int
+__cmpdi2(di_int a, di_int b)
+{
+ dwords x;
+ x.all = a;
+ dwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#ifdef __ARM_EABI__
+/* Returns: if (a < b) returns -1
+* if (a == b) returns 0
+* if (a > b) returns 1
+*/
+COMPILER_RT_ABI si_int
+__aeabi_lcmp(di_int a, di_int b)
+{
+ return __cmpdi2(a, b) - 1;
+}
+#endif
+
diff --git a/compiler-rt/lib/builtins/cmpti2.c b/compiler-rt/lib/builtins/cmpti2.c
new file mode 100644
index 0000000..2c8b56e
--- /dev/null
+++ b/compiler-rt/lib/builtins/cmpti2.c
@@ -0,0 +1,42 @@
+/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __cmpti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: if (a < b) returns 0
+ * if (a == b) returns 1
+ * if (a > b) returns 2
+ */
+
+COMPILER_RT_ABI si_int
+__cmpti2(ti_int a, ti_int b)
+{
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/comparedf2.c b/compiler-rt/lib/builtins/comparedf2.c
new file mode 100644
index 0000000..9e29752
--- /dev/null
+++ b/compiler-rt/lib/builtins/comparedf2.c
@@ -0,0 +1,146 @@
+//===-- lib/comparedf2.c - Double-precision comparisons -----------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// // This file implements the following soft-float comparison routines:
+//
+// __eqdf2 __gedf2 __unorddf2
+// __ledf2 __gtdf2
+// __ltdf2
+// __nedf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __ledf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gedf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unorddf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __ledf2( ) and __gedf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT
+__ledf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ else {
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmpdf2, __ledf2);
+#endif
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT
+__gedf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+ARM_EABI_FNALIAS(dcmpun, unorddf2)
+
+COMPILER_RT_ABI int
+__unorddf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT
+__eqdf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__ltdf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__nedf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT
+__gtdf2(fp_t a, fp_t b) {
+ return __gedf2(a, b);
+}
+
diff --git a/compiler-rt/lib/builtins/comparesf2.c b/compiler-rt/lib/builtins/comparesf2.c
new file mode 100644
index 0000000..1fd5063
--- /dev/null
+++ b/compiler-rt/lib/builtins/comparesf2.c
@@ -0,0 +1,145 @@
+//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the following soft-fp_t comparison routines:
+//
+// __eqsf2 __gesf2 __unordsf2
+// __lesf2 __gtsf2
+// __ltsf2
+// __nesf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __lesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordsf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT
+__lesf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a fp_ting-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ else {
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmpsf2, __lesf2);
+#endif
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT
+__gesf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+ARM_EABI_FNALIAS(fcmpun, unordsf2)
+
+COMPILER_RT_ABI int
+__unordsf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT
+__eqsf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__ltsf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__nesf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT
+__gtsf2(fp_t a, fp_t b) {
+ return __gesf2(a, b);
+}
diff --git a/compiler-rt/lib/builtins/comparetf2.c b/compiler-rt/lib/builtins/comparetf2.c
new file mode 100644
index 0000000..c0ad8ed
--- /dev/null
+++ b/compiler-rt/lib/builtins/comparetf2.c
@@ -0,0 +1,138 @@
+//===-- lib/comparetf2.c - Quad-precision comparisons -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// // This file implements the following soft-float comparison routines:
+//
+// __eqtf2 __getf2 __unordtf2
+// __letf2 __gttf2
+// __lttf2
+// __netf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __letf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __getf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordtf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __letf2( ) and __getf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+ else {
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmptf2, __letf2);
+#endif
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT __eqtf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __lttf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __netf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT __gttf2(fp_t a, fp_t b) {
+ return __getf2(a, b);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/ctzdi2.c b/compiler-rt/lib/builtins/ctzdi2.c
new file mode 100644
index 0000000..db3c6fd
--- /dev/null
+++ b/compiler-rt/lib/builtins/ctzdi2.c
@@ -0,0 +1,29 @@
+/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ctzdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: the number of trailing 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__ctzdi2(di_int a)
+{
+ dwords x;
+ x.all = a;
+ const si_int f = -(x.s.low == 0);
+ return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) +
+ (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
+}
diff --git a/compiler-rt/lib/builtins/ctzsi2.c b/compiler-rt/lib/builtins/ctzsi2.c
new file mode 100644
index 0000000..c69486e
--- /dev/null
+++ b/compiler-rt/lib/builtins/ctzsi2.c
@@ -0,0 +1,57 @@
+/* ===-- ctzsi2.c - Implement __ctzsi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ctzsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: the number of trailing 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__ctzsi2(si_int a)
+{
+ su_int x = (su_int)a;
+ si_int t = ((x & 0x0000FFFF) == 0) << 4; /* if (x has no small bits) t = 16 else 0 */
+ x >>= t; /* x = [0 - 0xFFFF] + higher garbage bits */
+ su_int r = t; /* r = [0, 16] */
+ /* return r + ctz(x) */
+ t = ((x & 0x00FF) == 0) << 3;
+ x >>= t; /* x = [0 - 0xFF] + higher garbage bits */
+ r += t; /* r = [0, 8, 16, 24] */
+ /* return r + ctz(x) */
+ t = ((x & 0x0F) == 0) << 2;
+ x >>= t; /* x = [0 - 0xF] + higher garbage bits */
+ r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */
+ /* return r + ctz(x) */
+ t = ((x & 0x3) == 0) << 1;
+ x >>= t;
+ x &= 3; /* x = [0 - 3] */
+ r += t; /* r = [0 - 30] and is even */
+ /* return r + ctz(x) */
+
+/* The branch-less return statement below is equivalent
+ * to the following switch statement:
+ * switch (x)
+ * {
+ * case 0:
+ * return r + 2;
+ * case 2:
+ * return r + 1;
+ * case 1:
+ * case 3:
+ * return r;
+ * }
+ */
+ return r + ((2 - (x >> 1)) & -((x & 1) == 0));
+}
diff --git a/compiler-rt/lib/builtins/ctzti2.c b/compiler-rt/lib/builtins/ctzti2.c
new file mode 100644
index 0000000..45de682
--- /dev/null
+++ b/compiler-rt/lib/builtins/ctzti2.c
@@ -0,0 +1,33 @@
+/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ctzti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the number of trailing 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__ctzti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.low == 0);
+ return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/divdc3.c b/compiler-rt/lib/builtins/divdc3.c
new file mode 100644
index 0000000..3c88390
--- /dev/null
+++ b/compiler-rt/lib/builtins/divdc3.c
@@ -0,0 +1,60 @@
+/* ===-- divdc3.c - Implement __divdc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divdc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI Dcomplex
+__divdc3(double __a, double __b, double __c, double __d)
+{
+ int __ilogbw = 0;
+ double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbn(__c, -__ilogbw);
+ __d = crt_scalbn(__d, -__ilogbw);
+ }
+ double __denom = __c * __c + __d * __d;
+ Dcomplex z;
+ COMPLEX_REAL(z) = crt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
+ {
+ COMPLEX_REAL(z) = crt_copysign(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysign(CRT_INFINITY, __c) * __b;
+ }
+ else if ((crt_isinf(__a) || crt_isinf(__b)) &&
+ crt_isfinite(__c) && crt_isfinite(__d))
+ {
+ __a = crt_copysign(crt_isinf(__a) ? 1.0 : 0.0, __a);
+ __b = crt_copysign(crt_isinf(__b) ? 1.0 : 0.0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ }
+ else if (crt_isinf(__logbw) && __logbw > 0.0 &&
+ crt_isfinite(__a) && crt_isfinite(__b))
+ {
+ __c = crt_copysign(crt_isinf(__c) ? 1.0 : 0.0, __c);
+ __d = crt_copysign(crt_isinf(__d) ? 1.0 : 0.0, __d);
+ COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/divdf3.c b/compiler-rt/lib/builtins/divdf3.c
new file mode 100644
index 0000000..ab44c2b
--- /dev/null
+++ b/compiler-rt/lib/builtins/divdf3.c
@@ -0,0 +1,185 @@
+//===-- lib/divdf3.c - Double-precision division ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(ddiv, divdf3)
+
+COMPILER_RT_ABI fp_t
+__divdf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q31 fixed-point number in the range
+ // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ const uint32_t q31b = bSignificand >> 21;
+ uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration, so after three iterations, we have about 28 binary
+ // digits of accuracy.
+ uint32_t correction32;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+
+ // recip32 might have overflowed to exactly zero in the preceding
+ // computation if the high word of b is exactly 1.0. This would sabotage
+ // the full-width final stage of the computation that follows, so we adjust
+ // recip32 downward by one bit.
+ recip32--;
+
+ // We need to perform one more iteration to get us to 56 binary digits;
+ // The last iteration needs to happen with extra precision.
+ const uint32_t q63blo = bSignificand << 11;
+ uint64_t correction, reciprocal;
+ correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32));
+ uint32_t cHi = correction >> 32;
+ uint32_t cLo = correction;
+ reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
+
+ // We already adjusted the 32-bit estimate, now we need to adjust the final
+ // 64-bit reciprocal estimate downward to ensure that it is strictly smaller
+ // than the infinitely precise exact reciprocal. Because the computation
+ // of the Newton-Raphson step is truncating at every step, this adjustment
+ // is small; most of the work is already done.
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-56, lies in the
+ // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
+ // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
+ // in Q53 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0.5, 2.0)
+ // 3. the error in q is bounded away from 2^-53 (actually, we have a
+ // couple of bits to spare, but this is all we need).
+
+ // We need a 64 x 64 multiply high to compute q, which isn't a basic
+ // operation in C, so we need to be a little bit fussy.
+ rep_t quotient, quotientLo;
+ wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo);
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ if (quotient < (implicitBit << 1)) {
+ residual = (aSignificand << 53) - quotient * bSignificand;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ residual = (aSignificand << 52) - quotient * bSignificand;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+
+ else {
+ const bool round = (residual << 1) > bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ const double result = fromRep(absResult | quotientSign);
+ return result;
+ }
+}
diff --git a/compiler-rt/lib/builtins/divdi3.c b/compiler-rt/lib/builtins/divdi3.c
new file mode 100644
index 0000000..b8eebcb
--- /dev/null
+++ b/compiler-rt/lib/builtins/divdi3.c
@@ -0,0 +1,29 @@
+/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI di_int
+__divdi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
+ di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /*sign of quotient */
+ return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/compiler-rt/lib/builtins/divmoddi4.c b/compiler-rt/lib/builtins/divmoddi4.c
new file mode 100644
index 0000000..0d4df67
--- /dev/null
+++ b/compiler-rt/lib/builtins/divmoddi4.c
@@ -0,0 +1,25 @@
+/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI di_int
+__divmoddi4(di_int a, di_int b, di_int* rem)
+{
+ di_int d = __divdi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
diff --git a/compiler-rt/lib/builtins/divmodsi4.c b/compiler-rt/lib/builtins/divmodsi4.c
new file mode 100644
index 0000000..dabe287
--- /dev/null
+++ b/compiler-rt/lib/builtins/divmodsi4.c
@@ -0,0 +1,27 @@
+/*===-- divmodsi4.c - Implement __divmodsi4 --------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divmodsi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI si_int
+__divmodsi4(si_int a, si_int b, si_int* rem)
+{
+ si_int d = __divsi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
+
+
diff --git a/compiler-rt/lib/builtins/divsc3.c b/compiler-rt/lib/builtins/divsc3.c
new file mode 100644
index 0000000..42a4831
--- /dev/null
+++ b/compiler-rt/lib/builtins/divsc3.c
@@ -0,0 +1,60 @@
+/*===-- divsc3.c - Implement __divsc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divsc3 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI Fcomplex
+__divsc3(float __a, float __b, float __c, float __d)
+{
+ int __ilogbw = 0;
+ float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnf(__c, -__ilogbw);
+ __d = crt_scalbnf(__d, -__ilogbw);
+ }
+ float __denom = __c * __c + __d * __d;
+ Fcomplex z;
+ COMPLEX_REAL(z) = crt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
+ {
+ COMPLEX_REAL(z) = crt_copysignf(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignf(CRT_INFINITY, __c) * __b;
+ }
+ else if ((crt_isinf(__a) || crt_isinf(__b)) &&
+ crt_isfinite(__c) && crt_isfinite(__d))
+ {
+ __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ }
+ else if (crt_isinf(__logbw) && __logbw > 0 &&
+ crt_isfinite(__a) && crt_isfinite(__b))
+ {
+ __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/divsf3.c b/compiler-rt/lib/builtins/divsf3.c
new file mode 100644
index 0000000..de2e376
--- /dev/null
+++ b/compiler-rt/lib/builtins/divsf3.c
@@ -0,0 +1,169 @@
+//===-- lib/divsf3.c - Single-precision division ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(fdiv, divsf3)
+
+COMPILER_RT_ABI fp_t
+__divsf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q31 fixed-point number in the range
+ // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ uint32_t q31b = bSignificand << 8;
+ uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration, so after three iterations, we have about 28 binary
+ // digits of accuracy.
+ uint32_t correction;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+
+ // Exhaustive testing shows that the error in reciprocal after three steps
+ // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
+ // expectations. We bump the reciprocal by a tiny value to force the error
+ // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to
+ // be specific). This also causes 1/1 to give a sensible approximation
+ // instead of zero (due to overflow).
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-28, lies in the
+ // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
+ // than the true reciprocal of b. Multiplying a by this reciprocal thus
+ // gives a numerical q = a/b in Q24 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0)
+ // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes
+ // from the fact that we truncate the product, and the 2^27 term
+ // is the error in the reciprocal of b scaled by the maximum
+ // possible value of a. As a consequence of this error bound,
+ // either q or nextafter(q) is the correctly rounded
+ rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ if (quotient < (implicitBit << 1)) {
+ residual = (aSignificand << 24) - quotient * bSignificand;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ residual = (aSignificand << 23) - quotient * bSignificand;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+
+ else {
+ const bool round = (residual << 1) > bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ return fromRep(absResult | quotientSign);
+ }
+}
diff --git a/compiler-rt/lib/builtins/divsi3.c b/compiler-rt/lib/builtins/divsi3.c
new file mode 100644
index 0000000..bab4aef
--- /dev/null
+++ b/compiler-rt/lib/builtins/divsi3.c
@@ -0,0 +1,37 @@
+/* ===-- divsi3.c - Implement __divsi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+ARM_EABI_FNALIAS(idiv, divsi3)
+
+COMPILER_RT_ABI si_int
+__divsi3(si_int a, si_int b)
+{
+ const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
+ si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */
+ si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /* sign of quotient */
+ /*
+ * On CPUs without unsigned hardware division support,
+ * this calls __udivsi3 (notice the cast to su_int).
+ * On CPUs with unsigned hardware division support,
+ * this uses the unsigned division instruction.
+ */
+ return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/compiler-rt/lib/builtins/divtc3.c b/compiler-rt/lib/builtins/divtc3.c
new file mode 100644
index 0000000..04693df
--- /dev/null
+++ b/compiler-rt/lib/builtins/divtc3.c
@@ -0,0 +1,60 @@
+/*===-- divtc3.c - Implement __divtc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divtc3 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI long double _Complex
+__divtc3(long double __a, long double __b, long double __c, long double __d)
+{
+ int __ilogbw = 0;
+ long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnl(__c, -__ilogbw);
+ __d = crt_scalbnl(__d, -__ilogbw);
+ }
+ long double __denom = __c * __c + __d * __d;
+ long double _Complex z;
+ __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ {
+ if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
+ {
+ __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a;
+ __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b;
+ }
+ else if ((crt_isinf(__a) || crt_isinf(__b)) &&
+ crt_isfinite(__c) && crt_isfinite(__d))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b);
+ __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
+ __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
+ }
+ else if (crt_isinf(__logbw) && __logbw > 0.0 &&
+ crt_isfinite(__a) && crt_isfinite(__b))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d);
+ __real__ z = 0.0 * (__a * __c + __b * __d);
+ __imag__ z = 0.0 * (__b * __c - __a * __d);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/divtf3.c b/compiler-rt/lib/builtins/divtf3.c
new file mode 100644
index 0000000..e81dab8
--- /dev/null
+++ b/compiler-rt/lib/builtins/divtf3.c
@@ -0,0 +1,203 @@
+//===-- lib/divtf3.c - Quad-precision division --------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q63 fixed-point number in the range
+ // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ const uint64_t q63b = bSignificand >> 49;
+ uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b;
+ // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration.
+ uint64_t correction64;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+
+ // recip64 might have overflowed to exactly zero in the preceeding
+ // computation if the high word of b is exactly 1.0. This would sabotage
+ // the full-width final stage of the computation that follows, so we adjust
+ // recip64 downward by one bit.
+ recip64--;
+
+ // We need to perform one more iteration to get us to 112 binary digits;
+ // The last iteration needs to happen with extra precision.
+ const uint64_t q127blo = bSignificand << 15;
+ rep_t correction, reciprocal;
+
+ // NOTE: This operation is equivalent to __multi3, which is not implemented
+ // in some architechure
+ rep_t r64q63, r64q127, r64cH, r64cL, dummy;
+ wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63);
+ wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127);
+
+ correction = -(r64q63 + (r64q127 >> 64));
+
+ uint64_t cHi = correction >> 64;
+ uint64_t cLo = correction;
+
+ wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH);
+ wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL);
+
+ reciprocal = r64cH + (r64cL >> 64);
+
+ // We already adjusted the 64-bit estimate, now we need to adjust the final
+ // 128-bit reciprocal estimate downward to ensure that it is strictly smaller
+ // than the infinitely precise exact reciprocal. Because the computation
+ // of the Newton-Raphson step is truncating at every step, this adjustment
+ // is small; most of the work is already done.
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-112, lies in the
+ // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
+ // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
+ // in Q127 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0.5, 2.0)
+ // 3. the error in q is bounded away from 2^-113 (actually, we have a
+ // couple of bits to spare, but this is all we need).
+
+ // We need a 128 x 128 multiply high to compute q, which isn't a basic
+ // operation in C, so we need to be a little bit fussy.
+ rep_t quotient, quotientLo;
+ wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo);
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ rep_t qb;
+
+ if (quotient < (implicitBit << 1)) {
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 113) - qb;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 112) - qb;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+ else {
+ const bool round = (residual << 1) >= bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ const long double result = fromRep(absResult | quotientSign);
+ return result;
+ }
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/divti3.c b/compiler-rt/lib/builtins/divti3.c
new file mode 100644
index 0000000..c73eae2
--- /dev/null
+++ b/compiler-rt/lib/builtins/divti3.c
@@ -0,0 +1,33 @@
+/* ===-- divti3.c - Implement __divti3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI ti_int
+__divti3(ti_int a, ti_int b)
+{
+ const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+ ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */
+ ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /* sign of quotient */
+ return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/divxc3.c b/compiler-rt/lib/builtins/divxc3.c
new file mode 100644
index 0000000..6f49280
--- /dev/null
+++ b/compiler-rt/lib/builtins/divxc3.c
@@ -0,0 +1,63 @@
+/* ===-- divxc3.c - Implement __divxc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divxc3 for the compiler_rt library.
+ *
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI Lcomplex
+__divxc3(long double __a, long double __b, long double __c, long double __d)
+{
+ int __ilogbw = 0;
+ long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnl(__c, -__ilogbw);
+ __d = crt_scalbnl(__d, -__ilogbw);
+ }
+ long double __denom = __c * __c + __d * __d;
+ Lcomplex z;
+ COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
+ {
+ COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
+ }
+ else if ((crt_isinf(__a) || crt_isinf(__b)) &&
+ crt_isfinite(__c) && crt_isfinite(__d))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ }
+ else if (crt_isinf(__logbw) && __logbw > 0 &&
+ crt_isfinite(__a) && crt_isfinite(__b))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
+ }
+ }
+ return z;
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/emutls.c b/compiler-rt/lib/builtins/emutls.c
new file mode 100644
index 0000000..09e7956
--- /dev/null
+++ b/compiler-rt/lib/builtins/emutls.c
@@ -0,0 +1,183 @@
+/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "int_lib.h"
+#include "int_util.h"
+
+/* Default is not to use posix_memalign, so systems like Android
+ * can use thread local data without heavier POSIX memory allocators.
+ */
+#ifndef EMUTLS_USE_POSIX_MEMALIGN
+#define EMUTLS_USE_POSIX_MEMALIGN 0
+#endif
+
+/* For every TLS variable xyz,
+ * there is one __emutls_control variable named __emutls_v.xyz.
+ * If xyz has non-zero initial value, __emutls_v.xyz's "value"
+ * will point to __emutls_t.xyz, which has the initial value.
+ */
+typedef struct __emutls_control {
+ size_t size; /* size of the object in bytes */
+ size_t align; /* alignment of the object in bytes */
+ union {
+ uintptr_t index; /* data[index-1] is the object address */
+ void* address; /* object address, when in single thread env */
+ } object;
+ void* value; /* null or non-zero initial value for the object */
+} __emutls_control;
+
+static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
+ void *base;
+#if EMUTLS_USE_POSIX_MEMALIGN
+ if (posix_memalign(&base, align, size) != 0)
+ abort();
+#else
+ #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
+ char* object;
+ if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
+ abort();
+ base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
+ & ~(uintptr_t)(align - 1));
+
+ ((void**)base)[-1] = object;
+#endif
+ return base;
+}
+
+static __inline void emutls_memalign_free(void *base) {
+#if EMUTLS_USE_POSIX_MEMALIGN
+ free(base);
+#else
+ /* The mallocated address is in ((void**)base)[-1] */
+ free(((void**)base)[-1]);
+#endif
+}
+
+/* Emulated TLS objects are always allocated at run-time. */
+static __inline void *emutls_allocate_object(__emutls_control *control) {
+ /* Use standard C types, check with gcc's emutls.o. */
+ typedef unsigned int gcc_word __attribute__((mode(word)));
+ typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
+ COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
+
+ size_t size = control->size;
+ size_t align = control->align;
+ if (align < sizeof(void*))
+ align = sizeof(void*);
+ /* Make sure that align is power of 2. */
+ if ((align & (align - 1)) != 0)
+ abort();
+
+ void* base = emutls_memalign_alloc(align, size);
+ if (control->value)
+ memcpy(base, control->value, size);
+ else
+ memset(base, 0, size);
+ return base;
+}
+
+static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static size_t emutls_num_object = 0; /* number of allocated TLS objects */
+
+typedef struct emutls_address_array {
+ uintptr_t size; /* number of elements in the 'data' array */
+ void* data[];
+} emutls_address_array;
+
+static pthread_key_t emutls_pthread_key;
+
+static void emutls_key_destructor(void* ptr) {
+ emutls_address_array* array = (emutls_address_array*)ptr;
+ uintptr_t i;
+ for (i = 0; i < array->size; ++i) {
+ if (array->data[i])
+ emutls_memalign_free(array->data[i]);
+ }
+ free(ptr);
+}
+
+static void emutls_init(void) {
+ if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
+ abort();
+}
+
+/* Returns control->object.index; set index if not allocated yet. */
+static __inline uintptr_t emutls_get_index(__emutls_control *control) {
+ uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
+ if (!index) {
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, emutls_init);
+ pthread_mutex_lock(&emutls_mutex);
+ index = control->object.index;
+ if (!index) {
+ index = ++emutls_num_object;
+ __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
+ }
+ pthread_mutex_unlock(&emutls_mutex);
+ }
+ return index;
+}
+
+/* Updates newly allocated thread local emutls_address_array. */
+static __inline void emutls_check_array_set_size(emutls_address_array *array,
+ uintptr_t size) {
+ if (array == NULL)
+ abort();
+ array->size = size;
+ pthread_setspecific(emutls_pthread_key, (void*)array);
+}
+
+/* Returns the new 'data' array size, number of elements,
+ * which must be no smaller than the given index.
+ */
+static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
+ /* Need to allocate emutls_address_array with one extra slot
+ * to store the data array size.
+ * Round up the emutls_address_array size to multiple of 16.
+ */
+ return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
+}
+
+/* Returns the thread local emutls_address_array.
+ * Extends its size if necessary to hold address at index.
+ */
+static __inline emutls_address_array *
+emutls_get_address_array(uintptr_t index) {
+ emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
+ if (array == NULL) {
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = calloc(new_size + 1, sizeof(void*));
+ emutls_check_array_set_size(array, new_size);
+ } else if (index > array->size) {
+ uintptr_t orig_size = array->size;
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = realloc(array, (new_size + 1) * sizeof(void*));
+ if (array)
+ memset(array->data + orig_size, 0,
+ (new_size - orig_size) * sizeof(void*));
+ emutls_check_array_set_size(array, new_size);
+ }
+ return array;
+}
+
+void* __emutls_get_address(__emutls_control* control) {
+ uintptr_t index = emutls_get_index(control);
+ emutls_address_array* array = emutls_get_address_array(index);
+ if (array->data[index - 1] == NULL)
+ array->data[index - 1] = emutls_allocate_object(control);
+ return array->data[index - 1];
+}
diff --git a/compiler-rt/lib/builtins/enable_execute_stack.c b/compiler-rt/lib/builtins/enable_execute_stack.c
new file mode 100644
index 0000000..0dc3482
--- /dev/null
+++ b/compiler-rt/lib/builtins/enable_execute_stack.c
@@ -0,0 +1,72 @@
+/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+
+/* #include "config.h"
+ * FIXME: CMake - include when cmake system is ready.
+ * Remove #define HAVE_SYSCONF 1 line.
+ */
+#define HAVE_SYSCONF 1
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#else
+#ifndef __APPLE__
+#include <unistd.h>
+#endif /* __APPLE__ */
+#endif /* _WIN32 */
+
+#if __LP64__
+ #define TRAMPOLINE_SIZE 48
+#else
+ #define TRAMPOLINE_SIZE 40
+#endif
+
+/*
+ * The compiler generates calls to __enable_execute_stack() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * It is expected to mark the page(s) containing the address
+ * and the next 48 bytes as executable. Since the stack is normally rw-
+ * that means changing the protection on those page(s) to rwx.
+ */
+
+COMPILER_RT_ABI void
+__enable_execute_stack(void* addr)
+{
+
+#if _WIN32
+ MEMORY_BASIC_INFORMATION mbi;
+ if (!VirtualQuery (addr, &mbi, sizeof(mbi)))
+ return; /* We should probably assert here because there is no return value */
+ VirtualProtect (mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
+#else
+#if __APPLE__
+ /* On Darwin, pagesize is always 4096 bytes */
+ const uintptr_t pageSize = 4096;
+#elif !defined(HAVE_SYSCONF)
+#error "HAVE_SYSCONF not defined! See enable_execute_stack.c"
+#else
+ const uintptr_t pageSize = sysconf(_SC_PAGESIZE);
+#endif /* __APPLE__ */
+
+ const uintptr_t pageAlignMask = ~(pageSize-1);
+ uintptr_t p = (uintptr_t)addr;
+ unsigned char* startPage = (unsigned char*)(p & pageAlignMask);
+ unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask);
+ size_t length = endPage - startPage;
+ (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
+#endif
+}
diff --git a/compiler-rt/lib/builtins/eprintf.c b/compiler-rt/lib/builtins/eprintf.c
new file mode 100644
index 0000000..89f34b1
--- /dev/null
+++ b/compiler-rt/lib/builtins/eprintf.c
@@ -0,0 +1,35 @@
+/* ===---------- eprintf.c - Implements __eprintf --------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+
+
+#include "int_lib.h"
+#include <stdio.h>
+
+
+/*
+ * __eprintf() was used in an old version of <assert.h>.
+ * It can eventually go away, but it is needed when linking
+ * .o files built with the old <assert.h>.
+ *
+ * It should never be exported from a dylib, so it is marked
+ * visibility hidden.
+ */
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+COMPILER_RT_ABI void
+__eprintf(const char* format, const char* assertion_expression,
+ const char* line, const char* file)
+{
+ fprintf(stderr, format, assertion_expression, line, file);
+ fflush(stderr);
+ compilerrt_abort();
+}
diff --git a/compiler-rt/lib/builtins/extenddftf2.c b/compiler-rt/lib/builtins/extenddftf2.c
new file mode 100644
index 0000000..86dab8f
--- /dev/null
+++ b/compiler-rt/lib/builtins/extenddftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extenddftf2.c - double -> quad conversion -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_DOUBLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extenddftf2(double a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/extendhfsf2.c b/compiler-rt/lib/builtins/extendhfsf2.c
new file mode 100644
index 0000000..27115a4
--- /dev/null
+++ b/compiler-rt/lib/builtins/extendhfsf2.c
@@ -0,0 +1,25 @@
+//===-- lib/extendhfsf2.c - half -> single conversion -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define SRC_HALF
+#define DST_SINGLE
+#include "fp_extend_impl.inc"
+
+ARM_EABI_FNALIAS(h2f, extendhfsf2)
+
+// Use a forwarding definition and noinline to implement a poor man's alias,
+// as there isn't a good cross-platform way of defining one.
+COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) {
+ return __extendXfYf2__(a);
+}
+
+COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) {
+ return __extendhfsf2(a);
+}
diff --git a/compiler-rt/lib/builtins/extendsfdf2.c b/compiler-rt/lib/builtins/extendsfdf2.c
new file mode 100644
index 0000000..7a267c2
--- /dev/null
+++ b/compiler-rt/lib/builtins/extendsfdf2.c
@@ -0,0 +1,19 @@
+//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define SRC_SINGLE
+#define DST_DOUBLE
+#include "fp_extend_impl.inc"
+
+ARM_EABI_FNALIAS(f2d, extendsfdf2)
+
+COMPILER_RT_ABI double __extendsfdf2(float a) {
+ return __extendXfYf2__(a);
+}
diff --git a/compiler-rt/lib/builtins/extendsftf2.c b/compiler-rt/lib/builtins/extendsftf2.c
new file mode 100644
index 0000000..2eeeba2
--- /dev/null
+++ b/compiler-rt/lib/builtins/extendsftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extendsftf2.c - single -> quad conversion -------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_SINGLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extendsftf2(float a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/ffsdi2.c b/compiler-rt/lib/builtins/ffsdi2.c
new file mode 100644
index 0000000..a5ac990
--- /dev/null
+++ b/compiler-rt/lib/builtins/ffsdi2.c
@@ -0,0 +1,33 @@
+/* ===-- ffsdi2.c - Implement __ffsdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ffsdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: the index of the least significant 1-bit in a, or
+ * the value zero if a is zero. The least significant bit is index one.
+ */
+
+COMPILER_RT_ABI si_int
+__ffsdi2(di_int a)
+{
+ dwords x;
+ x.all = a;
+ if (x.s.low == 0)
+ {
+ if (x.s.high == 0)
+ return 0;
+ return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT);
+ }
+ return __builtin_ctz(x.s.low) + 1;
+}
diff --git a/compiler-rt/lib/builtins/ffsti2.c b/compiler-rt/lib/builtins/ffsti2.c
new file mode 100644
index 0000000..dcdb3bd
--- /dev/null
+++ b/compiler-rt/lib/builtins/ffsti2.c
@@ -0,0 +1,37 @@
+/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ffsti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the index of the least significant 1-bit in a, or
+ * the value zero if a is zero. The least significant bit is index one.
+ */
+
+COMPILER_RT_ABI si_int
+__ffsti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ if (x.s.low == 0)
+ {
+ if (x.s.high == 0)
+ return 0;
+ return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT);
+ }
+ return __builtin_ctzll(x.s.low) + 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixdfdi.c b/compiler-rt/lib/builtins/fixdfdi.c
new file mode 100644
index 0000000..14283ef
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixdfdi.c
@@ -0,0 +1,46 @@
+/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+ARM_EABI_FNALIAS(d2lz, fixdfdi)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int __fixunsdfdi(double a);
+
+COMPILER_RT_ABI di_int
+__fixdfdi(double a)
+{
+ if (a < 0.0) {
+ return -__fixunsdfdi(-a);
+ }
+ return __fixunsdfdi(a);
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixdfdi(fp_t a) {
+ return __fixint(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fixdfsi.c b/compiler-rt/lib/builtins/fixdfsi.c
new file mode 100644
index 0000000..704e65b
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixdfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+ARM_EABI_FNALIAS(d2iz, fixdfsi)
+
+COMPILER_RT_ABI si_int
+__fixdfsi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/compiler-rt/lib/builtins/fixdfti.c b/compiler-rt/lib/builtins/fixdfti.c
new file mode 100644
index 0000000..aaf225e
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixdfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixdfti(fp_t a) {
+ return __fixint(a);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixsfdi.c b/compiler-rt/lib/builtins/fixsfdi.c
new file mode 100644
index 0000000..fab47e2
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixsfdi.c
@@ -0,0 +1,47 @@
+/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(f2lz, fixsfdi)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int __fixunssfdi(float a);
+
+COMPILER_RT_ABI di_int
+__fixsfdi(float a)
+{
+ if (a < 0.0f) {
+ return -__fixunssfdi(-a);
+ }
+ return __fixunssfdi(a);
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixsfdi(fp_t a) {
+ return __fixint(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fixsfsi.c b/compiler-rt/lib/builtins/fixsfsi.c
new file mode 100644
index 0000000..f045536
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixsfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+ARM_EABI_FNALIAS(f2iz, fixsfsi)
+
+COMPILER_RT_ABI si_int
+__fixsfsi(fp_t a) {
+ return __fixint(a);
+}
diff --git a/compiler-rt/lib/builtins/fixsfti.c b/compiler-rt/lib/builtins/fixsfti.c
new file mode 100644
index 0000000..3a159b3
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixsfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixsfti(fp_t a) {
+ return __fixint(a);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixtfdi.c b/compiler-rt/lib/builtins/fixtfdi.c
new file mode 100644
index 0000000..bc9dea1
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixtfdi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixtfdi(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixtfsi.c b/compiler-rt/lib/builtins/fixtfsi.c
new file mode 100644
index 0000000..feb3de8
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixtfsi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI si_int
+__fixtfsi(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixtfti.c b/compiler-rt/lib/builtins/fixtfti.c
new file mode 100644
index 0000000..ee4ada8
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixtfti.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixtfti(fp_t a) {
+ return __fixint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunsdfdi.c b/compiler-rt/lib/builtins/fixunsdfdi.c
new file mode 100644
index 0000000..4b0bc9e
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsdfdi.c
@@ -0,0 +1,44 @@
+/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int
+__fixunsdfdi(double a)
+{
+ if (a <= 0.0) return 0;
+ su_int high = a / 4294967296.f; /* a / 0x1p32f; */
+ su_int low = a - (double)high * 4294967296.f; /* high * 0x1p32f; */
+ return ((du_int)high << 32) | low;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunsdfdi(fp_t a) {
+ return __fixuint(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fixunsdfsi.c b/compiler-rt/lib/builtins/fixunsdfsi.c
new file mode 100644
index 0000000..232d342
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsdfsi.c
@@ -0,0 +1,21 @@
+/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
+
+COMPILER_RT_ABI su_int
+__fixunsdfsi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/compiler-rt/lib/builtins/fixunsdfti.c b/compiler-rt/lib/builtins/fixunsdfti.c
new file mode 100644
index 0000000..f8046a0
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsdfti.c
@@ -0,0 +1,23 @@
+/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunsdfti(fp_t a) {
+ return __fixuint(a);
+}
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixunssfdi.c b/compiler-rt/lib/builtins/fixunssfdi.c
new file mode 100644
index 0000000..f8ebab8
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunssfdi.c
@@ -0,0 +1,45 @@
+/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int
+__fixunssfdi(float a)
+{
+ if (a <= 0.0f) return 0;
+ double da = a;
+ su_int high = da / 4294967296.f; /* da / 0x1p32f; */
+ su_int low = da - (double)high * 4294967296.f; /* high * 0x1p32f; */
+ return ((du_int)high << 32) | low;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunssfdi(fp_t a) {
+ return __fixuint(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fixunssfsi.c b/compiler-rt/lib/builtins/fixunssfsi.c
new file mode 100644
index 0000000..cc2b05b
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunssfsi.c
@@ -0,0 +1,25 @@
+/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunssfsi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
+
+COMPILER_RT_ABI su_int
+__fixunssfsi(fp_t a) {
+ return __fixuint(a);
+}
diff --git a/compiler-rt/lib/builtins/fixunssfti.c b/compiler-rt/lib/builtins/fixunssfti.c
new file mode 100644
index 0000000..862d7bd
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunssfti.c
@@ -0,0 +1,26 @@
+/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunssfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunssfti(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfdi.c b/compiler-rt/lib/builtins/fixunstfdi.c
new file mode 100644
index 0000000..b2995f6
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunstfdi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunstfdi(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfsi.c b/compiler-rt/lib/builtins/fixunstfsi.c
new file mode 100644
index 0000000..b5d3f6a
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunstfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI su_int
+__fixunstfsi(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunstfti.c b/compiler-rt/lib/builtins/fixunstfti.c
new file mode 100644
index 0000000..22ff9df
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunstfti.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunstfti(fp_t a) {
+ return __fixuint(a);
+}
+#endif
diff --git a/compiler-rt/lib/builtins/fixunsxfdi.c b/compiler-rt/lib/builtins/fixunsxfdi.c
new file mode 100644
index 0000000..075304e
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsxfdi.c
@@ -0,0 +1,46 @@
+/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunsxfdi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * du_int is a 64 bit integral type
+ * value in long double is representable in du_int or is negative
+ * (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI du_int
+__fixunsxfdi(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
+ return ~(du_int)0;
+ return fb.u.low.all >> (63 - e);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fixunsxfsi.c b/compiler-rt/lib/builtins/fixunsxfsi.c
new file mode 100644
index 0000000..c3c70f7
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsxfsi.c
@@ -0,0 +1,45 @@
+/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunsxfsi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a unsigned int, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * su_int is a 32 bit integral type
+ * value in long double is representable in su_int or is negative
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI su_int
+__fixunsxfsi(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
+ return ~(su_int)0;
+ return fb.u.low.s.high >> (31 - e);
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/compiler-rt/lib/builtins/fixunsxfti.c b/compiler-rt/lib/builtins/fixunsxfti.c
new file mode 100644
index 0000000..fb39d00
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixunsxfti.c
@@ -0,0 +1,50 @@
+/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixunsxfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * tu_int is a 128 bit integral type
+ * value in long double is representable in tu_int or is negative
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI tu_int
+__fixunsxfti(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
+ return ~(tu_int)0;
+ tu_int r = fb.u.low.all;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/fixxfdi.c b/compiler-rt/lib/builtins/fixxfdi.c
new file mode 100644
index 0000000..011787f
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixxfdi.c
@@ -0,0 +1,48 @@
+/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixxfdi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * di_int is a 64 bit integral type
+ * value in long double is representable in di_int (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI di_int
+__fixxfdi(long double a)
+{
+ const di_int di_max = (di_int)((~(du_int)0) / 2);
+ const di_int di_min = -di_max - 1;
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
+ return a > 0 ? di_max : di_min;
+ di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ di_int r = fb.u.low.all;
+ r = (du_int)r >> (63 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/compiler-rt/lib/builtins/fixxfti.c b/compiler-rt/lib/builtins/fixxfti.c
new file mode 100644
index 0000000..968a4f0
--- /dev/null
+++ b/compiler-rt/lib/builtins/fixxfti.c
@@ -0,0 +1,51 @@
+/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __fixxfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * ti_int is a 128 bit integral type
+ * value in long double is representable in ti_int
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI ti_int
+__fixxfti(long double a)
+{
+ const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
+ const ti_int ti_min = -ti_max - 1;
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ ti_int r = fb.u.low.all;
+ if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
+ return a > 0 ? ti_max : ti_min;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floatdidf.c b/compiler-rt/lib/builtins/floatdidf.c
new file mode 100644
index 0000000..a300c9f
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatdidf.c
@@ -0,0 +1,107 @@
+/*===-- floatdidf.c - Implement __floatdidf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * This file implements __floatdidf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: convert a to a double, rounding toward even. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * di_int is a 64 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+ARM_EABI_FNALIAS(l2d, floatdidf)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; we'll set the inexact flag
+ * as a side-effect of this computation.
+ */
+
+COMPILER_RT_ABI double
+__floatdidf(di_int a)
+{
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop32 = 4294967296.0; // 0x1.0p32
+
+ union { int64_t x; double d; } low = { .d = twop52 };
+
+ const double high = (int32_t)(a >> 32) * twop32;
+ low.x |= a & INT64_C(0x00000000ffffffff);
+
+ const double result = (high - twop52) + low.d;
+ return result;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no flags to
+ * set, and we don't want to code-gen to an unknown soft-float implementation.
+ */
+
+COMPILER_RT_ABI double
+__floatdidf(di_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.high = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+#endif
diff --git a/compiler-rt/lib/builtins/floatdisf.c b/compiler-rt/lib/builtins/floatdisf.c
new file mode 100644
index 0000000..3e47580
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatdisf.c
@@ -0,0 +1,80 @@
+/*===-- floatdisf.c - Implement __floatdisf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * This file implements __floatdisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even.*/
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * di_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(l2f, floatdisf)
+
+COMPILER_RT_ABI float
+__floatdisf(di_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
diff --git a/compiler-rt/lib/builtins/floatditf.c b/compiler-rt/lib/builtins/floatditf.c
new file mode 100644
index 0000000..cd51dd8
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatditf.c
@@ -0,0 +1,50 @@
+//===-- lib/floatditf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements di_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatditf(di_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ du_int aAbs = (du_int)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs = ~(du_int)a + 1U;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(aAbs);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/floatdixf.c b/compiler-rt/lib/builtins/floatdixf.c
new file mode 100644
index 0000000..d39e81d
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatdixf.c
@@ -0,0 +1,46 @@
+/* ===-- floatdixf.c - Implement __floatdixf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatdixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * di_int is a 64 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floatdixf(di_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz ; /* exponent */
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */
+ (e + 16383); /* exponent */
+ fb.u.low.all = a << clz; /* mantissa */
+ return fb.f;
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/compiler-rt/lib/builtins/floatsidf.c b/compiler-rt/lib/builtins/floatsidf.c
new file mode 100644
index 0000000..1cf99b7
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatsidf.c
@@ -0,0 +1,53 @@
+//===-- lib/floatsidf.c - integer -> double-precision conversion --*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements integer to double-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(i2d, floatsidf)
+
+COMPILER_RT_ABI fp_t
+__floatsidf(int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit. Extra
+ // cast to unsigned int is necessary to get the correct behavior for
+ // the input INT_MIN.
+ const int shift = significandBits - exponent;
+ result = (rep_t)(unsigned int)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
diff --git a/compiler-rt/lib/builtins/floatsisf.c b/compiler-rt/lib/builtins/floatsisf.c
new file mode 100644
index 0000000..467dd1d
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatsisf.c
@@ -0,0 +1,59 @@
+//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements integer to single-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(i2f, floatsisf)
+
+COMPILER_RT_ABI fp_t
+__floatsisf(int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit) result++;
+ if (round == signBit) result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
diff --git a/compiler-rt/lib/builtins/floatsitf.c b/compiler-rt/lib/builtins/floatsitf.c
new file mode 100644
index 0000000..f0abca3
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatsitf.c
@@ -0,0 +1,50 @@
+//===-- lib/floatsitf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements integer to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatsitf(int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ unsigned aAbs = (unsigned)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs = ~(unsigned)a + 1U;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(aAbs);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/floattidf.c b/compiler-rt/lib/builtins/floattidf.c
new file mode 100644
index 0000000..6331ba5
--- /dev/null
+++ b/compiler-rt/lib/builtins/floattidf.c
@@ -0,0 +1,83 @@
+/* ===-- floattidf.c - Implement __floattidf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floattidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a double, rounding toward even.*/
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * ti_int is a 128 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI double
+__floattidf(ti_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.s.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floattisf.c b/compiler-rt/lib/builtins/floattisf.c
new file mode 100644
index 0000000..f1b585f
--- /dev/null
+++ b/compiler-rt/lib/builtins/floattisf.c
@@ -0,0 +1,82 @@
+/* ===-- floattisf.c - Implement __floattisf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floattisf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * ti_int is a 128 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI float
+__floattisf(ti_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floattixf.c b/compiler-rt/lib/builtins/floattixf.c
new file mode 100644
index 0000000..1203b3a
--- /dev/null
+++ b/compiler-rt/lib/builtins/floattixf.c
@@ -0,0 +1,84 @@
+/* ===-- floattixf.c - Implement __floattixf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floattixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * ti_int is a 128 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floattixf(ti_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > LDBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit LDBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << LDBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (LDBL_MANT_DIG - sd);
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */
+ (e + 16383); /* exponent */
+ fb.u.low.all = (du_int)a; /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floatundidf.c b/compiler-rt/lib/builtins/floatundidf.c
new file mode 100644
index 0000000..67aa86e
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatundidf.c
@@ -0,0 +1,106 @@
+/* ===-- floatundidf.c - Implement __floatundidf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatundidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a double, rounding toward even. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * du_int is a 64 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ul2d, floatundidf)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; we'll set the inexact flag
+ * as a side-effect of this computation.
+ */
+
+COMPILER_RT_ABI double
+__floatundidf(du_int a)
+{
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84
+ static const double twop84_plus_twop52 = 19342813118337666422669312.0; // 0x1.00000001p84
+
+ union { uint64_t x; double d; } high = { .d = twop84 };
+ union { uint64_t x; double d; } low = { .d = twop52 };
+
+ high.x |= a >> 32;
+ low.x |= a & UINT64_C(0x00000000ffffffff);
+
+ const double result = (high.d - twop84_plus_twop52) + low.d;
+ return result;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no flags to
+ * set, and we don't want to code-gen to an unknown soft-float implementation.
+ */
+
+COMPILER_RT_ABI double
+__floatundidf(du_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.high = ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+#endif
diff --git a/compiler-rt/lib/builtins/floatundisf.c b/compiler-rt/lib/builtins/floatundisf.c
new file mode 100644
index 0000000..713a44a
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatundisf.c
@@ -0,0 +1,77 @@
+/*===-- floatundisf.c - Implement __floatundisf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatundisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * du_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ul2f, floatundisf)
+
+COMPILER_RT_ABI float
+__floatundisf(du_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* 8 exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
diff --git a/compiler-rt/lib/builtins/floatunditf.c b/compiler-rt/lib/builtins/floatunditf.c
new file mode 100644
index 0000000..8098e95
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatunditf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunditf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements du_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunditf(du_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/floatundixf.c b/compiler-rt/lib/builtins/floatundixf.c
new file mode 100644
index 0000000..ca5e06d
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatundixf.c
@@ -0,0 +1,42 @@
+/* ===-- floatundixf.c - Implement __floatundixf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatundixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * du_int is a 64 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+COMPILER_RT_ABI long double
+__floatundixf(du_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz ; /* exponent */
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); /* exponent */
+ fb.u.low.all = a << clz; /* mantissa */
+ return fb.f;
+}
+
+#endif /* _ARCH_PPC */
diff --git a/compiler-rt/lib/builtins/floatunsidf.c b/compiler-rt/lib/builtins/floatunsidf.c
new file mode 100644
index 0000000..445e180
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatunsidf.c
@@ -0,0 +1,42 @@
+//===-- lib/floatunsidf.c - uint -> double-precision conversion ---*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unsigned integer to double-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ui2d, floatunsidf)
+
+COMPILER_RT_ABI fp_t
+__floatunsidf(unsigned int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
diff --git a/compiler-rt/lib/builtins/floatunsisf.c b/compiler-rt/lib/builtins/floatunsisf.c
new file mode 100644
index 0000000..ea6f161
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatunsisf.c
@@ -0,0 +1,50 @@
+//===-- lib/floatunsisf.c - uint -> single-precision conversion ---*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unsigned integer to single-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ui2f, floatunsisf)
+
+COMPILER_RT_ABI fp_t
+__floatunsisf(unsigned int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit) result++;
+ if (round == signBit) result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
diff --git a/compiler-rt/lib/builtins/floatunsitf.c b/compiler-rt/lib/builtins/floatunsitf.c
new file mode 100644
index 0000000..1cd1842
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatunsitf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunsitf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unsigned integer to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunsitf(unsigned int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/floatuntidf.c b/compiler-rt/lib/builtins/floatuntidf.c
new file mode 100644
index 0000000..06202d9
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatuntidf.c
@@ -0,0 +1,80 @@
+/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatuntidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a double, rounding toward even. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * tu_int is a 128 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI double
+__floatuntidf(tu_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.s.high = ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.s.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floatuntisf.c b/compiler-rt/lib/builtins/floatuntisf.c
new file mode 100644
index 0000000..c0dd027
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatuntisf.c
@@ -0,0 +1,79 @@
+/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatuntisf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * tu_int is a 128 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI float
+__floatuntisf(tu_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/floatuntixf.c b/compiler-rt/lib/builtins/floatuntixf.c
new file mode 100644
index 0000000..ea81cb1
--- /dev/null
+++ b/compiler-rt/lib/builtins/floatuntixf.c
@@ -0,0 +1,81 @@
+/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatuntixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * tu_int is a 128 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floatuntixf(tu_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > LDBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit LDBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (LDBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << LDBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (LDBL_MANT_DIG - sd);
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); /* exponent */
+ fb.u.low.all = (du_int)a; /* mantissa */
+ return fb.f;
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/fp_add_impl.inc b/compiler-rt/lib/builtins/fp_add_impl.inc
new file mode 100644
index 0000000..b47be1b
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_add_impl.inc
@@ -0,0 +1,144 @@
+//===----- lib/fp_add_impl.inc - floaing point addition -----------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements soft-float addition with the IEEE-754 default rounding
+// (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static __inline fp_t __addXf3__(fp_t a, fp_t b) {
+ rep_t aRep = toRep(a);
+ rep_t bRep = toRep(b);
+ const rep_t aAbs = aRep & absMask;
+ const rep_t bAbs = bRep & absMask;
+
+ // Detect if a or b is zero, infinity, or NaN.
+ if (aAbs - REP_C(1) >= infRep - REP_C(1) ||
+ bAbs - REP_C(1) >= infRep - REP_C(1)) {
+ // NaN + anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything + NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // +/-infinity + -/+infinity = qNaN
+ if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
+ // +/-infinity + anything remaining = +/- infinity
+ else return a;
+ }
+
+ // anything remaining + +/-infinity = +/-infinity
+ if (bAbs == infRep) return b;
+
+ // zero + anything = anything
+ if (!aAbs) {
+ // but we need to get the sign right for zero + zero
+ if (!bAbs) return fromRep(toRep(a) & toRep(b));
+ else return b;
+ }
+
+ // anything + zero = anything
+ if (!bAbs) return a;
+ }
+
+ // Swap a and b if necessary so that a has the larger absolute value.
+ if (bAbs > aAbs) {
+ const rep_t temp = aRep;
+ aRep = bRep;
+ bRep = temp;
+ }
+
+ // Extract the exponent and significand from the (possibly swapped) a and b.
+ int aExponent = aRep >> significandBits & maxExponent;
+ int bExponent = bRep >> significandBits & maxExponent;
+ rep_t aSignificand = aRep & significandMask;
+ rep_t bSignificand = bRep & significandMask;
+
+ // Normalize any denormals, and adjust the exponent accordingly.
+ if (aExponent == 0) aExponent = normalize(&aSignificand);
+ if (bExponent == 0) bExponent = normalize(&bSignificand);
+
+ // The sign of the result is the sign of the larger operand, a. If they
+ // have opposite signs, we are performing a subtraction; otherwise addition.
+ const rep_t resultSign = aRep & signBit;
+ const bool subtraction = (aRep ^ bRep) & signBit;
+
+ // Shift the significands to give us round, guard and sticky, and or in the
+ // implicit significand bit. (If we fell through from the denormal path it
+ // was already set by normalize( ), but setting it twice won't hurt
+ // anything.)
+ aSignificand = (aSignificand | implicitBit) << 3;
+ bSignificand = (bSignificand | implicitBit) << 3;
+
+ // Shift the significand of b by the difference in exponents, with a sticky
+ // bottom bit to get rounding correct.
+ const unsigned int align = aExponent - bExponent;
+ if (align) {
+ if (align < typeWidth) {
+ const bool sticky = bSignificand << (typeWidth - align);
+ bSignificand = bSignificand >> align | sticky;
+ } else {
+ bSignificand = 1; // sticky; b is known to be non-zero.
+ }
+ }
+ if (subtraction) {
+ aSignificand -= bSignificand;
+ // If a == -b, return +zero.
+ if (aSignificand == 0) return fromRep(0);
+
+ // If partial cancellation occured, we need to left-shift the result
+ // and adjust the exponent:
+ if (aSignificand < implicitBit << 3) {
+ const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
+ aSignificand <<= shift;
+ aExponent -= shift;
+ }
+ }
+ else /* addition */ {
+ aSignificand += bSignificand;
+
+ // If the addition carried up, we need to right-shift the result and
+ // adjust the exponent:
+ if (aSignificand & implicitBit << 4) {
+ const bool sticky = aSignificand & 1;
+ aSignificand = aSignificand >> 1 | sticky;
+ aExponent += 1;
+ }
+ }
+
+ // If we have overflowed the type, return +/- infinity:
+ if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
+
+ if (aExponent <= 0) {
+ // Result is denormal before rounding; the exponent is zero and we
+ // need to shift the significand.
+ const int shift = 1 - aExponent;
+ const bool sticky = aSignificand << (typeWidth - shift);
+ aSignificand = aSignificand >> shift | sticky;
+ aExponent = 0;
+ }
+
+ // Low three bits are round, guard, and sticky.
+ const int roundGuardSticky = aSignificand & 0x7;
+
+ // Shift the significand into place, and mask off the implicit bit.
+ rep_t result = aSignificand >> 3 & significandMask;
+
+ // Insert the exponent and sign.
+ result |= (rep_t)aExponent << significandBits;
+ result |= resultSign;
+
+ // Final rounding. The result may overflow to infinity, but that is the
+ // correct result in that case.
+ if (roundGuardSticky > 0x4) result++;
+ if (roundGuardSticky == 0x4) result += result & 1;
+ return fromRep(result);
+}
diff --git a/compiler-rt/lib/builtins/fp_extend.h b/compiler-rt/lib/builtins/fp_extend.h
new file mode 100644
index 0000000..6d95a06
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_extend.h
@@ -0,0 +1,89 @@
+//===-lib/fp_extend.h - low precision -> high precision conversion -*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_EXTEND_HEADER
+#define FP_EXTEND_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_SINGLE
+typedef float src_t;
+typedef uint32_t src_rep_t;
+#define SRC_REP_C UINT32_C
+static const int srcSigBits = 23;
+#define src_rep_t_clz __builtin_clz
+
+#elif defined SRC_DOUBLE
+typedef double src_t;
+typedef uint64_t src_rep_t;
+#define SRC_REP_C UINT64_C
+static const int srcSigBits = 52;
+static __inline int src_rep_t_clz(src_rep_t a) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#elif defined SRC_HALF
+typedef uint16_t src_t;
+typedef uint16_t src_rep_t;
+#define SRC_REP_C UINT16_C
+static const int srcSigBits = 10;
+#define src_rep_t_clz __builtin_clz
+
+#else
+#error Source should be half, single, or double precision!
+#endif //end source precision
+
+#if defined DST_SINGLE
+typedef float dst_t;
+typedef uint32_t dst_rep_t;
+#define DST_REP_C UINT32_C
+static const int dstSigBits = 23;
+
+#elif defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_QUAD
+typedef long double dst_t;
+typedef __uint128_t dst_rep_t;
+#define DST_REP_C (__uint128_t)
+static const int dstSigBits = 112;
+
+#else
+#error Destination should be single, double, or quad precision!
+#endif //end destination precision
+
+// End of specialization parameters. Two helper routines for conversion to and
+// from the representation of floating-point data as integer values follow.
+
+static __inline src_rep_t srcToRep(src_t x) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static __inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+// End helper routines. Conversion implementation follows.
+
+#endif //FP_EXTEND_HEADER
diff --git a/compiler-rt/lib/builtins/fp_extend_impl.inc b/compiler-rt/lib/builtins/fp_extend_impl.inc
new file mode 100644
index 0000000..b785cc7
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_extend_impl.inc
@@ -0,0 +1,108 @@
+//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a fairly generic conversion from a narrower to a wider
+// IEEE-754 floating-point type. The constants and types defined following the
+// includes below parameterize the conversion.
+//
+// It does not support types that don't use the usual IEEE-754 interchange
+// formats; specifically, some work would be needed to adapt it to
+// (for example) the Intel 80-bit format or PowerPC double-double format.
+//
+// Note please, however, that this implementation is only intended to support
+// *widening* operations; if you need to convert to a *narrower* floating-point
+// type (e.g. double -> float), then this routine will not do what you want it
+// to.
+//
+// It also requires that integer types at least as large as both formats
+// are available on the target platform; this may pose a problem when trying
+// to add support for quad on some 32-bit systems, for example. You also may
+// run into trouble finding an appropriate CLZ function for wide source types;
+// you will likely need to roll your own on some platforms.
+//
+// Finally, the following assumptions are made:
+//
+// 1. floating-point types and integer types have the same endianness on the
+// target platform
+//
+// 2. quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_extend.h"
+
+static __inline dst_t __extendXfYf2__(src_t a) {
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const int srcBits = sizeof(src_t)*CHAR_BIT;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
+
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
+
+ const int dstBits = sizeof(dst_t)*CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
+
+ const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
+
+ // Break a into a sign and representation of the absolute value
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
+
+ // If sizeof(src_rep_t) < sizeof(int), the subtraction result is promoted
+ // to (signed) int. To avoid that, explicitly cast to src_rep_t.
+ if ((src_rep_t)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
+ // a is a normal number.
+ // Extend to the destination type by shifting the significand and
+ // exponent into the proper position and rebiasing the exponent.
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
+ absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
+ }
+
+ else if (aAbs >= srcInfinity) {
+ // a is NaN or infinity.
+ // Conjure the result by beginning with infinity, then setting the qNaN
+ // bit (if needed) and right-aligning the rest of the trailing NaN
+ // payload field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
+ absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
+ }
+
+ else if (aAbs) {
+ // a is denormal.
+ // renormalize the significand and clear the leading bit, then insert
+ // the correct adjusted exponent in the destination type.
+ const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
+ absResult ^= dstMinNormal;
+ const int resultExponent = dstExpBias - srcExpBias - scale + 1;
+ absResult |= (dst_rep_t)resultExponent << dstSigBits;
+ }
+
+ else {
+ // a is zero.
+ absResult = 0;
+ }
+
+ // Apply the signbit to (dst_t)abs(a).
+ const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
+ return dstFromRep(result);
+}
diff --git a/compiler-rt/lib/builtins/fp_fixint_impl.inc b/compiler-rt/lib/builtins/fp_fixint_impl.inc
new file mode 100644
index 0000000..da70d4d
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_fixint_impl.inc
@@ -0,0 +1,41 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static __inline fixint_t __fixint(fp_t a) {
+ const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
+ const fixint_t fixint_min = -fixint_max - 1;
+ // Break a into sign, exponent, significand
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const fixint_t sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+ // If exponent is negative, the result is zero.
+ if (exponent < 0)
+ return 0;
+
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
+ return sign == 1 ? fixint_max : fixint_min;
+
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return sign * (significand >> (significandBits - exponent));
+ else
+ return sign * ((fixint_t)significand << (exponent - significandBits));
+}
diff --git a/compiler-rt/lib/builtins/fp_fixuint_impl.inc b/compiler-rt/lib/builtins/fp_fixuint_impl.inc
new file mode 100644
index 0000000..d68ccf2
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_fixuint_impl.inc
@@ -0,0 +1,39 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to unsigned integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static __inline fixuint_t __fixuint(fp_t a) {
+ // Break a into sign, exponent, significand
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const int sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+ // If either the value or the exponent is negative, the result is zero.
+ if (sign == -1 || exponent < 0)
+ return 0;
+
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT)
+ return ~(fixuint_t)0;
+
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return significand >> (significandBits - exponent);
+ else
+ return (fixuint_t)significand << (exponent - significandBits);
+}
diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h
new file mode 100644
index 0000000..223fb98
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_lib.h
@@ -0,0 +1,270 @@
+//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for soft-float routines in compiler-rt.
+// This file does not provide any part of the compiler-rt interface, but defines
+// many useful constants and utility routines that are used in the
+// implementation of the soft-float routines in compiler-rt.
+//
+// Assumes that float, double and long double correspond to the IEEE-754
+// binary32, binary64 and binary 128 types, respectively, and that integer
+// endianness matches floating point endianness on the target platform.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_LIB_HEADER
+#define FP_LIB_HEADER
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "int_lib.h"
+
+// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
+// 32-bit mode.
+#if defined(__FreeBSD__) && defined(__i386__)
+# include <sys/param.h>
+# if __FreeBSD_version < 903000 // v9.3
+# define uint64_t unsigned long long
+# define int64_t long long
+# undef UINT64_C
+# define UINT64_C(c) (c ## ULL)
+# endif
+#endif
+
+#if defined SINGLE_PRECISION
+
+typedef uint32_t rep_t;
+typedef int32_t srep_t;
+typedef float fp_t;
+#define REP_C UINT32_C
+#define significandBits 23
+
+static __inline int rep_clz(rep_t a) {
+ return __builtin_clz(a);
+}
+
+// 32x32 --> 64 bit multiply
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+ const uint64_t product = (uint64_t)a*b;
+ *hi = product >> 32;
+ *lo = product;
+}
+COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
+
+#elif defined DOUBLE_PRECISION
+
+typedef uint64_t rep_t;
+typedef int64_t srep_t;
+typedef double fp_t;
+#define REP_C UINT64_C
+#define significandBits 52
+
+static __inline int rep_clz(rep_t a) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#define loWord(a) (a & 0xffffffffU)
+#define hiWord(a) (a >> 32)
+
+// 64x64 -> 128 wide multiply for platforms that don't have such an operation;
+// many 64-bit platforms have this operation, but they tend to have hardware
+// floating-point, so we don't bother with a special case for them here.
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+ // Each of the component 32x32 -> 64 products
+ const uint64_t plolo = loWord(a) * loWord(b);
+ const uint64_t plohi = loWord(a) * hiWord(b);
+ const uint64_t philo = hiWord(a) * loWord(b);
+ const uint64_t phihi = hiWord(a) * hiWord(b);
+ // Sum terms that contribute to lo in a way that allows us to get the carry
+ const uint64_t r0 = loWord(plolo);
+ const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
+ *lo = r0 + (r1 << 32);
+ // Sum terms contributing to hi with the carry from lo
+ *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
+}
+#undef loWord
+#undef hiWord
+
+COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
+
+#elif defined QUAD_PRECISION
+#if __LDBL_MANT_DIG__ == 113
+#define CRT_LDBL_128BIT
+typedef __uint128_t rep_t;
+typedef __int128_t srep_t;
+typedef long double fp_t;
+#define REP_C (__uint128_t)
+// Note: Since there is no explicit way to tell compiler the constant is a
+// 128-bit integer, we let the constant be casted to 128-bit integer
+#define significandBits 112
+
+static __inline int rep_clz(rep_t a) {
+ const union
+ {
+ __uint128_t ll;
+#if _YUGA_BIG_ENDIAN
+ struct { uint64_t high, low; } s;
+#else
+ struct { uint64_t low, high; } s;
+#endif
+ } uu = { .ll = a };
+
+ uint64_t word;
+ uint64_t add;
+
+ if (uu.s.high){
+ word = uu.s.high;
+ add = 0;
+ }
+ else{
+ word = uu.s.low;
+ add = 64;
+ }
+ return __builtin_clzll(word) + add;
+}
+
+#define Word_LoMask UINT64_C(0x00000000ffffffff)
+#define Word_HiMask UINT64_C(0xffffffff00000000)
+#define Word_FullMask UINT64_C(0xffffffffffffffff)
+#define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask)
+#define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask)
+#define Word_3(a) (uint64_t)((a >> 32) & Word_LoMask)
+#define Word_4(a) (uint64_t)(a & Word_LoMask)
+
+// 128x128 -> 256 wide multiply for platforms that don't have such an operation;
+// many 64-bit platforms have this operation, but they tend to have hardware
+// floating-point, so we don't bother with a special case for them here.
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+
+ const uint64_t product11 = Word_1(a) * Word_1(b);
+ const uint64_t product12 = Word_1(a) * Word_2(b);
+ const uint64_t product13 = Word_1(a) * Word_3(b);
+ const uint64_t product14 = Word_1(a) * Word_4(b);
+ const uint64_t product21 = Word_2(a) * Word_1(b);
+ const uint64_t product22 = Word_2(a) * Word_2(b);
+ const uint64_t product23 = Word_2(a) * Word_3(b);
+ const uint64_t product24 = Word_2(a) * Word_4(b);
+ const uint64_t product31 = Word_3(a) * Word_1(b);
+ const uint64_t product32 = Word_3(a) * Word_2(b);
+ const uint64_t product33 = Word_3(a) * Word_3(b);
+ const uint64_t product34 = Word_3(a) * Word_4(b);
+ const uint64_t product41 = Word_4(a) * Word_1(b);
+ const uint64_t product42 = Word_4(a) * Word_2(b);
+ const uint64_t product43 = Word_4(a) * Word_3(b);
+ const uint64_t product44 = Word_4(a) * Word_4(b);
+
+ const __uint128_t sum0 = (__uint128_t)product44;
+ const __uint128_t sum1 = (__uint128_t)product34 +
+ (__uint128_t)product43;
+ const __uint128_t sum2 = (__uint128_t)product24 +
+ (__uint128_t)product33 +
+ (__uint128_t)product42;
+ const __uint128_t sum3 = (__uint128_t)product14 +
+ (__uint128_t)product23 +
+ (__uint128_t)product32 +
+ (__uint128_t)product41;
+ const __uint128_t sum4 = (__uint128_t)product13 +
+ (__uint128_t)product22 +
+ (__uint128_t)product31;
+ const __uint128_t sum5 = (__uint128_t)product12 +
+ (__uint128_t)product21;
+ const __uint128_t sum6 = (__uint128_t)product11;
+
+ const __uint128_t r0 = (sum0 & Word_FullMask) +
+ ((sum1 & Word_LoMask) << 32);
+ const __uint128_t r1 = (sum0 >> 64) +
+ ((sum1 >> 32) & Word_FullMask) +
+ (sum2 & Word_FullMask) +
+ ((sum3 << 32) & Word_HiMask);
+
+ *lo = r0 + (r1 << 64);
+ *hi = (r1 >> 64) +
+ (sum1 >> 96) +
+ (sum2 >> 64) +
+ (sum3 >> 32) +
+ sum4 +
+ (sum5 << 32) +
+ (sum6 << 64);
+}
+#undef Word_1
+#undef Word_2
+#undef Word_3
+#undef Word_4
+#undef Word_HiMask
+#undef Word_LoMask
+#undef Word_FullMask
+#endif // __LDBL_MANT_DIG__ == 113
+#else
+#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
+#endif
+
+#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || defined(CRT_LDBL_128BIT)
+#define typeWidth (sizeof(rep_t)*CHAR_BIT)
+#define exponentBits (typeWidth - significandBits - 1)
+#define maxExponent ((1 << exponentBits) - 1)
+#define exponentBias (maxExponent >> 1)
+
+#define implicitBit (REP_C(1) << significandBits)
+#define significandMask (implicitBit - 1U)
+#define signBit (REP_C(1) << (significandBits + exponentBits))
+#define absMask (signBit - 1U)
+#define exponentMask (absMask ^ significandMask)
+#define oneRep ((rep_t)exponentBias << significandBits)
+#define infRep exponentMask
+#define quietBit (implicitBit >> 1)
+#define qnanRep (exponentMask | quietBit)
+
+static __inline rep_t toRep(fp_t x) {
+ const union { fp_t f; rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static __inline fp_t fromRep(rep_t x) {
+ const union { fp_t f; rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+static __inline int normalize(rep_t *significand) {
+ const int shift = rep_clz(*significand) - rep_clz(implicitBit);
+ *significand <<= shift;
+ return 1 - shift;
+}
+
+static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
+ *hi = *hi << count | *lo >> (typeWidth - count);
+ *lo = *lo << count;
+}
+
+static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
+ if (count < typeWidth) {
+ const bool sticky = *lo << (typeWidth - count);
+ *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
+ *hi = *hi >> count;
+ }
+ else if (count < 2*typeWidth) {
+ const bool sticky = *hi << (2*typeWidth - count) | *lo;
+ *lo = *hi >> (count - typeWidth) | sticky;
+ *hi = 0;
+ } else {
+ const bool sticky = *hi | *lo;
+ *lo = sticky;
+ *hi = 0;
+ }
+}
+#endif
+
+#endif // FP_LIB_HEADER
diff --git a/compiler-rt/lib/builtins/fp_mul_impl.inc b/compiler-rt/lib/builtins/fp_mul_impl.inc
new file mode 100644
index 0000000..b34aa1b
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_mul_impl.inc
@@ -0,0 +1,116 @@
+//===---- lib/fp_mul_impl.inc - floating point multiplication -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements soft-float multiplication with the IEEE-754 default
+// rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static __inline fp_t __mulXf3__(fp_t a, fp_t b) {
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN * anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything * NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity * non-zero = +/- infinity
+ if (bAbs) return fromRep(aAbs | productSign);
+ // infinity * zero = NaN
+ else return fromRep(qnanRep);
+ }
+
+ if (bAbs == infRep) {
+ //? non-zero * infinity = +/- infinity
+ if (aAbs) return fromRep(bAbs | productSign);
+ // zero * infinity = NaN
+ else return fromRep(qnanRep);
+ }
+
+ // zero * anything = +/- zero
+ if (!aAbs) return fromRep(productSign);
+ // anything * zero = +/- zero
+ if (!bAbs) return fromRep(productSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale += normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+
+ // Get the significand of a*b. Before multiplying the significands, shift
+ // one of them left to left-align it in the field. Thus, the product will
+ // have (exponentBits + 2) integral digits, all but two of which must be
+ // zero. Normalizing this result is just a conditional left-shift by one
+ // and bumping the exponent accordingly.
+ rep_t productHi, productLo;
+ wideMultiply(aSignificand, bSignificand << exponentBits,
+ &productHi, &productLo);
+
+ int productExponent = aExponent + bExponent - exponentBias + scale;
+
+ // Normalize the significand, adjust exponent if needed.
+ if (productHi & implicitBit) productExponent++;
+ else wideLeftShift(&productHi, &productLo, 1);
+
+ // If we have overflowed the type, return +/- infinity.
+ if (productExponent >= maxExponent) return fromRep(infRep | productSign);
+
+ if (productExponent <= 0) {
+ // Result is denormal before rounding
+ //
+ // If the result is so small that it just underflows to zero, return
+ // a zero of the appropriate sign. Mathematically there is no need to
+ // handle this case separately, but we make it a special case to
+ // simplify the shift logic.
+ const unsigned int shift = REP_C(1) - (unsigned int)productExponent;
+ if (shift >= typeWidth) return fromRep(productSign);
+
+ // Otherwise, shift the significand of the result so that the round
+ // bit is the high bit of productLo.
+ wideRightShiftWithSticky(&productHi, &productLo, shift);
+ }
+ else {
+ // Result is normal before rounding; insert the exponent.
+ productHi &= significandMask;
+ productHi |= (rep_t)productExponent << significandBits;
+ }
+
+ // Insert the sign of the result:
+ productHi |= productSign;
+
+ // Final rounding. The final result may overflow to infinity, or underflow
+ // to zero, but those are the correct results in those cases. We use the
+ // default IEEE-754 round-to-nearest, ties-to-even rounding mode.
+ if (productLo > signBit) productHi++;
+ if (productLo == signBit) productHi += productHi & 1;
+ return fromRep(productHi);
+}
diff --git a/compiler-rt/lib/builtins/fp_trunc.h b/compiler-rt/lib/builtins/fp_trunc.h
new file mode 100644
index 0000000..d5e79bb
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_trunc.h
@@ -0,0 +1,76 @@
+//=== lib/fp_trunc.h - high precision -> low precision conversion *- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination precision setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_TRUNC_HEADER
+#define FP_TRUNC_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_SINGLE
+typedef float src_t;
+typedef uint32_t src_rep_t;
+#define SRC_REP_C UINT32_C
+static const int srcSigBits = 23;
+
+#elif defined SRC_DOUBLE
+typedef double src_t;
+typedef uint64_t src_rep_t;
+#define SRC_REP_C UINT64_C
+static const int srcSigBits = 52;
+
+#elif defined SRC_QUAD
+typedef long double src_t;
+typedef __uint128_t src_rep_t;
+#define SRC_REP_C (__uint128_t)
+static const int srcSigBits = 112;
+
+#else
+#error Source should be double precision or quad precision!
+#endif //end source precision
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_SINGLE
+typedef float dst_t;
+typedef uint32_t dst_rep_t;
+#define DST_REP_C UINT32_C
+static const int dstSigBits = 23;
+
+#elif defined DST_HALF
+typedef uint16_t dst_t;
+typedef uint16_t dst_rep_t;
+#define DST_REP_C UINT16_C
+static const int dstSigBits = 10;
+
+#else
+#error Destination should be single precision or double precision!
+#endif //end destination precision
+
+// End of specialization parameters. Two helper routines for conversion to and
+// from the representation of floating-point data as integer values follow.
+
+static __inline src_rep_t srcToRep(src_t x) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static __inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+#endif // FP_TRUNC_HEADER
diff --git a/compiler-rt/lib/builtins/fp_trunc_impl.inc b/compiler-rt/lib/builtins/fp_trunc_impl.inc
new file mode 100644
index 0000000..d88ae06
--- /dev/null
+++ b/compiler-rt/lib/builtins/fp_trunc_impl.inc
@@ -0,0 +1,135 @@
+//= lib/fp_trunc_impl.inc - high precision -> low precision conversion *-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a fairly generic conversion from a wider to a narrower
+// IEEE-754 floating-point type in the default (round to nearest, ties to even)
+// rounding mode. The constants and types defined following the includes below
+// parameterize the conversion.
+//
+// This routine can be trivially adapted to support conversions to
+// half-precision or from quad-precision. It does not support types that don't
+// use the usual IEEE-754 interchange formats; specifically, some work would be
+// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
+// double-double format.
+//
+// Note please, however, that this implementation is only intended to support
+// *narrowing* operations; if you need to convert to a *wider* floating-point
+// type (e.g. float -> double), then this routine will not do what you want it
+// to.
+//
+// It also requires that integer types at least as large as both formats
+// are available on the target platform; this may pose a problem when trying
+// to add support for quad on some 32-bit systems, for example.
+//
+// Finally, the following assumptions are made:
+//
+// 1. floating-point types and integer types have the same endianness on the
+// target platform
+//
+// 2. quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_trunc.h"
+
+static __inline dst_t __truncXfYf2__(src_t a) {
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const int srcBits = sizeof(src_t)*CHAR_BIT;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
+
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcSignificandMask = srcMinNormal - 1;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
+ const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
+
+ const int dstBits = sizeof(dst_t)*CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
+
+ const int underflowExponent = srcExpBias + 1 - dstExpBias;
+ const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
+ const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
+ const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
+
+ const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
+ const dst_rep_t dstNaNCode = dstQNaN - 1;
+
+ // Break a into a sign and representation of the absolute value
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
+
+ if (aAbs - underflow < aAbs - overflow) {
+ // The exponent of a is within the range of normal numbers in the
+ // destination format. We can convert by simply right-shifting with
+ // rounding and adjusting the exponent.
+ absResult = aAbs >> (srcSigBits - dstSigBits);
+ absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
+
+ const src_rep_t roundBits = aAbs & roundMask;
+ // Round to nearest
+ if (roundBits > halfway)
+ absResult++;
+ // Ties to even
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
+ }
+ else if (aAbs > srcInfinity) {
+ // a is NaN.
+ // Conjure the result by beginning with infinity, setting the qNaN
+ // bit and inserting the (truncated) trailing NaN field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= dstQNaN;
+ absResult |= ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
+ }
+ else if (aAbs >= overflow) {
+ // a overflows to infinity.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ }
+ else {
+ // a underflows on conversion to the destination type or is an exact
+ // zero. The result may be a denormal or zero. Extract the exponent
+ // to get the shift amount for the denormalization.
+ const int aExp = aAbs >> srcSigBits;
+ const int shift = srcExpBias - dstExpBias - aExp + 1;
+
+ const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
+
+ // Right shift by the denormalization amount with sticky.
+ if (shift > srcSigBits) {
+ absResult = 0;
+ } else {
+ const bool sticky = significand << (srcBits - shift);
+ src_rep_t denormalizedSignificand = significand >> shift | sticky;
+ absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
+ const src_rep_t roundBits = denormalizedSignificand & roundMask;
+ // Round to nearest
+ if (roundBits > halfway)
+ absResult++;
+ // Ties to even
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
+ }
+ }
+
+ // Apply the signbit to (dst_t)abs(a).
+ const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
+ return dstFromRep(result);
+}
diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
new file mode 100644
index 0000000..331dc2b
--- /dev/null
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -0,0 +1,209 @@
+/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ */
+
+#include "int_lib.h"
+
+#include <unwind.h>
+
+/*
+ * Pointer encodings documented at:
+ * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
+ */
+
+#define DW_EH_PE_omit 0xff /* no data follows */
+
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_uleb128 0x01
+#define DW_EH_PE_udata2 0x02
+#define DW_EH_PE_udata4 0x03
+#define DW_EH_PE_udata8 0x04
+#define DW_EH_PE_sleb128 0x09
+#define DW_EH_PE_sdata2 0x0A
+#define DW_EH_PE_sdata4 0x0B
+#define DW_EH_PE_sdata8 0x0C
+
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+#define DW_EH_PE_aligned 0x50
+#define DW_EH_PE_indirect 0x80 /* gcc extension */
+
+
+
+/* read a uleb128 encoded value and advance pointer */
+static uintptr_t readULEB128(const uint8_t** data)
+{
+ uintptr_t result = 0;
+ uintptr_t shift = 0;
+ unsigned char byte;
+ const uint8_t* p = *data;
+ do {
+ byte = *p++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ return result;
+}
+
+/* read a pointer encoded value and advance pointer */
+static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
+{
+ const uint8_t* p = *data;
+ uintptr_t result = 0;
+
+ if ( encoding == DW_EH_PE_omit )
+ return 0;
+
+ /* first get value */
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_absptr:
+ result = *((const uintptr_t*)p);
+ p += sizeof(uintptr_t);
+ break;
+ case DW_EH_PE_uleb128:
+ result = readULEB128(&p);
+ break;
+ case DW_EH_PE_udata2:
+ result = *((const uint16_t*)p);
+ p += sizeof(uint16_t);
+ break;
+ case DW_EH_PE_udata4:
+ result = *((const uint32_t*)p);
+ p += sizeof(uint32_t);
+ break;
+ case DW_EH_PE_udata8:
+ result = *((const uint64_t*)p);
+ p += sizeof(uint64_t);
+ break;
+ case DW_EH_PE_sdata2:
+ result = *((const int16_t*)p);
+ p += sizeof(int16_t);
+ break;
+ case DW_EH_PE_sdata4:
+ result = *((const int32_t*)p);
+ p += sizeof(int32_t);
+ break;
+ case DW_EH_PE_sdata8:
+ result = *((const int64_t*)p);
+ p += sizeof(int64_t);
+ break;
+ case DW_EH_PE_sleb128:
+ default:
+ /* not supported */
+ compilerrt_abort();
+ break;
+ }
+
+ /* then add relative offset */
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ /* do nothing */
+ break;
+ case DW_EH_PE_pcrel:
+ result += (uintptr_t)(*data);
+ break;
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ case DW_EH_PE_aligned:
+ default:
+ /* not supported */
+ compilerrt_abort();
+ break;
+ }
+
+ /* then apply indirection */
+ if (encoding & DW_EH_PE_indirect) {
+ result = *((const uintptr_t*)result);
+ }
+
+ *data = p;
+ return result;
+}
+
+
+/*
+ * The C compiler makes references to __gcc_personality_v0 in
+ * the dwarf unwind information for translation units that use
+ * __attribute__((cleanup(xx))) on local variables.
+ * This personality routine is called by the system unwinder
+ * on each frame as the stack is unwound during a C++ exception
+ * throw through a C function compiled with -fexceptions.
+ */
+#if __USING_SJLJ_EXCEPTIONS__
+// the setjump-longjump based exceptions personality routine has a different name
+COMPILER_RT_ABI _Unwind_Reason_Code
+__gcc_personality_sj0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context *context)
+#else
+COMPILER_RT_ABI _Unwind_Reason_Code
+__gcc_personality_v0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context *context)
+#endif
+{
+ /* Since C does not have catch clauses, there is nothing to do during */
+ /* phase 1 (the search phase). */
+ if ( actions & _UA_SEARCH_PHASE )
+ return _URC_CONTINUE_UNWIND;
+
+ /* There is nothing to do if there is no LSDA for this frame. */
+ const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
+ if ( lsda == (uint8_t*) 0 )
+ return _URC_CONTINUE_UNWIND;
+
+ uintptr_t pc = _Unwind_GetIP(context)-1;
+ uintptr_t funcStart = _Unwind_GetRegionStart(context);
+ uintptr_t pcOffset = pc - funcStart;
+
+ /* Parse LSDA header. */
+ uint8_t lpStartEncoding = *lsda++;
+ if (lpStartEncoding != DW_EH_PE_omit) {
+ readEncodedPointer(&lsda, lpStartEncoding);
+ }
+ uint8_t ttypeEncoding = *lsda++;
+ if (ttypeEncoding != DW_EH_PE_omit) {
+ readULEB128(&lsda);
+ }
+ /* Walk call-site table looking for range that includes current PC. */
+ uint8_t callSiteEncoding = *lsda++;
+ uint32_t callSiteTableLength = readULEB128(&lsda);
+ const uint8_t* callSiteTableStart = lsda;
+ const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
+ const uint8_t* p=callSiteTableStart;
+ while (p < callSiteTableEnd) {
+ uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
+ uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
+ uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+ readULEB128(&p); /* action value not used for C code */
+ if ( landingPad == 0 )
+ continue; /* no landing pad for this entry */
+ if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
+ /* Found landing pad for the PC.
+ * Set Instruction Pointer to so we re-enter function
+ * at landing pad. The landing pad is created by the compiler
+ * to take two parameters in registers.
+ */
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
+ (uintptr_t)exceptionObject);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
+ _Unwind_SetIP(context, (funcStart + landingPad));
+ return _URC_INSTALL_CONTEXT;
+ }
+ }
+
+ /* No landing pad found, continue unwinding. */
+ return _URC_CONTINUE_UNWIND;
+}
+
diff --git a/compiler-rt/lib/builtins/i386/Makefile.mk b/compiler-rt/lib/builtins/i386/Makefile.mk
new file mode 100644
index 0000000..f3776a0
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/i386/Makefile.mk ------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := i386
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/i386/ashldi3.S b/compiler-rt/lib/builtins/i386/ashldi3.S
new file mode 100644
index 0000000..3fbd739
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/ashldi3.S
@@ -0,0 +1,58 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __ashldi3(di_int input, int count);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashldi3)
+ movd 12(%esp), %xmm2 // Load count
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+ psllq %xmm2, %xmm0 // shift input by count
+ movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__ashldi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashldi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+ shldl %cl, %eax, %edx // left shift high by count
+ shll %cl, %eax // left shift low by count
+ ret
+
+1: movl %eax, %edx // Move low to high
+ xorl %eax, %eax // clear low
+ shll %cl, %edx // shift high by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__ashldi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/ashrdi3.S b/compiler-rt/lib/builtins/i386/ashrdi3.S
new file mode 100644
index 0000000..8f47424
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/ashrdi3.S
@@ -0,0 +1,69 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __ashrdi3(di_int input, int count);
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
+ movd 12(%esp), %xmm2 // Load count
+ movl 8(%esp), %eax
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+
+ psrlq %xmm2, %xmm0 // unsigned shift input by count
+
+ testl %eax, %eax // check the sign-bit of the input
+ jns 1f // early out for positive inputs
+
+ // If the input is negative, we need to construct the shifted sign bit
+ // to or into the result, as xmm does not have a signed right shift.
+ pcmpeqb %xmm1, %xmm1 // -1ULL
+ psrlq $58, %xmm1 // 0x3f
+ pandn %xmm1, %xmm2 // 63 - count
+ pcmpeqb %xmm1, %xmm1 // -1ULL
+ psubq %xmm1, %xmm2 // 64 - count
+ psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits
+ por %xmm1, %xmm0
+
+ // Move the result back to the general purpose registers and return
+1: movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__ashrdi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+
+ shrdl %cl, %edx, %eax // right shift low by count
+ sarl %cl, %edx // right shift high by count
+ ret
+
+1: movl %edx, %eax // Move high to low
+ sarl $31, %edx // clear high
+ sarl %cl, %eax // shift low by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__ashrdi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/chkstk.S b/compiler-rt/lib/builtins/i386/chkstk.S
new file mode 100644
index 0000000..b599748
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/chkstk.S
@@ -0,0 +1,34 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// _chkstk routine
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__chkstk_ms)
+ push %ecx
+ push %eax
+ cmp $0x1000,%eax
+ lea 12(%esp),%ecx
+ jb 1f
+2:
+ sub $0x1000,%ecx
+ test %ecx,(%ecx)
+ sub $0x1000,%eax
+ cmp $0x1000,%eax
+ ja 2b
+1:
+ sub %eax,%ecx
+ test %ecx,(%ecx)
+ pop %eax
+ pop %ecx
+ ret
+END_COMPILERRT_FUNCTION(__chkstk_ms)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/chkstk2.S b/compiler-rt/lib/builtins/i386/chkstk2.S
new file mode 100644
index 0000000..7d65bb0
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/chkstk2.S
@@ -0,0 +1,40 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+#ifdef __i386__
+
+// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
+// then decrement %esp by %eax. Preserves all registers except %esp and flags.
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(_alloca) // _chkstk and _alloca are the same function
+DEFINE_COMPILERRT_FUNCTION(__chkstk)
+ push %ecx
+ cmp $0x1000,%eax
+ lea 8(%esp),%ecx // esp before calling this routine -> ecx
+ jb 1f
+2:
+ sub $0x1000,%ecx
+ test %ecx,(%ecx)
+ sub $0x1000,%eax
+ cmp $0x1000,%eax
+ ja 2b
+1:
+ sub %eax,%ecx
+ test %ecx,(%ecx)
+
+ lea 4(%esp),%eax // load pointer to the return address into eax
+ mov %ecx,%esp // install the new top of stack pointer into esp
+ mov -4(%eax),%ecx // restore ecx
+ push (%eax) // push return address onto the stack
+ sub %esp,%eax // restore the original value in eax
+ ret
+END_COMPILERRT_FUNCTION(__chkstk)
+END_COMPILERRT_FUNCTION(_alloca)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/divdi3.S b/compiler-rt/lib/builtins/i386/divdi3.S
new file mode 100644
index 0000000..2cb0ddd
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/divdi3.S
@@ -0,0 +1,162 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __divdi3(di_int a, di_int b);
+
+// result = a / b.
+// both inputs and the output are 64-bit signed integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__divdi3)
+
+/* This is currently implemented by wrapping the unsigned divide up in an absolute
+ value, then restoring the correct sign at the end of the computation. This could
+ certainly be improved upon. */
+
+ pushl %esi
+ movl 20(%esp), %edx // high word of b
+ movl 16(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (b < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(b)
+ movl %edx, 20(%esp)
+ movl %eax, 16(%esp) // store abs(b) back to stack
+ movl %ecx, %esi // set aside sign of b
+
+ movl 12(%esp), %edx // high word of b
+ movl 8(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (a < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(a)
+ movl %edx, 12(%esp)
+ movl %eax, 8(%esp) // store abs(a) back to stack
+ xorl %ecx, %esi // sign of result = (sign of a) ^ (sign of b)
+
+ pushl %ebx
+ movl 24(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 16(%esp), %edx // Load the high and low words of a, and jump
+ movl 12(%esp), %eax // to [1] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 1f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+
+1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 16(%esp), %eax // Find qhi and rhi such that
+ movl 20(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 12(%esp), %eax // Find qlo such that
+ divl %ecx //
+ movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %ebx // Restore callee-save registers
+ popl %esi
+ retl // Return
+END_COMPILERRT_FUNCTION(__divdi3)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatdidf.S b/compiler-rt/lib/builtins/i386/floatdidf.S
new file mode 100644
index 0000000..dcc32f8
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatdidf.S
@@ -0,0 +1,39 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop32:
+ .quad 0x41f0000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdidf)
+ cvtsi2sd 8(%esp), %xmm1
+ movss 4(%esp), %xmm0 // low 32 bits of a
+ calll 0f
+0: popl %eax
+ mulsd REL_ADDR(twop32), %xmm1 // a_hi as a double (without rounding)
+ movsd REL_ADDR(twop52), %xmm2 // 0x1.0p52
+ subsd %xmm2, %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ orpd %xmm2, %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ movsd %xmm0, 4(%esp)
+ fldl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdidf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatdisf.S b/compiler-rt/lib/builtins/i386/floatdisf.S
new file mode 100644
index 0000000..f642767
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatdisf.S
@@ -0,0 +1,32 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatdisf(di_int a);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdisf)
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0
+ movq %xmm0, 4(%esp)
+#endif
+ fildll 4(%esp)
+ fstps 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdisf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatdixf.S b/compiler-rt/lib/builtins/i386/floatdixf.S
new file mode 100644
index 0000000..839b043
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatdixf.S
@@ -0,0 +1,30 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatdixf(di_int a);
+
+#ifdef __i386__
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdixf)
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0
+ movq %xmm0, 4(%esp)
+#endif
+ fildll 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdixf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatundidf.S b/compiler-rt/lib/builtins/i386/floatundidf.S
new file mode 100644
index 0000000..8058c2a
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatundidf.S
@@ -0,0 +1,52 @@
+//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatundidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52:
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundidf)
+ movss 8(%esp), %xmm1 // high 32 bits of a
+ movss 4(%esp), %xmm0 // low 32 bits of a
+ calll 0f
+0: popl %eax
+ orpd REL_ADDR(twop84), %xmm1 // 0x1p84 + a_hi (no rounding occurs)
+ subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ movsd %xmm0, 4(%esp)
+ fldl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundidf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatundisf.S b/compiler-rt/lib/builtins/i386/floatundisf.S
new file mode 100644
index 0000000..94c97e2
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatundisf.S
@@ -0,0 +1,105 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatundisf(du_int a);
+
+// Note that there is a hardware instruction, fildll, that does most of what
+// this function needs to do. However, because of our ia32 ABI, it will take
+// a write-small read-large stall, so the software implementation here is
+// actually several cycles faster.
+
+// This is a branch-free implementation. A branchy implementation might be
+// faster for the common case if you know something a priori about the input
+// distribution.
+
+/* branch-free x87 implementation - one cycle slower than without x87.
+
+#ifdef __i386__
+
+CONST_SECTION
+.balign 3
+
+ .quad 0x43f0000000000000
+twop64: .quad 0x0000000000000000
+
+#define TWOp64 twop64-0b(%ecx,%eax,8)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movl 8(%esp), %eax
+ movd 8(%esp), %xmm1
+ movd 4(%esp), %xmm0
+ punpckldq %xmm1, %xmm0
+ calll 0f
+0: popl %ecx
+ sarl $31, %eax
+ movq %xmm0, 4(%esp)
+ fildll 4(%esp)
+ faddl TWOp64
+ fstps 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __i386__
+
+*/
+
+/* branch-free, x87-free implementation - faster at the expense of code size */
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+ .quad 0x0000000000000fff
+
+ .balign 16
+sticky:
+ .quad 0x0000000000000000
+ .long 0x00000012
+
+ .balign 16
+twelve:
+ .long 0x00000000
+
+#define TWOp52 twop52-0b(%ecx)
+#define STICKY sticky-0b(%ecx,%eax,8)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movl 8(%esp), %eax
+ movd 8(%esp), %xmm1
+ movd 4(%esp), %xmm0
+ punpckldq %xmm1, %xmm0
+
+ calll 0f
+0: popl %ecx
+ shrl %eax // high 31 bits of input as sint32
+ addl $0x7ff80000, %eax
+ sarl $31, %eax // (big input) ? -1 : 0
+ movsd STICKY, %xmm1 // (big input) ? 0xfff : 0
+ movl $12, %edx
+ andl %eax, %edx // (big input) ? 12 : 0
+ movd %edx, %xmm3
+ andpd %xmm0, %xmm1 // (big input) ? input & 0xfff : 0
+ movsd TWOp52, %xmm2 // 0x1.0p52
+ psrlq %xmm3, %xmm0 // (big input) ? input >> 12 : input
+ orpd %xmm2, %xmm1 // 0x1.0p52 + ((big input) ? input & 0xfff : input)
+ orpd %xmm1, %xmm0 // 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input)
+ subsd %xmm2, %xmm0 // (double)((big input) ? (input >> 12 | input & 0xfff) : input)
+ cvtsd2ss %xmm0, %xmm0 // (float)((big input) ? (input >> 12 | input & 0xfff) : input)
+ pslld $23, %xmm3
+ paddd %xmm3, %xmm0 // (float)input
+ movd %xmm0, 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/floatundixf.S b/compiler-rt/lib/builtins/i386/floatundixf.S
new file mode 100644
index 0000000..814b52f
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/floatundixf.S
@@ -0,0 +1,43 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// long double __floatundixf(du_int a);16
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52_neg:
+ .quad 0xc530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ calll 0f
+0: popl %eax
+ movss 8(%esp), %xmm0 // hi 32 bits of input
+ movss 4(%esp), %xmm1 // lo 32 bits of input
+ orpd REL_ADDR(twop84), %xmm0 // 2^84 + hi (as a double)
+ orpd REL_ADDR(twop52), %xmm1 // 2^52 + lo (as a double)
+ addsd REL_ADDR(twop84_plus_twop52_neg), %xmm0 // hi - 2^52 (no rounding occurs)
+ movsd %xmm1, 4(%esp)
+ fldl 4(%esp)
+ movsd %xmm0, 4(%esp)
+ faddl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/lshrdi3.S b/compiler-rt/lib/builtins/i386/lshrdi3.S
new file mode 100644
index 0000000..b80f11a
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/lshrdi3.S
@@ -0,0 +1,59 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __lshrdi3(di_int input, int count);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
+ movd 12(%esp), %xmm2 // Load count
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+ psrlq %xmm2, %xmm0 // shift input by count
+ movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__lshrdi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+
+ shrdl %cl, %edx, %eax // right shift low by count
+ shrl %cl, %edx // right shift high by count
+ ret
+
+1: movl %edx, %eax // Move high to low
+ xorl %edx, %edx // clear high
+ shrl %cl, %eax // shift low by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__lshrdi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/moddi3.S b/compiler-rt/lib/builtins/i386/moddi3.S
new file mode 100644
index 0000000..b9cee9d
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/moddi3.S
@@ -0,0 +1,166 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __moddi3(di_int a, di_int b);
+
+// result = remainder of a / b.
+// both inputs and the output are 64-bit signed integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__moddi3)
+
+/* This is currently implemented by wrapping the unsigned modulus up in an absolute
+ value. This could certainly be improved upon. */
+
+ pushl %esi
+ movl 20(%esp), %edx // high word of b
+ movl 16(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (b < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(b)
+ movl %edx, 20(%esp)
+ movl %eax, 16(%esp) // store abs(b) back to stack
+
+ movl 12(%esp), %edx // high word of b
+ movl 8(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (a < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(a)
+ movl %edx, 12(%esp)
+ movl %eax, 8(%esp) // store abs(a) back to stack
+ movl %ecx, %esi // set aside sign of a
+
+ pushl %ebx
+ movl 24(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 16(%esp), %edx // Load the high and low words of a, and jump
+ movl 12(%esp), %eax // to [2] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 2f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 1f // if positive, this is the result.
+ addl 24(%esp), %ebx // otherwise
+ adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+1: movl %ebx, %eax
+ movl %ecx, %edx
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 3f // if positive, this is the result.
+ addl 24(%esp), %ebx // otherwise
+ adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+3: movl %ebx, %eax
+ movl %ecx, %edx
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+9: /* High word of b is zero on this branch */
+
+ movl 16(%esp), %eax // Find qhi and rhi such that
+ movl 20(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 12(%esp), %eax // Find rlo such that
+ divl %ecx //
+ movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ xorl %edx, %edx // and return 0:rlo
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %esi
+ retl // Return
+END_COMPILERRT_FUNCTION(__moddi3)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/muldi3.S b/compiler-rt/lib/builtins/i386/muldi3.S
new file mode 100644
index 0000000..15b6b49
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/muldi3.S
@@ -0,0 +1,30 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __muldi3(di_int a, di_int b);
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__muldi3)
+ pushl %ebx
+ movl 16(%esp), %eax // b.lo
+ movl 12(%esp), %ecx // a.hi
+ imull %eax, %ecx // b.lo * a.hi
+
+ movl 8(%esp), %edx // a.lo
+ movl 20(%esp), %ebx // b.hi
+ imull %edx, %ebx // a.lo * b.hi
+
+ mull %edx // EDX:EAX = a.lo * b.lo
+ addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo)
+ addl %ebx, %edx
+
+ popl %ebx
+ retl
+END_COMPILERRT_FUNCTION(__muldi3)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/udivdi3.S b/compiler-rt/lib/builtins/i386/udivdi3.S
new file mode 100644
index 0000000..41b2edf
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/udivdi3.S
@@ -0,0 +1,115 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// du_int __udivdi3(du_int a, du_int b);
+
+// result = a / b.
+// both inputs and the output are 64-bit unsigned integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__udivdi3)
+
+ pushl %ebx
+ movl 20(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 12(%esp), %edx // Load the high and low words of a, and jump
+ movl 8(%esp), %eax // to [1] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 1f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+ popl %edi
+ popl %ebx
+ retl
+
+
+1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+ popl %edi
+ popl %ebx
+ retl
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 12(%esp), %eax // Find qhi and rhi such that
+ movl 16(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 8(%esp), %eax // Find qlo such that
+ divl %ecx //
+ movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ retl // and return qhi:qlo
+END_COMPILERRT_FUNCTION(__udivdi3)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/i386/umoddi3.S b/compiler-rt/lib/builtins/i386/umoddi3.S
new file mode 100644
index 0000000..a190a7d
--- /dev/null
+++ b/compiler-rt/lib/builtins/i386/umoddi3.S
@@ -0,0 +1,126 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// du_int __umoddi3(du_int a, du_int b);
+
+// result = remainder of a / b.
+// both inputs and the output are 64-bit unsigned integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__umoddi3)
+
+ pushl %ebx
+ movl 20(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 12(%esp), %edx // Load the high and low words of a, and jump
+ movl 8(%esp), %eax // to [2] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 2f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 1f // if positive, this is the result.
+ addl 20(%esp), %ebx // otherwise
+ adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+1: movl %ebx, %eax
+ movl %ecx, %edx
+
+ popl %edi
+ popl %ebx
+ retl
+
+
+2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 3f // if positive, this is the result.
+ addl 20(%esp), %ebx // otherwise
+ adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+3: movl %ebx, %eax
+ movl %ecx, %edx
+
+ popl %edi
+ popl %ebx
+ retl
+
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 12(%esp), %eax // Find qhi and rhi such that
+ movl 16(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 8(%esp), %eax // Find rlo such that
+ divl %ecx //
+ movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ xorl %edx, %edx // and return 0:rlo
+ retl //
+END_COMPILERRT_FUNCTION(__umoddi3)
+
+#endif // __i386__
diff --git a/compiler-rt/lib/builtins/int_endianness.h b/compiler-rt/lib/builtins/int_endianness.h
new file mode 100644
index 0000000..7995ddb
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_endianness.h
@@ -0,0 +1,116 @@
+/* ===-- int_endianness.h - configuration header for compiler-rt ------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_ENDIANNESS_H
+#define INT_ENDIANNESS_H
+
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+ defined(__ORDER_LITTLE_ENDIAN__)
+
+/* Clang and GCC provide built-in endianness definitions. */
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* __BYTE_ORDER__ */
+
+#else /* Compilers other than Clang or GCC. */
+
+#if defined(__SVR4) && defined(__sun)
+#include <sys/byteorder.h>
+
+#if defined(_BIG_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif defined(_LITTLE_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#else /* !_LITTLE_ENDIAN */
+#error "unknown endianness"
+#endif /* !_LITTLE_ENDIAN */
+
+#endif /* Solaris and AuroraUX. */
+
+/* .. */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__minix)
+#include <sys/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* _BYTE_ORDER */
+
+#endif /* *BSD */
+
+#if defined(__OpenBSD__) || defined(__Bitrig__)
+#include <machine/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* _BYTE_ORDER */
+
+#endif /* OpenBSD and Bitrig. */
+
+/* .. */
+
+/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+ * compiler (at least with GCC) */
+#if defined(__APPLE__) || defined(__ellcc__ )
+
+#ifdef __BIG_ENDIAN__
+#if __BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#endif
+#endif /* __BIG_ENDIAN__ */
+
+#ifdef __LITTLE_ENDIAN__
+#if __LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif
+#endif /* __LITTLE_ENDIAN__ */
+
+#endif /* Mac OSX */
+
+/* .. */
+
+#if defined(_WIN32)
+
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+
+#endif /* Windows */
+
+#endif /* Clang or GCC. */
+
+/* . */
+
+#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
+#error Unable to determine endian
+#endif /* Check we found an endianness correctly. */
+
+#endif /* INT_ENDIANNESS_H */
diff --git a/compiler-rt/lib/builtins/int_lib.h b/compiler-rt/lib/builtins/int_lib.h
new file mode 100644
index 0000000..272f9d9
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_lib.h
@@ -0,0 +1,133 @@
+/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_LIB_H
+#define INT_LIB_H
+
+/* Assumption: Signed integral is 2's complement. */
+/* Assumption: Right shift of signed negative is arithmetic shift. */
+/* Assumption: Endianness is little or big (not mixed). */
+
+#if defined(__ELF__)
+#define FNALIAS(alias_name, original_name) \
+ void alias_name() __attribute__((alias(#original_name)))
+#else
+#define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")")
+#endif
+
+/* ABI macro definitions */
+
+#if __ARM_EABI__
+# define ARM_EABI_FNALIAS(aeabi_name, name) \
+ void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
+# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
+#else
+# define ARM_EABI_FNALIAS(aeabi_name, name)
+# if defined(__arm__) && defined(_WIN32) && (!defined(_MSC_VER) || defined(__clang__))
+# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
+# else
+# define COMPILER_RT_ABI
+# endif
+#endif
+
+#ifdef _MSC_VER
+#define ALWAYS_INLINE __forceinline
+#define NOINLINE __declspec(noinline)
+#define NORETURN __declspec(noreturn)
+#define UNUSED
+#else
+#define ALWAYS_INLINE __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+#define NORETURN __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+#endif
+
+#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
+/*
+ * Kernel and boot environment can't use normal headers,
+ * so use the equivalent system headers.
+ */
+# include <machine/limits.h>
+# include <sys/stdint.h>
+# include <sys/types.h>
+#else
+/* Include the standard compiler builtin headers we use functionality from. */
+# include <limits.h>
+# include <stdint.h>
+# include <stdbool.h>
+# include <float.h>
+#endif
+
+/* Include the commonly used internal type definitions. */
+#include "int_types.h"
+
+/* Include internal utility function declarations. */
+#include "int_util.h"
+
+COMPILER_RT_ABI si_int __paritysi2(si_int a);
+COMPILER_RT_ABI si_int __paritydi2(di_int a);
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
+COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
+
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem);
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
+#ifdef CRT_HAS_128BIT
+COMPILER_RT_ABI si_int __clzti2(ti_int a);
+COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
+#endif
+
+/* Definitions for builtins unavailable on MSVC */
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+
+uint32_t __inline __builtin_ctz(uint32_t value) {
+ uint32_t trailing_zero = 0;
+ if (_BitScanForward(&trailing_zero, value))
+ return trailing_zero;
+ return 32;
+}
+
+uint32_t __inline __builtin_clz(uint32_t value) {
+ uint32_t leading_zero = 0;
+ if (_BitScanReverse(&leading_zero, value))
+ return 31 - leading_zero;
+ return 32;
+}
+
+#if defined(_M_ARM) || defined(_M_X64)
+uint32_t __inline __builtin_clzll(uint64_t value) {
+ uint32_t leading_zero = 0;
+ if (_BitScanReverse64(&leading_zero, value))
+ return 63 - leading_zero;
+ return 64;
+}
+#else
+uint32_t __inline __builtin_clzll(uint64_t value) {
+ if (value == 0)
+ return 64;
+ uint32_t msh = (uint32_t)(value >> 32);
+ uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF);
+ if (msh != 0)
+ return __builtin_clz(msh);
+ return 32 + __builtin_clz(lsh);
+}
+#endif
+
+#define __builtin_clzl __builtin_clzll
+#endif // defined(_MSC_VER) && !defined(__clang__)
+
+#endif /* INT_LIB_H */
diff --git a/compiler-rt/lib/builtins/int_math.h b/compiler-rt/lib/builtins/int_math.h
new file mode 100644
index 0000000..fc81fb7
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_math.h
@@ -0,0 +1,114 @@
+/* ===-- int_math.h - internal math inlines ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines substitutes for the libm functions used in some of the
+ * compiler-rt implementations, defined in such a way that there is not a direct
+ * dependency on libm or math.h. Instead, we use the compiler builtin versions
+ * where available. This reduces our dependencies on the system SDK by foisting
+ * the responsibility onto the compiler.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef INT_MATH_H
+#define INT_MATH_H
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <math.h>
+#include <stdlib.h>
+#include <ymath.h>
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define CRT_INFINITY INFINITY
+#else
+#define CRT_INFINITY __builtin_huge_valf()
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_isfinite(x) _finite((x))
+#define crt_isinf(x) !_finite((x))
+#define crt_isnan(x) _isnan((x))
+#else
+/* Define crt_isfinite in terms of the builtin if available, otherwise provide
+ * an alternate version in terms of our other functions. This supports some
+ * versions of GCC which didn't have __builtin_isfinite.
+ */
+#if __has_builtin(__builtin_isfinite)
+# define crt_isfinite(x) __builtin_isfinite((x))
+#elif defined(__GNUC__)
+# define crt_isfinite(x) \
+ __extension__(({ \
+ __typeof((x)) x_ = (x); \
+ !crt_isinf(x_) && !crt_isnan(x_); \
+ }))
+#else
+# error "Do not know how to check for infinity"
+#endif /* __has_builtin(__builtin_isfinite) */
+#define crt_isinf(x) __builtin_isinf((x))
+#define crt_isnan(x) __builtin_isnan((x))
+#endif /* _MSC_VER */
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_copysign(x, y) copysign((x), (y))
+#define crt_copysignf(x, y) copysignf((x), (y))
+#define crt_copysignl(x, y) copysignl((x), (y))
+#else
+#define crt_copysign(x, y) __builtin_copysign((x), (y))
+#define crt_copysignf(x, y) __builtin_copysignf((x), (y))
+#define crt_copysignl(x, y) __builtin_copysignl((x), (y))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_fabs(x) fabs((x))
+#define crt_fabsf(x) fabsf((x))
+#define crt_fabsl(x) fabs((x))
+#else
+#define crt_fabs(x) __builtin_fabs((x))
+#define crt_fabsf(x) __builtin_fabsf((x))
+#define crt_fabsl(x) __builtin_fabsl((x))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_fmax(x, y) __max((x), (y))
+#define crt_fmaxf(x, y) __max((x), (y))
+#define crt_fmaxl(x, y) __max((x), (y))
+#else
+#define crt_fmax(x, y) __builtin_fmax((x), (y))
+#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y))
+#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_logb(x) logb((x))
+#define crt_logbf(x) logbf((x))
+#define crt_logbl(x) logbl((x))
+#else
+#define crt_logb(x) __builtin_logb((x))
+#define crt_logbf(x) __builtin_logbf((x))
+#define crt_logbl(x) __builtin_logbl((x))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_scalbn(x, y) scalbn((x), (y))
+#define crt_scalbnf(x, y) scalbnf((x), (y))
+#define crt_scalbnl(x, y) scalbnl((x), (y))
+#else
+#define crt_scalbn(x, y) __builtin_scalbn((x), (y))
+#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y))
+#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y))
+#endif
+
+#endif /* INT_MATH_H */
diff --git a/compiler-rt/lib/builtins/int_types.h b/compiler-rt/lib/builtins/int_types.h
new file mode 100644
index 0000000..2dad43b
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_types.h
@@ -0,0 +1,165 @@
+/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines various standard types, most importantly a number of unions
+ * used to access parts of larger types.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_TYPES_H
+#define INT_TYPES_H
+
+#include "int_endianness.h"
+
+/* si_int is defined in Linux sysroot's asm-generic/siginfo.h */
+#ifdef si_int
+#undef si_int
+#endif
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+typedef union
+{
+ di_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ su_int low;
+ si_int high;
+#else
+ si_int high;
+ su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} dwords;
+
+typedef union
+{
+ du_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ su_int low;
+ su_int high;
+#else
+ su_int high;
+ su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} udwords;
+
+/* MIPS64 issue: PR 20098 */
+#if defined(__LP64__) && !(defined(__mips__) && defined(__clang__))
+#define CRT_HAS_128BIT
+#endif
+
+#ifdef CRT_HAS_128BIT
+typedef int ti_int __attribute__ ((mode (TI)));
+typedef unsigned tu_int __attribute__ ((mode (TI)));
+
+typedef union
+{
+ ti_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ du_int low;
+ di_int high;
+#else
+ di_int high;
+ du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} twords;
+
+typedef union
+{
+ tu_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ du_int low;
+ du_int high;
+#else
+ du_int high;
+ du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} utwords;
+
+static __inline ti_int make_ti(di_int h, di_int l) {
+ twords r;
+ r.s.high = h;
+ r.s.low = l;
+ return r.all;
+}
+
+static __inline tu_int make_tu(du_int h, du_int l) {
+ utwords r;
+ r.s.high = h;
+ r.s.low = l;
+ return r.all;
+}
+
+#endif /* CRT_HAS_128BIT */
+
+typedef union
+{
+ su_int u;
+ float f;
+} float_bits;
+
+typedef union
+{
+ udwords u;
+ double f;
+} double_bits;
+
+typedef struct
+{
+#if _YUGA_LITTLE_ENDIAN
+ udwords low;
+ udwords high;
+#else
+ udwords high;
+ udwords low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+} uqwords;
+
+typedef union
+{
+ uqwords u;
+ long double f;
+} long_double_bits;
+
+#if __STDC_VERSION__ >= 199901L
+typedef float _Complex Fcomplex;
+typedef double _Complex Dcomplex;
+typedef long double _Complex Lcomplex;
+
+#define COMPLEX_REAL(x) __real__(x)
+#define COMPLEX_IMAGINARY(x) __imag__(x)
+#else
+typedef struct { float real, imaginary; } Fcomplex;
+
+typedef struct { double real, imaginary; } Dcomplex;
+
+typedef struct { long double real, imaginary; } Lcomplex;
+
+#define COMPLEX_REAL(x) (x).real
+#define COMPLEX_IMAGINARY(x) (x).imaginary
+#endif
+#endif /* INT_TYPES_H */
+
diff --git a/compiler-rt/lib/builtins/int_util.c b/compiler-rt/lib/builtins/int_util.c
new file mode 100644
index 0000000..420d1e2
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_util.c
@@ -0,0 +1,61 @@
+/* ===-- int_util.c - Implement internal utilities --------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_util.h"
+
+/* NOTE: The definitions in this file are declared weak because we clients to be
+ * able to arbitrarily package individual functions into separate .a files. If
+ * we did not declare these weak, some link situations might end up seeing
+ * duplicate strong definitions of the same symbol.
+ *
+ * We can't use this solution for kernel use (which may not support weak), but
+ * currently expect that when built for kernel use all the functionality is
+ * packaged into a single library.
+ */
+
+#ifdef KERNEL_USE
+
+NORETURN extern void panic(const char *, ...);
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+ panic("%s:%d: abort in %s", file, line, function);
+}
+
+#elif __APPLE__
+
+/* from libSystem.dylib */
+NORETURN extern void __assert_rtn(const char *func, const char *file, int line,
+ const char *message);
+
+#ifndef _WIN32
+__attribute__((weak))
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+ __assert_rtn(function, file, line, "libcompiler_rt abort");
+}
+
+#else
+
+/* Get the system definition of abort() */
+#include <stdlib.h>
+
+#ifndef _WIN32
+__attribute__((weak))
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+ abort();
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/int_util.h b/compiler-rt/lib/builtins/int_util.h
new file mode 100644
index 0000000..a7b20ed
--- /dev/null
+++ b/compiler-rt/lib/builtins/int_util.h
@@ -0,0 +1,33 @@
+/* ===-- int_util.h - internal utility functions ----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines non-inline utilities which are available for use in the
+ * library. The function definitions themselves are all contained in int_util.c
+ * which will always be compiled into any compiler-rt library.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef INT_UTIL_H
+#define INT_UTIL_H
+
+/** \brief Trigger a program abort (or panic for kernel code). */
+#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, __func__)
+
+NORETURN void compilerrt_abort_impl(const char *file, int line,
+ const char *function);
+
+#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
+#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
+#define COMPILE_TIME_ASSERT2(expr, cnt) \
+ typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
+
+#endif /* INT_UTIL_H */
diff --git a/compiler-rt/lib/builtins/lshrdi3.c b/compiler-rt/lib/builtins/lshrdi3.c
new file mode 100644
index 0000000..6b1ea92
--- /dev/null
+++ b/compiler-rt/lib/builtins/lshrdi3.c
@@ -0,0 +1,43 @@
+/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __lshrdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: logical a >> b */
+
+/* Precondition: 0 <= b < bits_in_dword */
+
+ARM_EABI_FNALIAS(llsr, lshrdi3)
+
+COMPILER_RT_ABI di_int
+__lshrdi3(di_int a, si_int b)
+{
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ udwords input;
+ udwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
+ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_word);
+ }
+ else /* 0 <= b < bits_in_word */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
diff --git a/compiler-rt/lib/builtins/lshrti3.c b/compiler-rt/lib/builtins/lshrti3.c
new file mode 100644
index 0000000..e4170ff
--- /dev/null
+++ b/compiler-rt/lib/builtins/lshrti3.c
@@ -0,0 +1,45 @@
+/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __lshrti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: logical a >> b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__lshrti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ utwords input;
+ utwords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/macho_embedded/CMakeLists.txt b/compiler-rt/lib/builtins/macho_embedded/CMakeLists.txt
new file mode 100644
index 0000000..266e422
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/CMakeLists.txt
@@ -0,0 +1,4 @@
+file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
+foreach(filter_file ${filter_files})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
+endforeach()
diff --git a/compiler-rt/lib/builtins/macho_embedded/arm.txt b/compiler-rt/lib/builtins/macho_embedded/arm.txt
new file mode 100644
index 0000000..4b1683a
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/arm.txt
@@ -0,0 +1,16 @@
+aeabi_cdcmpeq
+aeabi_cdrcmple
+aeabi_cfcmpeq
+aeabi_cfrcmple
+aeabi_dcmpeq
+aeabi_dcmpge
+aeabi_dcmpgt
+aeabi_dcmple
+aeabi_dcmplt
+aeabi_drsub
+aeabi_fcmpeq
+aeabi_fcmpge
+aeabi_fcmpgt
+aeabi_fcmple
+aeabi_fcmplt
+aeabi_frsub
diff --git a/compiler-rt/lib/builtins/macho_embedded/common.txt b/compiler-rt/lib/builtins/macho_embedded/common.txt
new file mode 100644
index 0000000..6ac85a7
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/common.txt
@@ -0,0 +1,92 @@
+absvdi2
+absvsi2
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdi3
+divsc3
+divmodsi4
+udivmodsi4
+do_global_dtors
+ffsdi2
+fixdfdi
+fixsfdi
+fixunsdfdi
+fixunsdfsi
+fixunssfdi
+fixunssfsi
+floatdidf
+floatdisf
+floatundidf
+floatundisf
+gcc_bcmp
+lshrdi3
+moddi3
+muldc3
+muldi3
+mulsc3
+mulvdi3
+mulvsi3
+negdi2
+negvdi2
+negvsi2
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subvdi3
+subvsi3
+ucmpdi2
+udiv_w_sdiv
+udivdi3
+udivmoddi4
+umoddi3
+adddf3
+addsf3
+cmpdf2
+cmpsf2
+div0
+divdf3
+divsf3
+divsi3
+extendsfdf2
+extendhfsf2
+ffssi2
+fixdfsi
+fixsfsi
+floatsidf
+floatsisf
+floatunsidf
+floatunsisf
+comparedf2
+comparesf2
+modsi3
+muldf3
+mulsf3
+negdf2
+negsf2
+subdf3
+subsf3
+truncdfhf2
+truncdfsf2
+truncsfhf2
+udivsi3
+umodsi3
+unorddf2
+unordsf2
+atomic_flag_clear
+atomic_flag_clear_explicit
+atomic_flag_test_and_set
+atomic_flag_test_and_set_explicit
+atomic_signal_fence
+atomic_thread_fence
+int_util
diff --git a/compiler-rt/lib/builtins/macho_embedded/i386.txt b/compiler-rt/lib/builtins/macho_embedded/i386.txt
new file mode 100644
index 0000000..b92e44b
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/i386.txt
@@ -0,0 +1,7 @@
+i686.get_pc_thunk.eax
+i686.get_pc_thunk.ebp
+i686.get_pc_thunk.ebx
+i686.get_pc_thunk.ecx
+i686.get_pc_thunk.edi
+i686.get_pc_thunk.edx
+i686.get_pc_thunk.esi
diff --git a/compiler-rt/lib/builtins/macho_embedded/thumb2-64.txt b/compiler-rt/lib/builtins/macho_embedded/thumb2-64.txt
new file mode 100644
index 0000000..1c72fb1
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/thumb2-64.txt
@@ -0,0 +1,10 @@
+sync_fetch_and_add_8
+sync_fetch_and_sub_8
+sync_fetch_and_and_8
+sync_fetch_and_or_8
+sync_fetch_and_xor_8
+sync_fetch_and_nand_8
+sync_fetch_and_max_8
+sync_fetch_and_umax_8
+sync_fetch_and_min_8
+sync_fetch_and_umin_8
diff --git a/compiler-rt/lib/builtins/macho_embedded/thumb2.txt b/compiler-rt/lib/builtins/macho_embedded/thumb2.txt
new file mode 100644
index 0000000..6add5ec
--- /dev/null
+++ b/compiler-rt/lib/builtins/macho_embedded/thumb2.txt
@@ -0,0 +1,14 @@
+switch16
+switch32
+switch8
+switchu8
+sync_fetch_and_add_4
+sync_fetch_and_sub_4
+sync_fetch_and_and_4
+sync_fetch_and_or_4
+sync_fetch_and_xor_4
+sync_fetch_and_nand_4
+sync_fetch_and_max_4
+sync_fetch_and_umax_4
+sync_fetch_and_min_4
+sync_fetch_and_umin_4
diff --git a/compiler-rt/lib/builtins/moddi3.c b/compiler-rt/lib/builtins/moddi3.c
new file mode 100644
index 0000000..a04279e
--- /dev/null
+++ b/compiler-rt/lib/builtins/moddi3.c
@@ -0,0 +1,30 @@
+/*===-- moddi3.c - Implement __moddi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __moddi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI di_int
+__moddi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */
+ b = (b ^ s) - s; /* negate if s == -1 */
+ s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */
+ a = (a ^ s) - s; /* negate if s == -1 */
+ du_int r;
+ __udivmoddi4(a, b, &r);
+ return ((di_int)r ^ s) - s; /* negate if s == -1 */
+}
diff --git a/compiler-rt/lib/builtins/modsi3.c b/compiler-rt/lib/builtins/modsi3.c
new file mode 100644
index 0000000..86c73ce
--- /dev/null
+++ b/compiler-rt/lib/builtins/modsi3.c
@@ -0,0 +1,23 @@
+/* ===-- modsi3.c - Implement __modsi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __modsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI si_int
+__modsi3(si_int a, si_int b)
+{
+ return a - __divsi3(a, b) * b;
+}
diff --git a/compiler-rt/lib/builtins/modti3.c b/compiler-rt/lib/builtins/modti3.c
new file mode 100644
index 0000000..d505c07
--- /dev/null
+++ b/compiler-rt/lib/builtins/modti3.c
@@ -0,0 +1,34 @@
+/* ===-- modti3.c - Implement __modti3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __modti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/*Returns: a % b */
+
+COMPILER_RT_ABI ti_int
+__modti3(ti_int a, ti_int b)
+{
+ const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+ ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */
+ b = (b ^ s) - s; /* negate if s == -1 */
+ s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */
+ a = (a ^ s) - s; /* negate if s == -1 */
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return ((ti_int)r ^ s) - s; /* negate if s == -1 */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/muldc3.c b/compiler-rt/lib/builtins/muldc3.c
new file mode 100644
index 0000000..16d8e98
--- /dev/null
+++ b/compiler-rt/lib/builtins/muldc3.c
@@ -0,0 +1,73 @@
+/* ===-- muldc3.c - Implement __muldc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __muldc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI Dcomplex
+__muldc3(double __a, double __b, double __c, double __d)
+{
+ double __ac = __a * __c;
+ double __bd = __b * __d;
+ double __ad = __a * __d;
+ double __bc = __b * __c;
+ Dcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc)
+ {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/muldf3.c b/compiler-rt/lib/builtins/muldf3.c
new file mode 100644
index 0000000..1eb7338
--- /dev/null
+++ b/compiler-rt/lib/builtins/muldf3.c
@@ -0,0 +1,22 @@
+//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(dmul, muldf3)
+
+COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/compiler-rt/lib/builtins/muldi3.c b/compiler-rt/lib/builtins/muldi3.c
new file mode 100644
index 0000000..2dae44c
--- /dev/null
+++ b/compiler-rt/lib/builtins/muldi3.c
@@ -0,0 +1,56 @@
+/* ===-- muldi3.c - Implement __muldi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __muldi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+static
+di_int
+__muldsi3(su_int a, su_int b)
+{
+ dwords r;
+ const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2;
+ const su_int lower_mask = (su_int)~0 >> bits_in_word_2;
+ r.s.low = (a & lower_mask) * (b & lower_mask);
+ su_int t = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_word_2) * (b & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_word_2;
+ r.s.high = t >> bits_in_word_2;
+ t = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t += (b >> bits_in_word_2) * (a & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_word_2;
+ r.s.high += t >> bits_in_word_2;
+ r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2);
+ return r.all;
+}
+
+/* Returns: a * b */
+
+ARM_EABI_FNALIAS(lmul, muldi3)
+
+COMPILER_RT_ABI di_int
+__muldi3(di_int a, di_int b)
+{
+ dwords x;
+ x.all = a;
+ dwords y;
+ y.all = b;
+ dwords r;
+ r.all = __muldsi3(x.s.low, y.s.low);
+ r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
+ return r.all;
+}
diff --git a/compiler-rt/lib/builtins/mulodi4.c b/compiler-rt/lib/builtins/mulodi4.c
new file mode 100644
index 0000000..d2fd7db
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulodi4.c
@@ -0,0 +1,58 @@
+/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulodi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI di_int
+__mulodi4(di_int a, di_int b, int* overflow)
+{
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ const di_int MIN = (di_int)1 << (N-1);
+ const di_int MAX = ~MIN;
+ *overflow = 0;
+ di_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ di_int sa = a >> (N - 1);
+ di_int abs_a = (a ^ sa) - sa;
+ di_int sb = b >> (N - 1);
+ di_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
diff --git a/compiler-rt/lib/builtins/mulosi4.c b/compiler-rt/lib/builtins/mulosi4.c
new file mode 100644
index 0000000..4225280
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulosi4.c
@@ -0,0 +1,58 @@
+/*===-- mulosi4.c - Implement __mulosi4 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulosi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI si_int
+__mulosi4(si_int a, si_int b, int* overflow)
+{
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ const si_int MIN = (si_int)1 << (N-1);
+ const si_int MAX = ~MIN;
+ *overflow = 0;
+ si_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ si_int sa = a >> (N - 1);
+ si_int abs_a = (a ^ sa) - sa;
+ si_int sb = b >> (N - 1);
+ si_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
diff --git a/compiler-rt/lib/builtins/muloti4.c b/compiler-rt/lib/builtins/muloti4.c
new file mode 100644
index 0000000..16b2189
--- /dev/null
+++ b/compiler-rt/lib/builtins/muloti4.c
@@ -0,0 +1,62 @@
+/*===-- muloti4.c - Implement __muloti4 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __muloti4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI ti_int
+__muloti4(ti_int a, ti_int b, int* overflow)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ const ti_int MIN = (ti_int)1 << (N-1);
+ const ti_int MAX = ~MIN;
+ *overflow = 0;
+ ti_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ ti_int sa = a >> (N - 1);
+ ti_int abs_a = (a ^ sa) - sa;
+ ti_int sb = b >> (N - 1);
+ ti_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/mulsc3.c b/compiler-rt/lib/builtins/mulsc3.c
new file mode 100644
index 0000000..c89cfd2
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulsc3.c
@@ -0,0 +1,73 @@
+/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulsc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI Fcomplex
+__mulsc3(float __a, float __b, float __c, float __d)
+{
+ float __ac = __a * __c;
+ float __bd = __b * __d;
+ float __ad = __a * __d;
+ float __bc = __b * __c;
+ Fcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc)
+ {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/mulsf3.c b/compiler-rt/lib/builtins/mulsf3.c
new file mode 100644
index 0000000..478b3bc
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(fmul, mulsf3)
+
+COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/compiler-rt/lib/builtins/multc3.c b/compiler-rt/lib/builtins/multc3.c
new file mode 100644
index 0000000..0518bc2
--- /dev/null
+++ b/compiler-rt/lib/builtins/multc3.c
@@ -0,0 +1,68 @@
+/* ===-- multc3.c - Implement __multc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __multc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI long double _Complex
+__multc3(long double a, long double b, long double c, long double d)
+{
+ long double ac = a * c;
+ long double bd = b * d;
+ long double ad = a * d;
+ long double bc = b * c;
+ long double _Complex z;
+ __real__ z = ac - bd;
+ __imag__ z = ad + bc;
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) {
+ int recalc = 0;
+ if (crt_isinf(a) || crt_isinf(b)) {
+ a = crt_copysignl(crt_isinf(a) ? 1 : 0, a);
+ b = crt_copysignl(crt_isinf(b) ? 1 : 0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
+ }
+ if (crt_isinf(c) || crt_isinf(d)) {
+ c = crt_copysignl(crt_isinf(c) ? 1 : 0, c);
+ d = crt_copysignl(crt_isinf(d) ? 1 : 0, d);
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ recalc = 1;
+ }
+ if (!recalc && (crt_isinf(ac) || crt_isinf(bd) ||
+ crt_isinf(ad) || crt_isinf(bc))) {
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
+ }
+ if (recalc) {
+ __real__ z = CRT_INFINITY * (a * c - b * d);
+ __imag__ z = CRT_INFINITY * (a * d + b * c);
+ }
+ }
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/multf3.c b/compiler-rt/lib/builtins/multf3.c
new file mode 100644
index 0000000..0b91592
--- /dev/null
+++ b/compiler-rt/lib/builtins/multf3.c
@@ -0,0 +1,25 @@
+//===-- lib/multf3.c - Quad-precision multiplication --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_mul_impl.inc"
+
+COMPILER_RT_ABI fp_t __multf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/multi3.c b/compiler-rt/lib/builtins/multi3.c
new file mode 100644
index 0000000..e0d52d4
--- /dev/null
+++ b/compiler-rt/lib/builtins/multi3.c
@@ -0,0 +1,58 @@
+/* ===-- multi3.c - Implement __multi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+
+ * This file implements __multi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+static
+ti_int
+__mulddi3(du_int a, du_int b)
+{
+ twords r;
+ const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2;
+ const du_int lower_mask = (du_int)~0 >> bits_in_dword_2;
+ r.s.low = (a & lower_mask) * (b & lower_mask);
+ du_int t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_dword_2) * (b & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high = t >> bits_in_dword_2;
+ t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (b >> bits_in_dword_2) * (a & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high += t >> bits_in_dword_2;
+ r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2);
+ return r.all;
+}
+
+/* Returns: a * b */
+
+COMPILER_RT_ABI ti_int
+__multi3(ti_int a, ti_int b)
+{
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ twords r;
+ r.all = __mulddi3(x.s.low, y.s.low);
+ r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
+ return r.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/mulvdi3.c b/compiler-rt/lib/builtins/mulvdi3.c
new file mode 100644
index 0000000..e63249e
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulvdi3.c
@@ -0,0 +1,56 @@
+/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI di_int
+__mulvdi3(di_int a, di_int b)
+{
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ const di_int MIN = (di_int)1 << (N-1);
+ const di_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ di_int sa = a >> (N - 1);
+ di_int abs_a = (a ^ sa) - sa;
+ di_int sb = b >> (N - 1);
+ di_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
diff --git a/compiler-rt/lib/builtins/mulvsi3.c b/compiler-rt/lib/builtins/mulvsi3.c
new file mode 100644
index 0000000..74ea4f2
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulvsi3.c
@@ -0,0 +1,56 @@
+/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI si_int
+__mulvsi3(si_int a, si_int b)
+{
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ const si_int MIN = (si_int)1 << (N-1);
+ const si_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ si_int sa = a >> (N - 1);
+ si_int abs_a = (a ^ sa) - sa;
+ si_int sb = b >> (N - 1);
+ si_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
diff --git a/compiler-rt/lib/builtins/mulvti3.c b/compiler-rt/lib/builtins/mulvti3.c
new file mode 100644
index 0000000..f4c7d16
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulvti3.c
@@ -0,0 +1,60 @@
+/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI ti_int
+__mulvti3(ti_int a, ti_int b)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ const ti_int MIN = (ti_int)1 << (N-1);
+ const ti_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ ti_int sa = a >> (N - 1);
+ ti_int abs_a = (a ^ sa) - sa;
+ ti_int sb = b >> (N - 1);
+ ti_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/mulxc3.c b/compiler-rt/lib/builtins/mulxc3.c
new file mode 100644
index 0000000..ba32216
--- /dev/null
+++ b/compiler-rt/lib/builtins/mulxc3.c
@@ -0,0 +1,77 @@
+/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __mulxc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI Lcomplex
+__mulxc3(long double __a, long double __b, long double __c, long double __d)
+{
+ long double __ac = __a * __c;
+ long double __bd = __b * __d;
+ long double __ad = __a * __d;
+ long double __bc = __b * __c;
+ Lcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc)
+ {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/negdf2.c b/compiler-rt/lib/builtins/negdf2.c
new file mode 100644
index 0000000..d634b42
--- /dev/null
+++ b/compiler-rt/lib/builtins/negdf2.c
@@ -0,0 +1,22 @@
+//===-- lib/negdf2.c - double-precision negation ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float negation.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(dneg, negdf2)
+
+COMPILER_RT_ABI fp_t
+__negdf2(fp_t a) {
+ return fromRep(toRep(a) ^ signBit);
+}
diff --git a/compiler-rt/lib/builtins/negdi2.c b/compiler-rt/lib/builtins/negdi2.c
new file mode 100644
index 0000000..3d49ba2
--- /dev/null
+++ b/compiler-rt/lib/builtins/negdi2.c
@@ -0,0 +1,26 @@
+/* ===-- negdi2.c - Implement __negdi2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __negdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: -a */
+
+COMPILER_RT_ABI di_int
+__negdi2(di_int a)
+{
+ /* Note: this routine is here for API compatibility; any sane compiler
+ * should expand it inline.
+ */
+ return -a;
+}
diff --git a/compiler-rt/lib/builtins/negsf2.c b/compiler-rt/lib/builtins/negsf2.c
new file mode 100644
index 0000000..29c17be
--- /dev/null
+++ b/compiler-rt/lib/builtins/negsf2.c
@@ -0,0 +1,22 @@
+//===-- lib/negsf2.c - single-precision negation ------------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float negation.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(fneg, negsf2)
+
+COMPILER_RT_ABI fp_t
+__negsf2(fp_t a) {
+ return fromRep(toRep(a) ^ signBit);
+}
diff --git a/compiler-rt/lib/builtins/negti2.c b/compiler-rt/lib/builtins/negti2.c
new file mode 100644
index 0000000..9b00b30
--- /dev/null
+++ b/compiler-rt/lib/builtins/negti2.c
@@ -0,0 +1,30 @@
+/* ===-- negti2.c - Implement __negti2 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __negti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: -a */
+
+COMPILER_RT_ABI ti_int
+__negti2(ti_int a)
+{
+ /* Note: this routine is here for API compatibility; any sane compiler
+ * should expand it inline.
+ */
+ return -a;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/negvdi2.c b/compiler-rt/lib/builtins/negvdi2.c
new file mode 100644
index 0000000..e336ecf
--- /dev/null
+++ b/compiler-rt/lib/builtins/negvdi2.c
@@ -0,0 +1,28 @@
+/* ===-- negvdi2.c - Implement __negvdi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __negvdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: -a */
+
+/* Effects: aborts if -a overflows */
+
+COMPILER_RT_ABI di_int
+__negvdi2(di_int a)
+{
+ const di_int MIN = (di_int)1 << ((int)(sizeof(di_int) * CHAR_BIT)-1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
+}
diff --git a/compiler-rt/lib/builtins/negvsi2.c b/compiler-rt/lib/builtins/negvsi2.c
new file mode 100644
index 0000000..b9e93fe
--- /dev/null
+++ b/compiler-rt/lib/builtins/negvsi2.c
@@ -0,0 +1,28 @@
+/* ===-- negvsi2.c - Implement __negvsi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __negvsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: -a */
+
+/* Effects: aborts if -a overflows */
+
+COMPILER_RT_ABI si_int
+__negvsi2(si_int a)
+{
+ const si_int MIN = (si_int)1 << ((int)(sizeof(si_int) * CHAR_BIT)-1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
+}
diff --git a/compiler-rt/lib/builtins/negvti2.c b/compiler-rt/lib/builtins/negvti2.c
new file mode 100644
index 0000000..85f9f7d
--- /dev/null
+++ b/compiler-rt/lib/builtins/negvti2.c
@@ -0,0 +1,32 @@
+/*===-- negvti2.c - Implement __negvti2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ *This file implements __negvti2 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: -a */
+
+/* Effects: aborts if -a overflows */
+
+COMPILER_RT_ABI ti_int
+__negvti2(ti_int a)
+{
+ const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/paritydi2.c b/compiler-rt/lib/builtins/paritydi2.c
new file mode 100644
index 0000000..8ea5ab4
--- /dev/null
+++ b/compiler-rt/lib/builtins/paritydi2.c
@@ -0,0 +1,25 @@
+/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __paritydi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: 1 if number of bits is odd else returns 0 */
+
+COMPILER_RT_ABI si_int
+__paritydi2(di_int a)
+{
+ dwords x;
+ x.all = a;
+ return __paritysi2(x.s.high ^ x.s.low);
+}
diff --git a/compiler-rt/lib/builtins/paritysi2.c b/compiler-rt/lib/builtins/paritysi2.c
new file mode 100644
index 0000000..5999846
--- /dev/null
+++ b/compiler-rt/lib/builtins/paritysi2.c
@@ -0,0 +1,27 @@
+/* ===-- paritysi2.c - Implement __paritysi2 -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __paritysi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: 1 if number of bits is odd else returns 0 */
+
+COMPILER_RT_ABI si_int
+__paritysi2(si_int a)
+{
+ su_int x = (su_int)a;
+ x ^= x >> 16;
+ x ^= x >> 8;
+ x ^= x >> 4;
+ return (0x6996 >> (x & 0xF)) & 1;
+}
diff --git a/compiler-rt/lib/builtins/parityti2.c b/compiler-rt/lib/builtins/parityti2.c
new file mode 100644
index 0000000..5a4fe49
--- /dev/null
+++ b/compiler-rt/lib/builtins/parityti2.c
@@ -0,0 +1,29 @@
+/* ===-- parityti2.c - Implement __parityti2 -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __parityti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: 1 if number of bits is odd else returns 0 */
+
+COMPILER_RT_ABI si_int
+__parityti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ return __paritydi2(x.s.high ^ x.s.low);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/popcountdi2.c b/compiler-rt/lib/builtins/popcountdi2.c
new file mode 100644
index 0000000..5e8a62f
--- /dev/null
+++ b/compiler-rt/lib/builtins/popcountdi2.c
@@ -0,0 +1,36 @@
+/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __popcountdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountdi2(di_int a)
+{
+ du_int x2 = (du_int)a;
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
+ /* Every 2 bits holds the sum of every pair of bits (32) */
+ x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ /* The lower 32 bits hold four 16 bit sums (5 significant bits). */
+ /* Upper 32 bits are garbage */
+ x = x + (x >> 16);
+ /* The lower 16 bits hold two 32 bit sums (6 significant bits). */
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */
+}
diff --git a/compiler-rt/lib/builtins/popcountsi2.c b/compiler-rt/lib/builtins/popcountsi2.c
new file mode 100644
index 0000000..44544ff
--- /dev/null
+++ b/compiler-rt/lib/builtins/popcountsi2.c
@@ -0,0 +1,33 @@
+/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __popcountsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountsi2(si_int a)
+{
+ su_int x = (su_int)a;
+ x = x - ((x >> 1) & 0x55555555);
+ /* Every 2 bits holds the sum of every pair of bits */
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */
+ x = (x + (x >> 16));
+ /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */
+}
diff --git a/compiler-rt/lib/builtins/popcountti2.c b/compiler-rt/lib/builtins/popcountti2.c
new file mode 100644
index 0000000..7451bbb
--- /dev/null
+++ b/compiler-rt/lib/builtins/popcountti2.c
@@ -0,0 +1,44 @@
+/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __popcountti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountti2(ti_int a)
+{
+ tu_int x3 = (tu_int)a;
+ x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) |
+ 0x5555555555555555uLL));
+ /* Every 2 bits holds the sum of every pair of bits (64) */
+ x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL))
+ + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL));
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */
+ x3 = (x3 + (x3 >> 4))
+ & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL);
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */
+ du_int x2 = (du_int)(x3 + (x3 >> 64));
+ /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */
+ x = x + (x >> 16);
+ /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/powidf2.c b/compiler-rt/lib/builtins/powidf2.c
new file mode 100644
index 0000000..ac13b17
--- /dev/null
+++ b/compiler-rt/lib/builtins/powidf2.c
@@ -0,0 +1,34 @@
+/* ===-- powidf2.cpp - Implement __powidf2 ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __powidf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI double
+__powidf2(double a, si_int b)
+{
+ const int recip = b < 0;
+ double r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
diff --git a/compiler-rt/lib/builtins/powisf2.c b/compiler-rt/lib/builtins/powisf2.c
new file mode 100644
index 0000000..0c400ec
--- /dev/null
+++ b/compiler-rt/lib/builtins/powisf2.c
@@ -0,0 +1,34 @@
+/*===-- powisf2.cpp - Implement __powisf2 ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __powisf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI float
+__powisf2(float a, si_int b)
+{
+ const int recip = b < 0;
+ float r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
diff --git a/compiler-rt/lib/builtins/powitf2.c b/compiler-rt/lib/builtins/powitf2.c
new file mode 100644
index 0000000..172f29f
--- /dev/null
+++ b/compiler-rt/lib/builtins/powitf2.c
@@ -0,0 +1,38 @@
+/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __powitf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#if _ARCH_PPC
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI long double
+__powitf2(long double a, si_int b)
+{
+ const int recip = b < 0;
+ long double r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/powixf2.c b/compiler-rt/lib/builtins/powixf2.c
new file mode 100644
index 0000000..0fd96e5
--- /dev/null
+++ b/compiler-rt/lib/builtins/powixf2.c
@@ -0,0 +1,38 @@
+/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __powixf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI long double
+__powixf2(long double a, si_int b)
+{
+ const int recip = b < 0;
+ long double r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/ppc/DD.h b/compiler-rt/lib/builtins/ppc/DD.h
new file mode 100644
index 0000000..3e5f9e5
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/DD.h
@@ -0,0 +1,45 @@
+#ifndef COMPILERRT_DD_HEADER
+#define COMPILERRT_DD_HEADER
+
+#include "../int_lib.h"
+
+typedef union {
+ long double ld;
+ struct {
+ double hi;
+ double lo;
+ }s;
+} DD;
+
+typedef union {
+ double d;
+ uint64_t x;
+} doublebits;
+
+#define LOWORDER(xy,xHi,xLo,yHi,yLo) \
+ (((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo))
+
+static __inline ALWAYS_INLINE double local_fabs(double x) {
+ doublebits result = {.d = x};
+ result.x &= UINT64_C(0x7fffffffffffffff);
+ return result.d;
+}
+
+static __inline ALWAYS_INLINE double high26bits(double x) {
+ doublebits result = {.d = x};
+ result.x &= UINT64_C(0xfffffffff8000000);
+ return result.d;
+}
+
+static __inline ALWAYS_INLINE int different_sign(double x, double y) {
+ doublebits xsignbit = {.d = x}, ysignbit = {.d = y};
+ int result = (int)(xsignbit.x >> 63) ^ (int)(ysignbit.x >> 63);
+ return result;
+}
+
+long double __gcc_qadd(long double, long double);
+long double __gcc_qsub(long double, long double);
+long double __gcc_qmul(long double, long double);
+long double __gcc_qdiv(long double, long double);
+
+#endif /* COMPILERRT_DD_HEADER */
diff --git a/compiler-rt/lib/builtins/ppc/Makefile.mk b/compiler-rt/lib/builtins/ppc/Makefile.mk
new file mode 100644
index 0000000..0adc623
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/ppc/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := ppc
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/ppc/divtc3.c b/compiler-rt/lib/builtins/ppc/divtc3.c
new file mode 100644
index 0000000..8ec41c5
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/divtc3.c
@@ -0,0 +1,91 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+#include "DD.h"
+#include "../int_math.h"
+
+#if !defined(CRT_INFINITY) && defined(HUGE_VAL)
+#define CRT_INFINITY HUGE_VAL
+#endif /* CRT_INFINITY */
+
+#define makeFinite(x) { \
+ (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
+ }
+
+long double _Complex
+__divtc3(long double a, long double b, long double c, long double d)
+{
+ DD cDD = { .ld = c };
+ DD dDD = { .ld = d };
+
+ int ilogbw = 0;
+ const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) ));
+
+ if (crt_isfinite(logbw))
+ {
+ ilogbw = (int)logbw;
+
+ cDD.s.hi = crt_scalbn(cDD.s.hi, -ilogbw);
+ cDD.s.lo = crt_scalbn(cDD.s.lo, -ilogbw);
+ dDD.s.hi = crt_scalbn(dDD.s.hi, -ilogbw);
+ dDD.s.lo = crt_scalbn(dDD.s.lo, -ilogbw);
+ }
+
+ const long double denom = __gcc_qadd(__gcc_qmul(cDD.ld, cDD.ld), __gcc_qmul(dDD.ld, dDD.ld));
+ const long double realNumerator = __gcc_qadd(__gcc_qmul(a,cDD.ld), __gcc_qmul(b,dDD.ld));
+ const long double imagNumerator = __gcc_qsub(__gcc_qmul(b,cDD.ld), __gcc_qmul(a,dDD.ld));
+
+ DD real = { .ld = __gcc_qdiv(realNumerator, denom) };
+ DD imag = { .ld = __gcc_qdiv(imagNumerator, denom) };
+
+ real.s.hi = crt_scalbn(real.s.hi, -ilogbw);
+ real.s.lo = crt_scalbn(real.s.lo, -ilogbw);
+ imag.s.hi = crt_scalbn(imag.s.hi, -ilogbw);
+ imag.s.lo = crt_scalbn(imag.s.lo, -ilogbw);
+
+ if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi))
+ {
+ DD aDD = { .ld = a };
+ DD bDD = { .ld = b };
+ DD rDD = { .ld = denom };
+
+ if ((rDD.s.hi == 0.0) && (!crt_isnan(aDD.s.hi) ||
+ !crt_isnan(bDD.s.hi)))
+ {
+ real.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * aDD.s.hi;
+ real.s.lo = 0.0;
+ imag.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * bDD.s.hi;
+ imag.s.lo = 0.0;
+ }
+
+ else if ((crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) &&
+ crt_isfinite(cDD.s.hi) && crt_isfinite(dDD.s.hi))
+ {
+ makeFinite(aDD);
+ makeFinite(bDD);
+ real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi);
+ real.s.lo = 0.0;
+ imag.s.hi = CRT_INFINITY * (bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi);
+ imag.s.lo = 0.0;
+ }
+
+ else if ((crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) &&
+ crt_isfinite(aDD.s.hi) && crt_isfinite(bDD.s.hi))
+ {
+ makeFinite(cDD);
+ makeFinite(dDD);
+ real.s.hi = crt_copysign(0.0,(aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi));
+ real.s.lo = 0.0;
+ imag.s.hi = crt_copysign(0.0,(bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi));
+ imag.s.lo = 0.0;
+ }
+ }
+
+ long double _Complex z;
+ __real__ z = real.ld;
+ __imag__ z = imag.ld;
+
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/ppc/fixtfdi.c b/compiler-rt/lib/builtins/ppc/fixtfdi.c
new file mode 100644
index 0000000..2c7c0f8
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/fixtfdi.c
@@ -0,0 +1,104 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* int64_t __fixunstfdi(long double x);
+ * This file implements the PowerPC 128-bit double-double -> int64_t conversion
+ */
+
+#include "DD.h"
+#include "../int_math.h"
+
+uint64_t __fixtfdi(long double input)
+{
+ const DD x = { .ld = input };
+ const doublebits hibits = { .d = x.s.hi };
+
+ const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff);
+ const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000);
+
+ /* If (1.0 - tiny) <= input < 0x1.0p63: */
+ if (UINT32_C(0x03f00000) > absHighWordMinusOne)
+ {
+ /* Do an unsigned conversion of the absolute value, then restore the sign. */
+ const int unbiasedHeadExponent = absHighWordMinusOne >> 20;
+
+ int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */
+ result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
+ result <<= 10; /* mantissa(hi) with one zero preceding bit. */
+
+ const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
+
+ /* If the tail is non-zero, we need to patch in the tail bits. */
+ if (0.0 != x.s.lo)
+ {
+ const doublebits lobits = { .d = x.s.lo };
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ /* At this point we have the mantissa of |tail| */
+ /* We need to negate it if head and tail have different signs. */
+ const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63;
+ const int64_t negationMask = loNegationMask ^ hiNegationMask;
+ tailMantissa = (tailMantissa ^ negationMask) - negationMask;
+
+ /* Now we have the mantissa of tail as a signed 2s-complement integer */
+
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+
+ /* Shift the tail mantissa into the right position, accounting for the
+ * bias of 10 that we shifted the head mantissa by.
+ */
+ tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10)));
+
+ result += tailMantissa;
+ }
+
+ result >>= (62 - unbiasedHeadExponent);
+
+ /* Restore the sign of the result and return */
+ result = (result ^ hiNegationMask) - hiNegationMask;
+ return result;
+
+ }
+
+ /* Edge cases handled here: */
+
+ /* |x| < 1, result is zero. */
+ if (1.0 > crt_fabs(x.s.hi))
+ return INT64_C(0);
+
+ /* x very close to INT64_MIN, care must be taken to see which side we are on. */
+ if (x.s.hi == -0x1.0p63) {
+
+ int64_t result = INT64_MIN;
+
+ if (0.0 < x.s.lo)
+ {
+ /* If the tail is positive, the correct result is something other than INT64_MIN.
+ * we'll need to figure out what it is.
+ */
+
+ const doublebits lobits = { .d = x.s.lo };
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ /* Now we negate the tailMantissa */
+ tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1);
+
+ /* And shift it by the appropriate amount */
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+ tailMantissa >>= 1075 - biasedTailExponent;
+
+ result -= tailMantissa;
+ }
+
+ return result;
+ }
+
+ /* Signed overflows, infinities, and NaNs */
+ if (x.s.hi > 0.0)
+ return INT64_MAX;
+ else
+ return INT64_MIN;
+}
diff --git a/compiler-rt/lib/builtins/ppc/fixunstfdi.c b/compiler-rt/lib/builtins/ppc/fixunstfdi.c
new file mode 100644
index 0000000..5e6e2ce
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/fixunstfdi.c
@@ -0,0 +1,59 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* uint64_t __fixunstfdi(long double x); */
+/* This file implements the PowerPC 128-bit double-double -> uint64_t conversion */
+
+#include "DD.h"
+
+uint64_t __fixunstfdi(long double input)
+{
+ const DD x = { .ld = input };
+ const doublebits hibits = { .d = x.s.hi };
+
+ const uint32_t highWordMinusOne = (uint32_t)(hibits.x >> 32) - UINT32_C(0x3ff00000);
+
+ /* If (1.0 - tiny) <= input < 0x1.0p64: */
+ if (UINT32_C(0x04000000) > highWordMinusOne)
+ {
+ const int unbiasedHeadExponent = highWordMinusOne >> 20;
+
+ uint64_t result = hibits.x & UINT64_C(0x000fffffffffffff); /* mantissa(hi) */
+ result |= UINT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
+ result <<= 11; /* mantissa(hi) left aligned in the int64 field. */
+
+ /* If the tail is non-zero, we need to patch in the tail bits. */
+ if (0.0 != x.s.lo)
+ {
+ const doublebits lobits = { .d = x.s.lo };
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ /* At this point we have the mantissa of |tail| */
+
+ const int64_t negationMask = ((int64_t)(lobits.x)) >> 63;
+ tailMantissa = (tailMantissa ^ negationMask) - negationMask;
+
+ /* Now we have the mantissa of tail as a signed 2s-complement integer */
+
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+
+ /* Shift the tail mantissa into the right position, accounting for the
+ * bias of 11 that we shifted the head mantissa by.
+ */
+ tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 11)));
+
+ result += tailMantissa;
+ }
+
+ result >>= (63 - unbiasedHeadExponent);
+ return result;
+ }
+
+ /* Edge cases are handled here, with saturation. */
+ if (1.0 > x.s.hi)
+ return UINT64_C(0);
+ else
+ return UINT64_MAX;
+}
diff --git a/compiler-rt/lib/builtins/ppc/floatditf.c b/compiler-rt/lib/builtins/ppc/floatditf.c
new file mode 100644
index 0000000..beabdd0
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/floatditf.c
@@ -0,0 +1,36 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __floatditf(long long x); */
+/* This file implements the PowerPC long long -> long double conversion */
+
+#include "DD.h"
+
+long double __floatditf(int64_t a) {
+
+ static const double twop32 = 0x1.0p32;
+ static const double twop52 = 0x1.0p52;
+
+ doublebits low = { .d = twop52 };
+ low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a. */
+
+ const double high_addend = (double)((int32_t)(a >> 32))*twop32 - twop52;
+
+ /* At this point, we have two double precision numbers
+ * high_addend and low.d, and we wish to return their sum
+ * as a canonicalized long double:
+ */
+
+ /* This implementation sets the inexact flag spuriously.
+ * This could be avoided, but at some substantial cost.
+ */
+
+ DD result;
+
+ result.s.hi = high_addend + low.d;
+ result.s.lo = (high_addend - result.s.hi) + low.d;
+
+ return result.ld;
+
+}
diff --git a/compiler-rt/lib/builtins/ppc/floatunditf.c b/compiler-rt/lib/builtins/ppc/floatunditf.c
new file mode 100644
index 0000000..b12e1e7
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/floatunditf.c
@@ -0,0 +1,41 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __floatunditf(unsigned long long x); */
+/* This file implements the PowerPC unsigned long long -> long double conversion */
+
+#include "DD.h"
+
+long double __floatunditf(uint64_t a) {
+
+ /* Begins with an exact copy of the code from __floatundidf */
+
+ static const double twop52 = 0x1.0p52;
+ static const double twop84 = 0x1.0p84;
+ static const double twop84_plus_twop52 = 0x1.00000001p84;
+
+ doublebits high = { .d = twop84 };
+ doublebits low = { .d = twop52 };
+
+ high.x |= a >> 32; /* 0x1.0p84 + high 32 bits of a */
+ low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a */
+
+ const double high_addend = high.d - twop84_plus_twop52;
+
+ /* At this point, we have two double precision numbers
+ * high_addend and low.d, and we wish to return their sum
+ * as a canonicalized long double:
+ */
+
+ /* This implementation sets the inexact flag spuriously. */
+ /* This could be avoided, but at some substantial cost. */
+
+ DD result;
+
+ result.s.hi = high_addend + low.d;
+ result.s.lo = (high_addend - result.s.hi) + low.d;
+
+ return result.ld;
+
+}
diff --git a/compiler-rt/lib/builtins/ppc/gcc_qadd.c b/compiler-rt/lib/builtins/ppc/gcc_qadd.c
new file mode 100644
index 0000000..32e16e9
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/gcc_qadd.c
@@ -0,0 +1,76 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qadd(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double add operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qadd(long double x, long double y)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = { .ld = x }, src = { .ld = y };
+
+ register double A = dst.s.hi, a = dst.s.lo,
+ B = src.s.hi, b = src.s.lo;
+
+ /* If both operands are zero: */
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If either operand is NaN or infinity: */
+ const doublebits abits = { .d = A };
+ const doublebits bbits = { .d = B };
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If the computation overflows: */
+ /* This may be playing things a little bit fast and loose, but it will do for a start. */
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = { .d = testForOverflow };
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
+}
diff --git a/compiler-rt/lib/builtins/ppc/gcc_qdiv.c b/compiler-rt/lib/builtins/ppc/gcc_qdiv.c
new file mode 100644
index 0000000..70aa00b
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/gcc_qdiv.c
@@ -0,0 +1,55 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qdiv(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double division operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qdiv(long double a, long double b)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+ DD dst = { .ld = a }, src = { .ld = b };
+
+ register double x = dst.s.hi, x1 = dst.s.lo,
+ y = src.s.hi, y1 = src.s.lo;
+
+ double yHi, yLo, qHi, qLo;
+ double yq, tmp, q;
+
+ q = x / y;
+
+ /* Detect special cases */
+ if (q == 0.0) {
+ dst.s.hi = q;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ const doublebits qBits = { .d = q };
+ if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = q;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ yHi = high26bits(y);
+ qHi = high26bits(q);
+
+ yq = y * q;
+ yLo = y - yHi;
+ qLo = q - qHi;
+
+ tmp = LOWORDER(yq, yHi, yLo, qHi, qLo);
+ tmp = (x - yq) - tmp;
+ tmp = ((tmp + x1) - y1 * q) / y;
+ x = q + tmp;
+
+ dst.s.lo = (q - x) + tmp;
+ dst.s.hi = x;
+
+ return dst.ld;
+}
diff --git a/compiler-rt/lib/builtins/ppc/gcc_qmul.c b/compiler-rt/lib/builtins/ppc/gcc_qmul.c
new file mode 100644
index 0000000..fb4c516
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/gcc_qmul.c
@@ -0,0 +1,53 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qmul(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double multiply operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qmul(long double x, long double y)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+ DD dst = { .ld = x }, src = { .ld = y };
+
+ register double A = dst.s.hi, a = dst.s.lo,
+ B = src.s.hi, b = src.s.lo;
+
+ double aHi, aLo, bHi, bLo;
+ double ab, tmp, tau;
+
+ ab = A * B;
+
+ /* Detect special cases */
+ if (ab == 0.0) {
+ dst.s.hi = ab;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ const doublebits abBits = { .d = ab };
+ if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = ab;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* Generic cases handled here. */
+ aHi = high26bits(A);
+ bHi = high26bits(B);
+ aLo = A - aHi;
+ bLo = B - bHi;
+
+ tmp = LOWORDER(ab, aHi, aLo, bHi, bLo);
+ tmp += (A * b + a * B);
+ tau = ab + tmp;
+
+ dst.s.lo = (ab - tau) + tmp;
+ dst.s.hi = tau;
+
+ return dst.ld;
+}
diff --git a/compiler-rt/lib/builtins/ppc/gcc_qsub.c b/compiler-rt/lib/builtins/ppc/gcc_qsub.c
new file mode 100644
index 0000000..c092e24
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/gcc_qsub.c
@@ -0,0 +1,76 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qsub(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double add operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qsub(long double x, long double y)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = { .ld = x }, src = { .ld = y };
+
+ register double A = dst.s.hi, a = dst.s.lo,
+ B = -src.s.hi, b = -src.s.lo;
+
+ /* If both operands are zero: */
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If either operand is NaN or infinity: */
+ const doublebits abits = { .d = A };
+ const doublebits bbits = { .d = B };
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If the computation overflows: */
+ /* This may be playing things a little bit fast and loose, but it will do for a start. */
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = { .d = testForOverflow };
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
+}
diff --git a/compiler-rt/lib/builtins/ppc/multc3.c b/compiler-rt/lib/builtins/ppc/multc3.c
new file mode 100644
index 0000000..9dd79c9
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/multc3.c
@@ -0,0 +1,90 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+#include "DD.h"
+#include "../int_math.h"
+
+#define makeFinite(x) { \
+ (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
+ }
+
+#define zeroNaN(x) { \
+ if (crt_isnan((x).s.hi)) { \
+ (x).s.hi = crt_copysign(0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
+ } \
+ }
+
+long double _Complex
+__multc3(long double a, long double b, long double c, long double d)
+{
+ long double ac = __gcc_qmul(a,c);
+ long double bd = __gcc_qmul(b,d);
+ long double ad = __gcc_qmul(a,d);
+ long double bc = __gcc_qmul(b,c);
+
+ DD real = { .ld = __gcc_qsub(ac,bd) };
+ DD imag = { .ld = __gcc_qadd(ad,bc) };
+
+ if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi))
+ {
+ int recalc = 0;
+
+ DD aDD = { .ld = a };
+ DD bDD = { .ld = b };
+ DD cDD = { .ld = c };
+ DD dDD = { .ld = d };
+
+ if (crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi))
+ {
+ makeFinite(aDD);
+ makeFinite(bDD);
+ zeroNaN(cDD);
+ zeroNaN(dDD);
+ recalc = 1;
+ }
+
+ if (crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi))
+ {
+ makeFinite(cDD);
+ makeFinite(dDD);
+ zeroNaN(aDD);
+ zeroNaN(bDD);
+ recalc = 1;
+ }
+
+ if (!recalc)
+ {
+ DD acDD = { .ld = ac };
+ DD bdDD = { .ld = bd };
+ DD adDD = { .ld = ad };
+ DD bcDD = { .ld = bc };
+
+ if (crt_isinf(acDD.s.hi) || crt_isinf(bdDD.s.hi) ||
+ crt_isinf(adDD.s.hi) || crt_isinf(bcDD.s.hi))
+ {
+ zeroNaN(aDD);
+ zeroNaN(bDD);
+ zeroNaN(cDD);
+ zeroNaN(dDD);
+ recalc = 1;
+ }
+ }
+
+ if (recalc)
+ {
+ real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi - bDD.s.hi*dDD.s.hi);
+ real.s.lo = 0.0;
+ imag.s.hi = CRT_INFINITY * (aDD.s.hi*dDD.s.hi + bDD.s.hi*cDD.s.hi);
+ imag.s.lo = 0.0;
+ }
+ }
+
+ long double _Complex z;
+ __real__ z = real.ld;
+ __imag__ z = imag.ld;
+
+ return z;
+}
diff --git a/compiler-rt/lib/builtins/ppc/restFP.S b/compiler-rt/lib/builtins/ppc/restFP.S
new file mode 100644
index 0000000..9503289
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/restFP.S
@@ -0,0 +1,43 @@
+//===-- restFP.S - Implement restFP ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// Helper function used by compiler to restore ppc floating point registers at
+// the end of the function epilog. This function returns to the address
+// in the LR slot. So a function epilog must branch (b) not branch and link
+// (bl) to this function.
+// If the compiler wants to restore f27..f31, it does a "b restFP+52"
+//
+// This function should never be exported by a shared library. Each linkage
+// unit carries its own copy of this function.
+//
+DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(restFP)
+ lfd f14,-144(r1)
+ lfd f15,-136(r1)
+ lfd f16,-128(r1)
+ lfd f17,-120(r1)
+ lfd f18,-112(r1)
+ lfd f19,-104(r1)
+ lfd f20,-96(r1)
+ lfd f21,-88(r1)
+ lfd f22,-80(r1)
+ lfd f23,-72(r1)
+ lfd f24,-64(r1)
+ lfd f25,-56(r1)
+ lfd f26,-48(r1)
+ lfd f27,-40(r1)
+ lfd f28,-32(r1)
+ lfd f29,-24(r1)
+ lfd f30,-16(r1)
+ lfd f31,-8(r1)
+ lwz r0,8(r1)
+ mtlr r0
+ blr
diff --git a/compiler-rt/lib/builtins/ppc/saveFP.S b/compiler-rt/lib/builtins/ppc/saveFP.S
new file mode 100644
index 0000000..72bd459
--- /dev/null
+++ b/compiler-rt/lib/builtins/ppc/saveFP.S
@@ -0,0 +1,40 @@
+//===-- saveFP.S - Implement saveFP ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+//
+// Helper function used by compiler to save ppc floating point registers in
+// function prologs. This routines also saves r0 in the LR slot.
+// If the compiler wants to save f27..f31, it does a "bl saveFP+52"
+//
+// This function should never be exported by a shared library. Each linkage
+// unit carries its own copy of this function.
+//
+DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(saveFP)
+ stfd f14,-144(r1)
+ stfd f15,-136(r1)
+ stfd f16,-128(r1)
+ stfd f17,-120(r1)
+ stfd f18,-112(r1)
+ stfd f19,-104(r1)
+ stfd f20,-96(r1)
+ stfd f21,-88(r1)
+ stfd f22,-80(r1)
+ stfd f23,-72(r1)
+ stfd f24,-64(r1)
+ stfd f25,-56(r1)
+ stfd f26,-48(r1)
+ stfd f27,-40(r1)
+ stfd f28,-32(r1)
+ stfd f29,-24(r1)
+ stfd f30,-16(r1)
+ stfd f31,-8(r1)
+ stw r0,8(r1)
+ blr
diff --git a/compiler-rt/lib/builtins/subdf3.c b/compiler-rt/lib/builtins/subdf3.c
new file mode 100644
index 0000000..7a79e5e
--- /dev/null
+++ b/compiler-rt/lib/builtins/subdf3.c
@@ -0,0 +1,25 @@
+//===-- lib/adddf3.c - Double-precision subtraction ---------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements double-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(dsub, subdf3)
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subdf3(fp_t a, fp_t b) {
+ return __adddf3(a, fromRep(toRep(b) ^ signBit));
+}
+
diff --git a/compiler-rt/lib/builtins/subsf3.c b/compiler-rt/lib/builtins/subsf3.c
new file mode 100644
index 0000000..c3b8514
--- /dev/null
+++ b/compiler-rt/lib/builtins/subsf3.c
@@ -0,0 +1,25 @@
+//===-- lib/subsf3.c - Single-precision subtraction ---------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements single-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(fsub, subsf3)
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subsf3(fp_t a, fp_t b) {
+ return __addsf3(a, fromRep(toRep(b) ^ signBit));
+}
+
diff --git a/compiler-rt/lib/builtins/subtf3.c b/compiler-rt/lib/builtins/subtf3.c
new file mode 100644
index 0000000..609b816
--- /dev/null
+++ b/compiler-rt/lib/builtins/subtf3.c
@@ -0,0 +1,27 @@
+//===-- lib/subtf3.c - Quad-precision subtraction -----------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements quad-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __addtf3(fp_t a, fp_t b);
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subtf3(fp_t a, fp_t b) {
+ return __addtf3(a, fromRep(toRep(b) ^ signBit));
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/subvdi3.c b/compiler-rt/lib/builtins/subvdi3.c
new file mode 100644
index 0000000..71fc70f
--- /dev/null
+++ b/compiler-rt/lib/builtins/subvdi3.c
@@ -0,0 +1,36 @@
+/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __subvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI di_int
+__subvdi3(di_int a, di_int b)
+{
+ di_int s = (du_int) a - (du_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/compiler-rt/lib/builtins/subvsi3.c b/compiler-rt/lib/builtins/subvsi3.c
new file mode 100644
index 0000000..e6c0fb6
--- /dev/null
+++ b/compiler-rt/lib/builtins/subvsi3.c
@@ -0,0 +1,36 @@
+/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __subvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI si_int
+__subvsi3(si_int a, si_int b)
+{
+ si_int s = (su_int) a - (su_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/compiler-rt/lib/builtins/subvti3.c b/compiler-rt/lib/builtins/subvti3.c
new file mode 100644
index 0000000..a6804d2
--- /dev/null
+++ b/compiler-rt/lib/builtins/subvti3.c
@@ -0,0 +1,40 @@
+/* ===-- subvti3.c - Implement __subvti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __subvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI ti_int
+__subvti3(ti_int a, ti_int b)
+{
+ ti_int s = (tu_int) a - (tu_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/trampoline_setup.c b/compiler-rt/lib/builtins/trampoline_setup.c
new file mode 100644
index 0000000..25b627a
--- /dev/null
+++ b/compiler-rt/lib/builtins/trampoline_setup.c
@@ -0,0 +1,48 @@
+/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+extern void __clear_cache(void* start, void* end);
+
+/*
+ * The ppc compiler generates calls to __trampoline_setup() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * This function creates a custom 40-byte trampoline function on the stack
+ * which loads r11 with a pointer to the outer function's locals
+ * and then jumps to the target nested function.
+ */
+
+#if __ppc__ && !defined(__powerpc64__)
+COMPILER_RT_ABI void
+__trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr)
+{
+ /* should never happen, but if compiler did not allocate */
+ /* enough space on stack for the trampoline, abort */
+ if ( trampSizeAllocated < 40 )
+ compilerrt_abort();
+
+ /* create trampoline */
+ trampOnStack[0] = 0x7c0802a6; /* mflr r0 */
+ trampOnStack[1] = 0x4800000d; /* bl Lbase */
+ trampOnStack[2] = (uint32_t)realFunc;
+ trampOnStack[3] = (uint32_t)localsPtr;
+ trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */
+ trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */
+ trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */
+ trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */
+ trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */
+ trampOnStack[9] = 0x4e800420; /* bctr */
+
+ /* clear instruction cache */
+ __clear_cache(trampOnStack, &trampOnStack[10]);
+}
+#endif /* __ppc__ && !defined(__powerpc64__) */
diff --git a/compiler-rt/lib/builtins/truncdfhf2.c b/compiler-rt/lib/builtins/truncdfhf2.c
new file mode 100644
index 0000000..17195cd
--- /dev/null
+++ b/compiler-rt/lib/builtins/truncdfhf2.c
@@ -0,0 +1,18 @@
+//===-- lib/truncdfhf2.c - double -> half conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_DOUBLE
+#define DST_HALF
+#include "fp_trunc_impl.inc"
+
+ARM_EABI_FNALIAS(d2h, truncdfhf2)
+
+COMPILER_RT_ABI uint16_t __truncdfhf2(double a) {
+ return __truncXfYf2__(a);
+}
diff --git a/compiler-rt/lib/builtins/truncdfsf2.c b/compiler-rt/lib/builtins/truncdfsf2.c
new file mode 100644
index 0000000..46ec11d
--- /dev/null
+++ b/compiler-rt/lib/builtins/truncdfsf2.c
@@ -0,0 +1,18 @@
+//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_DOUBLE
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+ARM_EABI_FNALIAS(d2f, truncdfsf2)
+
+COMPILER_RT_ABI float __truncdfsf2(double a) {
+ return __truncXfYf2__(a);
+}
diff --git a/compiler-rt/lib/builtins/truncsfhf2.c b/compiler-rt/lib/builtins/truncsfhf2.c
new file mode 100644
index 0000000..9d61895
--- /dev/null
+++ b/compiler-rt/lib/builtins/truncsfhf2.c
@@ -0,0 +1,24 @@
+//===-- lib/truncsfhf2.c - single -> half conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_SINGLE
+#define DST_HALF
+#include "fp_trunc_impl.inc"
+
+ARM_EABI_FNALIAS(f2h, truncsfhf2)
+
+// Use a forwarding definition and noinline to implement a poor man's alias,
+// as there isn't a good cross-platform way of defining one.
+COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) {
+ return __truncXfYf2__(a);
+}
+
+COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) {
+ return __truncsfhf2(a);
+}
diff --git a/compiler-rt/lib/builtins/trunctfdf2.c b/compiler-rt/lib/builtins/trunctfdf2.c
new file mode 100644
index 0000000..741a71b
--- /dev/null
+++ b/compiler-rt/lib/builtins/trunctfdf2.c
@@ -0,0 +1,22 @@
+//===-- lib/truncdfsf2.c - quad -> double conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_DOUBLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI double __trunctfdf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/trunctfsf2.c b/compiler-rt/lib/builtins/trunctfsf2.c
new file mode 100644
index 0000000..de96c1d
--- /dev/null
+++ b/compiler-rt/lib/builtins/trunctfsf2.c
@@ -0,0 +1,22 @@
+//===-- lib/trunctfsf2.c - quad -> single conversion --------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI float __trunctfsf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/compiler-rt/lib/builtins/ucmpdi2.c b/compiler-rt/lib/builtins/ucmpdi2.c
new file mode 100644
index 0000000..40af236
--- /dev/null
+++ b/compiler-rt/lib/builtins/ucmpdi2.c
@@ -0,0 +1,51 @@
+/* ===-- ucmpdi2.c - Implement __ucmpdi2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ucmpdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: if (a < b) returns 0
+ * if (a == b) returns 1
+ * if (a > b) returns 2
+ */
+
+COMPILER_RT_ABI si_int
+__ucmpdi2(du_int a, du_int b)
+{
+ udwords x;
+ x.all = a;
+ udwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#ifdef __ARM_EABI__
+/* Returns: if (a < b) returns -1
+* if (a == b) returns 0
+* if (a > b) returns 1
+*/
+COMPILER_RT_ABI si_int
+__aeabi_ulcmp(di_int a, di_int b)
+{
+ return __ucmpdi2(a, b) - 1;
+}
+#endif
+
diff --git a/compiler-rt/lib/builtins/ucmpti2.c b/compiler-rt/lib/builtins/ucmpti2.c
new file mode 100644
index 0000000..bda8083
--- /dev/null
+++ b/compiler-rt/lib/builtins/ucmpti2.c
@@ -0,0 +1,42 @@
+/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __ucmpti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: if (a < b) returns 0
+ * if (a == b) returns 1
+ * if (a > b) returns 2
+ */
+
+COMPILER_RT_ABI si_int
+__ucmpti2(tu_int a, tu_int b)
+{
+ utwords x;
+ x.all = a;
+ utwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/udivdi3.c b/compiler-rt/lib/builtins/udivdi3.c
new file mode 100644
index 0000000..dc68e15
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivdi3.c
@@ -0,0 +1,23 @@
+/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI du_int
+__udivdi3(du_int a, du_int b)
+{
+ return __udivmoddi4(a, b, 0);
+}
diff --git a/compiler-rt/lib/builtins/udivmoddi4.c b/compiler-rt/lib/builtins/udivmoddi4.c
new file mode 100644
index 0000000..0c8b4ff
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivmoddi4.c
@@ -0,0 +1,231 @@
+/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Effects: if rem != 0, *rem = a % b
+ * Returns: a / b
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+COMPILER_RT_ABI du_int
+__udivmoddi4(du_int a, du_int b, du_int* rem)
+{
+ const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ udwords n;
+ n.all = a;
+ udwords d;
+ d.all = b;
+ udwords q;
+ udwords r;
+ unsigned sr;
+ /* special cases, X is unknown, K != 0 */
+ if (n.s.high == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* 0 X
+ * ---
+ * 0 X
+ */
+ if (rem)
+ *rem = n.s.low % d.s.low;
+ return n.s.low / d.s.low;
+ }
+ /* 0 X
+ * ---
+ * K X
+ */
+ if (rem)
+ *rem = n.s.low;
+ return 0;
+ }
+ /* n.s.high != 0 */
+ if (d.s.low == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 0
+ */
+ if (rem)
+ *rem = n.s.high % d.s.low;
+ return n.s.high / d.s.low;
+ }
+ /* d.s.high != 0 */
+ if (n.s.low == 0)
+ {
+ /* K 0
+ * ---
+ * K 0
+ */
+ if (rem)
+ {
+ r.s.high = n.s.high % d.s.high;
+ r.s.low = 0;
+ *rem = r.all;
+ }
+ return n.s.high / d.s.high;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ {
+ r.s.low = n.s.low;
+ r.s.high = n.s.high & (d.s.high - 1);
+ *rem = r.all;
+ }
+ return n.s.high >> __builtin_ctz(d.s.high);
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+ /* 0 <= sr <= n_uword_bits - 2 or sr large */
+ if (sr > n_uword_bits - 2)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_uword_bits - 1 */
+ /* q.all = n.all << (n_udword_bits - sr); */
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ /* r.all = n.all >> sr; */
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ else /* d.s.low != 0 */
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 K
+ */
+ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ *rem = n.s.low & (d.s.low - 1);
+ if (d.s.low == 1)
+ return n.all;
+ sr = __builtin_ctz(d.s.low);
+ q.s.high = n.s.high >> sr;
+ q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ return q.all;
+ }
+ /* K X
+ * ---
+ * 0 K
+ */
+ sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
+ /* 2 <= sr <= n_udword_bits - 1
+ * q.all = n.all << (n_udword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_uword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = n.s.low << (n_udword_bits - sr);
+ q.s.high = (n.s.high << (n_udword_bits - sr)) |
+ (n.s.low >> (sr - n_uword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_uword_bits);
+ }
+ }
+ else
+ {
+ /* K X
+ * ---
+ * K K
+ */
+ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+ /* 0 <= sr <= n_uword_bits - 1 or sr large */
+ if (sr > n_uword_bits - 1)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_uword_bits */
+ /* q.all = n.all << (n_udword_bits - sr); */
+ q.s.low = 0;
+ if (sr == n_uword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ }
+ }
+ /* Not a special case
+ * q and r are initialized with:
+ * q.all = n.all << (n_udword_bits - sr);
+ * r.all = n.all >> sr;
+ * 1 <= sr <= n_udword_bits - 1
+ */
+ su_int carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
+ r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
+ q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
+ q.s.low = (q.s.low << 1) | carry;
+ /* carry = 0;
+ * if (r.all >= d.all)
+ * {
+ * r.all -= d.all;
+ * carry = 1;
+ * }
+ */
+ const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
+ carry = s & 1;
+ r.all -= d.all & s;
+ }
+ q.all = (q.all << 1) | carry;
+ if (rem)
+ *rem = r.all;
+ return q.all;
+}
diff --git a/compiler-rt/lib/builtins/udivmodsi4.c b/compiler-rt/lib/builtins/udivmodsi4.c
new file mode 100644
index 0000000..789c4b5
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivmodsi4.c
@@ -0,0 +1,27 @@
+/*===-- udivmodsi4.c - Implement __udivmodsi4 ------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivmodsi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI su_int
+__udivmodsi4(su_int a, su_int b, su_int* rem)
+{
+ si_int d = __udivsi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
+
+
diff --git a/compiler-rt/lib/builtins/udivmodti4.c b/compiler-rt/lib/builtins/udivmodti4.c
new file mode 100644
index 0000000..8031688
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivmodti4.c
@@ -0,0 +1,238 @@
+/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivmodti4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Effects: if rem != 0, *rem = a % b
+ * Returns: a / b
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+COMPILER_RT_ABI tu_int
+__udivmodti4(tu_int a, tu_int b, tu_int* rem)
+{
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
+ utwords n;
+ n.all = a;
+ utwords d;
+ d.all = b;
+ utwords q;
+ utwords r;
+ unsigned sr;
+ /* special cases, X is unknown, K != 0 */
+ if (n.s.high == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* 0 X
+ * ---
+ * 0 X
+ */
+ if (rem)
+ *rem = n.s.low % d.s.low;
+ return n.s.low / d.s.low;
+ }
+ /* 0 X
+ * ---
+ * K X
+ */
+ if (rem)
+ *rem = n.s.low;
+ return 0;
+ }
+ /* n.s.high != 0 */
+ if (d.s.low == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 0
+ */
+ if (rem)
+ *rem = n.s.high % d.s.low;
+ return n.s.high / d.s.low;
+ }
+ /* d.s.high != 0 */
+ if (n.s.low == 0)
+ {
+ /* K 0
+ * ---
+ * K 0
+ */
+ if (rem)
+ {
+ r.s.high = n.s.high % d.s.high;
+ r.s.low = 0;
+ *rem = r.all;
+ }
+ return n.s.high / d.s.high;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ {
+ r.s.low = n.s.low;
+ r.s.high = n.s.high & (d.s.high - 1);
+ *rem = r.all;
+ }
+ return n.s.high >> __builtin_ctzll(d.s.high);
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+ /* 0 <= sr <= n_udword_bits - 2 or sr large */
+ if (sr > n_udword_bits - 2)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits - 1 */
+ /* q.all = n.all << (n_utword_bits - sr); */
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ /* r.all = n.all >> sr; */
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ }
+ else /* d.s.low != 0 */
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 K
+ */
+ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ *rem = n.s.low & (d.s.low - 1);
+ if (d.s.low == 1)
+ return n.all;
+ sr = __builtin_ctzll(d.s.low);
+ q.s.high = n.s.high >> sr;
+ q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ return q.all;
+ }
+ /* K X
+ * ---
+ * 0 K
+ */
+ sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
+ - __builtin_clzll(n.s.high);
+ /* 2 <= sr <= n_utword_bits - 1
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_udword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+ {
+ q.s.low = n.s.low << (n_utword_bits - sr);
+ q.s.high = (n.s.high << (n_utword_bits - sr)) |
+ (n.s.low >> (sr - n_udword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_udword_bits);
+ }
+ }
+ else
+ {
+ /* K X
+ * ---
+ * K K
+ */
+ sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+ /*0 <= sr <= n_udword_bits - 1 or sr large */
+ if (sr > n_udword_bits - 1)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ q.s.low = 0;
+ if (sr == n_udword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ }
+ }
+ }
+ /* Not a special case
+ * q and r are initialized with:
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ * 1 <= sr <= n_utword_bits - 1
+ */
+ su_int carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
+ r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
+ q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
+ q.s.low = (q.s.low << 1) | carry;
+ /* carry = 0;
+ * if (r.all >= d.all)
+ * {
+ * r.all -= d.all;
+ * carry = 1;
+ * }
+ */
+ const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
+ carry = s & 1;
+ r.all -= d.all & s;
+ }
+ q.all = (q.all << 1) | carry;
+ if (rem)
+ *rem = r.all;
+ return q.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/udivsi3.c b/compiler-rt/lib/builtins/udivsi3.c
new file mode 100644
index 0000000..5d0140c
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivsi3.c
@@ -0,0 +1,66 @@
+/* ===-- udivsi3.c - Implement __udivsi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+ARM_EABI_FNALIAS(uidiv, udivsi3)
+
+/* This function should not call __divsi3! */
+COMPILER_RT_ABI su_int
+__udivsi3(su_int n, su_int d)
+{
+ const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
+ su_int q;
+ su_int r;
+ unsigned sr;
+ /* special cases */
+ if (d == 0)
+ return 0; /* ?! */
+ if (n == 0)
+ return 0;
+ sr = __builtin_clz(d) - __builtin_clz(n);
+ /* 0 <= sr <= n_uword_bits - 1 or sr large */
+ if (sr > n_uword_bits - 1) /* d > r */
+ return 0;
+ if (sr == n_uword_bits - 1) /* d == 1 */
+ return n;
+ ++sr;
+ /* 1 <= sr <= n_uword_bits - 1 */
+ /* Not a special case */
+ q = n << (n_uword_bits - sr);
+ r = n >> sr;
+ su_int carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r = (r << 1) | (q >> (n_uword_bits - 1));
+ q = (q << 1) | carry;
+ /* carry = 0;
+ * if (r.all >= d.all)
+ * {
+ * r.all -= d.all;
+ * carry = 1;
+ * }
+ */
+ const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1);
+ carry = s & 1;
+ r -= d & s;
+ }
+ q = (q << 1) | carry;
+ return q;
+}
diff --git a/compiler-rt/lib/builtins/udivti3.c b/compiler-rt/lib/builtins/udivti3.c
new file mode 100644
index 0000000..ec94673
--- /dev/null
+++ b/compiler-rt/lib/builtins/udivti3.c
@@ -0,0 +1,27 @@
+/* ===-- udivti3.c - Implement __udivti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI tu_int
+__udivti3(tu_int a, tu_int b)
+{
+ return __udivmodti4(a, b, 0);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/umoddi3.c b/compiler-rt/lib/builtins/umoddi3.c
new file mode 100644
index 0000000..d513f08
--- /dev/null
+++ b/compiler-rt/lib/builtins/umoddi3.c
@@ -0,0 +1,25 @@
+/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __umoddi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI du_int
+__umoddi3(du_int a, du_int b)
+{
+ du_int r;
+ __udivmoddi4(a, b, &r);
+ return r;
+}
diff --git a/compiler-rt/lib/builtins/umodsi3.c b/compiler-rt/lib/builtins/umodsi3.c
new file mode 100644
index 0000000..d5fda4a
--- /dev/null
+++ b/compiler-rt/lib/builtins/umodsi3.c
@@ -0,0 +1,23 @@
+/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __umodsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI su_int
+__umodsi3(su_int a, su_int b)
+{
+ return a - __udivsi3(a, b) * b;
+}
diff --git a/compiler-rt/lib/builtins/umodti3.c b/compiler-rt/lib/builtins/umodti3.c
new file mode 100644
index 0000000..6d1ca7a
--- /dev/null
+++ b/compiler-rt/lib/builtins/umodti3.c
@@ -0,0 +1,29 @@
+/* ===-- umodti3.c - Implement __umodti3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __umodti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI tu_int
+__umodti3(tu_int a, tu_int b)
+{
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/compiler-rt/lib/builtins/x86_64/Makefile.mk b/compiler-rt/lib/builtins/x86_64/Makefile.mk
new file mode 100644
index 0000000..83848dd
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/x86_64/Makefile.mk ----------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := x86_64 x86_64h
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/compiler-rt/lib/builtins/x86_64/chkstk.S b/compiler-rt/lib/builtins/x86_64/chkstk.S
new file mode 100644
index 0000000..4149ac6
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/chkstk.S
@@ -0,0 +1,39 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// _chkstk routine
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+// Notes from r227519
+// MSVC x64s __chkstk and cygmings ___chkstk_ms do not adjust %rsp
+// themselves. It also does not clobber %rax so we can reuse it when
+// adjusting %rsp.
+
+#ifdef __x86_64__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(___chkstk_ms)
+ push %rcx
+ push %rax
+ cmp $0x1000,%rax
+ lea 24(%rsp),%rcx
+ jb 1f
+2:
+ sub $0x1000,%rcx
+ test %rcx,(%rcx)
+ sub $0x1000,%rax
+ cmp $0x1000,%rax
+ ja 2b
+1:
+ sub %rax,%rcx
+ test %rcx,(%rcx)
+ pop %rax
+ pop %rcx
+ ret
+END_COMPILERRT_FUNCTION(___chkstk_ms)
+
+#endif // __x86_64__
diff --git a/compiler-rt/lib/builtins/x86_64/chkstk2.S b/compiler-rt/lib/builtins/x86_64/chkstk2.S
new file mode 100644
index 0000000..ac1eb92
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/chkstk2.S
@@ -0,0 +1,42 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+#ifdef __x86_64__
+
+// _chkstk (_alloca) routine - probe stack between %rsp and (%rsp-%rax) in 4k increments,
+// then decrement %rsp by %rax. Preserves all registers except %rsp and flags.
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__alloca)
+ mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx
+ // fallthrough
+DEFINE_COMPILERRT_FUNCTION(___chkstk)
+ push %rcx
+ cmp $0x1000,%rax
+ lea 16(%rsp),%rcx // rsp before calling this routine -> rcx
+ jb 1f
+2:
+ sub $0x1000,%rcx
+ test %rcx,(%rcx)
+ sub $0x1000,%rax
+ cmp $0x1000,%rax
+ ja 2b
+1:
+ sub %rax,%rcx
+ test %rcx,(%rcx)
+
+ lea 8(%rsp),%rax // load pointer to the return address into rax
+ mov %rcx,%rsp // install the new top of stack pointer into rsp
+ mov -8(%rax),%rcx // restore rcx
+ push (%rax) // push return address onto the stack
+ sub %rsp,%rax // restore the original value in rax
+ ret
+END_COMPILERRT_FUNCTION(___chkstk)
+END_COMPILERRT_FUNCTION(__alloca)
+
+#endif // __x86_64__
diff --git a/compiler-rt/lib/builtins/x86_64/floatdidf.c b/compiler-rt/lib/builtins/x86_64/floatdidf.c
new file mode 100644
index 0000000..388404e
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatdidf.c
@@ -0,0 +1,16 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* double __floatdidf(di_int a); */
+
+#ifdef __x86_64__
+
+#include "../int_lib.h"
+
+double __floatdidf(int64_t a)
+{
+ return (double)a;
+}
+
+#endif /* __x86_64__ */
diff --git a/compiler-rt/lib/builtins/x86_64/floatdisf.c b/compiler-rt/lib/builtins/x86_64/floatdisf.c
new file mode 100644
index 0000000..96c3728
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatdisf.c
@@ -0,0 +1,14 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+#ifdef __x86_64__
+
+#include "../int_lib.h"
+
+float __floatdisf(int64_t a)
+{
+ return (float)a;
+}
+
+#endif /* __x86_64__ */
diff --git a/compiler-rt/lib/builtins/x86_64/floatdixf.c b/compiler-rt/lib/builtins/x86_64/floatdixf.c
new file mode 100644
index 0000000..c01193a
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatdixf.c
@@ -0,0 +1,16 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __floatdixf(di_int a); */
+
+#ifdef __x86_64__
+
+#include "../int_lib.h"
+
+long double __floatdixf(int64_t a)
+{
+ return (long double)a;
+}
+
+#endif /* __i386__ */
diff --git a/compiler-rt/lib/builtins/x86_64/floatundidf.S b/compiler-rt/lib/builtins/x86_64/floatundidf.S
new file mode 100644
index 0000000..3cd5d02
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatundidf.S
@@ -0,0 +1,49 @@
+//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatundidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52:
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundidf)
+ movd %edi, %xmm0 // low 32 bits of a
+ shrq $32, %rdi // high 32 bits of a
+ orq REL_ADDR(twop84), %rdi // 0x1p84 + a_hi (no rounding occurs)
+ orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ movd %rdi, %xmm1
+ subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ ret
+END_COMPILERRT_FUNCTION(__floatundidf)
+
+#endif // __x86_64__
diff --git a/compiler-rt/lib/builtins/x86_64/floatundisf.S b/compiler-rt/lib/builtins/x86_64/floatundisf.S
new file mode 100644
index 0000000..61952f4
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatundisf.S
@@ -0,0 +1,35 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatundisf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+two:
+ .single 2.0
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movq $1, %rsi
+ testq %rdi, %rdi
+ js 1f
+ cvtsi2ssq %rdi, %xmm0
+ ret
+
+1: andq %rdi, %rsi
+ shrq %rdi
+ orq %rsi, %rdi
+ cvtsi2ssq %rdi, %xmm0
+ mulss REL_ADDR(two), %xmm0
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __x86_64__
diff --git a/compiler-rt/lib/builtins/x86_64/floatundixf.S b/compiler-rt/lib/builtins/x86_64/floatundixf.S
new file mode 100644
index 0000000..92961c8
--- /dev/null
+++ b/compiler-rt/lib/builtins/x86_64/floatundixf.S
@@ -0,0 +1,68 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// long double __floatundixf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+twop64:
+ .quad 0x43f0000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+ .text
+
+ .balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ movq %rdi, -8(%rsp)
+ fildq -8(%rsp)
+ test %rdi, %rdi
+ js 1f
+ ret
+1: faddl REL_ADDR(twop64)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __x86_64__
+
+
+/* Branch-free implementation is ever so slightly slower, but more beautiful.
+ It is likely superior for inlining, so I kept it around for future reference.
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 4
+twop52:
+ .quad 0x4330000000000000
+twop84_plus_twop52_neg:
+ .quad 0xc530000000100000
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ movl %edi, %esi // low 32 bits of input
+ shrq $32, %rdi // hi 32 bits of input
+ orq REL_ADDR(twop84), %rdi // 2^84 + hi (as a double)
+ orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double)
+ movq %rdi, -8(%rsp)
+ movq %rsi, -16(%rsp)
+ fldl REL_ADDR(twop84_plus_twop52_neg)
+ faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs)
+ faddl -16(%rsp) // hi + lo (as double extended)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __x86_64__
+
+*/
diff --git a/compiler-rt/lib/cfi/CMakeLists.txt b/compiler-rt/lib/cfi/CMakeLists.txt
new file mode 100644
index 0000000..24e5181
--- /dev/null
+++ b/compiler-rt/lib/cfi/CMakeLists.txt
@@ -0,0 +1,40 @@
+add_custom_target(cfi)
+
+set(CFI_SOURCES cfi.cc)
+
+include_directories(..)
+
+set(CFI_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+)
+
+set(CFI_DIAG_CFLAGS
+ -DCFI_ENABLE_DIAG=1
+)
+
+foreach(arch ${CFI_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.cfi
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ CFLAGS ${CFI_CFLAGS}
+ PARENT_TARGET cfi)
+ add_compiler_rt_runtime(clang_rt.cfi_diag
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTUbsan
+ RTUbsan_cxx
+ CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}
+ PARENT_TARGET cfi)
+endforeach()
+
+add_compiler_rt_resource_file(cfi_blacklist cfi_blacklist.txt)
+add_dependencies(cfi cfi_blacklist)
+add_dependencies(compiler-rt cfi)
diff --git a/compiler-rt/lib/cfi/cfi.cc b/compiler-rt/lib/cfi/cfi.cc
new file mode 100644
index 0000000..e6249e6
--- /dev/null
+++ b/compiler-rt/lib/cfi/cfi.cc
@@ -0,0 +1,271 @@
+//===-------- cfi.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the runtime support for the cross-DSO CFI.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Intercept dlopen/dlclose.
+// FIXME: Support diagnostic mode.
+// FIXME: Harden:
+// * mprotect shadow, use mremap for updates
+// * something else equally important
+
+#include <assert.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+
+typedef ElfW(Phdr) Elf_Phdr;
+typedef ElfW(Ehdr) Elf_Ehdr;
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "ubsan/ubsan_init.h"
+#include "ubsan/ubsan_flags.h"
+
+static uptr __cfi_shadow;
+static constexpr uptr kShadowGranularity = 12;
+static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
+
+static constexpr uint16_t kInvalidShadow = 0;
+static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
+
+static uint16_t *mem_to_shadow(uptr x) {
+ return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1));
+}
+
+typedef int (*CFICheckFn)(uptr, void *);
+
+class ShadowValue {
+ uptr addr;
+ uint16_t v;
+ explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
+
+public:
+ bool is_invalid() const { return v == kInvalidShadow; }
+
+ bool is_unchecked() const { return v == kUncheckedShadow; }
+
+ CFICheckFn get_cfi_check() const {
+ assert(!is_invalid() && !is_unchecked());
+ uptr aligned_addr = addr & ~(kShadowAlign - 1);
+ uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
+ return reinterpret_cast<CFICheckFn>(p);
+ }
+
+ // Load a shadow valud for the given application memory address.
+ static const ShadowValue load(uptr addr) {
+ return ShadowValue(addr, *mem_to_shadow(addr));
+ }
+};
+
+static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) {
+ assert(v == kInvalidShadow || v == kUncheckedShadow);
+ uint16_t *shadow_begin = mem_to_shadow(begin);
+ uint16_t *shadow_end = mem_to_shadow(end - 1) + 1;
+ memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin));
+}
+
+static void fill_shadow(uptr begin, uptr end, uptr cfi_check) {
+ assert((cfi_check & (kShadowAlign - 1)) == 0);
+
+ // Don't fill anything below cfi_check. We can not represent those addresses
+ // in the shadow, and must make sure at codegen to place all valid call
+ // targets above cfi_check.
+ uptr p = Max(begin, cfi_check);
+ uint16_t *s = mem_to_shadow(p);
+ uint16_t *s_end = mem_to_shadow(end - 1) + 1;
+ uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1;
+ for (; s < s_end; s++, sv++)
+ *s = sv;
+
+ // Sanity checks.
+ uptr q = p & ~(kShadowAlign - 1);
+ for (; q < end; q += kShadowAlign) {
+ assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check);
+ assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() ==
+ cfi_check);
+ assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() ==
+ cfi_check);
+ }
+}
+
+// This is a workaround for a glibc bug:
+// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
+// Other platforms can, hopefully, just do
+// dlopen(RTLD_NOLOAD | RTLD_LAZY)
+// dlsym("__cfi_check").
+static uptr find_cfi_check_in_dso(dl_phdr_info *info) {
+ const ElfW(Dyn) *dynamic = nullptr;
+ for (int i = 0; i < info->dlpi_phnum; ++i) {
+ if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
+ dynamic =
+ (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+ break;
+ }
+ }
+ if (!dynamic) return 0;
+ uptr strtab = 0, symtab = 0;
+ for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
+ if (p->d_tag == DT_SYMTAB)
+ symtab = p->d_un.d_ptr;
+ else if (p->d_tag == DT_STRTAB)
+ strtab = p->d_un.d_ptr;
+ }
+
+ if (symtab > strtab) {
+ VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab);
+ return 0;
+ }
+
+ // Verify that strtab and symtab are inside of the same LOAD segment.
+ // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
+ int phdr_idx;
+ for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
+ if (phdr->p_type == PT_LOAD) {
+ uptr beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr end = beg + phdr->p_memsz;
+ if (strtab >= beg && strtab < end && symtab >= beg && symtab < end)
+ break;
+ }
+ }
+ if (phdr_idx == info->dlpi_phnum) {
+ // Nope, either different segments or just bogus pointers.
+ // Can not handle this.
+ VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab);
+ return 0;
+ }
+
+ for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
+ ++p) {
+ char *name = (char*)(strtab + p->st_name);
+ if (strcmp(name, "__cfi_check") == 0) {
+ assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC));
+ uptr addr = info->dlpi_addr + p->st_value;
+ return addr;
+ }
+ }
+ return 0;
+}
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
+ uptr cfi_check = find_cfi_check_in_dso(info);
+ if (cfi_check)
+ VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);
+
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ // Jump tables are in the executable segment.
+ // VTables are in the non-executable one.
+ // Need to fill shadow for both.
+ // FIXME: reject writable if vtables are in the r/o segment. Depend on
+ // PT_RELRO?
+ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr cur_end = cur_beg + phdr->p_memsz;
+ if (cfi_check) {
+ VReport(1, " %zx .. %zx\n", cur_beg, cur_end);
+ fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1));
+ } else {
+ fill_shadow_constant(cur_beg, cur_end, kInvalidShadow);
+ }
+ }
+ }
+ return 0;
+}
+
+// Fill shadow for the initial libraries.
+static void init_shadow() {
+ dl_iterate_phdr(dl_iterate_phdr_cb, nullptr);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __cfi_slowpath(uptr CallSiteTypeId, void *Ptr) {
+ uptr Addr = (uptr)Ptr;
+ VReport(3, "__cfi_slowpath: %zx, %p\n", CallSiteTypeId, Ptr);
+ ShadowValue sv = ShadowValue::load(Addr);
+ if (sv.is_invalid()) {
+ VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr);
+ Die();
+ }
+ if (sv.is_unchecked()) {
+ VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
+ return;
+ }
+ CFICheckFn cfi_check = sv.get_cfi_check();
+ VReport(2, "__cfi_check at %p\n", cfi_check);
+ cfi_check(CallSiteTypeId, Ptr);
+}
+
+static void InitializeFlags() {
+ SetCommonFlagsDefaults();
+#ifdef CFI_ENABLE_DIAG
+ __ubsan::Flags *uf = __ubsan::flags();
+ uf->SetDefaults();
+#endif
+
+ FlagParser cfi_parser;
+ RegisterCommonFlags(&cfi_parser);
+ cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
+
+#ifdef CFI_ENABLE_DIAG
+ FlagParser ubsan_parser;
+ __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+ RegisterCommonFlags(&ubsan_parser);
+
+ const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+ ubsan_parser.ParseString(ubsan_default_options);
+ ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) {
+ cfi_parser.PrintFlagDescriptions();
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, the constructor is invoked using .preinit_array (see below)
+__attribute__((constructor(0)))
+#endif
+void __cfi_init() {
+ SanitizerToolName = "CFI";
+ InitializeFlags();
+
+ uptr vma = GetMaxVirtualAddress();
+ // Shadow is 2 -> 2**kShadowGranularity.
+ uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1;
+ VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size);
+ void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow");
+ VReport(1, "CFI: shadow at %zx .. %zx\n", shadow,
+ reinterpret_cast<uptr>(shadow) + shadow_size);
+ __cfi_shadow = (uptr)shadow;
+ init_shadow();
+
+#ifdef CFI_ENABLE_DIAG
+ __ubsan::InitAsPlugin();
+#endif
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, run cfi initialization before any other constructors.
+// On other platforms we use the constructor attribute to arrange to run our
+// initialization early.
+extern "C" {
+__attribute__((section(".preinit_array"),
+ used)) void (*__cfi_preinit)(void) = __cfi_init;
+}
+#endif
diff --git a/compiler-rt/lib/cfi/cfi_blacklist.txt b/compiler-rt/lib/cfi/cfi_blacklist.txt
new file mode 100644
index 0000000..1f0eeb3
--- /dev/null
+++ b/compiler-rt/lib/cfi/cfi_blacklist.txt
@@ -0,0 +1,26 @@
+# Standard library types.
+type:std::*
+
+# The stdext namespace contains Microsoft standard library extensions.
+type:stdext::*
+
+# Types with a uuid attribute, i.e. COM types.
+type:attr:uuid
+
+# STL allocators (T *allocator<T *>::allocate(size_type, const void*)).
+# The type signature mandates a cast from uninitialized void* to T*.
+# size_type can either be unsigned int (j) or unsigned long (m).
+fun:*8allocateEjPKv
+fun:*8allocateEmPKv
+
+# std::get_temporary_buffer, likewise (libstdc++, libc++).
+fun:_ZSt20get_temporary_buffer*
+fun:_ZNSt3__120get_temporary_buffer*
+
+# STL address-of magic (libstdc++, libc++).
+fun:*__addressof*
+fun:_ZNSt3__19addressof*
+
+# Windows C++ stdlib headers that contain bad unrelated casts.
+src:*xmemory0
+src:*xstddef
diff --git a/compiler-rt/lib/dfsan/.clang-format b/compiler-rt/lib/dfsan/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/dfsan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/dfsan/CMakeLists.txt b/compiler-rt/lib/dfsan/CMakeLists.txt
new file mode 100644
index 0000000..19a7909
--- /dev/null
+++ b/compiler-rt/lib/dfsan/CMakeLists.txt
@@ -0,0 +1,48 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+set(DFSAN_RTL_SOURCES
+ dfsan.cc
+ dfsan_custom.cc
+ dfsan_interceptors.cc)
+set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(DFSAN_COMMON_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
+
+# Static runtime library.
+add_custom_target(dfsan)
+foreach(arch ${DFSAN_SUPPORTED_ARCH})
+ set(DFSAN_CFLAGS ${DFSAN_COMMON_CFLAGS})
+ append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS)
+ add_compiler_rt_runtime(clang_rt.dfsan
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${DFSAN_RTL_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ CFLAGS ${DFSAN_CFLAGS}
+ PARENT_TARGET dfsan)
+ add_sanitizer_rt_symbols(clang_rt.dfsan
+ ARCHS ${arch}
+ EXTRA dfsan.syms.extra)
+ add_dependencies(dfsan
+ clang_rt.dfsan-${arch}-symbols)
+endforeach()
+
+set(dfsan_abilist_filename ${COMPILER_RT_OUTPUT_DIR}/dfsan_abilist.txt)
+add_custom_target(dfsan_abilist ALL
+ DEPENDS ${dfsan_abilist_filename})
+add_custom_command(OUTPUT ${dfsan_abilist_filename}
+ VERBATIM
+ COMMAND
+ cat ${CMAKE_CURRENT_SOURCE_DIR}/done_abilist.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1404_abilist.txt
+ > ${dfsan_abilist_filename}
+ DEPENDS done_abilist.txt libc_ubuntu1404_abilist.txt)
+add_dependencies(dfsan dfsan_abilist)
+install(FILES ${dfsan_abilist_filename}
+ DESTINATION ${COMPILER_RT_INSTALL_PATH})
+
+add_dependencies(compiler-rt dfsan)
diff --git a/compiler-rt/lib/dfsan/dfsan.cc b/compiler-rt/lib/dfsan/dfsan.cc
new file mode 100644
index 0000000..7285f20
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan.cc
@@ -0,0 +1,429 @@
+//===-- dfsan.cc ----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// DataFlowSanitizer runtime. This file defines the public interface to
+// DataFlowSanitizer as well as the definition of certain runtime functions
+// called automatically by the compiler (specifically the instrumentation pass
+// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
+//
+// The public interface is defined in include/sanitizer/dfsan_interface.h whose
+// functions are prefixed dfsan_ while the compiler interface functions are
+// prefixed __dfsan_.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#include "dfsan/dfsan.h"
+
+using namespace __dfsan;
+
+typedef atomic_uint16_t atomic_dfsan_label;
+static const dfsan_label kInitializingLabel = -1;
+
+static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8);
+
+static atomic_dfsan_label __dfsan_last_label;
+static dfsan_label_info __dfsan_label_info[kNumLabels];
+
+Flags __dfsan::flags_data;
+
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
+
+SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask;
+
+// On Linux/x86_64, memory is laid out as follows:
+//
+// +--------------------+ 0x800000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x700000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x200200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x200000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x000000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x000000000000
+//
+// To derive a shadow memory address from an application memory address,
+// bits 44-46 are cleared to bring the address into the range
+// [0x000000008000,0x100000000000). Then the address is shifted left by 1 to
+// account for the double byte representation of shadow labels and move the
+// address into the shadow memory range. See the function shadow_for below.
+
+// On Linux/MIPS64, memory is laid out as follows:
+//
+// +--------------------+ 0x10000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0xF000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x2200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x2000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
+// On Linux/AArch64 (39-bit VMA), memory is laid out as follow:
+//
+// +--------------------+ 0x8000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x7000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x1200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x1000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
+// On Linux/AArch64 (42-bit VMA), memory is laid out as follow:
+//
+// +--------------------+ 0x40000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x3ff00008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x1200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x8000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
+typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];
+
+#ifdef DFSAN_RUNTIME_VMA
+// Runtime detected VMA size.
+int __dfsan::vmaSize;
+#endif
+
+static uptr UnusedAddr() {
+ return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>()
+ + sizeof(dfsan_union_table_t);
+}
+
+static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
+ return &(*(dfsan_union_table_t *) UnionTableAddr())[l1][l2];
+}
+
+// Checks we do not run out of labels.
+static void dfsan_check_label(dfsan_label label) {
+ if (label == kInitializingLabel) {
+ Report("FATAL: DataFlowSanitizer: out of labels\n");
+ Die();
+ }
+}
+
+// Resolves the union of two unequal labels. Nonequality is a precondition for
+// this function (the instrumentation pass inlines the equality test).
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
+ DCHECK_NE(l1, l2);
+
+ if (l1 == 0)
+ return l2;
+ if (l2 == 0)
+ return l1;
+
+ if (l1 > l2)
+ Swap(l1, l2);
+
+ atomic_dfsan_label *table_ent = union_table(l1, l2);
+ // We need to deal with the case where two threads concurrently request
+ // a union of the same pair of labels. If the table entry is uninitialized,
+ // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel
+ // (i.e. -1) to mark that we are initializing it.
+ dfsan_label label = 0;
+ if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel,
+ memory_order_acquire)) {
+ // Check whether l2 subsumes l1. We don't need to check whether l1
+ // subsumes l2 because we are guaranteed here that l1 < l2, and (at least
+ // in the cases we are interested in) a label may only subsume labels
+ // created earlier (i.e. with a lower numerical value).
+ if (__dfsan_label_info[l2].l1 == l1 ||
+ __dfsan_label_info[l2].l2 == l1) {
+ label = l2;
+ } else {
+ label =
+ atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
+ dfsan_check_label(label);
+ __dfsan_label_info[label].l1 = l1;
+ __dfsan_label_info[label].l2 = l2;
+ }
+ atomic_store(table_ent, label, memory_order_release);
+ } else if (label == kInitializingLabel) {
+ // Another thread is initializing the entry. Wait until it is finished.
+ do {
+ internal_sched_yield();
+ label = atomic_load(table_ent, memory_order_acquire);
+ } while (label == kInitializingLabel);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
+ dfsan_label label = ls[0];
+ for (uptr i = 1; i != n; ++i) {
+ dfsan_label next_label = ls[i];
+ if (label != next_label)
+ label = __dfsan_union(label, next_label);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __dfsan_unimplemented(char *fname) {
+ if (flags().warn_unimplemented)
+ Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
+ fname);
+}
+
+// Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
+// to try to figure out where labels are being introduced in a nominally
+// label-free program.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
+ if (flags().warn_nonzero_labels)
+ Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
+}
+
+// Indirect call to an uninstrumented vararg function. We don't have a way of
+// handling these at the moment.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsan_vararg_wrapper(const char *fname) {
+ Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
+ "function %s\n", fname);
+ Die();
+}
+
+// Like __dfsan_union, but for use from the client or custom functions. Hence
+// the equality comparison is done here before calling __dfsan_union.
+SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_union(dfsan_label l1, dfsan_label l2) {
+ if (l1 == l2)
+ return l1;
+ return __dfsan_union(l1, l2);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label dfsan_create_label(const char *desc, void *userdata) {
+ dfsan_label label =
+ atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
+ dfsan_check_label(label);
+ __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
+ __dfsan_label_info[label].desc = desc;
+ __dfsan_label_info[label].userdata = userdata;
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __dfsan_set_label(dfsan_label label, void *addr, uptr size) {
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) {
+ // Don't write the label if it is already the value we need it to be.
+ // In a program where most addresses are not labeled, it is common that
+ // a page of shadow memory is entirely zeroed. The Linux copy-on-write
+ // implementation will share all of the zeroed pages, making a copy of a
+ // page when any value is written. The un-sharing will happen even if
+ // the value written does not change the value in memory. Avoiding the
+ // write when both |label| and |*labelp| are zero dramatically reduces
+ // the amount of real memory used by large programs.
+ if (label == *labelp)
+ continue;
+
+ *labelp = label;
+ }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
+ __dfsan_set_label(label, addr, size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+ if (*labelp != label)
+ *labelp = __dfsan_union(*labelp, label);
+}
+
+// Unlike the other dfsan interface functions the behavior of this function
+// depends on the label of one of its arguments. Hence it is implemented as a
+// custom function.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+__dfsw_dfsan_get_label(long data, dfsan_label data_label,
+ dfsan_label *ret_label) {
+ *ret_label = 0;
+ return data_label;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_read_label(const void *addr, uptr size) {
+ if (size == 0)
+ return 0;
+ return __dfsan_union_load(shadow_for(addr), size);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
+ return &__dfsan_label_info[label];
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
+dfsan_has_label(dfsan_label label, dfsan_label elem) {
+ if (label == elem)
+ return true;
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem);
+ } else {
+ return false;
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label_with_desc(info->l1, desc) ||
+ dfsan_has_label_with_desc(info->l2, desc);
+ } else {
+ return internal_strcmp(desc, info->desc) == 0;
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
+dfsan_get_label_count(void) {
+ dfsan_label max_label_allocated =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ return static_cast<uptr>(max_label_allocated);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+dfsan_dump_labels(int fd) {
+ dfsan_label last_label =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ for (uptr l = 1; l <= last_label; ++l) {
+ char buf[64];
+ internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
+ __dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
+ WriteToFile(fd, buf, internal_strlen(buf));
+ if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
+ WriteToFile(fd, __dfsan_label_info[l].desc,
+ internal_strlen(__dfsan_label_info[l].desc));
+ }
+ WriteToFile(fd, "\n", 1);
+ }
+}
+
+void Flags::SetDefaults() {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+}
+
+static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+}
+
+static void InitializeFlags() {
+ SetCommonFlagsDefaults();
+ flags().SetDefaults();
+
+ FlagParser parser;
+ RegisterCommonFlags(&parser);
+ RegisterDfsanFlags(&parser, &flags());
+ parser.ParseString(GetEnv("DFSAN_OPTIONS"));
+ SetVerbosity(common_flags()->verbosity);
+ if (Verbosity()) ReportUnrecognizedFlags();
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+}
+
+static void InitializePlatformEarly() {
+#ifdef DFSAN_RUNTIME_VMA
+ __dfsan::vmaSize =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+ if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42) {
+ __dfsan_shadow_ptr_mask = ShadowMask();
+ } else {
+ Printf("FATAL: DataFlowSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 39 and 42\n", __dfsan::vmaSize);
+ Die();
+ }
+#endif
+}
+
+static void dfsan_fini() {
+ if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
+ fd_t fd = OpenFile(flags().dump_labels_at_exit, WrOnly);
+ if (fd == kInvalidFd) {
+ Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
+ flags().dump_labels_at_exit);
+ return;
+ }
+
+ Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
+ flags().dump_labels_at_exit);
+ dfsan_dump_labels(fd);
+ CloseFile(fd);
+ }
+}
+
+static void dfsan_init(int argc, char **argv, char **envp) {
+ InitializeFlags();
+
+ InitializePlatformEarly();
+
+ MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr());
+
+ // Protect the region of memory we don't use, to preserve the one-to-one
+ // mapping from application to shadow memory. But if ASLR is disabled, Linux
+ // will load our executable in the middle of our unused region. This mostly
+ // works so long as the program doesn't use too much memory. We support this
+ // case by disabling memory protection when ASLR is disabled.
+ uptr init_addr = (uptr)&dfsan_init;
+ if (!(init_addr >= UnusedAddr() && init_addr < AppAddr()))
+ MmapNoAccess(UnusedAddr(), AppAddr() - UnusedAddr());
+
+ InitializeInterceptors();
+
+ // Register the fini callback to run when the program terminates successfully
+ // or it is killed by the runtime.
+ Atexit(dfsan_fini);
+ AddDieCallback(dfsan_fini);
+
+ __dfsan_label_info[kInitializingLabel].desc = "<init label>";
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
+#endif
diff --git a/compiler-rt/lib/dfsan/dfsan.h b/compiler-rt/lib/dfsan/dfsan.h
new file mode 100644
index 0000000..81f949e
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan.h
@@ -0,0 +1,70 @@
+//===-- dfsan.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Private DFSan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef DFSAN_H
+#define DFSAN_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "dfsan_platform.h"
+
+// Copy declarations from public sanitizer/dfsan_interface.h header here.
+typedef u16 dfsan_label;
+
+struct dfsan_label_info {
+ dfsan_label l1;
+ dfsan_label l2;
+ const char *desc;
+ void *userdata;
+};
+
+extern "C" {
+void dfsan_add_label(dfsan_label label, void *addr, uptr size);
+void dfsan_set_label(dfsan_label label, void *addr, uptr size);
+dfsan_label dfsan_read_label(const void *addr, uptr size);
+dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+namespace __dfsan {
+
+void InitializeInterceptors();
+
+inline dfsan_label *shadow_for(void *ptr) {
+ return (dfsan_label *) ((((uptr) ptr) & ShadowMask()) << 1);
+}
+
+inline const dfsan_label *shadow_for(const void *ptr) {
+ return shadow_for(const_cast<void *>(ptr));
+}
+
+struct Flags {
+#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "dfsan_flags.inc"
+#undef DFSAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags flags_data;
+inline Flags &flags() {
+ return flags_data;
+}
+
+} // namespace __dfsan
+
+#endif // DFSAN_H
diff --git a/compiler-rt/lib/dfsan/dfsan.syms.extra b/compiler-rt/lib/dfsan/dfsan.syms.extra
new file mode 100644
index 0000000..0d507ee
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan.syms.extra
@@ -0,0 +1,3 @@
+dfsan_*
+__dfsan_*
+__dfsw_*
diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cc b/compiler-rt/lib/dfsan/dfsan_custom.cc
new file mode 100644
index 0000000..e0cd16a
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan_custom.cc
@@ -0,0 +1,1135 @@
+//===-- dfsan.cc ----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// This file defines the custom functions listed in done_abilist.txt.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+
+#include "dfsan/dfsan.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+using namespace __dfsan;
+
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ do { \
+ if (f) \
+ f(__VA_ARGS__); \
+ } while (false)
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
+ dfsan_label buf_label, dfsan_label *ret_label) {
+ int ret = stat(path, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
+ dfsan_label fd_label,
+ dfsan_label buf_label,
+ dfsan_label *ret_label) {
+ int ret = fstat(fd, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label *ret_label) {
+ for (size_t i = 0;; ++i) {
+ if (s[i] == c || s[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = s_label;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
+ dfsan_union(s_label, c_label));
+ }
+ return s[i] == 0 ? nullptr : const_cast<char *>(s+i);
+ }
+ }
+}
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
+ const void *s1, const void *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label)
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
+ s1_label, s2_label, n_label);
+ const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
+ for (size_t i = 0; i != n; ++i) {
+ if (cs1[i] != cs2[i]) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
+ dfsan_read_label(cs2, i + 1));
+ }
+ return cs1[i] - cs2[i];
+ }
+ }
+
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, n),
+ dfsan_read_label(cs2, n));
+ }
+ return 0;
+}
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
+ const char *s1, const char *s2,
+ dfsan_label s1_label, dfsan_label s2_label)
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
+ dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label *ret_label) {
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
+ s1_label, s2_label);
+ for (size_t i = 0;; ++i) {
+ if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label *ret_label) {
+ for (size_t i = 0;; ++i) {
+ if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
+ const char *s1, const char *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label)
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
+ n, s1_label, s2_label, n_label);
+
+ for (size_t i = 0;; ++i) {
+ if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ for (size_t i = 0;; ++i) {
+ if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
+ i == n - 1) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
+ dfsan_label nmemb_label,
+ dfsan_label size_label,
+ dfsan_label *ret_label) {
+ void *p = calloc(nmemb, size);
+ dfsan_set_label(0, p, nmemb * size);
+ *ret_label = 0;
+ return p;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE size_t
+__dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
+ size_t ret = strlen(s);
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_read_label(s, ret + 1);
+ }
+ return ret;
+}
+
+
+static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
+ dfsan_label *sdest = shadow_for(dest);
+ const dfsan_label *ssrc = shadow_for(src);
+ internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
+ return internal_memcpy(dest, src, n);
+}
+
+static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
+ internal_memset(s, c, n);
+ dfsan_set_label(c_label, s, n);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__dfsw_memcpy(void *dest, const void *src, size_t n,
+ dfsan_label dest_label, dfsan_label src_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ *ret_label = dest_label;
+ return dfsan_memcpy(dest, src, n);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__dfsw_memset(void *s, int c, size_t n,
+ dfsan_label s_label, dfsan_label c_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ dfsan_memset(s, c, c_label, n);
+ *ret_label = s_label;
+ return s;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
+ size_t len = strlen(s);
+ void *p = malloc(len+1);
+ dfsan_memcpy(p, s, len+1);
+ *ret_label = 0;
+ return static_cast<char *>(p);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label,
+ dfsan_label *ret_label) {
+ size_t len = strlen(s2);
+ if (len < n) {
+ dfsan_memcpy(s1, s2, len+1);
+ dfsan_memset(s1+len+1, 0, 0, n-len-1);
+ } else {
+ dfsan_memcpy(s1, s2, n);
+ }
+
+ *ret_label = s1_label;
+ return s1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_pread(int fd, void *buf, size_t count, off_t offset,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label, dfsan_label offset_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = pread(fd, buf, count, offset);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_read(int fd, void *buf, size_t count,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = read(fd, buf, count);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
+ struct timespec *tp,
+ dfsan_label clk_id_label,
+ dfsan_label tp_label,
+ dfsan_label *ret_label) {
+ int ret = clock_gettime(clk_id, tp);
+ if (ret == 0)
+ dfsan_set_label(0, tp, sizeof(struct timespec));
+ *ret_label = 0;
+ return ret;
+}
+
+static void unpoison(const void *ptr, uptr size) {
+ dfsan_set_label(0, const_cast<void *>(ptr), size);
+}
+
+// dlopen() ultimately calls mmap() down inside the loader, which generally
+// doesn't participate in dynamic symbol resolution. Therefore we won't
+// intercept its calls to mmap, and we have to hook it here.
+SANITIZER_INTERFACE_ATTRIBUTE void *
+__dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
+ dfsan_label flag_label, dfsan_label *ret_label) {
+ void *handle = dlopen(filename, flag);
+ link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
+ if (map)
+ ForEachMappedRegion(map, unpoison);
+ *ret_label = 0;
+ return handle;
+}
+
+struct pthread_create_info {
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
+ void *start_routine;
+ void *arg;
+};
+
+static void *pthread_create_cb(void *p) {
+ pthread_create_info pci(*(pthread_create_info *)p);
+ free(p);
+ dfsan_label ret_label;
+ return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
+ &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
+ pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label,
+ dfsan_label *),
+ void *start_routine, void *arg, dfsan_label thread_label,
+ dfsan_label attr_label, dfsan_label start_routine_label,
+ dfsan_label arg_label, dfsan_label *ret_label) {
+ pthread_create_info *pci =
+ (pthread_create_info *)malloc(sizeof(pthread_create_info));
+ pci->start_routine_trampoline = start_routine_trampoline;
+ pci->start_routine = start_routine;
+ pci->arg = arg;
+ int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
+ if (rv != 0)
+ free(pci);
+ *ret_label = 0;
+ return rv;
+}
+
+struct dl_iterate_phdr_info {
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label);
+ void *callback;
+ void *data;
+};
+
+int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
+ dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
+ dfsan_set_label(0, *info);
+ dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
+ strlen(info->dlpi_name) + 1);
+ dfsan_set_label(
+ 0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
+ sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
+ dfsan_label ret_label;
+ return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
+ 0, &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label),
+ void *callback, void *data, dfsan_label callback_label,
+ dfsan_label data_label, dfsan_label *ret_label) {
+ dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
+ *ret_label = 0;
+ return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
+ dfsan_label buf_label, dfsan_label *ret_label) {
+ char *ret = ctime_r(timep, buf);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
+ strlen(buf) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
+ dfsan_label size_label, dfsan_label stream_label,
+ dfsan_label *ret_label) {
+ char *ret = fgets(s, size, stream);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = s_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
+ dfsan_label size_label, dfsan_label *ret_label) {
+ char *ret = getcwd(buf, size);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
+ char *ret = get_current_dir_name();
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
+ dfsan_label len_label, dfsan_label *ret_label) {
+ int ret = gethostname(name, len);
+ if (ret == 0) {
+ dfsan_set_label(0, name, strlen(name) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrlimit(int resource, struct rlimit *rlim,
+ dfsan_label resource_label, dfsan_label rlim_label,
+ dfsan_label *ret_label) {
+ int ret = getrlimit(resource, rlim);
+ if (ret == 0) {
+ dfsan_set_label(0, rlim, sizeof(struct rlimit));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
+ dfsan_label usage_label, dfsan_label *ret_label) {
+ int ret = getrusage(who, usage);
+ if (ret == 0) {
+ dfsan_set_label(0, usage, sizeof(struct rusage));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
+ dfsan_label src_label, dfsan_label *ret_label) {
+ char *ret = strcpy(dest, src);
+ if (ret) {
+ internal_memcpy(shadow_for(dest), shadow_for(src),
+ sizeof(dfsan_label) * (strlen(src) + 1));
+ }
+ *ret_label = dst_label;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long int __dfsw_strtol(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long int ret = strtol(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+double __dfsw_strtod(const char *nptr, char **endptr,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ double ret = strtod(nptr, &tmp_endptr);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_read_label(
+ nptr,
+ tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long int ret = strtoll(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
+ dfsan_label nptr_label,
+ int base, dfsan_label endptr_label,
+ dfsan_label base_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
+ time_t ret = time(t);
+ if (ret != (time_t) -1 && t) {
+ dfsan_set_label(0, t, sizeof(time_t));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
+ dfsan_label src_label, dfsan_label dst_label,
+ dfsan_label *ret_label) {
+ int ret = inet_pton(af, src, dst);
+ if (ret == 1) {
+ dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
+ af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
+ dfsan_label timep_label, dfsan_label result_label,
+ dfsan_label *ret_label) {
+ struct tm *ret = localtime_r(timep, result);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
+ sizeof(struct tm));
+ *ret_label = result_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
+ char *buf, size_t buflen, struct passwd **result,
+ dfsan_label uid_label, dfsan_label pwd_label,
+ dfsan_label buf_label, dfsan_label buflen_label,
+ dfsan_label result_label, dfsan_label *ret_label) {
+ // Store the data in pwd, the strings referenced from pwd in buf, and the
+ // address of pwd in *result. On failure, NULL is stored in *result.
+ int ret = getpwuid_r(uid, pwd, buf, buflen, result);
+ if (ret == 0) {
+ dfsan_set_label(0, pwd, sizeof(struct passwd));
+ dfsan_set_label(0, buf, strlen(buf) + 1);
+ }
+ *ret_label = 0;
+ dfsan_set_label(0, result, sizeof(struct passwd*));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
+ dfsan_label dfs_label, dfsan_label nfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = poll(fds, nfds, timeout);
+ if (ret >= 0) {
+ for (; nfds > 0; --nfds) {
+ dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
+ }
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout,
+ dfsan_label nfds_label, dfsan_label readfds_label,
+ dfsan_label writefds_label, dfsan_label exceptfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = select(nfds, readfds, writefds, exceptfds, timeout);
+ // Clear everything (also on error) since their content is either set or
+ // undefined.
+ if (readfds) {
+ dfsan_set_label(0, readfds, sizeof(fd_set));
+ }
+ if (writefds) {
+ dfsan_set_label(0, writefds, sizeof(fd_set));
+ }
+ if (exceptfds) {
+ dfsan_set_label(0, exceptfds, sizeof(fd_set));
+ }
+ dfsan_set_label(0, timeout, sizeof(struct timeval));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
+ dfsan_label pid_label,
+ dfsan_label cpusetsize_label,
+ dfsan_label mask_label, dfsan_label *ret_label) {
+ int ret = sched_getaffinity(pid, cpusetsize, mask);
+ if (ret == 0) {
+ dfsan_set_label(0, mask, cpusetsize);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
+ dfsan_label *ret_label) {
+ int ret = sigemptyset(set);
+ dfsan_set_label(0, set, sizeof(sigset_t));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact, dfsan_label signum_label,
+ dfsan_label act_label, dfsan_label oldact_label,
+ dfsan_label *ret_label) {
+ int ret = sigaction(signum, act, oldact);
+ if (oldact) {
+ dfsan_set_label(0, oldact, sizeof(struct sigaction));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
+ dfsan_label tv_label, dfsan_label tz_label,
+ dfsan_label *ret_label) {
+ int ret = gettimeofday(tv, tz);
+ if (tv) {
+ dfsan_set_label(0, tv, sizeof(struct timeval));
+ }
+ if (tz) {
+ dfsan_set_label(0, tz, sizeof(struct timezone));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ void *ret = memchr(s, c, n);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ size_t len =
+ ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
+ : n;
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label *ret_label) {
+ char *ret = strrchr(s, c);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, strlen(s) + 1),
+ dfsan_union(s_label, c_label));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
+ dfsan_label haystack_label,
+ dfsan_label needle_label,
+ dfsan_label *ret_label) {
+ char *ret = strstr(haystack, needle);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? haystack_label : 0;
+ } else {
+ size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
+ *ret_label =
+ dfsan_union(dfsan_read_label(haystack, len),
+ dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
+ dfsan_union(haystack_label, needle_label)));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
+ struct timespec *rem,
+ dfsan_label req_label,
+ dfsan_label rem_label,
+ dfsan_label *ret_label) {
+ int ret = nanosleep(req, rem);
+ *ret_label = 0;
+ if (ret == -1) {
+ // Interrupted by a signal, rem is filled with the remaining time.
+ dfsan_set_label(0, rem, sizeof(struct timespec));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_socketpair(int domain, int type, int protocol, int sv[2],
+ dfsan_label domain_label, dfsan_label type_label,
+ dfsan_label protocol_label, dfsan_label sv_label,
+ dfsan_label *ret_label) {
+ int ret = socketpair(domain, type, protocol, sv);
+ *ret_label = 0;
+ if (ret == 0) {
+ dfsan_set_label(0, sv, sizeof(*sv) * 2);
+ }
+ return ret;
+}
+
+// Type of the trampoline function passed to the custom version of
+// dfsan_set_write_callback.
+typedef void (*write_trampoline_t)(
+ void *callback,
+ int fd, const void *buf, ssize_t count,
+ dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
+
+// Calls to dfsan_set_write_callback() set the values in this struct.
+// Calls to the custom version of write() read (and invoke) them.
+static struct {
+ write_trampoline_t write_callback_trampoline = nullptr;
+ void *write_callback = nullptr;
+} write_callback_info;
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsw_dfsan_set_write_callback(
+ write_trampoline_t write_callback_trampoline,
+ void *write_callback,
+ dfsan_label write_callback_label,
+ dfsan_label *ret_label) {
+ write_callback_info.write_callback_trampoline = write_callback_trampoline;
+ write_callback_info.write_callback = write_callback;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_write(int fd, const void *buf, size_t count,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label, dfsan_label *ret_label) {
+ if (write_callback_info.write_callback) {
+ write_callback_info.write_callback_trampoline(
+ write_callback_info.write_callback,
+ fd, buf, count,
+ fd_label, buf_label, count_label);
+ }
+
+ *ret_label = 0;
+ return write(fd, buf, count);
+}
+} // namespace __dfsan
+
+// Type used to extract a dfsan_label with va_arg()
+typedef int dfsan_label_va;
+
+// Formats a chunk either a constant string or a single format directive (e.g.,
+// '%.3f').
+struct Formatter {
+ Formatter(char *str_, const char *fmt_, size_t size_)
+ : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
+ width(-1) {}
+
+ int format() {
+ char *tmp_fmt = build_format_string();
+ int retval =
+ snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
+ 0 /* used only to avoid warnings */);
+ free(tmp_fmt);
+ return retval;
+ }
+
+ template <typename T> int format(T arg) {
+ char *tmp_fmt = build_format_string();
+ int retval;
+ if (width >= 0) {
+ retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
+ tmp_fmt, width, arg);
+ } else {
+ retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
+ tmp_fmt, arg);
+ }
+ free(tmp_fmt);
+ return retval;
+ }
+
+ char *build_format_string() {
+ size_t fmt_size = fmt_cur - fmt_start + 1;
+ char *new_fmt = (char *)malloc(fmt_size + 1);
+ assert(new_fmt);
+ internal_memcpy(new_fmt, fmt_start, fmt_size);
+ new_fmt[fmt_size] = '\0';
+ return new_fmt;
+ }
+
+ char *str_cur() { return str + str_off; }
+
+ size_t num_written_bytes(int retval) {
+ if (retval < 0) {
+ return 0;
+ }
+
+ size_t num_avail = str_off < size ? size - str_off : 0;
+ if (num_avail == 0) {
+ return 0;
+ }
+
+ size_t num_written = retval;
+ // A return value of {v,}snprintf of size or more means that the output was
+ // truncated.
+ if (num_written >= num_avail) {
+ num_written -= num_avail;
+ }
+
+ return num_written;
+ }
+
+ char *str;
+ size_t str_off;
+ size_t size;
+ const char *fmt_start;
+ const char *fmt_cur;
+ int width;
+};
+
+// Formats the input and propagates the input labels to the output. The output
+// is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
+// 'ap' are the format string and the list of arguments for formatting. Returns
+// the return value vsnprintf would return.
+//
+// The function tokenizes the format string in chunks representing either a
+// constant string or a single format directive (e.g., '%.3f') and formats each
+// chunk independently into the output string. This approach allows to figure
+// out which bytes of the output string depends on which argument and thus to
+// propagate labels more precisely.
+//
+// WARNING: This implementation does not support conversion specifiers with
+// positional arguments.
+static int format_buffer(char *str, size_t size, const char *fmt,
+ dfsan_label *va_labels, dfsan_label *ret_label,
+ va_list ap) {
+ Formatter formatter(str, fmt, size);
+
+ while (*formatter.fmt_cur) {
+ formatter.fmt_start = formatter.fmt_cur;
+ formatter.width = -1;
+ int retval = 0;
+
+ if (*formatter.fmt_cur != '%') {
+ // Ordinary character. Consume all the characters until a '%' or the end
+ // of the string.
+ for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
+ ++formatter.fmt_cur) {}
+ retval = formatter.format();
+ dfsan_set_label(0, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ } else {
+ // Conversion directive. Consume all the characters until a conversion
+ // specifier or the end of the string.
+ bool end_fmt = false;
+ for (; *formatter.fmt_cur && !end_fmt; ) {
+ switch (*++formatter.fmt_cur) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ switch (*(formatter.fmt_cur - 1)) {
+ case 'h':
+ // Also covers the 'hh' case (since the size of the arg is still
+ // an int).
+ retval = formatter.format(va_arg(ap, int));
+ break;
+ case 'l':
+ if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
+ *(formatter.fmt_cur - 2) == 'l') {
+ retval = formatter.format(va_arg(ap, long long int));
+ } else {
+ retval = formatter.format(va_arg(ap, long int));
+ }
+ break;
+ case 'q':
+ retval = formatter.format(va_arg(ap, long long int));
+ break;
+ case 'j':
+ retval = formatter.format(va_arg(ap, intmax_t));
+ break;
+ case 'z':
+ case 't':
+ retval = formatter.format(va_arg(ap, size_t));
+ break;
+ default:
+ retval = formatter.format(va_arg(ap, int));
+ }
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ if (*(formatter.fmt_cur - 1) == 'L') {
+ retval = formatter.format(va_arg(ap, long double));
+ } else {
+ retval = formatter.format(va_arg(ap, double));
+ }
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'c':
+ retval = formatter.format(va_arg(ap, int));
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 's': {
+ char *arg = va_arg(ap, char *);
+ retval = formatter.format(arg);
+ va_labels++;
+ internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
+ sizeof(dfsan_label) *
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+ }
+
+ case 'p':
+ retval = formatter.format(va_arg(ap, void *));
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'n': {
+ int *ptr = va_arg(ap, int *);
+ *ptr = (int)formatter.str_off;
+ va_labels++;
+ dfsan_set_label(0, ptr, sizeof(ptr));
+ end_fmt = true;
+ break;
+ }
+
+ case '%':
+ retval = formatter.format();
+ dfsan_set_label(0, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case '*':
+ formatter.width = va_arg(ap, int);
+ va_labels++;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (retval < 0) {
+ return retval;
+ }
+
+ formatter.fmt_cur++;
+ formatter.str_off += retval;
+ }
+
+ *ret_label = 0;
+
+ // Number of bytes written in total.
+ return formatter.str_off;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_snprintf(char *str, size_t size, const char *format,
+ dfsan_label str_label, dfsan_label size_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
+} // extern "C"
diff --git a/compiler-rt/lib/dfsan/dfsan_flags.inc b/compiler-rt/lib/dfsan/dfsan_flags.inc
new file mode 100644
index 0000000..24fbfcb
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan_flags.inc
@@ -0,0 +1,32 @@
+//===-- dfsan_flags.inc -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// DFSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DFSAN_FLAG
+# error "Define DFSAN_FLAG prior to including this file!"
+#endif
+
+// DFSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+DFSAN_FLAG(bool, warn_unimplemented, true,
+ "Whether to warn on unimplemented functions.")
+DFSAN_FLAG(bool, warn_nonzero_labels, false,
+ "Whether to warn on unimplemented functions.")
+DFSAN_FLAG(
+ bool, strict_data_dependencies, true,
+ "Whether to propagate labels only when there is an obvious data dependency"
+ "(e.g., when comparing strings, ignore the fact that the output of the"
+ "comparison might be data-dependent on the content of the strings). This"
+ "applies only to the custom functions defined in 'custom.c'.")
+DFSAN_FLAG(const char *, dump_labels_at_exit, "", "The path of the file where "
+ "to dump the labels when the "
+ "program terminates.")
diff --git a/compiler-rt/lib/dfsan/dfsan_interceptors.cc b/compiler-rt/lib/dfsan/dfsan_interceptors.cc
new file mode 100644
index 0000000..8b7d64e
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan_interceptors.cc
@@ -0,0 +1,44 @@
+//===-- dfsan_interceptors.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Interceptors for standard library functions.
+//===----------------------------------------------------------------------===//
+
+#include "dfsan/dfsan.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF_T offset) {
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF64_T offset) {
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+namespace __dfsan {
+void InitializeInterceptors() {
+ static int inited = 0;
+ CHECK_EQ(inited, 0);
+
+ INTERCEPT_FUNCTION(mmap);
+ INTERCEPT_FUNCTION(mmap64);
+ inited = 1;
+}
+} // namespace __dfsan
diff --git a/compiler-rt/lib/dfsan/dfsan_platform.h b/compiler-rt/lib/dfsan/dfsan_platform.h
new file mode 100644
index 0000000..f1d9f10
--- /dev/null
+++ b/compiler-rt/lib/dfsan/dfsan_platform.h
@@ -0,0 +1,107 @@
+//===-- dfsan_platform.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Platform specific information for DFSan.
+//===----------------------------------------------------------------------===//
+
+#ifndef DFSAN_PLATFORM_H
+#define DFSAN_PLATFORM_H
+
+namespace __dfsan {
+
+#if defined(__x86_64__)
+struct Mapping {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x200000000000;
+ static const uptr kAppAddr = 0x700000008000;
+ static const uptr kShadowMask = ~0x700000000000;
+};
+#elif defined(__mips64)
+struct Mapping {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x2000000000;
+ static const uptr kAppAddr = 0xF000008000;
+ static const uptr kShadowMask = ~0xF000000000;
+};
+#elif defined(__aarch64__)
+struct Mapping39 {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x1000000000;
+ static const uptr kAppAddr = 0x7000008000;
+ static const uptr kShadowMask = ~0x7800000000;
+};
+
+struct Mapping42 {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x8000000000;
+ static const uptr kAppAddr = 0x3ff00008000;
+ static const uptr kShadowMask = ~0x3c000000000;
+};
+
+extern int vmaSize;
+# define DFSAN_RUNTIME_VMA 1
+#else
+# error "DFSan not supported for this platform!"
+#endif
+
+enum MappingType {
+ MAPPING_SHADOW_ADDR,
+ MAPPING_UNION_TABLE_ADDR,
+ MAPPING_APP_ADDR,
+ MAPPING_SHADOW_MASK
+};
+
+template<typename Mapping, int Type>
+uptr MappingImpl(void) {
+ switch (Type) {
+ case MAPPING_SHADOW_ADDR: return Mapping::kShadowAddr;
+ case MAPPING_UNION_TABLE_ADDR: return Mapping::kUnionTableAddr;
+ case MAPPING_APP_ADDR: return Mapping::kAppAddr;
+ case MAPPING_SHADOW_MASK: return Mapping::kShadowMask;
+ }
+}
+
+template<int Type>
+uptr MappingArchImpl(void) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return MappingImpl<Mapping39, Type>();
+ else
+ return MappingImpl<Mapping42, Type>();
+ DCHECK(0);
+#else
+ return MappingImpl<Mapping, Type>();
+#endif
+}
+
+ALWAYS_INLINE
+uptr ShadowAddr() {
+ return MappingArchImpl<MAPPING_SHADOW_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr UnionTableAddr() {
+ return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr AppAddr() {
+ return MappingArchImpl<MAPPING_APP_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr ShadowMask() {
+ return MappingArchImpl<MAPPING_SHADOW_MASK>();
+}
+
+} // namespace __dfsan
+
+#endif
diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt
new file mode 100644
index 0000000..7ca8aeb
--- /dev/null
+++ b/compiler-rt/lib/dfsan/done_abilist.txt
@@ -0,0 +1,306 @@
+fun:main=uninstrumented
+fun:main=discard
+
+###############################################################################
+# DFSan interface functions
+###############################################################################
+fun:dfsan_union=uninstrumented
+fun:dfsan_union=discard
+fun:dfsan_create_label=uninstrumented
+fun:dfsan_create_label=discard
+fun:dfsan_set_label=uninstrumented
+fun:dfsan_set_label=discard
+fun:dfsan_add_label=uninstrumented
+fun:dfsan_add_label=discard
+fun:dfsan_get_label=uninstrumented
+fun:dfsan_get_label=custom
+fun:dfsan_read_label=uninstrumented
+fun:dfsan_read_label=discard
+fun:dfsan_get_label_count=uninstrumented
+fun:dfsan_get_label_count=discard
+fun:dfsan_get_label_info=uninstrumented
+fun:dfsan_get_label_info=discard
+fun:dfsan_has_label=uninstrumented
+fun:dfsan_has_label=discard
+fun:dfsan_has_label_with_desc=uninstrumented
+fun:dfsan_has_label_with_desc=discard
+fun:dfsan_set_write_callback=uninstrumented
+fun:dfsan_set_write_callback=custom
+
+###############################################################################
+# glibc
+###############################################################################
+fun:malloc=discard
+fun:realloc=discard
+fun:free=discard
+
+# Functions that return a value that depends on the input, but the output might
+# not be necessarily data-dependent on the input.
+fun:isalpha=functional
+fun:isdigit=functional
+fun:isprint=functional
+fun:isxdigit=functional
+fun:isalnum=functional
+fun:ispunct=functional
+fun:isspace=functional
+fun:tolower=functional
+fun:toupper=functional
+
+# Functions that return a value that is data-dependent on the input.
+fun:btowc=functional
+fun:exp=functional
+fun:exp2=functional
+fun:fabs=functional
+fun:finite=functional
+fun:floor=functional
+fun:fmod=functional
+fun:isinf=functional
+fun:isnan=functional
+fun:log=functional
+fun:modf=functional
+fun:pow=functional
+fun:round=functional
+fun:sqrt=functional
+fun:wctob=functional
+
+# Functions that produce an output that does not depend on the input (shadow is
+# zeroed automatically).
+fun:__assert_fail=discard
+fun:__ctype_b_loc=discard
+fun:__cxa_atexit=discard
+fun:__errno_location=discard
+fun:__newlocale=discard
+fun:__sbrk=discard
+fun:__sigsetjmp=discard
+fun:__uselocale=discard
+fun:__wctype_l=discard
+fun:access=discard
+fun:alarm=discard
+fun:atexit=discard
+fun:bind=discard
+fun:chdir=discard
+fun:close=discard
+fun:closedir=discard
+fun:connect=discard
+fun:dladdr=discard
+fun:dlclose=discard
+fun:fclose=discard
+fun:feof=discard
+fun:ferror=discard
+fun:fflush=discard
+fun:fileno=discard
+fun:fopen=discard
+fun:fprintf=discard
+fun:fputc=discard
+fun:fputc=discard
+fun:fputs=discard
+fun:fputs=discard
+fun:fseek=discard
+fun:ftell=discard
+fun:fwrite=discard
+fun:getenv=discard
+fun:getuid=discard
+fun:geteuid=discard
+fun:getpagesize=discard
+fun:getpid=discard
+fun:kill=discard
+fun:listen=discard
+fun:lseek=discard
+fun:mkdir=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:open=discard
+fun:pipe=discard
+fun:posix_fadvise=discard
+fun:posix_memalign=discard
+fun:prctl=discard
+fun:printf=discard
+fun:pthread_sigmask=discard
+fun:putc=discard
+fun:putchar=discard
+fun:puts=discard
+fun:rand=discard
+fun:random=discard
+fun:remove=discard
+fun:sched_getcpu=discard
+fun:sched_get_priority_max=discard
+fun:sched_setaffinity=discard
+fun:sched_yield=discard
+fun:sem_destroy=discard
+fun:sem_init=discard
+fun:sem_post=discard
+fun:sem_wait=discard
+fun:send=discard
+fun:sendmsg=discard
+fun:sendto=discard
+fun:setsockopt=discard
+fun:shutdown=discard
+fun:sleep=discard
+fun:socket=discard
+fun:strerror=discard
+fun:strspn=discard
+fun:strcspn=discard
+fun:symlink=discard
+fun:syscall=discard
+fun:unlink=discard
+fun:uselocale=discard
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:calloc=custom
+fun:clock_gettime=custom
+fun:dlopen=custom
+fun:fgets=custom
+fun:fstat=custom
+fun:getcwd=custom
+fun:get_current_dir_name=custom
+fun:gethostname=custom
+fun:getrlimit=custom
+fun:getrusage=custom
+fun:nanosleep=custom
+fun:pread=custom
+fun:read=custom
+fun:socketpair=custom
+fun:stat=custom
+fun:time=custom
+
+# Functions that produce an output that depend on the input (propagate the
+# shadow manually).
+fun:ctime_r=custom
+fun:inet_pton=custom
+fun:localtime_r=custom
+fun:memcpy=custom
+fun:memset=custom
+fun:strcpy=custom
+fun:strdup=custom
+fun:strncpy=custom
+fun:strtod=custom
+fun:strtol=custom
+fun:strtoll=custom
+fun:strtoul=custom
+fun:strtoull=custom
+
+# Functions that produce an output that is computed from the input, but is not
+# necessarily data dependent.
+fun:memchr=custom
+fun:memcmp=custom
+fun:strcasecmp=custom
+fun:strchr=custom
+fun:strcmp=custom
+fun:strlen=custom
+fun:strncasecmp=custom
+fun:strncmp=custom
+fun:strrchr=custom
+fun:strstr=custom
+
+# Functions which take action based on global state, such as running a callback
+# set by a sepperate function.
+fun:write=custom
+
+# Functions that take a callback (wrap the callback manually).
+fun:dl_iterate_phdr=custom
+
+fun:getpwuid_r=custom
+fun:poll=custom
+fun:sched_getaffinity=custom
+fun:select=custom
+fun:sigemptyset=custom
+fun:sigaction=custom
+fun:gettimeofday=custom
+
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
+# TODO: custom
+fun:asprintf=discard
+fun:qsort=discard
+
+###############################################################################
+# pthread
+###############################################################################
+fun:pthread_equal=discard
+fun:pthread_getspecific=discard
+fun:pthread_key_create=discard
+fun:pthread_key_delete=discard
+fun:pthread_mutex_destroy=discard
+fun:pthread_mutex_init=discard
+fun:pthread_mutex_lock=discard
+fun:pthread_mutex_trylock=discard
+fun:pthread_mutex_unlock=discard
+fun:pthread_mutexattr_destroy=discard
+fun:pthread_mutexattr_init=discard
+fun:pthread_mutexattr_settype=discard
+fun:pthread_once=discard
+fun:pthread_self=discard
+fun:pthread_setspecific=discard
+
+# Functions that take a callback (wrap the callback manually).
+fun:pthread_create=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
+
+
+###############################################################################
+# lib/Fuzzer
+###############################################################################
+# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
+fun:__sanitizer_cov_trace_cmp=custom
+fun:__sanitizer_cov_trace_cmp=uninstrumented
+# Similar for __sanitizer_cov_trace_switch
+fun:__sanitizer_cov_trace_switch=custom
+fun:__sanitizer_cov_trace_switch=uninstrumented
+
+# Ignores all other __sanitizer callbacks.
+fun:__sanitizer_cov=uninstrumented
+fun:__sanitizer_cov=discard
+fun:__sanitizer_cov_module_init=uninstrumented
+fun:__sanitizer_cov_module_init=discard
+fun:__sanitizer_cov_with_check=uninstrumented
+fun:__sanitizer_cov_with_check=discard
+fun:__sanitizer_cov_indir_call16=uninstrumented
+fun:__sanitizer_cov_indir_call16=discard
+fun:__sanitizer_cov_indir_call16=uninstrumented
+fun:__sanitizer_cov_indir_call16=discard
+fun:__sanitizer_reset_coverage=uninstrumented
+fun:__sanitizer_reset_coverage=discard
+fun:__sanitizer_set_death_callback=uninstrumented
+fun:__sanitizer_set_death_callback=discard
+fun:__sanitizer_get_coverage_guards=uninstrumented
+fun:__sanitizer_get_coverage_guards=discard
+fun:__sanitizer_get_number_of_counters=uninstrumented
+fun:__sanitizer_get_number_of_counters=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+fun:__sanitizer_get_total_unique_coverage=uninstrumented
+fun:__sanitizer_get_total_unique_coverage=discard
+fun:__sanitizer_get_total_unique_coverage=uninstrumented
+fun:__sanitizer_get_total_unique_coverage=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+
+# Ignores the dfsan wrappers.
+fun:__dfsw_*=uninstrumented
+fun:__dfsw_*=discard
+
+# Don't add extra parameters to the Fuzzer callback.
+fun:LLVMFuzzerTestOneInput=uninstrumented
diff --git a/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt
new file mode 100644
index 0000000..a1ea0a0
--- /dev/null
+++ b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt
@@ -0,0 +1,3433 @@
+fun:_Exit=uninstrumented
+fun:_IO_adjust_column=uninstrumented
+fun:_IO_adjust_wcolumn=uninstrumented
+fun:_IO_default_doallocate=uninstrumented
+fun:_IO_default_finish=uninstrumented
+fun:_IO_default_pbackfail=uninstrumented
+fun:_IO_default_uflow=uninstrumented
+fun:_IO_default_xsgetn=uninstrumented
+fun:_IO_default_xsputn=uninstrumented
+fun:_IO_do_write=uninstrumented
+fun:_IO_doallocbuf=uninstrumented
+fun:_IO_fclose=uninstrumented
+fun:_IO_fdopen=uninstrumented
+fun:_IO_feof=uninstrumented
+fun:_IO_ferror=uninstrumented
+fun:_IO_fflush=uninstrumented
+fun:_IO_fgetpos=uninstrumented
+fun:_IO_fgetpos64=uninstrumented
+fun:_IO_fgets=uninstrumented
+fun:_IO_file_attach=uninstrumented
+fun:_IO_file_close=uninstrumented
+fun:_IO_file_close_it=uninstrumented
+fun:_IO_file_doallocate=uninstrumented
+fun:_IO_file_finish=uninstrumented
+fun:_IO_file_fopen=uninstrumented
+fun:_IO_file_init=uninstrumented
+fun:_IO_file_open=uninstrumented
+fun:_IO_file_overflow=uninstrumented
+fun:_IO_file_read=uninstrumented
+fun:_IO_file_seek=uninstrumented
+fun:_IO_file_seekoff=uninstrumented
+fun:_IO_file_setbuf=uninstrumented
+fun:_IO_file_stat=uninstrumented
+fun:_IO_file_sync=uninstrumented
+fun:_IO_file_underflow=uninstrumented
+fun:_IO_file_write=uninstrumented
+fun:_IO_file_xsputn=uninstrumented
+fun:_IO_flockfile=uninstrumented
+fun:_IO_flush_all=uninstrumented
+fun:_IO_flush_all_linebuffered=uninstrumented
+fun:_IO_fopen=uninstrumented
+fun:_IO_fprintf=uninstrumented
+fun:_IO_fputs=uninstrumented
+fun:_IO_fread=uninstrumented
+fun:_IO_free_backup_area=uninstrumented
+fun:_IO_free_wbackup_area=uninstrumented
+fun:_IO_fsetpos=uninstrumented
+fun:_IO_fsetpos64=uninstrumented
+fun:_IO_ftell=uninstrumented
+fun:_IO_ftrylockfile=uninstrumented
+fun:_IO_funlockfile=uninstrumented
+fun:_IO_fwrite=uninstrumented
+fun:_IO_getc=uninstrumented
+fun:_IO_getline=uninstrumented
+fun:_IO_getline_info=uninstrumented
+fun:_IO_gets=uninstrumented
+fun:_IO_init=uninstrumented
+fun:_IO_init_marker=uninstrumented
+fun:_IO_init_wmarker=uninstrumented
+fun:_IO_iter_begin=uninstrumented
+fun:_IO_iter_end=uninstrumented
+fun:_IO_iter_file=uninstrumented
+fun:_IO_iter_next=uninstrumented
+fun:_IO_least_wmarker=uninstrumented
+fun:_IO_link_in=uninstrumented
+fun:_IO_list_lock=uninstrumented
+fun:_IO_list_resetlock=uninstrumented
+fun:_IO_list_unlock=uninstrumented
+fun:_IO_marker_delta=uninstrumented
+fun:_IO_marker_difference=uninstrumented
+fun:_IO_padn=uninstrumented
+fun:_IO_peekc_locked=uninstrumented
+fun:_IO_popen=uninstrumented
+fun:_IO_printf=uninstrumented
+fun:_IO_proc_close=uninstrumented
+fun:_IO_proc_open=uninstrumented
+fun:_IO_putc=uninstrumented
+fun:_IO_puts=uninstrumented
+fun:_IO_remove_marker=uninstrumented
+fun:_IO_seekmark=uninstrumented
+fun:_IO_seekoff=uninstrumented
+fun:_IO_seekpos=uninstrumented
+fun:_IO_seekwmark=uninstrumented
+fun:_IO_setb=uninstrumented
+fun:_IO_setbuffer=uninstrumented
+fun:_IO_setvbuf=uninstrumented
+fun:_IO_sgetn=uninstrumented
+fun:_IO_sprintf=uninstrumented
+fun:_IO_sputbackc=uninstrumented
+fun:_IO_sputbackwc=uninstrumented
+fun:_IO_sscanf=uninstrumented
+fun:_IO_str_init_readonly=uninstrumented
+fun:_IO_str_init_static=uninstrumented
+fun:_IO_str_overflow=uninstrumented
+fun:_IO_str_pbackfail=uninstrumented
+fun:_IO_str_seekoff=uninstrumented
+fun:_IO_str_underflow=uninstrumented
+fun:_IO_sungetc=uninstrumented
+fun:_IO_sungetwc=uninstrumented
+fun:_IO_switch_to_get_mode=uninstrumented
+fun:_IO_switch_to_main_wget_area=uninstrumented
+fun:_IO_switch_to_wbackup_area=uninstrumented
+fun:_IO_switch_to_wget_mode=uninstrumented
+fun:_IO_un_link=uninstrumented
+fun:_IO_ungetc=uninstrumented
+fun:_IO_unsave_markers=uninstrumented
+fun:_IO_unsave_wmarkers=uninstrumented
+fun:_IO_vfprintf=uninstrumented
+fun:_IO_vfscanf=uninstrumented
+fun:_IO_vsprintf=uninstrumented
+fun:_IO_wdefault_doallocate=uninstrumented
+fun:_IO_wdefault_finish=uninstrumented
+fun:_IO_wdefault_pbackfail=uninstrumented
+fun:_IO_wdefault_uflow=uninstrumented
+fun:_IO_wdefault_xsgetn=uninstrumented
+fun:_IO_wdefault_xsputn=uninstrumented
+fun:_IO_wdo_write=uninstrumented
+fun:_IO_wdoallocbuf=uninstrumented
+fun:_IO_wfile_overflow=uninstrumented
+fun:_IO_wfile_seekoff=uninstrumented
+fun:_IO_wfile_sync=uninstrumented
+fun:_IO_wfile_underflow=uninstrumented
+fun:_IO_wfile_xsputn=uninstrumented
+fun:_IO_wmarker_delta=uninstrumented
+fun:_IO_wsetb=uninstrumented
+fun:_Unwind_Backtrace=uninstrumented
+fun:_Unwind_DeleteException=uninstrumented
+fun:_Unwind_FindEnclosingFunction=uninstrumented
+fun:_Unwind_Find_FDE=uninstrumented
+fun:_Unwind_ForcedUnwind=uninstrumented
+fun:_Unwind_GetCFA=uninstrumented
+fun:_Unwind_GetDataRelBase=uninstrumented
+fun:_Unwind_GetGR=uninstrumented
+fun:_Unwind_GetIP=uninstrumented
+fun:_Unwind_GetIPInfo=uninstrumented
+fun:_Unwind_GetLanguageSpecificData=uninstrumented
+fun:_Unwind_GetRegionStart=uninstrumented
+fun:_Unwind_GetTextRelBase=uninstrumented
+fun:_Unwind_RaiseException=uninstrumented
+fun:_Unwind_Resume=uninstrumented
+fun:_Unwind_Resume_or_Rethrow=uninstrumented
+fun:_Unwind_SetGR=uninstrumented
+fun:_Unwind_SetIP=uninstrumented
+fun:__absvdi2=uninstrumented
+fun:__absvsi2=uninstrumented
+fun:__absvti2=uninstrumented
+fun:__acos_finite=uninstrumented
+fun:__acosf_finite=uninstrumented
+fun:__acosh_finite=uninstrumented
+fun:__acoshf_finite=uninstrumented
+fun:__acoshl_finite=uninstrumented
+fun:__acosl_finite=uninstrumented
+fun:__addtf3=uninstrumented
+fun:__addvdi3=uninstrumented
+fun:__addvsi3=uninstrumented
+fun:__addvti3=uninstrumented
+fun:__adjtimex=uninstrumented
+fun:__arch_prctl=uninstrumented
+fun:__argz_count=uninstrumented
+fun:__argz_next=uninstrumented
+fun:__argz_stringify=uninstrumented
+fun:__ashlti3=uninstrumented
+fun:__ashrti3=uninstrumented
+fun:__asin_finite=uninstrumented
+fun:__asinf_finite=uninstrumented
+fun:__asinl_finite=uninstrumented
+fun:__asprintf=uninstrumented
+fun:__asprintf_chk=uninstrumented
+fun:__assert=uninstrumented
+fun:__assert_fail=uninstrumented
+fun:__assert_perror_fail=uninstrumented
+fun:__atan2_finite=uninstrumented
+fun:__atan2f_finite=uninstrumented
+fun:__atan2l_finite=uninstrumented
+fun:__atanh_finite=uninstrumented
+fun:__atanhf_finite=uninstrumented
+fun:__atanhl_finite=uninstrumented
+fun:__b64_ntop=uninstrumented
+fun:__b64_pton=uninstrumented
+fun:__backtrace=uninstrumented
+fun:__backtrace_symbols=uninstrumented
+fun:__backtrace_symbols_fd=uninstrumented
+fun:__bid128_abs=uninstrumented
+fun:__bid128_add=uninstrumented
+fun:__bid128_class=uninstrumented
+fun:__bid128_copy=uninstrumented
+fun:__bid128_copySign=uninstrumented
+fun:__bid128_div=uninstrumented
+fun:__bid128_fma=uninstrumented
+fun:__bid128_from_int32=uninstrumented
+fun:__bid128_from_int64=uninstrumented
+fun:__bid128_from_uint32=uninstrumented
+fun:__bid128_from_uint64=uninstrumented
+fun:__bid128_isCanonical=uninstrumented
+fun:__bid128_isFinite=uninstrumented
+fun:__bid128_isInf=uninstrumented
+fun:__bid128_isNaN=uninstrumented
+fun:__bid128_isNormal=uninstrumented
+fun:__bid128_isSignaling=uninstrumented
+fun:__bid128_isSigned=uninstrumented
+fun:__bid128_isSubnormal=uninstrumented
+fun:__bid128_isZero=uninstrumented
+fun:__bid128_mul=uninstrumented
+fun:__bid128_negate=uninstrumented
+fun:__bid128_quiet_equal=uninstrumented
+fun:__bid128_quiet_greater=uninstrumented
+fun:__bid128_quiet_greater_equal=uninstrumented
+fun:__bid128_quiet_greater_unordered=uninstrumented
+fun:__bid128_quiet_less=uninstrumented
+fun:__bid128_quiet_less_equal=uninstrumented
+fun:__bid128_quiet_less_unordered=uninstrumented
+fun:__bid128_quiet_not_equal=uninstrumented
+fun:__bid128_quiet_not_greater=uninstrumented
+fun:__bid128_quiet_not_less=uninstrumented
+fun:__bid128_quiet_ordered=uninstrumented
+fun:__bid128_quiet_unordered=uninstrumented
+fun:__bid128_radix=uninstrumented
+fun:__bid128_sameQuantum=uninstrumented
+fun:__bid128_signaling_greater=uninstrumented
+fun:__bid128_signaling_greater_equal=uninstrumented
+fun:__bid128_signaling_greater_unordered=uninstrumented
+fun:__bid128_signaling_less=uninstrumented
+fun:__bid128_signaling_less_equal=uninstrumented
+fun:__bid128_signaling_less_unordered=uninstrumented
+fun:__bid128_signaling_not_greater=uninstrumented
+fun:__bid128_signaling_not_less=uninstrumented
+fun:__bid128_sub=uninstrumented
+fun:__bid128_to_bid32=uninstrumented
+fun:__bid128_to_bid64=uninstrumented
+fun:__bid128_to_binary128=uninstrumented
+fun:__bid128_to_binary32=uninstrumented
+fun:__bid128_to_binary64=uninstrumented
+fun:__bid128_to_binary80=uninstrumented
+fun:__bid128_to_int32_ceil=uninstrumented
+fun:__bid128_to_int32_floor=uninstrumented
+fun:__bid128_to_int32_int=uninstrumented
+fun:__bid128_to_int32_rnint=uninstrumented
+fun:__bid128_to_int32_rninta=uninstrumented
+fun:__bid128_to_int32_xceil=uninstrumented
+fun:__bid128_to_int32_xfloor=uninstrumented
+fun:__bid128_to_int32_xint=uninstrumented
+fun:__bid128_to_int32_xrnint=uninstrumented
+fun:__bid128_to_int32_xrninta=uninstrumented
+fun:__bid128_to_int64_ceil=uninstrumented
+fun:__bid128_to_int64_floor=uninstrumented
+fun:__bid128_to_int64_int=uninstrumented
+fun:__bid128_to_int64_rnint=uninstrumented
+fun:__bid128_to_int64_rninta=uninstrumented
+fun:__bid128_to_int64_xceil=uninstrumented
+fun:__bid128_to_int64_xfloor=uninstrumented
+fun:__bid128_to_int64_xint=uninstrumented
+fun:__bid128_to_int64_xrnint=uninstrumented
+fun:__bid128_to_int64_xrninta=uninstrumented
+fun:__bid128_to_uint32_ceil=uninstrumented
+fun:__bid128_to_uint32_floor=uninstrumented
+fun:__bid128_to_uint32_int=uninstrumented
+fun:__bid128_to_uint32_rnint=uninstrumented
+fun:__bid128_to_uint32_rninta=uninstrumented
+fun:__bid128_to_uint32_xceil=uninstrumented
+fun:__bid128_to_uint32_xfloor=uninstrumented
+fun:__bid128_to_uint32_xint=uninstrumented
+fun:__bid128_to_uint32_xrnint=uninstrumented
+fun:__bid128_to_uint32_xrninta=uninstrumented
+fun:__bid128_to_uint64_ceil=uninstrumented
+fun:__bid128_to_uint64_floor=uninstrumented
+fun:__bid128_to_uint64_int=uninstrumented
+fun:__bid128_to_uint64_rnint=uninstrumented
+fun:__bid128_to_uint64_rninta=uninstrumented
+fun:__bid128_to_uint64_xceil=uninstrumented
+fun:__bid128_to_uint64_xfloor=uninstrumented
+fun:__bid128_to_uint64_xint=uninstrumented
+fun:__bid128_to_uint64_xrnint=uninstrumented
+fun:__bid128_to_uint64_xrninta=uninstrumented
+fun:__bid128_totalOrder=uninstrumented
+fun:__bid128_totalOrderMag=uninstrumented
+fun:__bid128dd_add=uninstrumented
+fun:__bid128dd_div=uninstrumented
+fun:__bid128dd_mul=uninstrumented
+fun:__bid128dd_sub=uninstrumented
+fun:__bid128ddd_fma=uninstrumented
+fun:__bid128ddq_fma=uninstrumented
+fun:__bid128dq_add=uninstrumented
+fun:__bid128dq_div=uninstrumented
+fun:__bid128dq_mul=uninstrumented
+fun:__bid128dq_sub=uninstrumented
+fun:__bid128dqd_fma=uninstrumented
+fun:__bid128dqq_fma=uninstrumented
+fun:__bid128qd_add=uninstrumented
+fun:__bid128qd_div=uninstrumented
+fun:__bid128qd_mul=uninstrumented
+fun:__bid128qd_sub=uninstrumented
+fun:__bid128qdd_fma=uninstrumented
+fun:__bid128qdq_fma=uninstrumented
+fun:__bid128qqd_fma=uninstrumented
+fun:__bid32_to_bid128=uninstrumented
+fun:__bid32_to_bid64=uninstrumented
+fun:__bid32_to_binary128=uninstrumented
+fun:__bid32_to_binary32=uninstrumented
+fun:__bid32_to_binary64=uninstrumented
+fun:__bid32_to_binary80=uninstrumented
+fun:__bid64_abs=uninstrumented
+fun:__bid64_add=uninstrumented
+fun:__bid64_class=uninstrumented
+fun:__bid64_copy=uninstrumented
+fun:__bid64_copySign=uninstrumented
+fun:__bid64_div=uninstrumented
+fun:__bid64_from_int32=uninstrumented
+fun:__bid64_from_int64=uninstrumented
+fun:__bid64_from_uint32=uninstrumented
+fun:__bid64_from_uint64=uninstrumented
+fun:__bid64_isCanonical=uninstrumented
+fun:__bid64_isFinite=uninstrumented
+fun:__bid64_isInf=uninstrumented
+fun:__bid64_isNaN=uninstrumented
+fun:__bid64_isNormal=uninstrumented
+fun:__bid64_isSignaling=uninstrumented
+fun:__bid64_isSigned=uninstrumented
+fun:__bid64_isSubnormal=uninstrumented
+fun:__bid64_isZero=uninstrumented
+fun:__bid64_mul=uninstrumented
+fun:__bid64_negate=uninstrumented
+fun:__bid64_quiet_equal=uninstrumented
+fun:__bid64_quiet_greater=uninstrumented
+fun:__bid64_quiet_greater_equal=uninstrumented
+fun:__bid64_quiet_greater_unordered=uninstrumented
+fun:__bid64_quiet_less=uninstrumented
+fun:__bid64_quiet_less_equal=uninstrumented
+fun:__bid64_quiet_less_unordered=uninstrumented
+fun:__bid64_quiet_not_equal=uninstrumented
+fun:__bid64_quiet_not_greater=uninstrumented
+fun:__bid64_quiet_not_less=uninstrumented
+fun:__bid64_quiet_ordered=uninstrumented
+fun:__bid64_quiet_unordered=uninstrumented
+fun:__bid64_radix=uninstrumented
+fun:__bid64_sameQuantum=uninstrumented
+fun:__bid64_signaling_greater=uninstrumented
+fun:__bid64_signaling_greater_equal=uninstrumented
+fun:__bid64_signaling_greater_unordered=uninstrumented
+fun:__bid64_signaling_less=uninstrumented
+fun:__bid64_signaling_less_equal=uninstrumented
+fun:__bid64_signaling_less_unordered=uninstrumented
+fun:__bid64_signaling_not_greater=uninstrumented
+fun:__bid64_signaling_not_less=uninstrumented
+fun:__bid64_sub=uninstrumented
+fun:__bid64_to_bid128=uninstrumented
+fun:__bid64_to_bid32=uninstrumented
+fun:__bid64_to_binary128=uninstrumented
+fun:__bid64_to_binary32=uninstrumented
+fun:__bid64_to_binary64=uninstrumented
+fun:__bid64_to_binary80=uninstrumented
+fun:__bid64_to_int32_ceil=uninstrumented
+fun:__bid64_to_int32_floor=uninstrumented
+fun:__bid64_to_int32_int=uninstrumented
+fun:__bid64_to_int32_rnint=uninstrumented
+fun:__bid64_to_int32_rninta=uninstrumented
+fun:__bid64_to_int32_xceil=uninstrumented
+fun:__bid64_to_int32_xfloor=uninstrumented
+fun:__bid64_to_int32_xint=uninstrumented
+fun:__bid64_to_int32_xrnint=uninstrumented
+fun:__bid64_to_int32_xrninta=uninstrumented
+fun:__bid64_to_int64_ceil=uninstrumented
+fun:__bid64_to_int64_floor=uninstrumented
+fun:__bid64_to_int64_int=uninstrumented
+fun:__bid64_to_int64_rnint=uninstrumented
+fun:__bid64_to_int64_rninta=uninstrumented
+fun:__bid64_to_int64_xceil=uninstrumented
+fun:__bid64_to_int64_xfloor=uninstrumented
+fun:__bid64_to_int64_xint=uninstrumented
+fun:__bid64_to_int64_xrnint=uninstrumented
+fun:__bid64_to_int64_xrninta=uninstrumented
+fun:__bid64_to_uint32_ceil=uninstrumented
+fun:__bid64_to_uint32_floor=uninstrumented
+fun:__bid64_to_uint32_int=uninstrumented
+fun:__bid64_to_uint32_rnint=uninstrumented
+fun:__bid64_to_uint32_rninta=uninstrumented
+fun:__bid64_to_uint32_xceil=uninstrumented
+fun:__bid64_to_uint32_xfloor=uninstrumented
+fun:__bid64_to_uint32_xint=uninstrumented
+fun:__bid64_to_uint32_xrnint=uninstrumented
+fun:__bid64_to_uint32_xrninta=uninstrumented
+fun:__bid64_to_uint64_ceil=uninstrumented
+fun:__bid64_to_uint64_floor=uninstrumented
+fun:__bid64_to_uint64_int=uninstrumented
+fun:__bid64_to_uint64_rnint=uninstrumented
+fun:__bid64_to_uint64_rninta=uninstrumented
+fun:__bid64_to_uint64_xceil=uninstrumented
+fun:__bid64_to_uint64_xfloor=uninstrumented
+fun:__bid64_to_uint64_xint=uninstrumented
+fun:__bid64_to_uint64_xrnint=uninstrumented
+fun:__bid64_to_uint64_xrninta=uninstrumented
+fun:__bid64_totalOrder=uninstrumented
+fun:__bid64_totalOrderMag=uninstrumented
+fun:__bid64ddq_fma=uninstrumented
+fun:__bid64dq_add=uninstrumented
+fun:__bid64dq_div=uninstrumented
+fun:__bid64dq_mul=uninstrumented
+fun:__bid64dq_sub=uninstrumented
+fun:__bid64dqd_fma=uninstrumented
+fun:__bid64dqq_fma=uninstrumented
+fun:__bid64qd_add=uninstrumented
+fun:__bid64qd_div=uninstrumented
+fun:__bid64qd_mul=uninstrumented
+fun:__bid64qd_sub=uninstrumented
+fun:__bid64qdd_fma=uninstrumented
+fun:__bid64qdq_fma=uninstrumented
+fun:__bid64qq_add=uninstrumented
+fun:__bid64qq_div=uninstrumented
+fun:__bid64qq_mul=uninstrumented
+fun:__bid64qq_sub=uninstrumented
+fun:__bid64qqd_fma=uninstrumented
+fun:__bid64qqq_fma=uninstrumented
+fun:__bid_adddd3=uninstrumented
+fun:__bid_addsd3=uninstrumented
+fun:__bid_addtd3=uninstrumented
+fun:__bid_divdd3=uninstrumented
+fun:__bid_divsd3=uninstrumented
+fun:__bid_divtd3=uninstrumented
+fun:__bid_eqdd2=uninstrumented
+fun:__bid_eqsd2=uninstrumented
+fun:__bid_eqtd2=uninstrumented
+fun:__bid_extendddtd2=uninstrumented
+fun:__bid_extendddtf=uninstrumented
+fun:__bid_extendddxf=uninstrumented
+fun:__bid_extenddfdd=uninstrumented
+fun:__bid_extenddftd=uninstrumented
+fun:__bid_extendsddd2=uninstrumented
+fun:__bid_extendsddf=uninstrumented
+fun:__bid_extendsdtd2=uninstrumented
+fun:__bid_extendsdtf=uninstrumented
+fun:__bid_extendsdxf=uninstrumented
+fun:__bid_extendsfdd=uninstrumented
+fun:__bid_extendsfsd=uninstrumented
+fun:__bid_extendsftd=uninstrumented
+fun:__bid_extendtftd=uninstrumented
+fun:__bid_extendxftd=uninstrumented
+fun:__bid_fixdddi=uninstrumented
+fun:__bid_fixddsi=uninstrumented
+fun:__bid_fixsddi=uninstrumented
+fun:__bid_fixsdsi=uninstrumented
+fun:__bid_fixtddi=uninstrumented
+fun:__bid_fixtdsi=uninstrumented
+fun:__bid_fixunsdddi=uninstrumented
+fun:__bid_fixunsddsi=uninstrumented
+fun:__bid_fixunssddi=uninstrumented
+fun:__bid_fixunssdsi=uninstrumented
+fun:__bid_fixunstddi=uninstrumented
+fun:__bid_fixunstdsi=uninstrumented
+fun:__bid_floatdidd=uninstrumented
+fun:__bid_floatdisd=uninstrumented
+fun:__bid_floatditd=uninstrumented
+fun:__bid_floatsidd=uninstrumented
+fun:__bid_floatsisd=uninstrumented
+fun:__bid_floatsitd=uninstrumented
+fun:__bid_floatunsdidd=uninstrumented
+fun:__bid_floatunsdisd=uninstrumented
+fun:__bid_floatunsditd=uninstrumented
+fun:__bid_floatunssidd=uninstrumented
+fun:__bid_floatunssisd=uninstrumented
+fun:__bid_floatunssitd=uninstrumented
+fun:__bid_gedd2=uninstrumented
+fun:__bid_gesd2=uninstrumented
+fun:__bid_getd2=uninstrumented
+fun:__bid_gtdd2=uninstrumented
+fun:__bid_gtsd2=uninstrumented
+fun:__bid_gttd2=uninstrumented
+fun:__bid_ledd2=uninstrumented
+fun:__bid_lesd2=uninstrumented
+fun:__bid_letd2=uninstrumented
+fun:__bid_ltdd2=uninstrumented
+fun:__bid_ltsd2=uninstrumented
+fun:__bid_lttd2=uninstrumented
+fun:__bid_muldd3=uninstrumented
+fun:__bid_mulsd3=uninstrumented
+fun:__bid_multd3=uninstrumented
+fun:__bid_nedd2=uninstrumented
+fun:__bid_nesd2=uninstrumented
+fun:__bid_netd2=uninstrumented
+fun:__bid_round128_19_38=uninstrumented
+fun:__bid_round192_39_57=uninstrumented
+fun:__bid_round256_58_76=uninstrumented
+fun:__bid_round64_2_18=uninstrumented
+fun:__bid_subdd3=uninstrumented
+fun:__bid_subsd3=uninstrumented
+fun:__bid_subtd3=uninstrumented
+fun:__bid_truncdddf=uninstrumented
+fun:__bid_truncddsd2=uninstrumented
+fun:__bid_truncddsf=uninstrumented
+fun:__bid_truncdfsd=uninstrumented
+fun:__bid_truncsdsf=uninstrumented
+fun:__bid_trunctddd2=uninstrumented
+fun:__bid_trunctddf=uninstrumented
+fun:__bid_trunctdsd2=uninstrumented
+fun:__bid_trunctdsf=uninstrumented
+fun:__bid_trunctdtf=uninstrumented
+fun:__bid_trunctdxf=uninstrumented
+fun:__bid_trunctfdd=uninstrumented
+fun:__bid_trunctfsd=uninstrumented
+fun:__bid_truncxfdd=uninstrumented
+fun:__bid_truncxfsd=uninstrumented
+fun:__bid_unorddd2=uninstrumented
+fun:__bid_unordsd2=uninstrumented
+fun:__bid_unordtd2=uninstrumented
+fun:__binary128_to_bid128=uninstrumented
+fun:__binary128_to_bid32=uninstrumented
+fun:__binary128_to_bid64=uninstrumented
+fun:__binary32_to_bid128=uninstrumented
+fun:__binary32_to_bid32=uninstrumented
+fun:__binary32_to_bid64=uninstrumented
+fun:__binary64_to_bid128=uninstrumented
+fun:__binary64_to_bid32=uninstrumented
+fun:__binary64_to_bid64=uninstrumented
+fun:__binary80_to_bid128=uninstrumented
+fun:__binary80_to_bid32=uninstrumented
+fun:__binary80_to_bid64=uninstrumented
+fun:__bsd_getpgrp=uninstrumented
+fun:__bswapdi2=uninstrumented
+fun:__bswapsi2=uninstrumented
+fun:__bzero=uninstrumented
+fun:__call_tls_dtors=uninstrumented
+fun:__chk_fail=uninstrumented
+fun:__clear_cache=uninstrumented
+fun:__clock_getcpuclockid=uninstrumented
+fun:__clock_getres=uninstrumented
+fun:__clock_gettime=uninstrumented
+fun:__clock_nanosleep=uninstrumented
+fun:__clock_settime=uninstrumented
+fun:__clog10=uninstrumented
+fun:__clog10f=uninstrumented
+fun:__clog10l=uninstrumented
+fun:__clone=uninstrumented
+fun:__close=uninstrumented
+fun:__clrsbdi2=uninstrumented
+fun:__clrsbti2=uninstrumented
+fun:__clzdi2=uninstrumented
+fun:__clzti2=uninstrumented
+fun:__cmpti2=uninstrumented
+fun:__cmsg_nxthdr=uninstrumented
+fun:__confstr_chk=uninstrumented
+fun:__connect=uninstrumented
+fun:__cosh_finite=uninstrumented
+fun:__coshf_finite=uninstrumented
+fun:__coshl_finite=uninstrumented
+fun:__cpu_indicator_init=uninstrumented
+fun:__create_ib_request=uninstrumented
+fun:__ctype_b_loc=uninstrumented
+fun:__ctype_get_mb_cur_max=uninstrumented
+fun:__ctype_init=uninstrumented
+fun:__ctype_tolower_loc=uninstrumented
+fun:__ctype_toupper_loc=uninstrumented
+fun:__ctzdi2=uninstrumented
+fun:__ctzti2=uninstrumented
+fun:__cxa_at_quick_exit=uninstrumented
+fun:__cxa_atexit=uninstrumented
+fun:__cxa_finalize=uninstrumented
+fun:__cxa_thread_atexit_impl=uninstrumented
+fun:__cyg_profile_func_enter=uninstrumented
+fun:__cyg_profile_func_exit=uninstrumented
+fun:__dcgettext=uninstrumented
+fun:__default_morecore=uninstrumented
+fun:__deregister_frame=uninstrumented
+fun:__deregister_frame_info=uninstrumented
+fun:__deregister_frame_info_bases=uninstrumented
+fun:__dfp_clear_except=uninstrumented
+fun:__dfp_get_round=uninstrumented
+fun:__dfp_raise_except=uninstrumented
+fun:__dfp_set_round=uninstrumented
+fun:__dfp_test_except=uninstrumented
+fun:__dgettext=uninstrumented
+fun:__divdc3=uninstrumented
+fun:__divsc3=uninstrumented
+fun:__divtc3=uninstrumented
+fun:__divtf3=uninstrumented
+fun:__divti3=uninstrumented
+fun:__divxc3=uninstrumented
+fun:__dn_comp=uninstrumented
+fun:__dn_count_labels=uninstrumented
+fun:__dn_expand=uninstrumented
+fun:__dn_skipname=uninstrumented
+fun:__do_niscall3=uninstrumented
+fun:__dprintf_chk=uninstrumented
+fun:__dup2=uninstrumented
+fun:__duplocale=uninstrumented
+fun:__emutls_get_address=uninstrumented
+fun:__emutls_register_common=uninstrumented
+fun:__enable_execute_stack=uninstrumented
+fun:__endmntent=uninstrumented
+fun:__eprintf=uninstrumented
+fun:__eqtf2=uninstrumented
+fun:__errno_location=uninstrumented
+fun:__exp10_finite=uninstrumented
+fun:__exp10f_finite=uninstrumented
+fun:__exp10l_finite=uninstrumented
+fun:__exp2_finite=uninstrumented
+fun:__exp2f_finite=uninstrumented
+fun:__exp2l_finite=uninstrumented
+fun:__exp_finite=uninstrumented
+fun:__expf_finite=uninstrumented
+fun:__expl_finite=uninstrumented
+fun:__extenddftf2=uninstrumented
+fun:__extendsftf2=uninstrumented
+fun:__extendxftf2=uninstrumented
+fun:__fbufsize=uninstrumented
+fun:__fcntl=uninstrumented
+fun:__fdelt_chk=uninstrumented
+fun:__fdelt_warn=uninstrumented
+fun:__fentry__=uninstrumented
+fun:__ffs=uninstrumented
+fun:__ffsdi2=uninstrumented
+fun:__ffsti2=uninstrumented
+fun:__fgets_chk=uninstrumented
+fun:__fgets_unlocked_chk=uninstrumented
+fun:__fgetws_chk=uninstrumented
+fun:__fgetws_unlocked_chk=uninstrumented
+fun:__finite=uninstrumented
+fun:__finitef=uninstrumented
+fun:__finitel=uninstrumented
+fun:__fixdfti=uninstrumented
+fun:__fixsfti=uninstrumented
+fun:__fixtfdi=uninstrumented
+fun:__fixtfsi=uninstrumented
+fun:__fixtfti=uninstrumented
+fun:__fixunsdfdi=uninstrumented
+fun:__fixunsdfti=uninstrumented
+fun:__fixunssfdi=uninstrumented
+fun:__fixunssfti=uninstrumented
+fun:__fixunstfdi=uninstrumented
+fun:__fixunstfsi=uninstrumented
+fun:__fixunstfti=uninstrumented
+fun:__fixunsxfdi=uninstrumented
+fun:__fixunsxfti=uninstrumented
+fun:__fixxfti=uninstrumented
+fun:__flbf=uninstrumented
+fun:__floatditf=uninstrumented
+fun:__floatsitf=uninstrumented
+fun:__floattidf=uninstrumented
+fun:__floattisf=uninstrumented
+fun:__floattitf=uninstrumented
+fun:__floattixf=uninstrumented
+fun:__floatunditf=uninstrumented
+fun:__floatunsitf=uninstrumented
+fun:__floatuntidf=uninstrumented
+fun:__floatuntisf=uninstrumented
+fun:__floatuntitf=uninstrumented
+fun:__floatuntixf=uninstrumented
+fun:__fmod_finite=uninstrumented
+fun:__fmodf_finite=uninstrumented
+fun:__fmodl_finite=uninstrumented
+fun:__follow_path=uninstrumented
+fun:__fork=uninstrumented
+fun:__fortify_fail=uninstrumented
+fun:__fp_nquery=uninstrumented
+fun:__fp_query=uninstrumented
+fun:__fp_resstat=uninstrumented
+fun:__fpclassify=uninstrumented
+fun:__fpclassifyf=uninstrumented
+fun:__fpclassifyl=uninstrumented
+fun:__fpending=uninstrumented
+fun:__fprintf_chk=uninstrumented
+fun:__fpurge=uninstrumented
+fun:__fread_chk=uninstrumented
+fun:__fread_unlocked_chk=uninstrumented
+fun:__freadable=uninstrumented
+fun:__freading=uninstrumented
+fun:__free_fdresult=uninstrumented
+fun:__freelocale=uninstrumented
+fun:__fsetlocking=uninstrumented
+fun:__fstat=uninstrumented
+fun:__fwprintf_chk=uninstrumented
+fun:__fwritable=uninstrumented
+fun:__fwriting=uninstrumented
+fun:__fxstat=uninstrumented
+fun:__fxstat64=uninstrumented
+fun:__fxstatat=uninstrumented
+fun:__fxstatat64=uninstrumented
+fun:__gai_sigqueue=uninstrumented
+fun:__gamma_r_finite=uninstrumented
+fun:__gammaf_r_finite=uninstrumented
+fun:__gammal_r_finite=uninstrumented
+fun:__gcc_bcmp=uninstrumented
+fun:__gcc_personality_v0=uninstrumented
+fun:__gconv_get_alias_db=uninstrumented
+fun:__gconv_get_cache=uninstrumented
+fun:__gconv_get_modules_db=uninstrumented
+fun:__generic_findstack=uninstrumented
+fun:__generic_morestack=uninstrumented
+fun:__generic_morestack_set_initial_sp=uninstrumented
+fun:__generic_releasestack=uninstrumented
+fun:__get_cpu_features=uninstrumented
+fun:__getauxval=uninstrumented
+fun:__getcwd_chk=uninstrumented
+fun:__getdelim=uninstrumented
+fun:__getdomainname_chk=uninstrumented
+fun:__getf2=uninstrumented
+fun:__getgroups_chk=uninstrumented
+fun:__gethostname_chk=uninstrumented
+fun:__getlogin_r_chk=uninstrumented
+fun:__getmntent_r=uninstrumented
+fun:__getpagesize=uninstrumented
+fun:__getpgid=uninstrumented
+fun:__getpid=uninstrumented
+fun:__gets_chk=uninstrumented
+fun:__gettimeofday=uninstrumented
+fun:__getwd_chk=uninstrumented
+fun:__gmtime_r=uninstrumented
+fun:__gttf2=uninstrumented
+fun:__h_errno_location=uninstrumented
+fun:__hostalias=uninstrumented
+fun:__hypot_finite=uninstrumented
+fun:__hypotf_finite=uninstrumented
+fun:__hypotl_finite=uninstrumented
+fun:__internal_endnetgrent=uninstrumented
+fun:__internal_getnetgrent_r=uninstrumented
+fun:__internal_setnetgrent=uninstrumented
+fun:__isalnum_l=uninstrumented
+fun:__isalpha_l=uninstrumented
+fun:__isascii_l=uninstrumented
+fun:__isblank_l=uninstrumented
+fun:__iscntrl_l=uninstrumented
+fun:__isctype=uninstrumented
+fun:__isdigit_l=uninstrumented
+fun:__isgraph_l=uninstrumented
+fun:__isinf=uninstrumented
+fun:__isinff=uninstrumented
+fun:__isinfl=uninstrumented
+fun:__islower_l=uninstrumented
+fun:__isnan=uninstrumented
+fun:__isnanf=uninstrumented
+fun:__isnanl=uninstrumented
+fun:__isoc99_fscanf=uninstrumented
+fun:__isoc99_fwscanf=uninstrumented
+fun:__isoc99_scanf=uninstrumented
+fun:__isoc99_sscanf=uninstrumented
+fun:__isoc99_swscanf=uninstrumented
+fun:__isoc99_vfscanf=uninstrumented
+fun:__isoc99_vfwscanf=uninstrumented
+fun:__isoc99_vscanf=uninstrumented
+fun:__isoc99_vsscanf=uninstrumented
+fun:__isoc99_vswscanf=uninstrumented
+fun:__isoc99_vwscanf=uninstrumented
+fun:__isoc99_wscanf=uninstrumented
+fun:__isprint_l=uninstrumented
+fun:__ispunct_l=uninstrumented
+fun:__issignaling=uninstrumented
+fun:__issignalingf=uninstrumented
+fun:__issignalingl=uninstrumented
+fun:__isspace_l=uninstrumented
+fun:__isupper_l=uninstrumented
+fun:__iswalnum_l=uninstrumented
+fun:__iswalpha_l=uninstrumented
+fun:__iswblank_l=uninstrumented
+fun:__iswcntrl_l=uninstrumented
+fun:__iswctype=uninstrumented
+fun:__iswctype_l=uninstrumented
+fun:__iswdigit_l=uninstrumented
+fun:__iswgraph_l=uninstrumented
+fun:__iswlower_l=uninstrumented
+fun:__iswprint_l=uninstrumented
+fun:__iswpunct_l=uninstrumented
+fun:__iswspace_l=uninstrumented
+fun:__iswupper_l=uninstrumented
+fun:__iswxdigit_l=uninstrumented
+fun:__isxdigit_l=uninstrumented
+fun:__ivaliduser=uninstrumented
+fun:__j0_finite=uninstrumented
+fun:__j0f_finite=uninstrumented
+fun:__j0l_finite=uninstrumented
+fun:__j1_finite=uninstrumented
+fun:__j1f_finite=uninstrumented
+fun:__j1l_finite=uninstrumented
+fun:__jn_finite=uninstrumented
+fun:__jnf_finite=uninstrumented
+fun:__jnl_finite=uninstrumented
+fun:__letf2=uninstrumented
+fun:__lgamma_r_finite=uninstrumented
+fun:__lgammaf_r_finite=uninstrumented
+fun:__lgammal_r_finite=uninstrumented
+fun:__libc_alloca_cutoff=uninstrumented
+fun:__libc_allocate_rtsig=uninstrumented
+fun:__libc_allocate_rtsig_private=uninstrumented
+fun:__libc_calloc=uninstrumented
+fun:__libc_clntudp_bufcreate=uninstrumented
+fun:__libc_csu_fini=uninstrumented
+fun:__libc_csu_init=uninstrumented
+fun:__libc_current_sigrtmax=uninstrumented
+fun:__libc_current_sigrtmax_private=uninstrumented
+fun:__libc_current_sigrtmin=uninstrumented
+fun:__libc_current_sigrtmin_private=uninstrumented
+fun:__libc_dl_error_tsd=uninstrumented
+fun:__libc_dlclose=uninstrumented
+fun:__libc_dlopen_mode=uninstrumented
+fun:__libc_dlsym=uninstrumented
+fun:__libc_fatal=uninstrumented
+fun:__libc_fork=uninstrumented
+fun:__libc_free=uninstrumented
+fun:__libc_freeres=uninstrumented
+fun:__libc_ifunc_impl_list=uninstrumented
+fun:__libc_init_first=uninstrumented
+fun:__libc_longjmp=uninstrumented
+fun:__libc_mallinfo=uninstrumented
+fun:__libc_malloc=uninstrumented
+fun:__libc_mallopt=uninstrumented
+fun:__libc_memalign=uninstrumented
+fun:__libc_pthread_init=uninstrumented
+fun:__libc_pvalloc=uninstrumented
+fun:__libc_pwrite=uninstrumented
+fun:__libc_realloc=uninstrumented
+fun:__libc_res_nquery=uninstrumented
+fun:__libc_res_nsearch=uninstrumented
+fun:__libc_rpc_getport=uninstrumented
+fun:__libc_sa_len=uninstrumented
+fun:__libc_secure_getenv=uninstrumented
+fun:__libc_siglongjmp=uninstrumented
+fun:__libc_start_main=uninstrumented
+fun:__libc_system=uninstrumented
+fun:__libc_thread_freeres=uninstrumented
+fun:__libc_valloc=uninstrumented
+fun:__loc_aton=uninstrumented
+fun:__loc_ntoa=uninstrumented
+fun:__log10_finite=uninstrumented
+fun:__log10f_finite=uninstrumented
+fun:__log10l_finite=uninstrumented
+fun:__log2_finite=uninstrumented
+fun:__log2f_finite=uninstrumented
+fun:__log2l_finite=uninstrumented
+fun:__log_finite=uninstrumented
+fun:__logf_finite=uninstrumented
+fun:__logl_finite=uninstrumented
+fun:__longjmp_chk=uninstrumented
+fun:__lseek=uninstrumented
+fun:__lshrti3=uninstrumented
+fun:__lstat=uninstrumented
+fun:__lttf2=uninstrumented
+fun:__lxstat=uninstrumented
+fun:__lxstat64=uninstrumented
+fun:__madvise=uninstrumented
+fun:__mbrlen=uninstrumented
+fun:__mbrtowc=uninstrumented
+fun:__mbsnrtowcs_chk=uninstrumented
+fun:__mbsrtowcs_chk=uninstrumented
+fun:__mbstowcs_chk=uninstrumented
+fun:__memcpy_chk=uninstrumented
+fun:__memmove_chk=uninstrumented
+fun:__mempcpy=uninstrumented
+fun:__mempcpy_chk=uninstrumented
+fun:__mempcpy_small=uninstrumented
+fun:__memset_chk=uninstrumented
+fun:__mknod=uninstrumented
+fun:__mktemp=uninstrumented
+fun:__modti3=uninstrumented
+fun:__monstartup=uninstrumented
+fun:__morestack=uninstrumented
+fun:__morestack_allocate_stack_space=uninstrumented
+fun:__morestack_block_signals=uninstrumented
+fun:__morestack_fail=uninstrumented
+fun:__morestack_get_guard=uninstrumented
+fun:__morestack_large_model=uninstrumented
+fun:__morestack_load_mmap=uninstrumented
+fun:__morestack_make_guard=uninstrumented
+fun:__morestack_non_split=uninstrumented
+fun:__morestack_release_segments=uninstrumented
+fun:__morestack_set_guard=uninstrumented
+fun:__morestack_unblock_signals=uninstrumented
+fun:__mq_open_2=uninstrumented
+fun:__muldc3=uninstrumented
+fun:__mulsc3=uninstrumented
+fun:__multc3=uninstrumented
+fun:__multf3=uninstrumented
+fun:__multi3=uninstrumented
+fun:__mulvdi3=uninstrumented
+fun:__mulvsi3=uninstrumented
+fun:__mulvti3=uninstrumented
+fun:__mulxc3=uninstrumented
+fun:__nanosleep=uninstrumented
+fun:__negtf2=uninstrumented
+fun:__negti2=uninstrumented
+fun:__negvdi2=uninstrumented
+fun:__negvsi2=uninstrumented
+fun:__negvti2=uninstrumented
+fun:__netf2=uninstrumented
+fun:__newlocale=uninstrumented
+fun:__nis_default_access=uninstrumented
+fun:__nis_default_group=uninstrumented
+fun:__nis_default_owner=uninstrumented
+fun:__nis_default_ttl=uninstrumented
+fun:__nis_finddirectory=uninstrumented
+fun:__nis_hash=uninstrumented
+fun:__nisbind_connect=uninstrumented
+fun:__nisbind_create=uninstrumented
+fun:__nisbind_destroy=uninstrumented
+fun:__nisbind_next=uninstrumented
+fun:__nl_langinfo_l=uninstrumented
+fun:__ns_get16=uninstrumented
+fun:__ns_get32=uninstrumented
+fun:__ns_name_ntop=uninstrumented
+fun:__ns_name_unpack=uninstrumented
+fun:__nss_configure_lookup=uninstrumented
+fun:__nss_database_lookup=uninstrumented
+fun:__nss_disable_nscd=uninstrumented
+fun:__nss_group_lookup=uninstrumented
+fun:__nss_group_lookup2=uninstrumented
+fun:__nss_hostname_digits_dots=uninstrumented
+fun:__nss_hosts_lookup=uninstrumented
+fun:__nss_hosts_lookup2=uninstrumented
+fun:__nss_lookup=uninstrumented
+fun:__nss_lookup_function=uninstrumented
+fun:__nss_next=uninstrumented
+fun:__nss_next2=uninstrumented
+fun:__nss_passwd_lookup=uninstrumented
+fun:__nss_passwd_lookup2=uninstrumented
+fun:__nss_services_lookup2=uninstrumented
+fun:__obstack_printf_chk=uninstrumented
+fun:__obstack_vprintf_chk=uninstrumented
+fun:__open=uninstrumented
+fun:__open64=uninstrumented
+fun:__open64_2=uninstrumented
+fun:__open_2=uninstrumented
+fun:__open_catalog=uninstrumented
+fun:__openat64_2=uninstrumented
+fun:__openat_2=uninstrumented
+fun:__overflow=uninstrumented
+fun:__p_cdname=uninstrumented
+fun:__p_cdnname=uninstrumented
+fun:__p_class=uninstrumented
+fun:__p_fqname=uninstrumented
+fun:__p_fqnname=uninstrumented
+fun:__p_option=uninstrumented
+fun:__p_query=uninstrumented
+fun:__p_rcode=uninstrumented
+fun:__p_secstodate=uninstrumented
+fun:__p_time=uninstrumented
+fun:__p_type=uninstrumented
+fun:__paritydi2=uninstrumented
+fun:__parityti2=uninstrumented
+fun:__pipe=uninstrumented
+fun:__poll=uninstrumented
+fun:__poll_chk=uninstrumented
+fun:__popcountdi2=uninstrumented
+fun:__popcountti2=uninstrumented
+fun:__posix_getopt=uninstrumented
+fun:__pow_finite=uninstrumented
+fun:__powf_finite=uninstrumented
+fun:__powidf2=uninstrumented
+fun:__powisf2=uninstrumented
+fun:__powitf2=uninstrumented
+fun:__powixf2=uninstrumented
+fun:__powl_finite=uninstrumented
+fun:__ppoll_chk=uninstrumented
+fun:__pread64=uninstrumented
+fun:__pread64_chk=uninstrumented
+fun:__pread_chk=uninstrumented
+fun:__prepare_niscall=uninstrumented
+fun:__printf_chk=uninstrumented
+fun:__printf_fp=uninstrumented
+fun:__profile_frequency=uninstrumented
+fun:__pthread_atfork=uninstrumented
+fun:__pthread_cleanup_routine=uninstrumented
+fun:__pthread_clock_gettime=uninstrumented
+fun:__pthread_clock_settime=uninstrumented
+fun:__pthread_get_minstack=uninstrumented
+fun:__pthread_getspecific=uninstrumented
+fun:__pthread_initialize_minimal=uninstrumented
+fun:__pthread_key_create=uninstrumented
+fun:__pthread_mutex_destroy=uninstrumented
+fun:__pthread_mutex_init=uninstrumented
+fun:__pthread_mutex_lock=uninstrumented
+fun:__pthread_mutex_trylock=uninstrumented
+fun:__pthread_mutex_unlock=uninstrumented
+fun:__pthread_mutexattr_destroy=uninstrumented
+fun:__pthread_mutexattr_init=uninstrumented
+fun:__pthread_mutexattr_settype=uninstrumented
+fun:__pthread_once=uninstrumented
+fun:__pthread_register_cancel=uninstrumented
+fun:__pthread_register_cancel_defer=uninstrumented
+fun:__pthread_rwlock_destroy=uninstrumented
+fun:__pthread_rwlock_init=uninstrumented
+fun:__pthread_rwlock_rdlock=uninstrumented
+fun:__pthread_rwlock_tryrdlock=uninstrumented
+fun:__pthread_rwlock_trywrlock=uninstrumented
+fun:__pthread_rwlock_unlock=uninstrumented
+fun:__pthread_rwlock_wrlock=uninstrumented
+fun:__pthread_setspecific=uninstrumented
+fun:__pthread_unregister_cancel=uninstrumented
+fun:__pthread_unregister_cancel_restore=uninstrumented
+fun:__pthread_unwind=uninstrumented
+fun:__pthread_unwind_next=uninstrumented
+fun:__ptsname_r_chk=uninstrumented
+fun:__putlong=uninstrumented
+fun:__putshort=uninstrumented
+fun:__pwrite64=uninstrumented
+fun:__rawmemchr=uninstrumented
+fun:__read=uninstrumented
+fun:__read_chk=uninstrumented
+fun:__readlink_chk=uninstrumented
+fun:__readlinkat_chk=uninstrumented
+fun:__realpath_chk=uninstrumented
+fun:__recv_chk=uninstrumented
+fun:__recvfrom_chk=uninstrumented
+fun:__register_atfork=uninstrumented
+fun:__register_frame=uninstrumented
+fun:__register_frame_info=uninstrumented
+fun:__register_frame_info_bases=uninstrumented
+fun:__register_frame_info_table=uninstrumented
+fun:__register_frame_info_table_bases=uninstrumented
+fun:__register_frame_table=uninstrumented
+fun:__remainder_finite=uninstrumented
+fun:__remainderf_finite=uninstrumented
+fun:__remainderl_finite=uninstrumented
+fun:__res_close=uninstrumented
+fun:__res_dnok=uninstrumented
+fun:__res_hnok=uninstrumented
+fun:__res_hostalias=uninstrumented
+fun:__res_iclose=uninstrumented
+fun:__res_init=uninstrumented
+fun:__res_isourserver=uninstrumented
+fun:__res_mailok=uninstrumented
+fun:__res_maybe_init=uninstrumented
+fun:__res_mkquery=uninstrumented
+fun:__res_nameinquery=uninstrumented
+fun:__res_nclose=uninstrumented
+fun:__res_ninit=uninstrumented
+fun:__res_nmkquery=uninstrumented
+fun:__res_nquery=uninstrumented
+fun:__res_nquerydomain=uninstrumented
+fun:__res_nsearch=uninstrumented
+fun:__res_nsend=uninstrumented
+fun:__res_ownok=uninstrumented
+fun:__res_queriesmatch=uninstrumented
+fun:__res_query=uninstrumented
+fun:__res_querydomain=uninstrumented
+fun:__res_randomid=uninstrumented
+fun:__res_search=uninstrumented
+fun:__res_send=uninstrumented
+fun:__res_state=uninstrumented
+fun:__rpc_thread_createerr=uninstrumented
+fun:__rpc_thread_svc_fdset=uninstrumented
+fun:__rpc_thread_svc_max_pollfd=uninstrumented
+fun:__rpc_thread_svc_pollfd=uninstrumented
+fun:__sbrk=uninstrumented
+fun:__scalb_finite=uninstrumented
+fun:__scalbf_finite=uninstrumented
+fun:__scalbl_finite=uninstrumented
+fun:__sched_cpualloc=uninstrumented
+fun:__sched_cpucount=uninstrumented
+fun:__sched_cpufree=uninstrumented
+fun:__sched_get_priority_max=uninstrumented
+fun:__sched_get_priority_min=uninstrumented
+fun:__sched_getparam=uninstrumented
+fun:__sched_getscheduler=uninstrumented
+fun:__sched_setscheduler=uninstrumented
+fun:__sched_yield=uninstrumented
+fun:__secure_getenv=uninstrumented
+fun:__select=uninstrumented
+fun:__send=uninstrumented
+fun:__sendmmsg=uninstrumented
+fun:__setmntent=uninstrumented
+fun:__setpgid=uninstrumented
+fun:__sfp_handle_exceptions=uninstrumented
+fun:__sigaction=uninstrumented
+fun:__sigaddset=uninstrumented
+fun:__sigdelset=uninstrumented
+fun:__sigismember=uninstrumented
+fun:__signbit=uninstrumented
+fun:__signbitf=uninstrumented
+fun:__signbitl=uninstrumented
+fun:__sigpause=uninstrumented
+fun:__sigsetjmp=uninstrumented
+fun:__sigsuspend=uninstrumented
+fun:__sinh_finite=uninstrumented
+fun:__sinhf_finite=uninstrumented
+fun:__sinhl_finite=uninstrumented
+fun:__snprintf_chk=uninstrumented
+fun:__splitstack_block_signals=uninstrumented
+fun:__splitstack_block_signals_context=uninstrumented
+fun:__splitstack_find=uninstrumented
+fun:__splitstack_find_context=uninstrumented
+fun:__splitstack_getcontext=uninstrumented
+fun:__splitstack_makecontext=uninstrumented
+fun:__splitstack_releasecontext=uninstrumented
+fun:__splitstack_resetcontext=uninstrumented
+fun:__splitstack_setcontext=uninstrumented
+fun:__sprintf_chk=uninstrumented
+fun:__sqrt_finite=uninstrumented
+fun:__sqrtf_finite=uninstrumented
+fun:__sqrtl_finite=uninstrumented
+fun:__stack_chk_fail=uninstrumented
+fun:__stack_chk_fail_local=uninstrumented
+fun:__stack_split_initialize=uninstrumented
+fun:__stat=uninstrumented
+fun:__statfs=uninstrumented
+fun:__stpcpy=uninstrumented
+fun:__stpcpy_chk=uninstrumented
+fun:__stpcpy_small=uninstrumented
+fun:__stpncpy=uninstrumented
+fun:__stpncpy_chk=uninstrumented
+fun:__strcasecmp=uninstrumented
+fun:__strcasecmp_l=uninstrumented
+fun:__strcasestr=uninstrumented
+fun:__strcat_chk=uninstrumented
+fun:__strcoll_l=uninstrumented
+fun:__strcpy_chk=uninstrumented
+fun:__strcpy_small=uninstrumented
+fun:__strcspn_c1=uninstrumented
+fun:__strcspn_c2=uninstrumented
+fun:__strcspn_c3=uninstrumented
+fun:__strdup=uninstrumented
+fun:__strerror_r=uninstrumented
+fun:__strfmon_l=uninstrumented
+fun:__strftime_l=uninstrumented
+fun:__strncasecmp_l=uninstrumented
+fun:__strncat_chk=uninstrumented
+fun:__strncpy_chk=uninstrumented
+fun:__strndup=uninstrumented
+fun:__strpbrk_c2=uninstrumented
+fun:__strpbrk_c3=uninstrumented
+fun:__strsep_1c=uninstrumented
+fun:__strsep_2c=uninstrumented
+fun:__strsep_3c=uninstrumented
+fun:__strsep_g=uninstrumented
+fun:__strspn_c1=uninstrumented
+fun:__strspn_c2=uninstrumented
+fun:__strspn_c3=uninstrumented
+fun:__strtod_internal=uninstrumented
+fun:__strtod_l=uninstrumented
+fun:__strtof_internal=uninstrumented
+fun:__strtof_l=uninstrumented
+fun:__strtok_r=uninstrumented
+fun:__strtok_r_1c=uninstrumented
+fun:__strtol_internal=uninstrumented
+fun:__strtol_l=uninstrumented
+fun:__strtold_internal=uninstrumented
+fun:__strtold_l=uninstrumented
+fun:__strtoll_internal=uninstrumented
+fun:__strtoll_l=uninstrumented
+fun:__strtoul_internal=uninstrumented
+fun:__strtoul_l=uninstrumented
+fun:__strtoull_internal=uninstrumented
+fun:__strtoull_l=uninstrumented
+fun:__strverscmp=uninstrumented
+fun:__strxfrm_l=uninstrumented
+fun:__subtf3=uninstrumented
+fun:__subvdi3=uninstrumented
+fun:__subvsi3=uninstrumented
+fun:__subvti3=uninstrumented
+fun:__swprintf_chk=uninstrumented
+fun:__sym_ntop=uninstrumented
+fun:__sym_ntos=uninstrumented
+fun:__sym_ston=uninstrumented
+fun:__sysconf=uninstrumented
+fun:__sysctl=uninstrumented
+fun:__syslog_chk=uninstrumented
+fun:__sysv_signal=uninstrumented
+fun:__tls_get_addr=uninstrumented
+fun:__toascii_l=uninstrumented
+fun:__tolower_l=uninstrumented
+fun:__toupper_l=uninstrumented
+fun:__towctrans=uninstrumented
+fun:__towctrans_l=uninstrumented
+fun:__towlower_l=uninstrumented
+fun:__towupper_l=uninstrumented
+fun:__trunctfdf2=uninstrumented
+fun:__trunctfsf2=uninstrumented
+fun:__trunctfxf2=uninstrumented
+fun:__ttyname_r_chk=uninstrumented
+fun:__ucmpti2=uninstrumented
+fun:__udiv_w_sdiv=uninstrumented
+fun:__udivmodti4=uninstrumented
+fun:__udivti3=uninstrumented
+fun:__uflow=uninstrumented
+fun:__umodti3=uninstrumented
+fun:__underflow=uninstrumented
+fun:__unordtf2=uninstrumented
+fun:__uselocale=uninstrumented
+fun:__vasprintf_chk=uninstrumented
+fun:__vdprintf_chk=uninstrumented
+fun:__vfork=uninstrumented
+fun:__vfprintf_chk=uninstrumented
+fun:__vfscanf=uninstrumented
+fun:__vfwprintf_chk=uninstrumented
+fun:__vprintf_chk=uninstrumented
+fun:__vsnprintf=uninstrumented
+fun:__vsnprintf_chk=uninstrumented
+fun:__vsprintf_chk=uninstrumented
+fun:__vsscanf=uninstrumented
+fun:__vswprintf_chk=uninstrumented
+fun:__vsyslog_chk=uninstrumented
+fun:__vwprintf_chk=uninstrumented
+fun:__wait=uninstrumented
+fun:__waitpid=uninstrumented
+fun:__warn_memset_zero_len=uninstrumented
+fun:__wcpcpy_chk=uninstrumented
+fun:__wcpncpy_chk=uninstrumented
+fun:__wcrtomb_chk=uninstrumented
+fun:__wcscasecmp_l=uninstrumented
+fun:__wcscat_chk=uninstrumented
+fun:__wcscoll_l=uninstrumented
+fun:__wcscpy_chk=uninstrumented
+fun:__wcsftime_l=uninstrumented
+fun:__wcsncasecmp_l=uninstrumented
+fun:__wcsncat_chk=uninstrumented
+fun:__wcsncpy_chk=uninstrumented
+fun:__wcsnrtombs_chk=uninstrumented
+fun:__wcsrtombs_chk=uninstrumented
+fun:__wcstod_internal=uninstrumented
+fun:__wcstod_l=uninstrumented
+fun:__wcstof_internal=uninstrumented
+fun:__wcstof_l=uninstrumented
+fun:__wcstol_internal=uninstrumented
+fun:__wcstol_l=uninstrumented
+fun:__wcstold_internal=uninstrumented
+fun:__wcstold_l=uninstrumented
+fun:__wcstoll_internal=uninstrumented
+fun:__wcstoll_l=uninstrumented
+fun:__wcstombs_chk=uninstrumented
+fun:__wcstoul_internal=uninstrumented
+fun:__wcstoul_l=uninstrumented
+fun:__wcstoull_internal=uninstrumented
+fun:__wcstoull_l=uninstrumented
+fun:__wcsxfrm_l=uninstrumented
+fun:__wctomb_chk=uninstrumented
+fun:__wctrans_l=uninstrumented
+fun:__wctype_l=uninstrumented
+fun:__wmemcpy_chk=uninstrumented
+fun:__wmemmove_chk=uninstrumented
+fun:__wmempcpy_chk=uninstrumented
+fun:__wmemset_chk=uninstrumented
+fun:__woverflow=uninstrumented
+fun:__wprintf_chk=uninstrumented
+fun:__wrap_pthread_create=uninstrumented
+fun:__write=uninstrumented
+fun:__wuflow=uninstrumented
+fun:__wunderflow=uninstrumented
+fun:__xmknod=uninstrumented
+fun:__xmknodat=uninstrumented
+fun:__xpg_basename=uninstrumented
+fun:__xpg_sigpause=uninstrumented
+fun:__xpg_strerror_r=uninstrumented
+fun:__xstat=uninstrumented
+fun:__xstat64=uninstrumented
+fun:__y0_finite=uninstrumented
+fun:__y0f_finite=uninstrumented
+fun:__y0l_finite=uninstrumented
+fun:__y1_finite=uninstrumented
+fun:__y1f_finite=uninstrumented
+fun:__y1l_finite=uninstrumented
+fun:__yn_finite=uninstrumented
+fun:__ynf_finite=uninstrumented
+fun:__ynl_finite=uninstrumented
+fun:__yp_check=uninstrumented
+fun:_authenticate=uninstrumented
+fun:_dl_addr=uninstrumented
+fun:_dl_allocate_tls=uninstrumented
+fun:_dl_allocate_tls_init=uninstrumented
+fun:_dl_deallocate_tls=uninstrumented
+fun:_dl_debug_state=uninstrumented
+fun:_dl_find_dso_for_object=uninstrumented
+fun:_dl_get_tls_static_info=uninstrumented
+fun:_dl_make_stack_executable=uninstrumented
+fun:_dl_mcount=uninstrumented
+fun:_dl_mcount_wrapper=uninstrumented
+fun:_dl_mcount_wrapper_check=uninstrumented
+fun:_dl_rtld_di_serinfo=uninstrumented
+fun:_dl_sym=uninstrumented
+fun:_dl_tls_setup=uninstrumented
+fun:_dl_vsym=uninstrumented
+fun:_exit=uninstrumented
+fun:_flushlbf=uninstrumented
+fun:_gethtbyaddr=uninstrumented
+fun:_gethtbyname=uninstrumented
+fun:_gethtbyname2=uninstrumented
+fun:_gethtent=uninstrumented
+fun:_getlong=uninstrumented
+fun:_getshort=uninstrumented
+fun:_longjmp=uninstrumented
+fun:_mcleanup=uninstrumented
+fun:_mcount=uninstrumented
+fun:_nsl_default_nss=uninstrumented
+fun:_nss_files_parse_grent=uninstrumented
+fun:_nss_files_parse_pwent=uninstrumented
+fun:_nss_files_parse_sgent=uninstrumented
+fun:_nss_files_parse_spent=uninstrumented
+fun:_obstack_allocated_p=uninstrumented
+fun:_obstack_begin=uninstrumented
+fun:_obstack_begin_1=uninstrumented
+fun:_obstack_free=uninstrumented
+fun:_obstack_memory_used=uninstrumented
+fun:_obstack_newchunk=uninstrumented
+fun:_pthread_cleanup_pop=uninstrumented
+fun:_pthread_cleanup_pop_restore=uninstrumented
+fun:_pthread_cleanup_push=uninstrumented
+fun:_pthread_cleanup_push_defer=uninstrumented
+fun:_rpc_dtablesize=uninstrumented
+fun:_seterr_reply=uninstrumented
+fun:_sethtent=uninstrumented
+fun:_setjmp=uninstrumented
+fun:_tolower=uninstrumented
+fun:_toupper=uninstrumented
+fun:_xdr_ib_request=uninstrumented
+fun:_xdr_nis_result=uninstrumented
+fun:a64l=uninstrumented
+fun:abort=uninstrumented
+fun:abs=uninstrumented
+fun:accept=uninstrumented
+fun:accept4=uninstrumented
+fun:access=uninstrumented
+fun:acct=uninstrumented
+fun:acos=uninstrumented
+fun:acosf=uninstrumented
+fun:acosh=uninstrumented
+fun:acoshf=uninstrumented
+fun:acoshl=uninstrumented
+fun:acosl=uninstrumented
+fun:addmntent=uninstrumented
+fun:addseverity=uninstrumented
+fun:adjtime=uninstrumented
+fun:adjtimex=uninstrumented
+fun:advance=uninstrumented
+fun:aio_cancel=uninstrumented
+fun:aio_cancel64=uninstrumented
+fun:aio_error=uninstrumented
+fun:aio_error64=uninstrumented
+fun:aio_fsync=uninstrumented
+fun:aio_fsync64=uninstrumented
+fun:aio_init=uninstrumented
+fun:aio_read=uninstrumented
+fun:aio_read64=uninstrumented
+fun:aio_return=uninstrumented
+fun:aio_return64=uninstrumented
+fun:aio_suspend=uninstrumented
+fun:aio_suspend64=uninstrumented
+fun:aio_write=uninstrumented
+fun:aio_write64=uninstrumented
+fun:alarm=uninstrumented
+fun:aligned_alloc=uninstrumented
+fun:alphasort=uninstrumented
+fun:alphasort64=uninstrumented
+fun:arch_prctl=uninstrumented
+fun:argp_error=uninstrumented
+fun:argp_failure=uninstrumented
+fun:argp_help=uninstrumented
+fun:argp_parse=uninstrumented
+fun:argp_state_help=uninstrumented
+fun:argp_usage=uninstrumented
+fun:argz_add=uninstrumented
+fun:argz_add_sep=uninstrumented
+fun:argz_append=uninstrumented
+fun:argz_count=uninstrumented
+fun:argz_create=uninstrumented
+fun:argz_create_sep=uninstrumented
+fun:argz_delete=uninstrumented
+fun:argz_extract=uninstrumented
+fun:argz_insert=uninstrumented
+fun:argz_next=uninstrumented
+fun:argz_replace=uninstrumented
+fun:argz_stringify=uninstrumented
+fun:asctime=uninstrumented
+fun:asctime_r=uninstrumented
+fun:asin=uninstrumented
+fun:asinf=uninstrumented
+fun:asinh=uninstrumented
+fun:asinhf=uninstrumented
+fun:asinhl=uninstrumented
+fun:asinl=uninstrumented
+fun:asprintf=uninstrumented
+fun:at_quick_exit=uninstrumented
+fun:atan=uninstrumented
+fun:atan2=uninstrumented
+fun:atan2f=uninstrumented
+fun:atan2l=uninstrumented
+fun:atanf=uninstrumented
+fun:atanh=uninstrumented
+fun:atanhf=uninstrumented
+fun:atanhl=uninstrumented
+fun:atanl=uninstrumented
+fun:atexit=uninstrumented
+fun:atof=uninstrumented
+fun:atoi=uninstrumented
+fun:atol=uninstrumented
+fun:atoll=uninstrumented
+fun:authdes_create=uninstrumented
+fun:authdes_getucred=uninstrumented
+fun:authdes_pk_create=uninstrumented
+fun:authnone_create=uninstrumented
+fun:authunix_create=uninstrumented
+fun:authunix_create_default=uninstrumented
+fun:backtrace=uninstrumented
+fun:backtrace_symbols=uninstrumented
+fun:backtrace_symbols_fd=uninstrumented
+fun:basename=uninstrumented
+fun:bcmp=uninstrumented
+fun:bcopy=uninstrumented
+fun:bdflush=uninstrumented
+fun:bind=uninstrumented
+fun:bind_textdomain_codeset=uninstrumented
+fun:bindresvport=uninstrumented
+fun:bindtextdomain=uninstrumented
+fun:brk=uninstrumented
+fun:bsd_signal=uninstrumented
+fun:bsearch=uninstrumented
+fun:btowc=uninstrumented
+fun:bzero=uninstrumented
+fun:c16rtomb=uninstrumented
+fun:c32rtomb=uninstrumented
+fun:cabs=uninstrumented
+fun:cabsf=uninstrumented
+fun:cabsl=uninstrumented
+fun:cacos=uninstrumented
+fun:cacosf=uninstrumented
+fun:cacosh=uninstrumented
+fun:cacoshf=uninstrumented
+fun:cacoshl=uninstrumented
+fun:cacosl=uninstrumented
+fun:calloc=uninstrumented
+fun:callrpc=uninstrumented
+fun:canonicalize_file_name=uninstrumented
+fun:capget=uninstrumented
+fun:capset=uninstrumented
+fun:carg=uninstrumented
+fun:cargf=uninstrumented
+fun:cargl=uninstrumented
+fun:casin=uninstrumented
+fun:casinf=uninstrumented
+fun:casinh=uninstrumented
+fun:casinhf=uninstrumented
+fun:casinhl=uninstrumented
+fun:casinl=uninstrumented
+fun:catan=uninstrumented
+fun:catanf=uninstrumented
+fun:catanh=uninstrumented
+fun:catanhf=uninstrumented
+fun:catanhl=uninstrumented
+fun:catanl=uninstrumented
+fun:catclose=uninstrumented
+fun:catgets=uninstrumented
+fun:catopen=uninstrumented
+fun:cbc_crypt=uninstrumented
+fun:cbrt=uninstrumented
+fun:cbrtf=uninstrumented
+fun:cbrtl=uninstrumented
+fun:ccos=uninstrumented
+fun:ccosf=uninstrumented
+fun:ccosh=uninstrumented
+fun:ccoshf=uninstrumented
+fun:ccoshl=uninstrumented
+fun:ccosl=uninstrumented
+fun:ceil=uninstrumented
+fun:ceilf=uninstrumented
+fun:ceill=uninstrumented
+fun:cexp=uninstrumented
+fun:cexpf=uninstrumented
+fun:cexpl=uninstrumented
+fun:cfgetispeed=uninstrumented
+fun:cfgetospeed=uninstrumented
+fun:cfmakeraw=uninstrumented
+fun:cfree=uninstrumented
+fun:cfsetispeed=uninstrumented
+fun:cfsetospeed=uninstrumented
+fun:cfsetspeed=uninstrumented
+fun:chdir=uninstrumented
+fun:chflags=uninstrumented
+fun:chmod=uninstrumented
+fun:chown=uninstrumented
+fun:chroot=uninstrumented
+fun:cimag=uninstrumented
+fun:cimagf=uninstrumented
+fun:cimagl=uninstrumented
+fun:clearenv=uninstrumented
+fun:clearerr=uninstrumented
+fun:clearerr_unlocked=uninstrumented
+fun:clnt_broadcast=uninstrumented
+fun:clnt_create=uninstrumented
+fun:clnt_pcreateerror=uninstrumented
+fun:clnt_perrno=uninstrumented
+fun:clnt_perror=uninstrumented
+fun:clnt_spcreateerror=uninstrumented
+fun:clnt_sperrno=uninstrumented
+fun:clnt_sperror=uninstrumented
+fun:clntraw_create=uninstrumented
+fun:clnttcp_create=uninstrumented
+fun:clntudp_bufcreate=uninstrumented
+fun:clntudp_create=uninstrumented
+fun:clntunix_create=uninstrumented
+fun:clock=uninstrumented
+fun:clock_adjtime=uninstrumented
+fun:clock_getcpuclockid=uninstrumented
+fun:clock_getres=uninstrumented
+fun:clock_gettime=uninstrumented
+fun:clock_nanosleep=uninstrumented
+fun:clock_settime=uninstrumented
+fun:clog=uninstrumented
+fun:clog10=uninstrumented
+fun:clog10f=uninstrumented
+fun:clog10l=uninstrumented
+fun:clogf=uninstrumented
+fun:clogl=uninstrumented
+fun:clone=uninstrumented
+fun:close=uninstrumented
+fun:closedir=uninstrumented
+fun:closelog=uninstrumented
+fun:confstr=uninstrumented
+fun:conj=uninstrumented
+fun:conjf=uninstrumented
+fun:conjl=uninstrumented
+fun:connect=uninstrumented
+fun:copysign=uninstrumented
+fun:copysignf=uninstrumented
+fun:copysignl=uninstrumented
+fun:cos=uninstrumented
+fun:cosf=uninstrumented
+fun:cosh=uninstrumented
+fun:coshf=uninstrumented
+fun:coshl=uninstrumented
+fun:cosl=uninstrumented
+fun:cpow=uninstrumented
+fun:cpowf=uninstrumented
+fun:cpowl=uninstrumented
+fun:cproj=uninstrumented
+fun:cprojf=uninstrumented
+fun:cprojl=uninstrumented
+fun:creal=uninstrumented
+fun:crealf=uninstrumented
+fun:creall=uninstrumented
+fun:creat=uninstrumented
+fun:creat64=uninstrumented
+fun:create_module=uninstrumented
+fun:crypt=uninstrumented
+fun:crypt_r=uninstrumented
+fun:csin=uninstrumented
+fun:csinf=uninstrumented
+fun:csinh=uninstrumented
+fun:csinhf=uninstrumented
+fun:csinhl=uninstrumented
+fun:csinl=uninstrumented
+fun:csqrt=uninstrumented
+fun:csqrtf=uninstrumented
+fun:csqrtl=uninstrumented
+fun:ctan=uninstrumented
+fun:ctanf=uninstrumented
+fun:ctanh=uninstrumented
+fun:ctanhf=uninstrumented
+fun:ctanhl=uninstrumented
+fun:ctanl=uninstrumented
+fun:ctermid=uninstrumented
+fun:ctime=uninstrumented
+fun:ctime_r=uninstrumented
+fun:cuserid=uninstrumented
+fun:daemon=uninstrumented
+fun:dcgettext=uninstrumented
+fun:dcngettext=uninstrumented
+fun:delete_module=uninstrumented
+fun:des_setparity=uninstrumented
+fun:dgettext=uninstrumented
+fun:difftime=uninstrumented
+fun:dirfd=uninstrumented
+fun:dirname=uninstrumented
+fun:div=uninstrumented
+fun:dl_iterate_phdr=uninstrumented
+fun:dladdr=uninstrumented
+fun:dladdr1=uninstrumented
+fun:dlclose=uninstrumented
+fun:dlerror=uninstrumented
+fun:dlinfo=uninstrumented
+fun:dlmopen=uninstrumented
+fun:dlopen=uninstrumented
+fun:dlsym=uninstrumented
+fun:dlvsym=uninstrumented
+fun:dngettext=uninstrumented
+fun:dprintf=uninstrumented
+fun:drand48=uninstrumented
+fun:drand48_r=uninstrumented
+fun:drem=uninstrumented
+fun:dremf=uninstrumented
+fun:dreml=uninstrumented
+fun:dup=uninstrumented
+fun:dup2=uninstrumented
+fun:dup3=uninstrumented
+fun:duplocale=uninstrumented
+fun:dysize=uninstrumented
+fun:eaccess=uninstrumented
+fun:ecb_crypt=uninstrumented
+fun:ecvt=uninstrumented
+fun:ecvt_r=uninstrumented
+fun:encrypt=uninstrumented
+fun:encrypt_r=uninstrumented
+fun:endaliasent=uninstrumented
+fun:endfsent=uninstrumented
+fun:endgrent=uninstrumented
+fun:endhostent=uninstrumented
+fun:endmntent=uninstrumented
+fun:endnetent=uninstrumented
+fun:endnetgrent=uninstrumented
+fun:endprotoent=uninstrumented
+fun:endpwent=uninstrumented
+fun:endrpcent=uninstrumented
+fun:endservent=uninstrumented
+fun:endsgent=uninstrumented
+fun:endspent=uninstrumented
+fun:endttyent=uninstrumented
+fun:endusershell=uninstrumented
+fun:endutent=uninstrumented
+fun:endutxent=uninstrumented
+fun:envz_add=uninstrumented
+fun:envz_entry=uninstrumented
+fun:envz_get=uninstrumented
+fun:envz_merge=uninstrumented
+fun:envz_remove=uninstrumented
+fun:envz_strip=uninstrumented
+fun:epoll_create=uninstrumented
+fun:epoll_create1=uninstrumented
+fun:epoll_ctl=uninstrumented
+fun:epoll_pwait=uninstrumented
+fun:epoll_wait=uninstrumented
+fun:erand48=uninstrumented
+fun:erand48_r=uninstrumented
+fun:erf=uninstrumented
+fun:erfc=uninstrumented
+fun:erfcf=uninstrumented
+fun:erfcl=uninstrumented
+fun:erff=uninstrumented
+fun:erfl=uninstrumented
+fun:err=uninstrumented
+fun:error=uninstrumented
+fun:error_at_line=uninstrumented
+fun:errx=uninstrumented
+fun:ether_aton=uninstrumented
+fun:ether_aton_r=uninstrumented
+fun:ether_hostton=uninstrumented
+fun:ether_line=uninstrumented
+fun:ether_ntoa=uninstrumented
+fun:ether_ntoa_r=uninstrumented
+fun:ether_ntohost=uninstrumented
+fun:euidaccess=uninstrumented
+fun:eventfd=uninstrumented
+fun:eventfd_read=uninstrumented
+fun:eventfd_write=uninstrumented
+fun:execl=uninstrumented
+fun:execle=uninstrumented
+fun:execlp=uninstrumented
+fun:execv=uninstrumented
+fun:execve=uninstrumented
+fun:execvp=uninstrumented
+fun:execvpe=uninstrumented
+fun:exit=uninstrumented
+fun:exp=uninstrumented
+fun:exp10=uninstrumented
+fun:exp10f=uninstrumented
+fun:exp10l=uninstrumented
+fun:exp2=uninstrumented
+fun:exp2f=uninstrumented
+fun:exp2l=uninstrumented
+fun:expf=uninstrumented
+fun:expl=uninstrumented
+fun:expm1=uninstrumented
+fun:expm1f=uninstrumented
+fun:expm1l=uninstrumented
+fun:fabs=uninstrumented
+fun:fabsf=uninstrumented
+fun:fabsl=uninstrumented
+fun:faccessat=uninstrumented
+fun:fallocate=uninstrumented
+fun:fallocate64=uninstrumented
+fun:fanotify_init=uninstrumented
+fun:fanotify_mark=uninstrumented
+fun:fattach=uninstrumented
+fun:fchdir=uninstrumented
+fun:fchflags=uninstrumented
+fun:fchmod=uninstrumented
+fun:fchmodat=uninstrumented
+fun:fchown=uninstrumented
+fun:fchownat=uninstrumented
+fun:fclose=uninstrumented
+fun:fcloseall=uninstrumented
+fun:fcntl=uninstrumented
+fun:fcrypt=uninstrumented
+fun:fcvt=uninstrumented
+fun:fcvt_r=uninstrumented
+fun:fdatasync=uninstrumented
+fun:fdetach=uninstrumented
+fun:fdim=uninstrumented
+fun:fdimf=uninstrumented
+fun:fdiml=uninstrumented
+fun:fdopen=uninstrumented
+fun:fdopendir=uninstrumented
+fun:feclearexcept=uninstrumented
+fun:fedisableexcept=uninstrumented
+fun:feenableexcept=uninstrumented
+fun:fegetenv=uninstrumented
+fun:fegetexcept=uninstrumented
+fun:fegetexceptflag=uninstrumented
+fun:fegetround=uninstrumented
+fun:feholdexcept=uninstrumented
+fun:feof=uninstrumented
+fun:feof_unlocked=uninstrumented
+fun:feraiseexcept=uninstrumented
+fun:ferror=uninstrumented
+fun:ferror_unlocked=uninstrumented
+fun:fesetenv=uninstrumented
+fun:fesetexceptflag=uninstrumented
+fun:fesetround=uninstrumented
+fun:fetestexcept=uninstrumented
+fun:feupdateenv=uninstrumented
+fun:fexecve=uninstrumented
+fun:fflush=uninstrumented
+fun:fflush_unlocked=uninstrumented
+fun:ffs=uninstrumented
+fun:ffsl=uninstrumented
+fun:ffsll=uninstrumented
+fun:fgetc=uninstrumented
+fun:fgetc_unlocked=uninstrumented
+fun:fgetgrent=uninstrumented
+fun:fgetgrent_r=uninstrumented
+fun:fgetpos=uninstrumented
+fun:fgetpos64=uninstrumented
+fun:fgetpwent=uninstrumented
+fun:fgetpwent_r=uninstrumented
+fun:fgets=uninstrumented
+fun:fgets_unlocked=uninstrumented
+fun:fgetsgent=uninstrumented
+fun:fgetsgent_r=uninstrumented
+fun:fgetspent=uninstrumented
+fun:fgetspent_r=uninstrumented
+fun:fgetwc=uninstrumented
+fun:fgetwc_unlocked=uninstrumented
+fun:fgetws=uninstrumented
+fun:fgetws_unlocked=uninstrumented
+fun:fgetxattr=uninstrumented
+fun:fileno=uninstrumented
+fun:fileno_unlocked=uninstrumented
+fun:finite=uninstrumented
+fun:finitef=uninstrumented
+fun:finitel=uninstrumented
+fun:flistxattr=uninstrumented
+fun:flock=uninstrumented
+fun:flockfile=uninstrumented
+fun:floor=uninstrumented
+fun:floorf=uninstrumented
+fun:floorl=uninstrumented
+fun:fma=uninstrumented
+fun:fmaf=uninstrumented
+fun:fmal=uninstrumented
+fun:fmax=uninstrumented
+fun:fmaxf=uninstrumented
+fun:fmaxl=uninstrumented
+fun:fmemopen=uninstrumented
+fun:fmin=uninstrumented
+fun:fminf=uninstrumented
+fun:fminl=uninstrumented
+fun:fmod=uninstrumented
+fun:fmodf=uninstrumented
+fun:fmodl=uninstrumented
+fun:fmtmsg=uninstrumented
+fun:fnmatch=uninstrumented
+fun:fopen=uninstrumented
+fun:fopen64=uninstrumented
+fun:fopencookie=uninstrumented
+fun:fork=uninstrumented
+fun:forkpty=uninstrumented
+fun:fpathconf=uninstrumented
+fun:fprintf=uninstrumented
+fun:fputc=uninstrumented
+fun:fputc_unlocked=uninstrumented
+fun:fputs=uninstrumented
+fun:fputs_unlocked=uninstrumented
+fun:fputwc=uninstrumented
+fun:fputwc_unlocked=uninstrumented
+fun:fputws=uninstrumented
+fun:fputws_unlocked=uninstrumented
+fun:fread=uninstrumented
+fun:fread_unlocked=uninstrumented
+fun:free=uninstrumented
+fun:freeaddrinfo=uninstrumented
+fun:freeifaddrs=uninstrumented
+fun:freelocale=uninstrumented
+fun:fremovexattr=uninstrumented
+fun:freopen=uninstrumented
+fun:freopen64=uninstrumented
+fun:frexp=uninstrumented
+fun:frexpf=uninstrumented
+fun:frexpl=uninstrumented
+fun:fscanf=uninstrumented
+fun:fseek=uninstrumented
+fun:fseeko=uninstrumented
+fun:fseeko64=uninstrumented
+fun:fsetpos=uninstrumented
+fun:fsetpos64=uninstrumented
+fun:fsetxattr=uninstrumented
+fun:fstat=uninstrumented
+fun:fstat64=uninstrumented
+fun:fstatat=uninstrumented
+fun:fstatat64=uninstrumented
+fun:fstatfs=uninstrumented
+fun:fstatfs64=uninstrumented
+fun:fstatvfs=uninstrumented
+fun:fstatvfs64=uninstrumented
+fun:fsync=uninstrumented
+fun:ftell=uninstrumented
+fun:ftello=uninstrumented
+fun:ftello64=uninstrumented
+fun:ftime=uninstrumented
+fun:ftok=uninstrumented
+fun:ftruncate=uninstrumented
+fun:ftruncate64=uninstrumented
+fun:ftrylockfile=uninstrumented
+fun:fts_children=uninstrumented
+fun:fts_close=uninstrumented
+fun:fts_open=uninstrumented
+fun:fts_read=uninstrumented
+fun:fts_set=uninstrumented
+fun:ftw=uninstrumented
+fun:ftw64=uninstrumented
+fun:funlockfile=uninstrumented
+fun:futimens=uninstrumented
+fun:futimes=uninstrumented
+fun:futimesat=uninstrumented
+fun:fwide=uninstrumented
+fun:fwprintf=uninstrumented
+fun:fwrite=uninstrumented
+fun:fwrite_unlocked=uninstrumented
+fun:fwscanf=uninstrumented
+fun:gai_cancel=uninstrumented
+fun:gai_error=uninstrumented
+fun:gai_strerror=uninstrumented
+fun:gai_suspend=uninstrumented
+fun:gamma=uninstrumented
+fun:gammaf=uninstrumented
+fun:gammal=uninstrumented
+fun:gcvt=uninstrumented
+fun:get_avphys_pages=uninstrumented
+fun:get_current_dir_name=uninstrumented
+fun:get_kernel_syms=uninstrumented
+fun:get_myaddress=uninstrumented
+fun:get_nprocs=uninstrumented
+fun:get_nprocs_conf=uninstrumented
+fun:get_phys_pages=uninstrumented
+fun:getaddrinfo=uninstrumented
+fun:getaddrinfo_a=uninstrumented
+fun:getaliasbyname=uninstrumented
+fun:getaliasbyname_r=uninstrumented
+fun:getaliasent=uninstrumented
+fun:getaliasent_r=uninstrumented
+fun:getauxval=uninstrumented
+fun:getc=uninstrumented
+fun:getc_unlocked=uninstrumented
+fun:getchar=uninstrumented
+fun:getchar_unlocked=uninstrumented
+fun:getcontext=uninstrumented
+fun:getcwd=uninstrumented
+fun:getdate=uninstrumented
+fun:getdate_r=uninstrumented
+fun:getdelim=uninstrumented
+fun:getdirentries=uninstrumented
+fun:getdirentries64=uninstrumented
+fun:getdomainname=uninstrumented
+fun:getdtablesize=uninstrumented
+fun:getegid=uninstrumented
+fun:getenv=uninstrumented
+fun:geteuid=uninstrumented
+fun:getfsent=uninstrumented
+fun:getfsfile=uninstrumented
+fun:getfsspec=uninstrumented
+fun:getgid=uninstrumented
+fun:getgrent=uninstrumented
+fun:getgrent_r=uninstrumented
+fun:getgrgid=uninstrumented
+fun:getgrgid_r=uninstrumented
+fun:getgrnam=uninstrumented
+fun:getgrnam_r=uninstrumented
+fun:getgrouplist=uninstrumented
+fun:getgroups=uninstrumented
+fun:gethostbyaddr=uninstrumented
+fun:gethostbyaddr_r=uninstrumented
+fun:gethostbyname=uninstrumented
+fun:gethostbyname2=uninstrumented
+fun:gethostbyname2_r=uninstrumented
+fun:gethostbyname_r=uninstrumented
+fun:gethostent=uninstrumented
+fun:gethostent_r=uninstrumented
+fun:gethostid=uninstrumented
+fun:gethostname=uninstrumented
+fun:getifaddrs=uninstrumented
+fun:getipv4sourcefilter=uninstrumented
+fun:getitimer=uninstrumented
+fun:getline=uninstrumented
+fun:getloadavg=uninstrumented
+fun:getlogin=uninstrumented
+fun:getlogin_r=uninstrumented
+fun:getmntent=uninstrumented
+fun:getmntent_r=uninstrumented
+fun:getmsg=uninstrumented
+fun:getnameinfo=uninstrumented
+fun:getnetbyaddr=uninstrumented
+fun:getnetbyaddr_r=uninstrumented
+fun:getnetbyname=uninstrumented
+fun:getnetbyname_r=uninstrumented
+fun:getnetent=uninstrumented
+fun:getnetent_r=uninstrumented
+fun:getnetgrent=uninstrumented
+fun:getnetgrent_r=uninstrumented
+fun:getnetname=uninstrumented
+fun:getopt=uninstrumented
+fun:getopt_long=uninstrumented
+fun:getopt_long_only=uninstrumented
+fun:getpagesize=uninstrumented
+fun:getpass=uninstrumented
+fun:getpeername=uninstrumented
+fun:getpgid=uninstrumented
+fun:getpgrp=uninstrumented
+fun:getpid=uninstrumented
+fun:getpmsg=uninstrumented
+fun:getppid=uninstrumented
+fun:getpriority=uninstrumented
+fun:getprotobyname=uninstrumented
+fun:getprotobyname_r=uninstrumented
+fun:getprotobynumber=uninstrumented
+fun:getprotobynumber_r=uninstrumented
+fun:getprotoent=uninstrumented
+fun:getprotoent_r=uninstrumented
+fun:getpt=uninstrumented
+fun:getpublickey=uninstrumented
+fun:getpw=uninstrumented
+fun:getpwent=uninstrumented
+fun:getpwent_r=uninstrumented
+fun:getpwnam=uninstrumented
+fun:getpwnam_r=uninstrumented
+fun:getpwuid=uninstrumented
+fun:getpwuid_r=uninstrumented
+fun:getresgid=uninstrumented
+fun:getresuid=uninstrumented
+fun:getrlimit=uninstrumented
+fun:getrlimit64=uninstrumented
+fun:getrpcbyname=uninstrumented
+fun:getrpcbyname_r=uninstrumented
+fun:getrpcbynumber=uninstrumented
+fun:getrpcbynumber_r=uninstrumented
+fun:getrpcent=uninstrumented
+fun:getrpcent_r=uninstrumented
+fun:getrpcport=uninstrumented
+fun:getrusage=uninstrumented
+fun:gets=uninstrumented
+fun:getsecretkey=uninstrumented
+fun:getservbyname=uninstrumented
+fun:getservbyname_r=uninstrumented
+fun:getservbyport=uninstrumented
+fun:getservbyport_r=uninstrumented
+fun:getservent=uninstrumented
+fun:getservent_r=uninstrumented
+fun:getsgent=uninstrumented
+fun:getsgent_r=uninstrumented
+fun:getsgnam=uninstrumented
+fun:getsgnam_r=uninstrumented
+fun:getsid=uninstrumented
+fun:getsockname=uninstrumented
+fun:getsockopt=uninstrumented
+fun:getsourcefilter=uninstrumented
+fun:getspent=uninstrumented
+fun:getspent_r=uninstrumented
+fun:getspnam=uninstrumented
+fun:getspnam_r=uninstrumented
+fun:getsubopt=uninstrumented
+fun:gettext=uninstrumented
+fun:gettimeofday=uninstrumented
+fun:getttyent=uninstrumented
+fun:getttynam=uninstrumented
+fun:getuid=uninstrumented
+fun:getusershell=uninstrumented
+fun:getutent=uninstrumented
+fun:getutent_r=uninstrumented
+fun:getutid=uninstrumented
+fun:getutid_r=uninstrumented
+fun:getutline=uninstrumented
+fun:getutline_r=uninstrumented
+fun:getutmp=uninstrumented
+fun:getutmpx=uninstrumented
+fun:getutxent=uninstrumented
+fun:getutxid=uninstrumented
+fun:getutxline=uninstrumented
+fun:getw=uninstrumented
+fun:getwc=uninstrumented
+fun:getwc_unlocked=uninstrumented
+fun:getwchar=uninstrumented
+fun:getwchar_unlocked=uninstrumented
+fun:getwd=uninstrumented
+fun:getxattr=uninstrumented
+fun:glob=uninstrumented
+fun:glob64=uninstrumented
+fun:glob_pattern_p=uninstrumented
+fun:globfree=uninstrumented
+fun:globfree64=uninstrumented
+fun:gmtime=uninstrumented
+fun:gmtime_r=uninstrumented
+fun:gnu_dev_major=uninstrumented
+fun:gnu_dev_makedev=uninstrumented
+fun:gnu_dev_minor=uninstrumented
+fun:gnu_get_libc_release=uninstrumented
+fun:gnu_get_libc_version=uninstrumented
+fun:grantpt=uninstrumented
+fun:group_member=uninstrumented
+fun:gsignal=uninstrumented
+fun:gtty=uninstrumented
+fun:hasmntopt=uninstrumented
+fun:hcreate=uninstrumented
+fun:hcreate_r=uninstrumented
+fun:hdestroy=uninstrumented
+fun:hdestroy_r=uninstrumented
+fun:herror=uninstrumented
+fun:host2netname=uninstrumented
+fun:hsearch=uninstrumented
+fun:hsearch_r=uninstrumented
+fun:hstrerror=uninstrumented
+fun:htonl=uninstrumented
+fun:htons=uninstrumented
+fun:hypot=uninstrumented
+fun:hypotf=uninstrumented
+fun:hypotl=uninstrumented
+fun:iconv=uninstrumented
+fun:iconv_close=uninstrumented
+fun:iconv_open=uninstrumented
+fun:idna_to_ascii_lz=uninstrumented
+fun:idna_to_unicode_lzlz=uninstrumented
+fun:if_freenameindex=uninstrumented
+fun:if_indextoname=uninstrumented
+fun:if_nameindex=uninstrumented
+fun:if_nametoindex=uninstrumented
+fun:ilogb=uninstrumented
+fun:ilogbf=uninstrumented
+fun:ilogbl=uninstrumented
+fun:imaxabs=uninstrumented
+fun:imaxdiv=uninstrumented
+fun:index=uninstrumented
+fun:inet6_opt_append=uninstrumented
+fun:inet6_opt_find=uninstrumented
+fun:inet6_opt_finish=uninstrumented
+fun:inet6_opt_get_val=uninstrumented
+fun:inet6_opt_init=uninstrumented
+fun:inet6_opt_next=uninstrumented
+fun:inet6_opt_set_val=uninstrumented
+fun:inet6_option_alloc=uninstrumented
+fun:inet6_option_append=uninstrumented
+fun:inet6_option_find=uninstrumented
+fun:inet6_option_init=uninstrumented
+fun:inet6_option_next=uninstrumented
+fun:inet6_option_space=uninstrumented
+fun:inet6_rth_add=uninstrumented
+fun:inet6_rth_getaddr=uninstrumented
+fun:inet6_rth_init=uninstrumented
+fun:inet6_rth_reverse=uninstrumented
+fun:inet6_rth_segments=uninstrumented
+fun:inet6_rth_space=uninstrumented
+fun:inet_addr=uninstrumented
+fun:inet_aton=uninstrumented
+fun:inet_lnaof=uninstrumented
+fun:inet_makeaddr=uninstrumented
+fun:inet_net_ntop=uninstrumented
+fun:inet_net_pton=uninstrumented
+fun:inet_neta=uninstrumented
+fun:inet_netof=uninstrumented
+fun:inet_network=uninstrumented
+fun:inet_nsap_addr=uninstrumented
+fun:inet_nsap_ntoa=uninstrumented
+fun:inet_ntoa=uninstrumented
+fun:inet_ntop=uninstrumented
+fun:inet_pton=uninstrumented
+fun:init_module=uninstrumented
+fun:initgroups=uninstrumented
+fun:initstate=uninstrumented
+fun:initstate_r=uninstrumented
+fun:innetgr=uninstrumented
+fun:inotify_add_watch=uninstrumented
+fun:inotify_init=uninstrumented
+fun:inotify_init1=uninstrumented
+fun:inotify_rm_watch=uninstrumented
+fun:insque=uninstrumented
+fun:ioctl=uninstrumented
+fun:ioperm=uninstrumented
+fun:iopl=uninstrumented
+fun:iruserok=uninstrumented
+fun:iruserok_af=uninstrumented
+fun:isalnum=uninstrumented
+fun:isalnum_l=uninstrumented
+fun:isalpha=uninstrumented
+fun:isalpha_l=uninstrumented
+fun:isascii=uninstrumented
+fun:isastream=uninstrumented
+fun:isatty=uninstrumented
+fun:isblank=uninstrumented
+fun:isblank_l=uninstrumented
+fun:iscntrl=uninstrumented
+fun:iscntrl_l=uninstrumented
+fun:isctype=uninstrumented
+fun:isdigit=uninstrumented
+fun:isdigit_l=uninstrumented
+fun:isfdtype=uninstrumented
+fun:isgraph=uninstrumented
+fun:isgraph_l=uninstrumented
+fun:isinf=uninstrumented
+fun:isinfd128=uninstrumented
+fun:isinfd32=uninstrumented
+fun:isinfd64=uninstrumented
+fun:isinff=uninstrumented
+fun:isinfl=uninstrumented
+fun:islower=uninstrumented
+fun:islower_l=uninstrumented
+fun:isnan=uninstrumented
+fun:isnanf=uninstrumented
+fun:isnanl=uninstrumented
+fun:isprint=uninstrumented
+fun:isprint_l=uninstrumented
+fun:ispunct=uninstrumented
+fun:ispunct_l=uninstrumented
+fun:isspace=uninstrumented
+fun:isspace_l=uninstrumented
+fun:isupper=uninstrumented
+fun:isupper_l=uninstrumented
+fun:iswalnum=uninstrumented
+fun:iswalnum_l=uninstrumented
+fun:iswalpha=uninstrumented
+fun:iswalpha_l=uninstrumented
+fun:iswblank=uninstrumented
+fun:iswblank_l=uninstrumented
+fun:iswcntrl=uninstrumented
+fun:iswcntrl_l=uninstrumented
+fun:iswctype=uninstrumented
+fun:iswctype_l=uninstrumented
+fun:iswdigit=uninstrumented
+fun:iswdigit_l=uninstrumented
+fun:iswgraph=uninstrumented
+fun:iswgraph_l=uninstrumented
+fun:iswlower=uninstrumented
+fun:iswlower_l=uninstrumented
+fun:iswprint=uninstrumented
+fun:iswprint_l=uninstrumented
+fun:iswpunct=uninstrumented
+fun:iswpunct_l=uninstrumented
+fun:iswspace=uninstrumented
+fun:iswspace_l=uninstrumented
+fun:iswupper=uninstrumented
+fun:iswupper_l=uninstrumented
+fun:iswxdigit=uninstrumented
+fun:iswxdigit_l=uninstrumented
+fun:isxdigit=uninstrumented
+fun:isxdigit_l=uninstrumented
+fun:j0=uninstrumented
+fun:j0f=uninstrumented
+fun:j0l=uninstrumented
+fun:j1=uninstrumented
+fun:j1f=uninstrumented
+fun:j1l=uninstrumented
+fun:jn=uninstrumented
+fun:jnf=uninstrumented
+fun:jnl=uninstrumented
+fun:jrand48=uninstrumented
+fun:jrand48_r=uninstrumented
+fun:key_decryptsession=uninstrumented
+fun:key_decryptsession_pk=uninstrumented
+fun:key_encryptsession=uninstrumented
+fun:key_encryptsession_pk=uninstrumented
+fun:key_gendes=uninstrumented
+fun:key_get_conv=uninstrumented
+fun:key_secretkey_is_set=uninstrumented
+fun:key_setnet=uninstrumented
+fun:key_setsecret=uninstrumented
+fun:kill=uninstrumented
+fun:killpg=uninstrumented
+fun:klogctl=uninstrumented
+fun:l64a=uninstrumented
+fun:labs=uninstrumented
+fun:lchmod=uninstrumented
+fun:lchown=uninstrumented
+fun:lckpwdf=uninstrumented
+fun:lcong48=uninstrumented
+fun:lcong48_r=uninstrumented
+fun:ldexp=uninstrumented
+fun:ldexpf=uninstrumented
+fun:ldexpl=uninstrumented
+fun:ldiv=uninstrumented
+fun:lfind=uninstrumented
+fun:lgamma=uninstrumented
+fun:lgamma_r=uninstrumented
+fun:lgammaf=uninstrumented
+fun:lgammaf_r=uninstrumented
+fun:lgammal=uninstrumented
+fun:lgammal_r=uninstrumented
+fun:lgetxattr=uninstrumented
+fun:link=uninstrumented
+fun:linkat=uninstrumented
+fun:lio_listio=uninstrumented
+fun:lio_listio64=uninstrumented
+fun:listen=uninstrumented
+fun:listxattr=uninstrumented
+fun:llabs=uninstrumented
+fun:lldiv=uninstrumented
+fun:llistxattr=uninstrumented
+fun:llrint=uninstrumented
+fun:llrintf=uninstrumented
+fun:llrintl=uninstrumented
+fun:llround=uninstrumented
+fun:llroundf=uninstrumented
+fun:llroundl=uninstrumented
+fun:llseek=uninstrumented
+fun:localeconv=uninstrumented
+fun:localtime=uninstrumented
+fun:localtime_r=uninstrumented
+fun:lockf=uninstrumented
+fun:lockf64=uninstrumented
+fun:log=uninstrumented
+fun:log10=uninstrumented
+fun:log10f=uninstrumented
+fun:log10l=uninstrumented
+fun:log1p=uninstrumented
+fun:log1pf=uninstrumented
+fun:log1pl=uninstrumented
+fun:log2=uninstrumented
+fun:log2f=uninstrumented
+fun:log2l=uninstrumented
+fun:logb=uninstrumented
+fun:logbf=uninstrumented
+fun:logbl=uninstrumented
+fun:logf=uninstrumented
+fun:login=uninstrumented
+fun:login_tty=uninstrumented
+fun:logl=uninstrumented
+fun:logout=uninstrumented
+fun:logwtmp=uninstrumented
+fun:longjmp=uninstrumented
+fun:lrand48=uninstrumented
+fun:lrand48_r=uninstrumented
+fun:lremovexattr=uninstrumented
+fun:lrint=uninstrumented
+fun:lrintf=uninstrumented
+fun:lrintl=uninstrumented
+fun:lround=uninstrumented
+fun:lroundf=uninstrumented
+fun:lroundl=uninstrumented
+fun:lsearch=uninstrumented
+fun:lseek=uninstrumented
+fun:lseek64=uninstrumented
+fun:lsetxattr=uninstrumented
+fun:lstat=uninstrumented
+fun:lstat64=uninstrumented
+fun:lutimes=uninstrumented
+fun:madvise=uninstrumented
+fun:makecontext=uninstrumented
+fun:mallinfo=uninstrumented
+fun:malloc=uninstrumented
+fun:malloc_get_state=uninstrumented
+fun:malloc_info=uninstrumented
+fun:malloc_set_state=uninstrumented
+fun:malloc_stats=uninstrumented
+fun:malloc_trim=uninstrumented
+fun:malloc_usable_size=uninstrumented
+fun:mallopt=uninstrumented
+fun:matherr=uninstrumented
+fun:mblen=uninstrumented
+fun:mbrlen=uninstrumented
+fun:mbrtoc16=uninstrumented
+fun:mbrtoc32=uninstrumented
+fun:mbrtowc=uninstrumented
+fun:mbsinit=uninstrumented
+fun:mbsnrtowcs=uninstrumented
+fun:mbsrtowcs=uninstrumented
+fun:mbstowcs=uninstrumented
+fun:mbtowc=uninstrumented
+fun:mcheck=uninstrumented
+fun:mcheck_check_all=uninstrumented
+fun:mcheck_pedantic=uninstrumented
+fun:mcount=uninstrumented
+fun:memalign=uninstrumented
+fun:memccpy=uninstrumented
+fun:memchr=uninstrumented
+fun:memcmp=uninstrumented
+fun:memcpy=uninstrumented
+fun:memfrob=uninstrumented
+fun:memmem=uninstrumented
+fun:memmove=uninstrumented
+fun:mempcpy=uninstrumented
+fun:memrchr=uninstrumented
+fun:memset=uninstrumented
+fun:mincore=uninstrumented
+fun:mkdir=uninstrumented
+fun:mkdirat=uninstrumented
+fun:mkdtemp=uninstrumented
+fun:mkfifo=uninstrumented
+fun:mkfifoat=uninstrumented
+fun:mknod=uninstrumented
+fun:mknodat=uninstrumented
+fun:mkostemp=uninstrumented
+fun:mkostemp64=uninstrumented
+fun:mkostemps=uninstrumented
+fun:mkostemps64=uninstrumented
+fun:mkstemp=uninstrumented
+fun:mkstemp64=uninstrumented
+fun:mkstemps=uninstrumented
+fun:mkstemps64=uninstrumented
+fun:mktemp=uninstrumented
+fun:mktime=uninstrumented
+fun:mlock=uninstrumented
+fun:mlockall=uninstrumented
+fun:mmap=uninstrumented
+fun:mmap64=uninstrumented
+fun:modf=uninstrumented
+fun:modff=uninstrumented
+fun:modfl=uninstrumented
+fun:modify_ldt=uninstrumented
+fun:moncontrol=uninstrumented
+fun:monstartup=uninstrumented
+fun:mount=uninstrumented
+fun:mprobe=uninstrumented
+fun:mprotect=uninstrumented
+fun:mq_close=uninstrumented
+fun:mq_getattr=uninstrumented
+fun:mq_notify=uninstrumented
+fun:mq_open=uninstrumented
+fun:mq_receive=uninstrumented
+fun:mq_send=uninstrumented
+fun:mq_setattr=uninstrumented
+fun:mq_timedreceive=uninstrumented
+fun:mq_timedsend=uninstrumented
+fun:mq_unlink=uninstrumented
+fun:mrand48=uninstrumented
+fun:mrand48_r=uninstrumented
+fun:mremap=uninstrumented
+fun:msgctl=uninstrumented
+fun:msgget=uninstrumented
+fun:msgrcv=uninstrumented
+fun:msgsnd=uninstrumented
+fun:msync=uninstrumented
+fun:mtrace=uninstrumented
+fun:munlock=uninstrumented
+fun:munlockall=uninstrumented
+fun:munmap=uninstrumented
+fun:muntrace=uninstrumented
+fun:name_to_handle_at=uninstrumented
+fun:nan=uninstrumented
+fun:nanf=uninstrumented
+fun:nanl=uninstrumented
+fun:nanosleep=uninstrumented
+fun:nearbyint=uninstrumented
+fun:nearbyintf=uninstrumented
+fun:nearbyintl=uninstrumented
+fun:netname2host=uninstrumented
+fun:netname2user=uninstrumented
+fun:newlocale=uninstrumented
+fun:nextafter=uninstrumented
+fun:nextafterf=uninstrumented
+fun:nextafterl=uninstrumented
+fun:nexttoward=uninstrumented
+fun:nexttowardf=uninstrumented
+fun:nexttowardl=uninstrumented
+fun:nfsservctl=uninstrumented
+fun:nftw=uninstrumented
+fun:nftw64=uninstrumented
+fun:ngettext=uninstrumented
+fun:nice=uninstrumented
+fun:nis_add=uninstrumented
+fun:nis_add_entry=uninstrumented
+fun:nis_addmember=uninstrumented
+fun:nis_checkpoint=uninstrumented
+fun:nis_clone_directory=uninstrumented
+fun:nis_clone_object=uninstrumented
+fun:nis_clone_result=uninstrumented
+fun:nis_creategroup=uninstrumented
+fun:nis_destroy_object=uninstrumented
+fun:nis_destroygroup=uninstrumented
+fun:nis_dir_cmp=uninstrumented
+fun:nis_domain_of=uninstrumented
+fun:nis_domain_of_r=uninstrumented
+fun:nis_first_entry=uninstrumented
+fun:nis_free_directory=uninstrumented
+fun:nis_free_object=uninstrumented
+fun:nis_free_request=uninstrumented
+fun:nis_freenames=uninstrumented
+fun:nis_freeresult=uninstrumented
+fun:nis_freeservlist=uninstrumented
+fun:nis_freetags=uninstrumented
+fun:nis_getnames=uninstrumented
+fun:nis_getservlist=uninstrumented
+fun:nis_ismember=uninstrumented
+fun:nis_leaf_of=uninstrumented
+fun:nis_leaf_of_r=uninstrumented
+fun:nis_lerror=uninstrumented
+fun:nis_list=uninstrumented
+fun:nis_local_directory=uninstrumented
+fun:nis_local_group=uninstrumented
+fun:nis_local_host=uninstrumented
+fun:nis_local_principal=uninstrumented
+fun:nis_lookup=uninstrumented
+fun:nis_mkdir=uninstrumented
+fun:nis_modify=uninstrumented
+fun:nis_modify_entry=uninstrumented
+fun:nis_name_of=uninstrumented
+fun:nis_name_of_r=uninstrumented
+fun:nis_next_entry=uninstrumented
+fun:nis_perror=uninstrumented
+fun:nis_ping=uninstrumented
+fun:nis_print_directory=uninstrumented
+fun:nis_print_entry=uninstrumented
+fun:nis_print_group=uninstrumented
+fun:nis_print_group_entry=uninstrumented
+fun:nis_print_link=uninstrumented
+fun:nis_print_object=uninstrumented
+fun:nis_print_result=uninstrumented
+fun:nis_print_rights=uninstrumented
+fun:nis_print_table=uninstrumented
+fun:nis_read_obj=uninstrumented
+fun:nis_remove=uninstrumented
+fun:nis_remove_entry=uninstrumented
+fun:nis_removemember=uninstrumented
+fun:nis_rmdir=uninstrumented
+fun:nis_servstate=uninstrumented
+fun:nis_sperrno=uninstrumented
+fun:nis_sperror=uninstrumented
+fun:nis_sperror_r=uninstrumented
+fun:nis_stats=uninstrumented
+fun:nis_verifygroup=uninstrumented
+fun:nis_write_obj=uninstrumented
+fun:nl_langinfo=uninstrumented
+fun:nl_langinfo_l=uninstrumented
+fun:nrand48=uninstrumented
+fun:nrand48_r=uninstrumented
+fun:ns_datetosecs=uninstrumented
+fun:ns_format_ttl=uninstrumented
+fun:ns_get16=uninstrumented
+fun:ns_get32=uninstrumented
+fun:ns_initparse=uninstrumented
+fun:ns_makecanon=uninstrumented
+fun:ns_msg_getflag=uninstrumented
+fun:ns_name_compress=uninstrumented
+fun:ns_name_ntol=uninstrumented
+fun:ns_name_ntop=uninstrumented
+fun:ns_name_pack=uninstrumented
+fun:ns_name_pton=uninstrumented
+fun:ns_name_rollback=uninstrumented
+fun:ns_name_skip=uninstrumented
+fun:ns_name_uncompress=uninstrumented
+fun:ns_name_unpack=uninstrumented
+fun:ns_parse_ttl=uninstrumented
+fun:ns_parserr=uninstrumented
+fun:ns_put16=uninstrumented
+fun:ns_put32=uninstrumented
+fun:ns_samedomain=uninstrumented
+fun:ns_samename=uninstrumented
+fun:ns_skiprr=uninstrumented
+fun:ns_sprintrr=uninstrumented
+fun:ns_sprintrrf=uninstrumented
+fun:ns_subdomain=uninstrumented
+fun:ntohl=uninstrumented
+fun:ntohs=uninstrumented
+fun:ntp_adjtime=uninstrumented
+fun:ntp_gettime=uninstrumented
+fun:ntp_gettimex=uninstrumented
+fun:obstack_free=uninstrumented
+fun:obstack_printf=uninstrumented
+fun:obstack_vprintf=uninstrumented
+fun:on_exit=uninstrumented
+fun:open=uninstrumented
+fun:open64=uninstrumented
+fun:open_by_handle_at=uninstrumented
+fun:open_memstream=uninstrumented
+fun:open_wmemstream=uninstrumented
+fun:openat=uninstrumented
+fun:openat64=uninstrumented
+fun:opendir=uninstrumented
+fun:openlog=uninstrumented
+fun:openpty=uninstrumented
+fun:parse_printf_format=uninstrumented
+fun:passwd2des=uninstrumented
+fun:pathconf=uninstrumented
+fun:pause=uninstrumented
+fun:pclose=uninstrumented
+fun:perror=uninstrumented
+fun:personality=uninstrumented
+fun:pipe=uninstrumented
+fun:pipe2=uninstrumented
+fun:pivot_root=uninstrumented
+fun:pmap_getmaps=uninstrumented
+fun:pmap_getport=uninstrumented
+fun:pmap_rmtcall=uninstrumented
+fun:pmap_set=uninstrumented
+fun:pmap_unset=uninstrumented
+fun:poll=uninstrumented
+fun:popen=uninstrumented
+fun:posix_fadvise=uninstrumented
+fun:posix_fadvise64=uninstrumented
+fun:posix_fallocate=uninstrumented
+fun:posix_fallocate64=uninstrumented
+fun:posix_madvise=uninstrumented
+fun:posix_memalign=uninstrumented
+fun:posix_openpt=uninstrumented
+fun:posix_spawn=uninstrumented
+fun:posix_spawn_file_actions_addclose=uninstrumented
+fun:posix_spawn_file_actions_adddup2=uninstrumented
+fun:posix_spawn_file_actions_addopen=uninstrumented
+fun:posix_spawn_file_actions_destroy=uninstrumented
+fun:posix_spawn_file_actions_init=uninstrumented
+fun:posix_spawnattr_destroy=uninstrumented
+fun:posix_spawnattr_getflags=uninstrumented
+fun:posix_spawnattr_getpgroup=uninstrumented
+fun:posix_spawnattr_getschedparam=uninstrumented
+fun:posix_spawnattr_getschedpolicy=uninstrumented
+fun:posix_spawnattr_getsigdefault=uninstrumented
+fun:posix_spawnattr_getsigmask=uninstrumented
+fun:posix_spawnattr_init=uninstrumented
+fun:posix_spawnattr_setflags=uninstrumented
+fun:posix_spawnattr_setpgroup=uninstrumented
+fun:posix_spawnattr_setschedparam=uninstrumented
+fun:posix_spawnattr_setschedpolicy=uninstrumented
+fun:posix_spawnattr_setsigdefault=uninstrumented
+fun:posix_spawnattr_setsigmask=uninstrumented
+fun:posix_spawnp=uninstrumented
+fun:pow=uninstrumented
+fun:pow10=uninstrumented
+fun:pow10f=uninstrumented
+fun:pow10l=uninstrumented
+fun:powf=uninstrumented
+fun:powl=uninstrumented
+fun:ppoll=uninstrumented
+fun:prctl=uninstrumented
+fun:pread=uninstrumented
+fun:pread64=uninstrumented
+fun:preadv=uninstrumented
+fun:preadv64=uninstrumented
+fun:printf=uninstrumented
+fun:printf_size=uninstrumented
+fun:printf_size_info=uninstrumented
+fun:prlimit=uninstrumented
+fun:prlimit64=uninstrumented
+fun:process_vm_readv=uninstrumented
+fun:process_vm_writev=uninstrumented
+fun:profil=uninstrumented
+fun:pselect=uninstrumented
+fun:psiginfo=uninstrumented
+fun:psignal=uninstrumented
+fun:pthread_atfork=uninstrumented
+fun:pthread_attr_destroy=uninstrumented
+fun:pthread_attr_getaffinity_np=uninstrumented
+fun:pthread_attr_getdetachstate=uninstrumented
+fun:pthread_attr_getguardsize=uninstrumented
+fun:pthread_attr_getinheritsched=uninstrumented
+fun:pthread_attr_getschedparam=uninstrumented
+fun:pthread_attr_getschedpolicy=uninstrumented
+fun:pthread_attr_getscope=uninstrumented
+fun:pthread_attr_getstack=uninstrumented
+fun:pthread_attr_getstackaddr=uninstrumented
+fun:pthread_attr_getstacksize=uninstrumented
+fun:pthread_attr_init=uninstrumented
+fun:pthread_attr_setaffinity_np=uninstrumented
+fun:pthread_attr_setdetachstate=uninstrumented
+fun:pthread_attr_setguardsize=uninstrumented
+fun:pthread_attr_setinheritsched=uninstrumented
+fun:pthread_attr_setschedparam=uninstrumented
+fun:pthread_attr_setschedpolicy=uninstrumented
+fun:pthread_attr_setscope=uninstrumented
+fun:pthread_attr_setstack=uninstrumented
+fun:pthread_attr_setstackaddr=uninstrumented
+fun:pthread_attr_setstacksize=uninstrumented
+fun:pthread_barrier_destroy=uninstrumented
+fun:pthread_barrier_init=uninstrumented
+fun:pthread_barrier_wait=uninstrumented
+fun:pthread_barrierattr_destroy=uninstrumented
+fun:pthread_barrierattr_getpshared=uninstrumented
+fun:pthread_barrierattr_init=uninstrumented
+fun:pthread_barrierattr_setpshared=uninstrumented
+fun:pthread_cancel=uninstrumented
+fun:pthread_cond_broadcast=uninstrumented
+fun:pthread_cond_destroy=uninstrumented
+fun:pthread_cond_init=uninstrumented
+fun:pthread_cond_signal=uninstrumented
+fun:pthread_cond_timedwait=uninstrumented
+fun:pthread_cond_wait=uninstrumented
+fun:pthread_condattr_destroy=uninstrumented
+fun:pthread_condattr_getclock=uninstrumented
+fun:pthread_condattr_getpshared=uninstrumented
+fun:pthread_condattr_init=uninstrumented
+fun:pthread_condattr_setclock=uninstrumented
+fun:pthread_condattr_setpshared=uninstrumented
+fun:pthread_create=uninstrumented
+fun:pthread_detach=uninstrumented
+fun:pthread_equal=uninstrumented
+fun:pthread_exit=uninstrumented
+fun:pthread_getaffinity_np=uninstrumented
+fun:pthread_getattr_default_np=uninstrumented
+fun:pthread_getattr_np=uninstrumented
+fun:pthread_getconcurrency=uninstrumented
+fun:pthread_getcpuclockid=uninstrumented
+fun:pthread_getname_np=uninstrumented
+fun:pthread_getschedparam=uninstrumented
+fun:pthread_getspecific=uninstrumented
+fun:pthread_join=uninstrumented
+fun:pthread_key_create=uninstrumented
+fun:pthread_key_delete=uninstrumented
+fun:pthread_kill=uninstrumented
+fun:pthread_kill_other_threads_np=uninstrumented
+fun:pthread_mutex_consistent=uninstrumented
+fun:pthread_mutex_consistent_np=uninstrumented
+fun:pthread_mutex_destroy=uninstrumented
+fun:pthread_mutex_getprioceiling=uninstrumented
+fun:pthread_mutex_init=uninstrumented
+fun:pthread_mutex_lock=uninstrumented
+fun:pthread_mutex_setprioceiling=uninstrumented
+fun:pthread_mutex_timedlock=uninstrumented
+fun:pthread_mutex_trylock=uninstrumented
+fun:pthread_mutex_unlock=uninstrumented
+fun:pthread_mutexattr_destroy=uninstrumented
+fun:pthread_mutexattr_getkind_np=uninstrumented
+fun:pthread_mutexattr_getprioceiling=uninstrumented
+fun:pthread_mutexattr_getprotocol=uninstrumented
+fun:pthread_mutexattr_getpshared=uninstrumented
+fun:pthread_mutexattr_getrobust=uninstrumented
+fun:pthread_mutexattr_getrobust_np=uninstrumented
+fun:pthread_mutexattr_gettype=uninstrumented
+fun:pthread_mutexattr_init=uninstrumented
+fun:pthread_mutexattr_setkind_np=uninstrumented
+fun:pthread_mutexattr_setprioceiling=uninstrumented
+fun:pthread_mutexattr_setprotocol=uninstrumented
+fun:pthread_mutexattr_setpshared=uninstrumented
+fun:pthread_mutexattr_setrobust=uninstrumented
+fun:pthread_mutexattr_setrobust_np=uninstrumented
+fun:pthread_mutexattr_settype=uninstrumented
+fun:pthread_once=uninstrumented
+fun:pthread_rwlock_destroy=uninstrumented
+fun:pthread_rwlock_init=uninstrumented
+fun:pthread_rwlock_rdlock=uninstrumented
+fun:pthread_rwlock_timedrdlock=uninstrumented
+fun:pthread_rwlock_timedwrlock=uninstrumented
+fun:pthread_rwlock_tryrdlock=uninstrumented
+fun:pthread_rwlock_trywrlock=uninstrumented
+fun:pthread_rwlock_unlock=uninstrumented
+fun:pthread_rwlock_wrlock=uninstrumented
+fun:pthread_rwlockattr_destroy=uninstrumented
+fun:pthread_rwlockattr_getkind_np=uninstrumented
+fun:pthread_rwlockattr_getpshared=uninstrumented
+fun:pthread_rwlockattr_init=uninstrumented
+fun:pthread_rwlockattr_setkind_np=uninstrumented
+fun:pthread_rwlockattr_setpshared=uninstrumented
+fun:pthread_self=uninstrumented
+fun:pthread_setaffinity_np=uninstrumented
+fun:pthread_setattr_default_np=uninstrumented
+fun:pthread_setcancelstate=uninstrumented
+fun:pthread_setcanceltype=uninstrumented
+fun:pthread_setconcurrency=uninstrumented
+fun:pthread_setname_np=uninstrumented
+fun:pthread_setschedparam=uninstrumented
+fun:pthread_setschedprio=uninstrumented
+fun:pthread_setspecific=uninstrumented
+fun:pthread_sigmask=uninstrumented
+fun:pthread_sigqueue=uninstrumented
+fun:pthread_spin_destroy=uninstrumented
+fun:pthread_spin_init=uninstrumented
+fun:pthread_spin_lock=uninstrumented
+fun:pthread_spin_trylock=uninstrumented
+fun:pthread_spin_unlock=uninstrumented
+fun:pthread_testcancel=uninstrumented
+fun:pthread_timedjoin_np=uninstrumented
+fun:pthread_tryjoin_np=uninstrumented
+fun:pthread_yield=uninstrumented
+fun:ptrace=uninstrumented
+fun:ptsname=uninstrumented
+fun:ptsname_r=uninstrumented
+fun:putc=uninstrumented
+fun:putc_unlocked=uninstrumented
+fun:putchar=uninstrumented
+fun:putchar_unlocked=uninstrumented
+fun:putenv=uninstrumented
+fun:putgrent=uninstrumented
+fun:putmsg=uninstrumented
+fun:putpmsg=uninstrumented
+fun:putpwent=uninstrumented
+fun:puts=uninstrumented
+fun:putsgent=uninstrumented
+fun:putspent=uninstrumented
+fun:pututline=uninstrumented
+fun:pututxline=uninstrumented
+fun:putw=uninstrumented
+fun:putwc=uninstrumented
+fun:putwc_unlocked=uninstrumented
+fun:putwchar=uninstrumented
+fun:putwchar_unlocked=uninstrumented
+fun:pvalloc=uninstrumented
+fun:pwrite=uninstrumented
+fun:pwrite64=uninstrumented
+fun:pwritev=uninstrumented
+fun:pwritev64=uninstrumented
+fun:qecvt=uninstrumented
+fun:qecvt_r=uninstrumented
+fun:qfcvt=uninstrumented
+fun:qfcvt_r=uninstrumented
+fun:qgcvt=uninstrumented
+fun:qsort=uninstrumented
+fun:qsort_r=uninstrumented
+fun:query_module=uninstrumented
+fun:quick_exit=uninstrumented
+fun:quotactl=uninstrumented
+fun:raise=uninstrumented
+fun:rand=uninstrumented
+fun:rand_r=uninstrumented
+fun:random=uninstrumented
+fun:random_r=uninstrumented
+fun:rawmemchr=uninstrumented
+fun:rcmd=uninstrumented
+fun:rcmd_af=uninstrumented
+fun:re_comp=uninstrumented
+fun:re_compile_fastmap=uninstrumented
+fun:re_compile_pattern=uninstrumented
+fun:re_exec=uninstrumented
+fun:re_match=uninstrumented
+fun:re_match_2=uninstrumented
+fun:re_search=uninstrumented
+fun:re_search_2=uninstrumented
+fun:re_set_registers=uninstrumented
+fun:re_set_syntax=uninstrumented
+fun:read=uninstrumented
+fun:readColdStartFile=uninstrumented
+fun:readahead=uninstrumented
+fun:readdir=uninstrumented
+fun:readdir64=uninstrumented
+fun:readdir64_r=uninstrumented
+fun:readdir_r=uninstrumented
+fun:readlink=uninstrumented
+fun:readlinkat=uninstrumented
+fun:readv=uninstrumented
+fun:realloc=uninstrumented
+fun:realpath=uninstrumented
+fun:reboot=uninstrumented
+fun:recv=uninstrumented
+fun:recvfrom=uninstrumented
+fun:recvmmsg=uninstrumented
+fun:recvmsg=uninstrumented
+fun:regcomp=uninstrumented
+fun:regerror=uninstrumented
+fun:regexec=uninstrumented
+fun:regfree=uninstrumented
+fun:register_printf_function=uninstrumented
+fun:register_printf_modifier=uninstrumented
+fun:register_printf_specifier=uninstrumented
+fun:register_printf_type=uninstrumented
+fun:registerrpc=uninstrumented
+fun:remainder=uninstrumented
+fun:remainderf=uninstrumented
+fun:remainderl=uninstrumented
+fun:remap_file_pages=uninstrumented
+fun:remove=uninstrumented
+fun:removexattr=uninstrumented
+fun:remque=uninstrumented
+fun:remquo=uninstrumented
+fun:remquof=uninstrumented
+fun:remquol=uninstrumented
+fun:rename=uninstrumented
+fun:renameat=uninstrumented
+fun:res_gethostbyaddr=uninstrumented
+fun:res_gethostbyname=uninstrumented
+fun:res_gethostbyname2=uninstrumented
+fun:res_send_setqhook=uninstrumented
+fun:res_send_setrhook=uninstrumented
+fun:revoke=uninstrumented
+fun:rewind=uninstrumented
+fun:rewinddir=uninstrumented
+fun:rexec=uninstrumented
+fun:rexec_af=uninstrumented
+fun:rindex=uninstrumented
+fun:rint=uninstrumented
+fun:rintf=uninstrumented
+fun:rintl=uninstrumented
+fun:rmdir=uninstrumented
+fun:round=uninstrumented
+fun:roundf=uninstrumented
+fun:roundl=uninstrumented
+fun:rpmatch=uninstrumented
+fun:rresvport=uninstrumented
+fun:rresvport_af=uninstrumented
+fun:rtime=uninstrumented
+fun:ruserok=uninstrumented
+fun:ruserok_af=uninstrumented
+fun:ruserpass=uninstrumented
+fun:sbrk=uninstrumented
+fun:scalb=uninstrumented
+fun:scalbf=uninstrumented
+fun:scalbl=uninstrumented
+fun:scalbln=uninstrumented
+fun:scalblnf=uninstrumented
+fun:scalblnl=uninstrumented
+fun:scalbn=uninstrumented
+fun:scalbnf=uninstrumented
+fun:scalbnl=uninstrumented
+fun:scandir=uninstrumented
+fun:scandir64=uninstrumented
+fun:scandirat=uninstrumented
+fun:scandirat64=uninstrumented
+fun:scanf=uninstrumented
+fun:sched_get_priority_max=uninstrumented
+fun:sched_get_priority_min=uninstrumented
+fun:sched_getaffinity=uninstrumented
+fun:sched_getcpu=uninstrumented
+fun:sched_getparam=uninstrumented
+fun:sched_getscheduler=uninstrumented
+fun:sched_rr_get_interval=uninstrumented
+fun:sched_setaffinity=uninstrumented
+fun:sched_setparam=uninstrumented
+fun:sched_setscheduler=uninstrumented
+fun:sched_yield=uninstrumented
+fun:secure_getenv=uninstrumented
+fun:seed48=uninstrumented
+fun:seed48_r=uninstrumented
+fun:seekdir=uninstrumented
+fun:select=uninstrumented
+fun:sem_close=uninstrumented
+fun:sem_destroy=uninstrumented
+fun:sem_getvalue=uninstrumented
+fun:sem_init=uninstrumented
+fun:sem_open=uninstrumented
+fun:sem_post=uninstrumented
+fun:sem_timedwait=uninstrumented
+fun:sem_trywait=uninstrumented
+fun:sem_unlink=uninstrumented
+fun:sem_wait=uninstrumented
+fun:semctl=uninstrumented
+fun:semget=uninstrumented
+fun:semop=uninstrumented
+fun:semtimedop=uninstrumented
+fun:send=uninstrumented
+fun:sendfile=uninstrumented
+fun:sendfile64=uninstrumented
+fun:sendmmsg=uninstrumented
+fun:sendmsg=uninstrumented
+fun:sendto=uninstrumented
+fun:setaliasent=uninstrumented
+fun:setbuf=uninstrumented
+fun:setbuffer=uninstrumented
+fun:setcontext=uninstrumented
+fun:setdomainname=uninstrumented
+fun:setegid=uninstrumented
+fun:setenv=uninstrumented
+fun:seteuid=uninstrumented
+fun:setfsent=uninstrumented
+fun:setfsgid=uninstrumented
+fun:setfsuid=uninstrumented
+fun:setgid=uninstrumented
+fun:setgrent=uninstrumented
+fun:setgroups=uninstrumented
+fun:sethostent=uninstrumented
+fun:sethostid=uninstrumented
+fun:sethostname=uninstrumented
+fun:setipv4sourcefilter=uninstrumented
+fun:setitimer=uninstrumented
+fun:setjmp=uninstrumented
+fun:setkey=uninstrumented
+fun:setkey_r=uninstrumented
+fun:setlinebuf=uninstrumented
+fun:setlocale=uninstrumented
+fun:setlogin=uninstrumented
+fun:setlogmask=uninstrumented
+fun:setmntent=uninstrumented
+fun:setnetent=uninstrumented
+fun:setnetgrent=uninstrumented
+fun:setns=uninstrumented
+fun:setpgid=uninstrumented
+fun:setpgrp=uninstrumented
+fun:setpriority=uninstrumented
+fun:setprotoent=uninstrumented
+fun:setpwent=uninstrumented
+fun:setregid=uninstrumented
+fun:setresgid=uninstrumented
+fun:setresuid=uninstrumented
+fun:setreuid=uninstrumented
+fun:setrlimit=uninstrumented
+fun:setrlimit64=uninstrumented
+fun:setrpcent=uninstrumented
+fun:setservent=uninstrumented
+fun:setsgent=uninstrumented
+fun:setsid=uninstrumented
+fun:setsockopt=uninstrumented
+fun:setsourcefilter=uninstrumented
+fun:setspent=uninstrumented
+fun:setstate=uninstrumented
+fun:setstate_r=uninstrumented
+fun:settimeofday=uninstrumented
+fun:setttyent=uninstrumented
+fun:setuid=uninstrumented
+fun:setusershell=uninstrumented
+fun:setutent=uninstrumented
+fun:setutxent=uninstrumented
+fun:setvbuf=uninstrumented
+fun:setxattr=uninstrumented
+fun:sgetsgent=uninstrumented
+fun:sgetsgent_r=uninstrumented
+fun:sgetspent=uninstrumented
+fun:sgetspent_r=uninstrumented
+fun:shm_open=uninstrumented
+fun:shm_unlink=uninstrumented
+fun:shmat=uninstrumented
+fun:shmctl=uninstrumented
+fun:shmdt=uninstrumented
+fun:shmget=uninstrumented
+fun:shutdown=uninstrumented
+fun:sigaction=uninstrumented
+fun:sigaddset=uninstrumented
+fun:sigaltstack=uninstrumented
+fun:sigandset=uninstrumented
+fun:sigblock=uninstrumented
+fun:sigdelset=uninstrumented
+fun:sigemptyset=uninstrumented
+fun:sigfillset=uninstrumented
+fun:siggetmask=uninstrumented
+fun:sighold=uninstrumented
+fun:sigignore=uninstrumented
+fun:siginterrupt=uninstrumented
+fun:sigisemptyset=uninstrumented
+fun:sigismember=uninstrumented
+fun:siglongjmp=uninstrumented
+fun:signal=uninstrumented
+fun:signalfd=uninstrumented
+fun:significand=uninstrumented
+fun:significandf=uninstrumented
+fun:significandl=uninstrumented
+fun:sigorset=uninstrumented
+fun:sigpause=uninstrumented
+fun:sigpending=uninstrumented
+fun:sigprocmask=uninstrumented
+fun:sigqueue=uninstrumented
+fun:sigrelse=uninstrumented
+fun:sigreturn=uninstrumented
+fun:sigset=uninstrumented
+fun:sigsetmask=uninstrumented
+fun:sigstack=uninstrumented
+fun:sigsuspend=uninstrumented
+fun:sigtimedwait=uninstrumented
+fun:sigvec=uninstrumented
+fun:sigwait=uninstrumented
+fun:sigwaitinfo=uninstrumented
+fun:sin=uninstrumented
+fun:sincos=uninstrumented
+fun:sincosf=uninstrumented
+fun:sincosl=uninstrumented
+fun:sinf=uninstrumented
+fun:sinh=uninstrumented
+fun:sinhf=uninstrumented
+fun:sinhl=uninstrumented
+fun:sinl=uninstrumented
+fun:sleep=uninstrumented
+fun:snprintf=uninstrumented
+fun:sockatmark=uninstrumented
+fun:socket=uninstrumented
+fun:socketpair=uninstrumented
+fun:splice=uninstrumented
+fun:sprintf=uninstrumented
+fun:sprofil=uninstrumented
+fun:sqrt=uninstrumented
+fun:sqrtf=uninstrumented
+fun:sqrtl=uninstrumented
+fun:srand=uninstrumented
+fun:srand48=uninstrumented
+fun:srand48_r=uninstrumented
+fun:srandom=uninstrumented
+fun:srandom_r=uninstrumented
+fun:sscanf=uninstrumented
+fun:ssignal=uninstrumented
+fun:sstk=uninstrumented
+fun:stat=uninstrumented
+fun:stat64=uninstrumented
+fun:statfs=uninstrumented
+fun:statfs64=uninstrumented
+fun:statvfs=uninstrumented
+fun:statvfs64=uninstrumented
+fun:step=uninstrumented
+fun:stime=uninstrumented
+fun:stpcpy=uninstrumented
+fun:stpncpy=uninstrumented
+fun:strcasecmp=uninstrumented
+fun:strcasecmp_l=uninstrumented
+fun:strcasestr=uninstrumented
+fun:strcat=uninstrumented
+fun:strchr=uninstrumented
+fun:strchrnul=uninstrumented
+fun:strcmp=uninstrumented
+fun:strcoll=uninstrumented
+fun:strcoll_l=uninstrumented
+fun:strcpy=uninstrumented
+fun:strcspn=uninstrumented
+fun:strdup=uninstrumented
+fun:strerror=uninstrumented
+fun:strerror_l=uninstrumented
+fun:strerror_r=uninstrumented
+fun:strfmon=uninstrumented
+fun:strfmon_l=uninstrumented
+fun:strfry=uninstrumented
+fun:strftime=uninstrumented
+fun:strftime_l=uninstrumented
+fun:strlen=uninstrumented
+fun:strncasecmp=uninstrumented
+fun:strncasecmp_l=uninstrumented
+fun:strncat=uninstrumented
+fun:strncmp=uninstrumented
+fun:strncpy=uninstrumented
+fun:strndup=uninstrumented
+fun:strnlen=uninstrumented
+fun:strpbrk=uninstrumented
+fun:strptime=uninstrumented
+fun:strptime_l=uninstrumented
+fun:strrchr=uninstrumented
+fun:strsep=uninstrumented
+fun:strsignal=uninstrumented
+fun:strspn=uninstrumented
+fun:strstr=uninstrumented
+fun:strtod=uninstrumented
+fun:strtod_l=uninstrumented
+fun:strtof=uninstrumented
+fun:strtof_l=uninstrumented
+fun:strtoimax=uninstrumented
+fun:strtok=uninstrumented
+fun:strtok_r=uninstrumented
+fun:strtol=uninstrumented
+fun:strtol_l=uninstrumented
+fun:strtold=uninstrumented
+fun:strtold_l=uninstrumented
+fun:strtoll=uninstrumented
+fun:strtoll_l=uninstrumented
+fun:strtoq=uninstrumented
+fun:strtoul=uninstrumented
+fun:strtoul_l=uninstrumented
+fun:strtoull=uninstrumented
+fun:strtoull_l=uninstrumented
+fun:strtoumax=uninstrumented
+fun:strtouq=uninstrumented
+fun:strverscmp=uninstrumented
+fun:strxfrm=uninstrumented
+fun:strxfrm_l=uninstrumented
+fun:stty=uninstrumented
+fun:svc_exit=uninstrumented
+fun:svc_getreq=uninstrumented
+fun:svc_getreq_common=uninstrumented
+fun:svc_getreq_poll=uninstrumented
+fun:svc_getreqset=uninstrumented
+fun:svc_register=uninstrumented
+fun:svc_run=uninstrumented
+fun:svc_sendreply=uninstrumented
+fun:svc_unregister=uninstrumented
+fun:svcerr_auth=uninstrumented
+fun:svcerr_decode=uninstrumented
+fun:svcerr_noproc=uninstrumented
+fun:svcerr_noprog=uninstrumented
+fun:svcerr_progvers=uninstrumented
+fun:svcerr_systemerr=uninstrumented
+fun:svcerr_weakauth=uninstrumented
+fun:svcfd_create=uninstrumented
+fun:svcraw_create=uninstrumented
+fun:svctcp_create=uninstrumented
+fun:svcudp_bufcreate=uninstrumented
+fun:svcudp_create=uninstrumented
+fun:svcudp_enablecache=uninstrumented
+fun:svcunix_create=uninstrumented
+fun:svcunixfd_create=uninstrumented
+fun:swab=uninstrumented
+fun:swapcontext=uninstrumented
+fun:swapoff=uninstrumented
+fun:swapon=uninstrumented
+fun:swprintf=uninstrumented
+fun:swscanf=uninstrumented
+fun:symlink=uninstrumented
+fun:symlinkat=uninstrumented
+fun:sync=uninstrumented
+fun:sync_file_range=uninstrumented
+fun:syncfs=uninstrumented
+fun:syscall=uninstrumented
+fun:sysconf=uninstrumented
+fun:sysctl=uninstrumented
+fun:sysinfo=uninstrumented
+fun:syslog=uninstrumented
+fun:system=uninstrumented
+fun:sysv_signal=uninstrumented
+fun:tan=uninstrumented
+fun:tanf=uninstrumented
+fun:tanh=uninstrumented
+fun:tanhf=uninstrumented
+fun:tanhl=uninstrumented
+fun:tanl=uninstrumented
+fun:tcdrain=uninstrumented
+fun:tcflow=uninstrumented
+fun:tcflush=uninstrumented
+fun:tcgetattr=uninstrumented
+fun:tcgetpgrp=uninstrumented
+fun:tcgetsid=uninstrumented
+fun:tcsendbreak=uninstrumented
+fun:tcsetattr=uninstrumented
+fun:tcsetpgrp=uninstrumented
+fun:td_init=uninstrumented
+fun:td_log=uninstrumented
+fun:td_symbol_list=uninstrumented
+fun:td_ta_clear_event=uninstrumented
+fun:td_ta_delete=uninstrumented
+fun:td_ta_enable_stats=uninstrumented
+fun:td_ta_event_addr=uninstrumented
+fun:td_ta_event_getmsg=uninstrumented
+fun:td_ta_get_nthreads=uninstrumented
+fun:td_ta_get_ph=uninstrumented
+fun:td_ta_get_stats=uninstrumented
+fun:td_ta_map_id2thr=uninstrumented
+fun:td_ta_map_lwp2thr=uninstrumented
+fun:td_ta_new=uninstrumented
+fun:td_ta_reset_stats=uninstrumented
+fun:td_ta_set_event=uninstrumented
+fun:td_ta_setconcurrency=uninstrumented
+fun:td_ta_thr_iter=uninstrumented
+fun:td_ta_tsd_iter=uninstrumented
+fun:td_thr_clear_event=uninstrumented
+fun:td_thr_dbresume=uninstrumented
+fun:td_thr_dbsuspend=uninstrumented
+fun:td_thr_event_enable=uninstrumented
+fun:td_thr_event_getmsg=uninstrumented
+fun:td_thr_get_info=uninstrumented
+fun:td_thr_getfpregs=uninstrumented
+fun:td_thr_getgregs=uninstrumented
+fun:td_thr_getxregs=uninstrumented
+fun:td_thr_getxregsize=uninstrumented
+fun:td_thr_set_event=uninstrumented
+fun:td_thr_setfpregs=uninstrumented
+fun:td_thr_setgregs=uninstrumented
+fun:td_thr_setprio=uninstrumented
+fun:td_thr_setsigpending=uninstrumented
+fun:td_thr_setxregs=uninstrumented
+fun:td_thr_sigsetmask=uninstrumented
+fun:td_thr_tls_get_addr=uninstrumented
+fun:td_thr_tlsbase=uninstrumented
+fun:td_thr_tsd=uninstrumented
+fun:td_thr_validate=uninstrumented
+fun:tdelete=uninstrumented
+fun:tdestroy=uninstrumented
+fun:tee=uninstrumented
+fun:telldir=uninstrumented
+fun:tempnam=uninstrumented
+fun:textdomain=uninstrumented
+fun:tfind=uninstrumented
+fun:tgamma=uninstrumented
+fun:tgammaf=uninstrumented
+fun:tgammal=uninstrumented
+fun:time=uninstrumented
+fun:timegm=uninstrumented
+fun:timelocal=uninstrumented
+fun:timer_create=uninstrumented
+fun:timer_delete=uninstrumented
+fun:timer_getoverrun=uninstrumented
+fun:timer_gettime=uninstrumented
+fun:timer_settime=uninstrumented
+fun:timerfd_create=uninstrumented
+fun:timerfd_gettime=uninstrumented
+fun:timerfd_settime=uninstrumented
+fun:times=uninstrumented
+fun:timespec_get=uninstrumented
+fun:tmpfile=uninstrumented
+fun:tmpfile64=uninstrumented
+fun:tmpnam=uninstrumented
+fun:tmpnam_r=uninstrumented
+fun:toascii=uninstrumented
+fun:tolower=uninstrumented
+fun:tolower_l=uninstrumented
+fun:toupper=uninstrumented
+fun:toupper_l=uninstrumented
+fun:towctrans=uninstrumented
+fun:towctrans_l=uninstrumented
+fun:towlower=uninstrumented
+fun:towlower_l=uninstrumented
+fun:towupper=uninstrumented
+fun:towupper_l=uninstrumented
+fun:tr_break=uninstrumented
+fun:trunc=uninstrumented
+fun:truncate=uninstrumented
+fun:truncate64=uninstrumented
+fun:truncf=uninstrumented
+fun:truncl=uninstrumented
+fun:tsearch=uninstrumented
+fun:ttyname=uninstrumented
+fun:ttyname_r=uninstrumented
+fun:ttyslot=uninstrumented
+fun:twalk=uninstrumented
+fun:tzset=uninstrumented
+fun:ualarm=uninstrumented
+fun:ulckpwdf=uninstrumented
+fun:ulimit=uninstrumented
+fun:umask=uninstrumented
+fun:umount=uninstrumented
+fun:umount2=uninstrumented
+fun:uname=uninstrumented
+fun:ungetc=uninstrumented
+fun:ungetwc=uninstrumented
+fun:unlink=uninstrumented
+fun:unlinkat=uninstrumented
+fun:unlockpt=uninstrumented
+fun:unsetenv=uninstrumented
+fun:unshare=uninstrumented
+fun:updwtmp=uninstrumented
+fun:updwtmpx=uninstrumented
+fun:uselib=uninstrumented
+fun:uselocale=uninstrumented
+fun:user2netname=uninstrumented
+fun:usleep=uninstrumented
+fun:ustat=uninstrumented
+fun:utime=uninstrumented
+fun:utimensat=uninstrumented
+fun:utimes=uninstrumented
+fun:utmpname=uninstrumented
+fun:utmpxname=uninstrumented
+fun:valloc=uninstrumented
+fun:vasprintf=uninstrumented
+fun:vdprintf=uninstrumented
+fun:verr=uninstrumented
+fun:verrx=uninstrumented
+fun:versionsort=uninstrumented
+fun:versionsort64=uninstrumented
+fun:vfork=uninstrumented
+fun:vfprintf=uninstrumented
+fun:vfscanf=uninstrumented
+fun:vfwprintf=uninstrumented
+fun:vfwscanf=uninstrumented
+fun:vhangup=uninstrumented
+fun:vlimit=uninstrumented
+fun:vmsplice=uninstrumented
+fun:vprintf=uninstrumented
+fun:vscanf=uninstrumented
+fun:vsnprintf=uninstrumented
+fun:vsprintf=uninstrumented
+fun:vsscanf=uninstrumented
+fun:vswprintf=uninstrumented
+fun:vswscanf=uninstrumented
+fun:vsyslog=uninstrumented
+fun:vtimes=uninstrumented
+fun:vwarn=uninstrumented
+fun:vwarnx=uninstrumented
+fun:vwprintf=uninstrumented
+fun:vwscanf=uninstrumented
+fun:wait=uninstrumented
+fun:wait3=uninstrumented
+fun:wait4=uninstrumented
+fun:waitid=uninstrumented
+fun:waitpid=uninstrumented
+fun:warn=uninstrumented
+fun:warnx=uninstrumented
+fun:wcpcpy=uninstrumented
+fun:wcpncpy=uninstrumented
+fun:wcrtomb=uninstrumented
+fun:wcscasecmp=uninstrumented
+fun:wcscasecmp_l=uninstrumented
+fun:wcscat=uninstrumented
+fun:wcschr=uninstrumented
+fun:wcschrnul=uninstrumented
+fun:wcscmp=uninstrumented
+fun:wcscoll=uninstrumented
+fun:wcscoll_l=uninstrumented
+fun:wcscpy=uninstrumented
+fun:wcscspn=uninstrumented
+fun:wcsdup=uninstrumented
+fun:wcsftime=uninstrumented
+fun:wcsftime_l=uninstrumented
+fun:wcslen=uninstrumented
+fun:wcsncasecmp=uninstrumented
+fun:wcsncasecmp_l=uninstrumented
+fun:wcsncat=uninstrumented
+fun:wcsncmp=uninstrumented
+fun:wcsncpy=uninstrumented
+fun:wcsnlen=uninstrumented
+fun:wcsnrtombs=uninstrumented
+fun:wcspbrk=uninstrumented
+fun:wcsrchr=uninstrumented
+fun:wcsrtombs=uninstrumented
+fun:wcsspn=uninstrumented
+fun:wcsstr=uninstrumented
+fun:wcstod=uninstrumented
+fun:wcstod_l=uninstrumented
+fun:wcstof=uninstrumented
+fun:wcstof_l=uninstrumented
+fun:wcstoimax=uninstrumented
+fun:wcstok=uninstrumented
+fun:wcstol=uninstrumented
+fun:wcstol_l=uninstrumented
+fun:wcstold=uninstrumented
+fun:wcstold_l=uninstrumented
+fun:wcstoll=uninstrumented
+fun:wcstoll_l=uninstrumented
+fun:wcstombs=uninstrumented
+fun:wcstoq=uninstrumented
+fun:wcstoul=uninstrumented
+fun:wcstoul_l=uninstrumented
+fun:wcstoull=uninstrumented
+fun:wcstoull_l=uninstrumented
+fun:wcstoumax=uninstrumented
+fun:wcstouq=uninstrumented
+fun:wcswcs=uninstrumented
+fun:wcswidth=uninstrumented
+fun:wcsxfrm=uninstrumented
+fun:wcsxfrm_l=uninstrumented
+fun:wctob=uninstrumented
+fun:wctomb=uninstrumented
+fun:wctrans=uninstrumented
+fun:wctrans_l=uninstrumented
+fun:wctype=uninstrumented
+fun:wctype_l=uninstrumented
+fun:wcwidth=uninstrumented
+fun:wmemchr=uninstrumented
+fun:wmemcmp=uninstrumented
+fun:wmemcpy=uninstrumented
+fun:wmemmove=uninstrumented
+fun:wmempcpy=uninstrumented
+fun:wmemset=uninstrumented
+fun:wordexp=uninstrumented
+fun:wordfree=uninstrumented
+fun:wprintf=uninstrumented
+fun:write=uninstrumented
+fun:writeColdStartFile=uninstrumented
+fun:writev=uninstrumented
+fun:wscanf=uninstrumented
+fun:xdecrypt=uninstrumented
+fun:xdr_accepted_reply=uninstrumented
+fun:xdr_array=uninstrumented
+fun:xdr_authdes_cred=uninstrumented
+fun:xdr_authdes_verf=uninstrumented
+fun:xdr_authunix_parms=uninstrumented
+fun:xdr_bool=uninstrumented
+fun:xdr_bytes=uninstrumented
+fun:xdr_callhdr=uninstrumented
+fun:xdr_callmsg=uninstrumented
+fun:xdr_cback_data=uninstrumented
+fun:xdr_char=uninstrumented
+fun:xdr_cryptkeyarg=uninstrumented
+fun:xdr_cryptkeyarg2=uninstrumented
+fun:xdr_cryptkeyres=uninstrumented
+fun:xdr_des_block=uninstrumented
+fun:xdr_domainname=uninstrumented
+fun:xdr_double=uninstrumented
+fun:xdr_enum=uninstrumented
+fun:xdr_float=uninstrumented
+fun:xdr_free=uninstrumented
+fun:xdr_getcredres=uninstrumented
+fun:xdr_hyper=uninstrumented
+fun:xdr_int=uninstrumented
+fun:xdr_int16_t=uninstrumented
+fun:xdr_int32_t=uninstrumented
+fun:xdr_int64_t=uninstrumented
+fun:xdr_int8_t=uninstrumented
+fun:xdr_key_netstarg=uninstrumented
+fun:xdr_key_netstres=uninstrumented
+fun:xdr_keybuf=uninstrumented
+fun:xdr_keydat=uninstrumented
+fun:xdr_keystatus=uninstrumented
+fun:xdr_long=uninstrumented
+fun:xdr_longlong_t=uninstrumented
+fun:xdr_mapname=uninstrumented
+fun:xdr_netnamestr=uninstrumented
+fun:xdr_netobj=uninstrumented
+fun:xdr_obj_p=uninstrumented
+fun:xdr_opaque=uninstrumented
+fun:xdr_opaque_auth=uninstrumented
+fun:xdr_peername=uninstrumented
+fun:xdr_pmap=uninstrumented
+fun:xdr_pmaplist=uninstrumented
+fun:xdr_pointer=uninstrumented
+fun:xdr_quad_t=uninstrumented
+fun:xdr_reference=uninstrumented
+fun:xdr_rejected_reply=uninstrumented
+fun:xdr_replymsg=uninstrumented
+fun:xdr_rmtcall_args=uninstrumented
+fun:xdr_rmtcallres=uninstrumented
+fun:xdr_short=uninstrumented
+fun:xdr_sizeof=uninstrumented
+fun:xdr_string=uninstrumented
+fun:xdr_u_char=uninstrumented
+fun:xdr_u_hyper=uninstrumented
+fun:xdr_u_int=uninstrumented
+fun:xdr_u_long=uninstrumented
+fun:xdr_u_longlong_t=uninstrumented
+fun:xdr_u_quad_t=uninstrumented
+fun:xdr_u_short=uninstrumented
+fun:xdr_uint16_t=uninstrumented
+fun:xdr_uint32_t=uninstrumented
+fun:xdr_uint64_t=uninstrumented
+fun:xdr_uint8_t=uninstrumented
+fun:xdr_union=uninstrumented
+fun:xdr_unixcred=uninstrumented
+fun:xdr_valdat=uninstrumented
+fun:xdr_vector=uninstrumented
+fun:xdr_void=uninstrumented
+fun:xdr_wrapstring=uninstrumented
+fun:xdr_yp_buf=uninstrumented
+fun:xdr_ypall=uninstrumented
+fun:xdr_ypbind_binding=uninstrumented
+fun:xdr_ypbind_resp=uninstrumented
+fun:xdr_ypbind_resptype=uninstrumented
+fun:xdr_ypbind_setdom=uninstrumented
+fun:xdr_ypdelete_args=uninstrumented
+fun:xdr_ypmap_parms=uninstrumented
+fun:xdr_ypmaplist=uninstrumented
+fun:xdr_yppush_status=uninstrumented
+fun:xdr_yppushresp_xfr=uninstrumented
+fun:xdr_ypreq_key=uninstrumented
+fun:xdr_ypreq_nokey=uninstrumented
+fun:xdr_ypreq_xfr=uninstrumented
+fun:xdr_ypresp_all=uninstrumented
+fun:xdr_ypresp_key_val=uninstrumented
+fun:xdr_ypresp_maplist=uninstrumented
+fun:xdr_ypresp_master=uninstrumented
+fun:xdr_ypresp_order=uninstrumented
+fun:xdr_ypresp_val=uninstrumented
+fun:xdr_ypresp_xfr=uninstrumented
+fun:xdr_ypstat=uninstrumented
+fun:xdr_ypupdate_args=uninstrumented
+fun:xdr_ypxfrstat=uninstrumented
+fun:xdrmem_create=uninstrumented
+fun:xdrrec_create=uninstrumented
+fun:xdrrec_endofrecord=uninstrumented
+fun:xdrrec_eof=uninstrumented
+fun:xdrrec_skiprecord=uninstrumented
+fun:xdrstdio_create=uninstrumented
+fun:xencrypt=uninstrumented
+fun:xprt_register=uninstrumented
+fun:xprt_unregister=uninstrumented
+fun:y0=uninstrumented
+fun:y0f=uninstrumented
+fun:y0l=uninstrumented
+fun:y1=uninstrumented
+fun:y1f=uninstrumented
+fun:y1l=uninstrumented
+fun:yn=uninstrumented
+fun:ynf=uninstrumented
+fun:ynl=uninstrumented
+fun:yp_all=uninstrumented
+fun:yp_bind=uninstrumented
+fun:yp_first=uninstrumented
+fun:yp_get_default_domain=uninstrumented
+fun:yp_maplist=uninstrumented
+fun:yp_master=uninstrumented
+fun:yp_match=uninstrumented
+fun:yp_next=uninstrumented
+fun:yp_order=uninstrumented
+fun:yp_unbind=uninstrumented
+fun:yp_update=uninstrumented
+fun:ypbinderr_string=uninstrumented
+fun:yperr_string=uninstrumented
+fun:ypprot_err=uninstrumented
diff --git a/compiler-rt/lib/dfsan/scripts/build-libc-list.py b/compiler-rt/lib/dfsan/scripts/build-libc-list.py
new file mode 100755
index 0000000..eddb6c0
--- /dev/null
+++ b/compiler-rt/lib/dfsan/scripts/build-libc-list.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#===- lib/dfsan/scripts/build-libc-list.py ---------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# The purpose of this script is to identify every function symbol in a set of
+# libraries (in this case, libc and libgcc) so that they can be marked as
+# uninstrumented, thus allowing the instrumentation pass to treat calls to those
+# functions correctly.
+
+import os
+import subprocess
+import sys
+from optparse import OptionParser
+
+def defined_function_list(object):
+ functions = []
+ readelf_proc = subprocess.Popen(['readelf', '-s', '-W', object],
+ stdout=subprocess.PIPE)
+ readelf = readelf_proc.communicate()[0].split('\n')
+ if readelf_proc.returncode != 0:
+ raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
+ for line in readelf:
+ if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
+ line[39:44] != 'LOCAL' and \
+ line[55:58] != 'UND':
+ function_name = line[59:].split('@')[0]
+ functions.append(function_name)
+ return functions
+
+p = OptionParser()
+
+p.add_option('--libc-dso-path', metavar='PATH',
+ help='path to libc DSO directory',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--libc-archive-path', metavar='PATH',
+ help='path to libc archive directory',
+ default='/usr/lib/x86_64-linux-gnu')
+
+p.add_option('--libgcc-dso-path', metavar='PATH',
+ help='path to libgcc DSO directory',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--libgcc-archive-path', metavar='PATH',
+ help='path to libgcc archive directory',
+ default='/usr/lib/gcc/x86_64-linux-gnu/4.6')
+
+p.add_option('--with-libstdcxx', action='store_true',
+ dest='with_libstdcxx',
+ help='include libstdc++ in the list (inadvisable)')
+p.add_option('--libstdcxx-dso-path', metavar='PATH',
+ help='path to libstdc++ DSO directory',
+ default='/usr/lib/x86_64-linux-gnu')
+
+(options, args) = p.parse_args()
+
+libs = [os.path.join(options.libc_dso_path, name) for name in
+ ['ld-linux-x86-64.so.2',
+ 'libanl.so.1',
+ 'libBrokenLocale.so.1',
+ 'libcidn.so.1',
+ 'libcrypt.so.1',
+ 'libc.so.6',
+ 'libdl.so.2',
+ 'libm.so.6',
+ 'libnsl.so.1',
+ 'libpthread.so.0',
+ 'libresolv.so.2',
+ 'librt.so.1',
+ 'libthread_db.so.1',
+ 'libutil.so.1']]
+libs += [os.path.join(options.libc_archive_path, name) for name in
+ ['libc_nonshared.a',
+ 'libpthread_nonshared.a']]
+
+libs.append(os.path.join(options.libgcc_dso_path, 'libgcc_s.so.1'))
+libs.append(os.path.join(options.libgcc_archive_path, 'libgcc.a'))
+
+if options.with_libstdcxx:
+ libs.append(os.path.join(options.libstdcxx_dso_path, 'libstdc++.so.6'))
+
+functions = []
+for l in libs:
+ if os.path.exists(l):
+ functions += defined_function_list(l)
+ else:
+ print >> sys.stderr, 'warning: library %s not found' % l
+
+functions = list(set(functions))
+functions.sort()
+
+for f in functions:
+ print 'fun:%s=uninstrumented' % f
diff --git a/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh b/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
new file mode 100755
index 0000000..99bf50c
--- /dev/null
+++ b/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+DFSAN_DIR=$(dirname "$0")/../
+DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
+DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
+DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
+
+DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+
+on_exit() {
+ rm -f ${DIFFOUT} 2> /dev/null
+ rm -f ${ERRORLOG} 2> /dev/null
+ rm -f ${DIFF_A} 2> /dev/null
+ rm -f ${DIFF_B} 2> /dev/null
+}
+
+# Ignore __sanitizer_cov_trace* because they are implemented elsewhere.
+trap on_exit EXIT
+grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} \
+ | grep -v "dfsan_get_label\|__sanitizer_cov_trace" \
+ | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
+grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
+ echo "the implemented custom wrappers have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
+grep -E "^[[:space:]]*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
+ | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the implemented " >> ${ERRORLOG}
+ echo "custom wrappers and the tests have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+if [ -s ${ERRORLOG} ]
+then
+ cat ${ERRORLOG}
+ exit 1
+fi
+
diff --git a/compiler-rt/lib/interception/.clang-format b/compiler-rt/lib/interception/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/interception/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/interception/Android.bp b/compiler-rt/lib/interception/Android.bp
new file mode 100644
index 0000000..479ea67
--- /dev/null
+++ b/compiler-rt/lib/interception/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+cc_library_static {
+ name: "libinterception",
+ host_supported: true,
+ clang: true,
+ sdk_version: "19",
+
+ include_dirs: ["external/compiler-rt/lib"],
+ cppflags: [
+ "-fvisibility=hidden",
+ "-fno-exceptions",
+ "-std=c++11",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+ srcs: [
+ "interception_linux.cc",
+ "interception_mac.cc",
+ "interception_type_test.cc",
+ "interception_win.cc",
+ ],
+ stl: "none",
+ sanitize: {
+ never: true,
+ },
+ compile_multilib: "both",
+}
diff --git a/compiler-rt/lib/interception/CMakeLists.txt b/compiler-rt/lib/interception/CMakeLists.txt
new file mode 100644
index 0000000..16b41c9
--- /dev/null
+++ b/compiler-rt/lib/interception/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Build for the runtime interception helper library.
+
+set(INTERCEPTION_SOURCES
+ interception_linux.cc
+ interception_mac.cc
+ interception_win.cc
+ interception_type_test.cc
+ )
+
+include_directories(..)
+
+set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(INTERCEPTION_CFLAGS)
+
+add_compiler_rt_object_libraries(RTInterception
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${INTERCEPTION_SOURCES}
+ CFLAGS ${INTERCEPTION_CFLAGS})
diff --git a/compiler-rt/lib/interception/Makefile.mk b/compiler-rt/lib/interception/Makefile.mk
new file mode 100644
index 0000000..88aa6cb
--- /dev/null
+++ b/compiler-rt/lib/interception/Makefile.mk
@@ -0,0 +1,23 @@
+#===- lib/interception/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := interception
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
+
+# Define a convenience variable for all the interception functions.
+InterceptionFunctions := $(Sources:%.cc=%)
diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h
new file mode 100644
index 0000000..9e9aca2
--- /dev/null
+++ b/compiler-rt/lib/interception/interception.h
@@ -0,0 +1,261 @@
+//===-- interception.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Machinery for providing replacements/wrappers for system functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERCEPTION_H
+#define INTERCEPTION_H
+
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32)
+# error "Interception doesn't work on this operating system."
+#endif
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+// These typedefs should be used only in the interceptor definitions to replace
+// the standard system types (e.g. SSIZE_T instead of ssize_t)
+typedef __sanitizer::uptr SIZE_T;
+typedef __sanitizer::sptr SSIZE_T;
+typedef __sanitizer::sptr PTRDIFF_T;
+typedef __sanitizer::s64 INTMAX_T;
+typedef __sanitizer::OFF_T OFF_T;
+typedef __sanitizer::OFF64_T OFF64_T;
+
+// How to add an interceptor:
+// Suppose you need to wrap/replace system function (generally, from libc):
+// int foo(const char *bar, double baz);
+// You'll need to:
+// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
+// your source file. See the notes below for cases when
+// INTERCEPTOR_WITH_SUFFIX(...) should be used instead.
+// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
+// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
+// intercepted successfully.
+// You can access original function by calling REAL(foo)(bar, baz).
+// By default, REAL(foo) will be visible only inside your interceptor, and if
+// you want to use it in other parts of RTL, you'll need to:
+// 3a) add DECLARE_REAL(int, foo, const char*, double) to a
+// header file.
+// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
+// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
+// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
+// to a header file.
+
+// Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or
+// DECLARE_REAL(...) are located inside namespaces.
+// 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to
+// effectively redirect calls from "foo" to "zoo". In this case
+// you aren't required to implement
+// INTERCEPTOR(int, foo, const char *bar, double baz) {...}
+// but instead you'll have to add
+// DECLARE_REAL(int, foo, const char *bar, double baz) in your
+// source file (to define a pointer to overriden function).
+// 3. Some Mac functions have symbol variants discriminated by
+// additional suffixes, e.g. _$UNIX2003 (see
+// https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html
+// for more details). To intercept such functions you need to use the
+// INTERCEPTOR_WITH_SUFFIX(...) macro.
+
+// How it works:
+// To replace system functions on Linux we just need to declare functions
+// with same names in our library and then obtain the real function pointers
+// using dlsym().
+// There is one complication. A user may also intercept some of the functions
+// we intercept. To resolve this we declare our interceptors with __interceptor_
+// prefix, and then make actual interceptors weak aliases to __interceptor_
+// functions.
+//
+// This is not so on Mac OS, where the two-level namespace makes
+// our replacement functions invisible to other libraries. This may be overcomed
+// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
+// libraries in Chromium were noticed when doing so.
+// Instead we create a dylib containing a __DATA,__interpose section that
+// associates library functions with their wrappers. When this dylib is
+// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
+// the calls to interposed functions done through stubs to the wrapper
+// functions.
+// As it's decided at compile time which functions are to be intercepted on Mac,
+// INTERCEPT_FUNCTION() is effectively a no-op on this system.
+
+#if defined(__APPLE__)
+#include <sys/cdefs.h> // For __DARWIN_ALIAS_C().
+
+// Just a pair of pointers.
+struct interpose_substitution {
+ const uptr replacement;
+ const uptr original;
+};
+
+// For a function foo() create a global pair of pointers { wrap_foo, foo } in
+// the __DATA,__interpose section.
+// As a result all the calls to foo() will be routed to wrap_foo() at runtime.
+#define INTERPOSER(func_name) __attribute__((used)) \
+const interpose_substitution substitution_##func_name[] \
+ __attribute__((section("__DATA, __interpose"))) = { \
+ { reinterpret_cast<const uptr>(WRAP(func_name)), \
+ reinterpret_cast<const uptr>(func_name) } \
+}
+
+// For a function foo() and a wrapper function bar() create a global pair
+// of pointers { bar, foo } in the __DATA,__interpose section.
+// As a result all the calls to foo() will be routed to bar() at runtime.
+#define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \
+const interpose_substitution substitution_##func_name[] \
+ __attribute__((section("__DATA, __interpose"))) = { \
+ { reinterpret_cast<const uptr>(wrapper_name), \
+ reinterpret_cast<const uptr>(func_name) } \
+}
+
+# define WRAP(x) wrap_##x
+# define WRAPPER_NAME(x) "wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE
+# define DECLARE_WRAPPER(ret_type, func, ...)
+
+#elif defined(_WIN32)
+# define WRAP(x) __asan_wrap_##x
+# define WRAPPER_NAME(x) "__asan_wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__);
+# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
+ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
+#elif defined(__FreeBSD__)
+# define WRAP(x) __interceptor_ ## x
+# define WRAPPER_NAME(x) "__interceptor_" #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
+// priority than weak ones so weak aliases won't work for indirect calls
+// in position-independent (-fPIC / -fPIE) mode.
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) \
+ __attribute__((alias("__interceptor_" #func), visibility("default")));
+#else
+# define WRAP(x) __interceptor_ ## x
+# define WRAPPER_NAME(x) "__interceptor_" #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) \
+ __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
+#endif
+
+#if !defined(__APPLE__)
+# define PTR_TO_REAL(x) real_##x
+# define REAL(x) __interception::PTR_TO_REAL(x)
+# define FUNC_TYPE(x) x##_f
+
+# define DECLARE_REAL(ret_type, func, ...) \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ extern FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+#else // __APPLE__
+# define REAL(x) x
+# define DECLARE_REAL(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__);
+#endif // __APPLE__
+
+#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
+ DECLARE_REAL(ret_type, func, __VA_ARGS__) \
+ extern "C" ret_type WRAP(func)(__VA_ARGS__);
+
+// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
+// macros does its job. In exceptional cases you may need to call REAL(foo)
+// without defining INTERCEPTOR(..., foo, ...). For example, if you override
+// foo with an interceptor for other function.
+#if !defined(__APPLE__)
+# define DEFINE_REAL(ret_type, func, ...) \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+#else
+# define DEFINE_REAL(ret_type, func, ...)
+#endif
+
+#if !defined(__APPLE__)
+#define INTERCEPTOR(ret_type, func, ...) \
+ DEFINE_REAL(ret_type, func, __VA_ARGS__) \
+ DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
+ extern "C" \
+ INTERCEPTOR_ATTRIBUTE \
+ ret_type WRAP(func)(__VA_ARGS__)
+
+// We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now.
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+ INTERCEPTOR(ret_type, func, __VA_ARGS__)
+
+#else // __APPLE__
+
+#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) suffix; \
+ extern "C" ret_type WRAP(func)(__VA_ARGS__); \
+ INTERPOSER(func); \
+ extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
+
+#define INTERCEPTOR(ret_type, func, ...) \
+ INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__)
+
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+ INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__)
+
+// Override |overridee| with |overrider|.
+#define OVERRIDE_FUNCTION(overridee, overrider) \
+ INTERPOSER_2(overridee, WRAP(overrider))
+#endif
+
+#if defined(_WIN32)
+# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
+ typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ FUNC_TYPE(func) PTR_TO_REAL(func); \
+ } \
+ extern "C" \
+ INTERCEPTOR_ATTRIBUTE \
+ ret_type __stdcall WRAP(func)(__VA_ARGS__)
+#endif
+
+// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
+// so we use casting via an integral type __interception::uptr,
+// assuming that system is POSIX-compliant. Using other hacks seem
+// challenging, as we don't even pass function type to
+// INTERCEPT_FUNCTION macro, only its name.
+namespace __interception {
+#if defined(_WIN64)
+typedef unsigned long long uptr; // NOLINT
+#else
+typedef unsigned long uptr; // NOLINT
+#endif // _WIN64
+} // namespace __interception
+
+#define INCLUDED_FROM_INTERCEPTION_LIB
+
+#if defined(__linux__) || defined(__FreeBSD__)
+# include "interception_linux.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver)
+#elif defined(__APPLE__)
+# include "interception_mac.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_MAC(func, symver)
+#else // defined(_WIN32)
+# include "interception_win.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_WIN(func, symver)
+#endif
+
+#undef INCLUDED_FROM_INTERCEPTION_LIB
+
+#endif // INTERCEPTION_H
diff --git a/compiler-rt/lib/interception/interception_linux.cc b/compiler-rt/lib/interception/interception_linux.cc
new file mode 100644
index 0000000..6e908ac
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_linux.cc
@@ -0,0 +1,36 @@
+//===-- interception_linux.cc -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__FreeBSD__)
+#include "interception.h"
+
+#include <dlfcn.h> // for dlsym() and dlvsym()
+
+namespace __interception {
+bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
+ uptr real, uptr wrapper) {
+ *func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
+ return real == wrapper;
+}
+
+#if !defined(__ANDROID__) // android does not have dlvsym
+void *GetFuncAddrVer(const char *func_name, const char *ver) {
+ return dlvsym(RTLD_NEXT, func_name, ver);
+}
+#endif // !defined(__ANDROID__)
+
+} // namespace __interception
+
+
+#endif // __linux__ || __FreeBSD__
diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h
new file mode 100644
index 0000000..27a66c8
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_linux.h
@@ -0,0 +1,47 @@
+//===-- interception_linux.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__FreeBSD__)
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_linux.h should be included from interception library only"
+#endif
+
+#ifndef INTERCEPTION_LINUX_H
+#define INTERCEPTION_LINUX_H
+
+namespace __interception {
+// returns true if a function with the given name was found.
+bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
+ uptr real, uptr wrapper);
+void *GetFuncAddrVer(const char *func_name, const char *ver);
+} // namespace __interception
+
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
+ ::__interception::GetRealFunctionAddress( \
+ #func, (::__interception::uptr *)&__interception::PTR_TO_REAL(func), \
+ (::__interception::uptr) & (func), \
+ (::__interception::uptr) & WRAP(func))
+
+#if !defined(__ANDROID__) // android does not have dlvsym
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ (::__interception::real_##func = (func##_f)( \
+ unsigned long)::__interception::GetFuncAddrVer(#func, symver))
+#else
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+#endif // !defined(__ANDROID__)
+
+#endif // INTERCEPTION_LINUX_H
+#endif // __linux__ || __FreeBSD__
diff --git a/compiler-rt/lib/interception/interception_mac.cc b/compiler-rt/lib/interception/interception_mac.cc
new file mode 100644
index 0000000..b035cf9
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_mac.cc
@@ -0,0 +1,20 @@
+//===-- interception_mac.cc -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#include "interception.h"
+
+
+#endif // __APPLE__
diff --git a/compiler-rt/lib/interception/interception_mac.h b/compiler-rt/lib/interception/interception_mac.h
new file mode 100644
index 0000000..e5a35c6
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_mac.h
@@ -0,0 +1,28 @@
+//===-- interception_mac.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_mac.h should be included from interception.h only"
+#endif
+
+#ifndef INTERCEPTION_MAC_H
+#define INTERCEPTION_MAC_H
+
+#define INTERCEPT_FUNCTION_MAC(func)
+#define INTERCEPT_FUNCTION_VER_MAC(func, symver)
+
+#endif // INTERCEPTION_MAC_H
+#endif // __APPLE__
diff --git a/compiler-rt/lib/interception/interception_type_test.cc b/compiler-rt/lib/interception/interception_type_test.cc
new file mode 100644
index 0000000..98ce2e6
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_type_test.cc
@@ -0,0 +1,39 @@
+//===-- interception_type_test.cc -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Compile-time tests of the internal type definitions.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "interception.h"
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
+
+#ifndef __APPLE__
+COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t));
+#endif
+
+// The following are the cases when pread (and friends) is used instead of
+// pread64. In those cases we need OFF_T to match off_t. We don't care about the
+// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+ _FILE_OFFSET_BITS != 64
+COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t));
+# endif
+
+#endif
diff --git a/compiler-rt/lib/interception/interception_win.cc b/compiler-rt/lib/interception/interception_win.cc
new file mode 100644
index 0000000..4c04c83
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_win.cc
@@ -0,0 +1,273 @@
+//===-- interception_linux.cc -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Windows-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+
+#include "interception.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace __interception {
+
+// FIXME: internal_str* and internal_mem* functions should be moved from the
+// ASan sources into interception/.
+
+static void _memset(void *p, int value, size_t sz) {
+ for (size_t i = 0; i < sz; ++i)
+ ((char*)p)[i] = (char)value;
+}
+
+static void _memcpy(void *dst, void *src, size_t sz) {
+ char *dst_c = (char*)dst,
+ *src_c = (char*)src;
+ for (size_t i = 0; i < sz; ++i)
+ dst_c[i] = src_c[i];
+}
+
+static void WriteJumpInstruction(char *jmp_from, char *to) {
+ // jmp XXYYZZWW = E9 WW ZZ YY XX, where XXYYZZWW is an offset fromt jmp_from
+ // to the next instruction to the destination.
+ ptrdiff_t offset = to - jmp_from - 5;
+ *jmp_from = '\xE9';
+ *(ptrdiff_t*)(jmp_from + 1) = offset;
+}
+
+static char *GetMemoryForTrampoline(size_t size) {
+ // Trampolines are allocated from a common pool.
+ const int POOL_SIZE = 1024;
+ static char *pool = NULL;
+ static size_t pool_used = 0;
+ if (!pool) {
+ pool = (char *)VirtualAlloc(NULL, POOL_SIZE, MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ // FIXME: Might want to apply PAGE_EXECUTE_READ access after all the
+ // interceptors are in place.
+ if (!pool)
+ return NULL;
+ _memset(pool, 0xCC /* int 3 */, POOL_SIZE);
+ }
+
+ if (pool_used + size > POOL_SIZE)
+ return NULL;
+
+ char *ret = pool + pool_used;
+ pool_used += size;
+ return ret;
+}
+
+// Returns 0 on error.
+static size_t RoundUpToInstrBoundary(size_t size, char *code) {
+ size_t cursor = 0;
+ while (cursor < size) {
+ switch (code[cursor]) {
+ case '\x51': // push ecx
+ case '\x52': // push edx
+ case '\x53': // push ebx
+ case '\x54': // push esp
+ case '\x55': // push ebp
+ case '\x56': // push esi
+ case '\x57': // push edi
+ case '\x5D': // pop ebp
+ cursor++;
+ continue;
+ case '\x6A': // 6A XX = push XX
+ cursor += 2;
+ continue;
+ case '\xE9': // E9 XX YY ZZ WW = jmp WWZZYYXX
+ case '\xB8': // B8 XX YY ZZ WW = mov eax, WWZZYYXX
+ cursor += 5;
+ continue;
+ }
+ switch (*(unsigned short*)(code + cursor)) { // NOLINT
+ case 0xFF8B: // 8B FF = mov edi, edi
+ case 0xEC8B: // 8B EC = mov ebp, esp
+ case 0xC033: // 33 C0 = xor eax, eax
+ cursor += 2;
+ continue;
+ case 0x458B: // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
+ case 0x5D8B: // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
+ case 0xEC83: // 83 EC XX = sub esp, XX
+ case 0x75FF: // FF 75 XX = push dword ptr [ebp+XXh]
+ cursor += 3;
+ continue;
+ case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
+ case 0x25FF: // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
+ cursor += 6;
+ continue;
+ case 0x3D83: // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
+ cursor += 7;
+ continue;
+ }
+ switch (0x00FFFFFF & *(unsigned int*)(code + cursor)) {
+ case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
+ case 0x24448B: // 8B 44 24 XX = mov eax, dword ptr [esp+XXh]
+ case 0x244C8B: // 8B 4C 24 XX = mov ecx, dword ptr [esp+XXh]
+ case 0x24548B: // 8B 54 24 XX = mov edx, dword ptr [esp+XXh]
+ case 0x24748B: // 8B 74 24 XX = mov esi, dword ptr [esp+XXh]
+ case 0x247C8B: // 8B 7C 24 XX = mov edi, dword ptr [esp+XXh]
+ cursor += 4;
+ continue;
+ }
+
+ // Unknown instruction!
+ // FIXME: Unknown instruction failures might happen when we add a new
+ // interceptor or a new compiler version. In either case, they should result
+ // in visible and readable error messages. However, merely calling abort()
+ // leads to an infinite recursion in CheckFailed.
+ // Do we have a good way to abort with an error message here?
+ __debugbreak();
+ return 0;
+ }
+
+ return cursor;
+}
+
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
+#ifdef _WIN64
+#error OverrideFunction is not yet supported on x64
+#endif
+ // Function overriding works basically like this:
+ // We write "jmp <new_func>" (5 bytes) at the beginning of the 'old_func'
+ // to override it.
+ // We might want to be able to execute the original 'old_func' from the
+ // wrapper, in this case we need to keep the leading 5+ bytes ('head')
+ // of the original code somewhere with a "jmp <old_func+head>".
+ // We call these 'head'+5 bytes of instructions a "trampoline".
+ char *old_bytes = (char *)old_func;
+
+ // We'll need at least 5 bytes for a 'jmp'.
+ size_t head = 5;
+ if (orig_old_func) {
+ // Find out the number of bytes of the instructions we need to copy
+ // to the trampoline and store it in 'head'.
+ head = RoundUpToInstrBoundary(head, old_bytes);
+ if (!head)
+ return false;
+
+ // Put the needed instructions into the trampoline bytes.
+ char *trampoline = GetMemoryForTrampoline(head + 5);
+ if (!trampoline)
+ return false;
+ _memcpy(trampoline, old_bytes, head);
+ WriteJumpInstruction(trampoline + head, old_bytes + head);
+ *orig_old_func = (uptr)trampoline;
+ }
+
+ // Now put the "jmp <new_func>" instruction at the original code location.
+ // We should preserve the EXECUTE flag as some of our own code might be
+ // located in the same page (sic!). FIXME: might consider putting the
+ // __interception code into a separate section or something?
+ DWORD old_prot, unused_prot;
+ if (!VirtualProtect((void *)old_bytes, head, PAGE_EXECUTE_READWRITE,
+ &old_prot))
+ return false;
+
+ WriteJumpInstruction(old_bytes, (char *)new_func);
+ _memset(old_bytes + 5, 0xCC /* int 3 */, head - 5);
+
+ // Restore the original permissions.
+ if (!VirtualProtect((void *)old_bytes, head, old_prot, &unused_prot))
+ return false; // not clear if this failure bothers us.
+
+ return true;
+}
+
+static void **InterestingDLLsAvailable() {
+ const char *InterestingDLLs[] = {
+ "kernel32.dll",
+ "msvcr110.dll", // VS2012
+ "msvcr120.dll", // VS2013
+ // NTDLL should go last as it exports some functions that we should override
+ // in the CRT [presumably only used internally].
+ "ntdll.dll", NULL
+ };
+ static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
+ if (!result[0]) {
+ for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
+ if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
+ result[j++] = (void *)h;
+ }
+ }
+ return &result[0];
+}
+
+namespace {
+// Utility for reading loaded PE images.
+template <typename T> class RVAPtr {
+ public:
+ RVAPtr(void *module, uptr rva)
+ : ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(module) + rva)) {}
+ operator T *() { return ptr_; }
+ T *operator->() { return ptr_; }
+ T *operator++() { return ++ptr_; }
+
+ private:
+ T *ptr_;
+};
+} // namespace
+
+// Internal implementation of GetProcAddress. At least since Windows 8,
+// GetProcAddress appears to initialize DLLs before returning function pointers
+// into them. This is problematic for the sanitizers, because they typically
+// want to intercept malloc *before* MSVCRT initializes. Our internal
+// implementation walks the export list manually without doing initialization.
+uptr InternalGetProcAddress(void *module, const char *func_name) {
+ // Check that the module header is full and present.
+ RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0);
+ RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew);
+ if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ"
+ headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0"
+ headers->FileHeader.SizeOfOptionalHeader <
+ sizeof(IMAGE_OPTIONAL_HEADER)) {
+ return 0;
+ }
+
+ IMAGE_DATA_DIRECTORY *export_directory =
+ &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
+ export_directory->VirtualAddress);
+ RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
+ RVAPtr<DWORD> names(module, exports->AddressOfNames);
+ RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals);
+
+ for (DWORD i = 0; i < exports->NumberOfNames; i++) {
+ RVAPtr<char> name(module, names[i]);
+ if (!strcmp(func_name, name)) {
+ DWORD index = ordinals[i];
+ RVAPtr<char> func(module, functions[index]);
+ return (uptr)(char *)func;
+ }
+ }
+
+ return 0;
+}
+
+static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
+ *func_addr = 0;
+ void **DLLs = InterestingDLLsAvailable();
+ for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
+ *func_addr = InternalGetProcAddress(DLLs[i], func_name);
+ return (*func_addr != 0);
+}
+
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
+ uptr orig_func;
+ if (!GetFunctionAddressInDLLs(name, &orig_func))
+ return false;
+ return OverrideFunction(orig_func, new_func, orig_old_func);
+}
+
+} // namespace __interception
+
+#endif // _WIN32
diff --git a/compiler-rt/lib/interception/interception_win.h b/compiler-rt/lib/interception/interception_win.h
new file mode 100644
index 0000000..96c4a0c
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_win.h
@@ -0,0 +1,54 @@
+//===-- interception_linux.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Windows-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_win.h should be included from interception library only"
+#endif
+
+#ifndef INTERCEPTION_WIN_H
+#define INTERCEPTION_WIN_H
+
+namespace __interception {
+// All the functions in the OverrideFunction() family return true on success,
+// false on failure (including "couldn't find the function").
+
+// Overrides a function by its address.
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
+
+// Overrides a function in a system DLL or DLL CRT by its exported name.
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
+
+// Windows-only replacement for GetProcAddress. Useful for some sanitizers.
+uptr InternalGetProcAddress(void *module, const char *func_name);
+
+} // namespace __interception
+
+#if defined(INTERCEPTION_DYNAMIC_CRT)
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction(#func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
+#else
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction((::__interception::uptr)func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
+#endif
+
+#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
+
+#endif // INTERCEPTION_WIN_H
+#endif // _WIN32
diff --git a/compiler-rt/lib/lsan/.clang-format b/compiler-rt/lib/lsan/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/lsan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/lsan/Android.bp b/compiler-rt/lib/lsan/Android.bp
new file mode 100644
index 0000000..97f55c3
--- /dev/null
+++ b/compiler-rt/lib/lsan/Android.bp
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+cc_library_static {
+ name: "liblsan",
+ host_supported: true,
+ defaults: ["asan_arch_defaults"],
+ include_dirs: [
+ "external/compiler-rt/lib",
+ "external/compiler-rt/include",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-fno-exceptions",
+ "-Wno-covered-switch-default",
+ "-Wno-non-virtual-dtor",
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ "-std=c++11",
+ "-fno-rtti",
+ "-fno-builtin",
+ ],
+ srcs: [
+ "lsan_common.cc",
+ "lsan_common_linux.cc",
+ ],
+
+ clang: true,
+ sdk_version: "19",
+ stl: "none",
+
+ sanitize: {
+ never: true,
+ },
+}
diff --git a/compiler-rt/lib/lsan/CMakeLists.txt b/compiler-rt/lib/lsan/CMakeLists.txt
new file mode 100644
index 0000000..20e4093
--- /dev/null
+++ b/compiler-rt/lib/lsan/CMakeLists.txt
@@ -0,0 +1,42 @@
+include_directories(..)
+
+set(LSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(LSAN_CFLAGS)
+
+set(LSAN_COMMON_SOURCES
+ lsan_common.cc
+ lsan_common_linux.cc)
+
+set(LSAN_SOURCES
+ lsan.cc
+ lsan_allocator.cc
+ lsan_interceptors.cc
+ lsan_preinit.cc
+ lsan_thread.cc)
+
+set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+add_custom_target(lsan)
+
+add_compiler_rt_object_libraries(RTLSanCommon
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${LSAN_COMMON_SUPPORTED_ARCH}
+ SOURCES ${LSAN_COMMON_SOURCES}
+ CFLAGS ${LSAN_CFLAGS})
+
+if(COMPILER_RT_HAS_LSAN)
+ foreach(arch ${LSAN_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.lsan
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${LSAN_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ CFLAGS ${LSAN_CFLAGS}
+ PARENT_TARGET lsan)
+ endforeach()
+endif()
+
+add_dependencies(compiler-rt lsan)
diff --git a/compiler-rt/lib/lsan/Makefile.mk b/compiler-rt/lib/lsan/Makefile.mk
new file mode 100644
index 0000000..5e70634
--- /dev/null
+++ b/compiler-rt/lib/lsan/Makefile.mk
@@ -0,0 +1,25 @@
+#===- lib/lsan/Makefile.mk ---------------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := lsan
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../interception/*.h)
+Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
+
+# lsan functions used in another sanitizers.
+LsanCommonSources := $(foreach file,$(wildcard $(Dir)/lsan_common*.cc),$(notdir $(file)))
+LsanCommonFunctions := $(LsanCommonSources:%.cc=%)
diff --git a/compiler-rt/lib/lsan/lsan.cc b/compiler-rt/lib/lsan/lsan.cc
new file mode 100644
index 0000000..f3e6ad7
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan.cc
@@ -0,0 +1,98 @@
+//=-- lsan.cc -------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
+#include "lsan_thread.h"
+
+bool lsan_inited;
+bool lsan_init_is_running;
+
+namespace __lsan {
+
+///// Interface to the common LSan module. /////
+bool WordIsPoisoned(uptr addr) {
+ return false;
+}
+
+} // namespace __lsan
+
+using namespace __lsan; // NOLINT
+
+static void InitializeFlags() {
+ // Set all the default values.
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = 30;
+ cf.detect_leaks = true;
+ cf.exitcode = 23;
+ OverrideCommonFlags(cf);
+ }
+
+ Flags *f = flags();
+ f->SetDefaults();
+
+ FlagParser parser;
+ RegisterLsanFlags(&parser, f);
+ RegisterCommonFlags(&parser);
+
+ parser.ParseString(GetEnv("LSAN_OPTIONS"));
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+}
+
+extern "C" void __lsan_init() {
+ CHECK(!lsan_init_is_running);
+ if (lsan_inited)
+ return;
+ lsan_init_is_running = true;
+ SanitizerToolName = "LeakSanitizer";
+ CacheBinaryName();
+ InitializeFlags();
+ InitCommonLsan();
+ InitializeAllocator();
+ InitTlsSize();
+ InitializeInterceptors();
+ InitializeThreadRegistry();
+ u32 tid = ThreadCreate(0, 0, true);
+ CHECK_EQ(tid, 0);
+ ThreadStart(tid, GetTid());
+ SetCurrentThread(tid);
+
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
+ Atexit(DoLeakCheck);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ lsan_inited = true;
+ lsan_init_is_running = false;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_STACK_TRACE_FATAL;
+ stack.Print();
+}
diff --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h
new file mode 100644
index 0000000..53783cd
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan.h
@@ -0,0 +1,47 @@
+//=-- lsan.h --------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Private header for standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ { \
+ uptr stack_top = 0, stack_bottom = 0; \
+ ThreadContext *t; \
+ if (fast && (t = CurrentThreadContext())) { \
+ stack_top = t->stack_end(); \
+ stack_bottom = t->stack_begin(); \
+ } \
+ stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ /* context */ 0, stack_top, stack_bottom, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
+ common_flags()->fast_unwind_on_malloc)
+
+namespace __lsan {
+
+void InitializeInterceptors();
+
+} // namespace __lsan
+
+extern bool lsan_inited;
+extern bool lsan_init_is_running;
+
+extern "C" void __lsan_init();
diff --git a/compiler-rt/lib/lsan/lsan_allocator.cc b/compiler-rt/lib/lsan/lsan_allocator.cc
new file mode 100644
index 0000000..0a36781
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_allocator.cc
@@ -0,0 +1,250 @@
+//=-- lsan_allocator.cc ---------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// See lsan_allocator.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_allocator.h"
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_common.h"
+
+extern "C" void *memset(void *ptr, int value, uptr num);
+
+namespace __lsan {
+
+struct ChunkMetadata {
+ u8 allocated : 8; // Must be first.
+ ChunkTag tag : 2;
+ uptr requested_size : 54;
+ u32 stack_trace_id;
+};
+
+#if defined(__mips64) || defined(__aarch64__)
+static const uptr kMaxAllowedMallocSize = 4UL << 30;
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
+ sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
+ PrimaryAllocator;
+#else
+static const uptr kMaxAllowedMallocSize = 8UL << 30;
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
+ sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static THREADLOCAL AllocatorCache cache;
+
+void InitializeAllocator() {
+ allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null);
+}
+
+void AllocatorThreadFinish() {
+ allocator.SwallowCache(&cache);
+}
+
+static ChunkMetadata *Metadata(const void *p) {
+ return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
+}
+
+static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
+ if (!p) return;
+ ChunkMetadata *m = Metadata(p);
+ CHECK(m);
+ m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
+ m->stack_trace_id = StackDepotPut(stack);
+ m->requested_size = size;
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
+}
+
+static void RegisterDeallocation(void *p) {
+ if (!p) return;
+ ChunkMetadata *m = Metadata(p);
+ CHECK(m);
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
+}
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+ bool cleared) {
+ if (size == 0)
+ size = 1;
+ if (size > kMaxAllowedMallocSize) {
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
+ return nullptr;
+ }
+ void *p = allocator.Allocate(&cache, size, alignment, false);
+ // Do not rely on the allocator to clear the memory (it's slow).
+ if (cleared && allocator.FromPrimary(p))
+ memset(p, 0, size);
+ RegisterAllocation(stack, p, size);
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
+ return p;
+}
+
+void Deallocate(void *p) {
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
+ RegisterDeallocation(p);
+ allocator.Deallocate(&cache, p);
+}
+
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+ uptr alignment) {
+ RegisterDeallocation(p);
+ if (new_size > kMaxAllowedMallocSize) {
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
+ allocator.Deallocate(&cache, p);
+ return nullptr;
+ }
+ p = allocator.Reallocate(&cache, p, new_size, alignment);
+ RegisterAllocation(stack, p, new_size);
+ return p;
+}
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&cache;
+ *end = *begin + sizeof(cache);
+}
+
+uptr GetMallocUsableSize(const void *p) {
+ ChunkMetadata *m = Metadata(p);
+ if (!m) return 0;
+ return m->requested_size;
+}
+
+///// Interface to the common LSan module. /////
+
+void LockAllocator() {
+ allocator.ForceLock();
+}
+
+void UnlockAllocator() {
+ allocator.ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+ *begin = (uptr)&allocator;
+ *end = *begin + sizeof(allocator);
+}
+
+uptr PointsIntoChunk(void* p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
+ if (!chunk) return 0;
+ // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
+ // valid, but we don't want that.
+ if (addr < chunk) return 0;
+ ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
+ CHECK(m);
+ if (!m->allocated)
+ return 0;
+ if (addr < chunk + m->requested_size)
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr))
+ return chunk;
+ return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+ return chunk;
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = Metadata(reinterpret_cast<void *>(chunk));
+ CHECK(metadata_);
+}
+
+bool LsanMetadata::allocated() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
+}
+
+ChunkTag LsanMetadata::tag() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+ reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+ return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ void *chunk = allocator.GetBlockBegin(p);
+ if (!chunk || p < chunk) return kIgnoreObjectInvalid;
+ ChunkMetadata *m = Metadata(chunk);
+ CHECK(m);
+ if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
+ if (m->tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->tag = kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
+}
+} // namespace __lsan
+
+using namespace __lsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_free_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_unmapped_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_get_ownership(const void *p) { return Metadata(p) != nullptr; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_allocated_size(const void *p) {
+ return GetMallocUsableSize(p);
+}
+} // extern "C"
diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h
new file mode 100644
index 0000000..f564601
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_allocator.h
@@ -0,0 +1,39 @@
+//=-- lsan_allocator.h ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Allocator for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_ALLOCATOR_H
+#define LSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __lsan {
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+ bool cleared);
+void Deallocate(void *p);
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+ uptr alignment);
+uptr GetMallocUsableSize(const void *p);
+
+template<typename Callable>
+void ForEachChunk(const Callable &callback);
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end);
+void AllocatorThreadFinish();
+void InitializeAllocator();
+
+} // namespace __lsan
+
+#endif // LSAN_ALLOCATOR_H
diff --git a/compiler-rt/lib/lsan/lsan_common.cc b/compiler-rt/lib/lsan/lsan_common.cc
new file mode 100644
index 0000000..1cffac4
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_common.cc
@@ -0,0 +1,723 @@
+//=-- lsan_common.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+
+#if CAN_SANITIZE_LEAKS
+namespace __lsan {
+
+// This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and
+// also to protect the global list of root regions.
+BlockingMutex global_mutex(LINKER_INITIALIZED);
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+
+Flags lsan_flags;
+
+void Flags::SetDefaults() {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+}
+
+void RegisterLsanFlags(FlagParser *parser, Flags *f) {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+}
+
+#define LOG_POINTERS(...) \
+ do { \
+ if (flags()->log_pointers) Report(__VA_ARGS__); \
+ } while (0);
+
+#define LOG_THREADS(...) \
+ do { \
+ if (flags()->log_threads) Report(__VA_ARGS__); \
+ } while (0);
+
+ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = nullptr;
+static const char kSuppressionLeak[] = "leak";
+static const char *kSuppressionTypes[] = { kSuppressionLeak };
+
+void InitializeSuppressions() {
+ CHECK_EQ(nullptr, suppression_ctx);
+ suppression_ctx = new (suppression_placeholder) // NOLINT
+ SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+ suppression_ctx->ParseFromFile(flags()->suppressions);
+ if (&__lsan_default_suppressions)
+ suppression_ctx->Parse(__lsan_default_suppressions());
+}
+
+static SuppressionContext *GetSuppressionContext() {
+ CHECK(suppression_ctx);
+ return suppression_ctx;
+}
+
+struct RootRegion {
+ const void *begin;
+ uptr size;
+};
+
+InternalMmapVector<RootRegion> *root_regions;
+
+void InitializeRootRegions() {
+ CHECK(!root_regions);
+ ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)];
+ root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
+}
+
+void InitCommonLsan() {
+ InitializeRootRegions();
+ if (common_flags()->detect_leaks) {
+ // Initialization which can fail or print warnings should only be done if
+ // LSan is actually enabled.
+ InitializeSuppressions();
+ InitializePlatformSpecificModules();
+ }
+}
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Error() { return Red(); }
+ const char *Leak() { return Blue(); }
+ const char *End() { return Default(); }
+};
+
+static inline bool CanBeAHeapPointer(uptr p) {
+ // Since our heap is located in mmap-ed memory, we can assume a sensible lower
+ // bound on heap addresses.
+ const uptr kMinAddress = 4 * 4096;
+ if (p < kMinAddress) return false;
+#if defined(__x86_64__)
+ // Accept only canonical form user-space addresses.
+ return ((p >> 47) == 0);
+#elif defined(__mips64)
+ return ((p >> 40) == 0);
+#elif defined(__aarch64__)
+ unsigned runtimeVMA =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+ return ((p >> runtimeVMA) == 0);
+#else
+ return true;
+#endif
+}
+
+// Scans the memory range, looking for byte patterns that point into allocator
+// chunks. Marks those chunks with |tag| and adds them to |frontier|.
+// There are two usage modes for this function: finding reachable chunks
+// (|tag| = kReachable) and finding indirectly leaked chunks
+// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
+// so |frontier| = 0.
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
+ const char *region_type, ChunkTag tag) {
+ CHECK(tag == kReachable || tag == kIndirectlyLeaked);
+ const uptr alignment = flags()->pointer_alignment();
+ LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, begin, end);
+ uptr pp = begin;
+ if (pp % alignment)
+ pp = pp + alignment - pp % alignment;
+ for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT
+ void *p = *reinterpret_cast<void **>(pp);
+ if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
+ uptr chunk = PointsIntoChunk(p);
+ if (!chunk) continue;
+ // Pointers to self don't count. This matters when tag == kIndirectlyLeaked.
+ if (chunk == begin) continue;
+ LsanMetadata m(chunk);
+ if (m.tag() == kReachable || m.tag() == kIgnored) continue;
+
+ // Do this check relatively late so we can log only the interesting cases.
+ if (!flags()->use_poisoned && WordIsPoisoned(pp)) {
+ LOG_POINTERS(
+ "%p is poisoned: ignoring %p pointing into chunk %p-%p of size "
+ "%zu.\n",
+ pp, p, chunk, chunk + m.requested_size(), m.requested_size());
+ continue;
+ }
+
+ m.set_tag(tag);
+ LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
+ chunk, chunk + m.requested_size(), m.requested_size());
+ if (frontier)
+ frontier->push_back(chunk);
+ }
+}
+
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(arg);
+ ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
+}
+
+// Scans thread data (stacks and TLS) for heap pointers.
+static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+ Frontier *frontier) {
+ InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
+ uptr registers_begin = reinterpret_cast<uptr>(registers.data());
+ uptr registers_end = registers_begin + registers.size();
+ for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
+ uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
+ LOG_THREADS("Processing thread %d.\n", os_id);
+ uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
+ bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
+ &tls_begin, &tls_end,
+ &cache_begin, &cache_end);
+ if (!thread_found) {
+ // If a thread can't be found in the thread registry, it's probably in the
+ // process of destruction. Log this event and move on.
+ LOG_THREADS("Thread %d not found in registry.\n", os_id);
+ continue;
+ }
+ uptr sp;
+ bool have_registers =
+ (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
+ if (!have_registers) {
+ Report("Unable to get registers from thread %d.\n");
+ // If unable to get SP, consider the entire stack to be reachable.
+ sp = stack_begin;
+ }
+
+ if (flags()->use_registers && have_registers)
+ ScanRangeForPointers(registers_begin, registers_end, frontier,
+ "REGISTERS", kReachable);
+
+ if (flags()->use_stacks) {
+ LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp);
+ if (sp < stack_begin || sp >= stack_end) {
+ // SP is outside the recorded stack range (e.g. the thread is running a
+ // signal handler on alternate stack). Again, consider the entire stack
+ // range to be reachable.
+ LOG_THREADS("WARNING: stack pointer not in stack range.\n");
+ } else {
+ // Shrink the stack range to ignore out-of-scope values.
+ stack_begin = sp;
+ }
+ ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
+ kReachable);
+ ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
+ }
+
+ if (flags()->use_tls) {
+ LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
+ if (cache_begin == cache_end) {
+ ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
+ } else {
+ // Because LSan should not be loaded with dlopen(), we can assume
+ // that allocator cache will be part of static TLS image.
+ CHECK_LE(tls_begin, cache_begin);
+ CHECK_GE(tls_end, cache_end);
+ if (tls_begin < cache_begin)
+ ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
+ kReachable);
+ if (tls_end > cache_end)
+ ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
+ }
+ }
+ }
+}
+
+static void ProcessRootRegion(Frontier *frontier, uptr root_begin,
+ uptr root_end) {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr begin, end, prot;
+ while (proc_maps.Next(&begin, &end,
+ /*offset*/ nullptr, /*filename*/ nullptr,
+ /*filename_size*/ 0, &prot)) {
+ uptr intersection_begin = Max(root_begin, begin);
+ uptr intersection_end = Min(end, root_end);
+ if (intersection_begin >= intersection_end) continue;
+ bool is_readable = prot & MemoryMappingLayout::kProtectionRead;
+ LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
+ root_begin, root_end, begin, end,
+ is_readable ? "readable" : "unreadable");
+ if (is_readable)
+ ScanRangeForPointers(intersection_begin, intersection_end, frontier,
+ "ROOT", kReachable);
+ }
+}
+
+// Scans root regions for heap pointers.
+static void ProcessRootRegions(Frontier *frontier) {
+ if (!flags()->use_root_regions) return;
+ CHECK(root_regions);
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ uptr begin_addr = reinterpret_cast<uptr>(region.begin);
+ ProcessRootRegion(frontier, begin_addr, begin_addr + region.size);
+ }
+}
+
+static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
+ while (frontier->size()) {
+ uptr next_chunk = frontier->back();
+ frontier->pop_back();
+ LsanMetadata m(next_chunk);
+ ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
+ "HEAP", tag);
+ }
+}
+
+// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks
+// which are reachable from it as indirectly leaked.
+static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kReachable) {
+ ScanRangeForPointers(chunk, chunk + m.requested_size(),
+ /* frontier */ nullptr, "HEAP", kIndirectlyLeaked);
+ }
+}
+
+// ForEachChunk callback. If chunk is marked as ignored, adds its address to
+// frontier.
+static void CollectIgnoredCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() == kIgnored) {
+ LOG_POINTERS("Ignored: chunk %p-%p of size %zu.\n",
+ chunk, chunk + m.requested_size(), m.requested_size());
+ reinterpret_cast<Frontier *>(arg)->push_back(chunk);
+ }
+}
+
+// Sets the appropriate tag on each chunk.
+static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
+ // Holds the flood fill frontier.
+ Frontier frontier(1);
+
+ ForEachChunk(CollectIgnoredCb, &frontier);
+ ProcessGlobalRegions(&frontier);
+ ProcessThreads(suspended_threads, &frontier);
+ ProcessRootRegions(&frontier);
+ FloodFillTag(&frontier, kReachable);
+
+ // The check here is relatively expensive, so we do this in a separate flood
+ // fill. That way we can skip the check for chunks that are reachable
+ // otherwise.
+ LOG_POINTERS("Processing platform-specific allocations.\n");
+ CHECK_EQ(0, frontier.size());
+ ProcessPlatformSpecificAllocations(&frontier);
+ FloodFillTag(&frontier, kReachable);
+
+ // Iterate over leaked chunks and mark those that are reachable from other
+ // leaked chunks.
+ LOG_POINTERS("Scanning leaked chunks.\n");
+ ForEachChunk(MarkIndirectlyLeakedCb, nullptr);
+}
+
+// ForEachChunk callback. Resets the tags to pre-leak-check state.
+static void ResetTagsCb(uptr chunk, void *arg) {
+ (void)arg;
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kIgnored)
+ m.set_tag(kDirectlyLeaked);
+}
+
+static void PrintStackTraceById(u32 stack_trace_id) {
+ CHECK(stack_trace_id);
+ StackDepotGet(stack_trace_id).Print();
+}
+
+// ForEachChunk callback. Aggregates information about unreachable chunks into
+// a LeakReport.
+static void CollectLeaksCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (!m.allocated()) return;
+ if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+ u32 resolution = flags()->resolution;
+ u32 stack_trace_id = 0;
+ if (resolution > 0) {
+ StackTrace stack = StackDepotGet(m.stack_trace_id());
+ stack.size = Min(stack.size, resolution);
+ stack_trace_id = StackDepotPut(stack);
+ } else {
+ stack_trace_id = m.stack_trace_id();
+ }
+ leak_report->AddLeakedChunk(chunk, stack_trace_id, m.requested_size(),
+ m.tag());
+ }
+}
+
+static void PrintMatchedSuppressions() {
+ InternalMmapVector<Suppression *> matched(1);
+ GetSuppressionContext()->GetMatched(&matched);
+ if (!matched.size())
+ return;
+ const char *line = "-----------------------------------------------------";
+ Printf("%s\n", line);
+ Printf("Suppressions used:\n");
+ Printf(" count bytes template\n");
+ for (uptr i = 0; i < matched.size(); i++)
+ Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
+ &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
+ Printf("%s\n\n", line);
+}
+
+struct CheckForLeaksParam {
+ bool success;
+ LeakReport leak_report;
+};
+
+static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
+ void *arg) {
+ CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
+ CHECK(param);
+ CHECK(!param->success);
+ ClassifyAllChunks(suspended_threads);
+ ForEachChunk(CollectLeaksCb, ¶m->leak_report);
+ // Clean up for subsequent leak checks. This assumes we did not overwrite any
+ // kIgnored tags.
+ ForEachChunk(ResetTagsCb, nullptr);
+ param->success = true;
+}
+
+static bool CheckForLeaks() {
+ if (&__lsan_is_turned_off && __lsan_is_turned_off())
+ return false;
+ EnsureMainThreadIDIsCorrect();
+ CheckForLeaksParam param;
+ param.success = false;
+ LockThreadRegistry();
+ LockAllocator();
+ DoStopTheWorld(CheckForLeaksCallback, ¶m);
+ UnlockAllocator();
+ UnlockThreadRegistry();
+
+ if (!param.success) {
+ Report("LeakSanitizer has encountered a fatal error.\n");
+ Die();
+ }
+ param.leak_report.ApplySuppressions();
+ uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
+ if (unsuppressed_count > 0) {
+ Decorator d;
+ Printf("\n"
+ "================================================================="
+ "\n");
+ Printf("%s", d.Error());
+ Report("ERROR: LeakSanitizer: detected memory leaks\n");
+ Printf("%s", d.End());
+ param.leak_report.ReportTopLeaks(flags()->max_leaks);
+ }
+ if (common_flags()->print_suppressions)
+ PrintMatchedSuppressions();
+ if (unsuppressed_count > 0) {
+ param.leak_report.PrintSummary();
+ return true;
+ }
+ return false;
+}
+
+void DoLeakCheck() {
+ BlockingMutexLock l(&global_mutex);
+ static bool already_done;
+ if (already_done) return;
+ already_done = true;
+ bool have_leaks = CheckForLeaks();
+ if (!have_leaks) {
+ return;
+ }
+ if (common_flags()->exitcode) {
+ Die();
+ }
+}
+
+static int DoRecoverableLeakCheck() {
+ BlockingMutexLock l(&global_mutex);
+ bool have_leaks = CheckForLeaks();
+ return have_leaks ? 1 : 0;
+}
+
+static Suppression *GetSuppressionForAddr(uptr addr) {
+ Suppression *s = nullptr;
+
+ // Suppress by module name.
+ SuppressionContext *suppressions = GetSuppressionContext();
+ if (const char *module_name =
+ Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
+ if (suppressions->Match(module_name, kSuppressionLeak, &s))
+ return s;
+
+ // Suppress by file or function name.
+ SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
+ suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
+ break;
+ }
+ }
+ frames->ClearAll();
+ return s;
+}
+
+static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+ StackTrace stack = StackDepotGet(stack_trace_id);
+ for (uptr i = 0; i < stack.size; i++) {
+ Suppression *s = GetSuppressionForAddr(
+ StackTrace::GetPreviousInstructionPc(stack.trace[i]));
+ if (s) return s;
+ }
+ return nullptr;
+}
+
+///// LeakReport implementation. /////
+
+// A hard limit on the number of distinct leaks, to avoid quadratic complexity
+// in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks
+// in real-world applications.
+// FIXME: Get rid of this limit by changing the implementation of LeakReport to
+// use a hash table.
+const uptr kMaxLeaksConsidered = 5000;
+
+void LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id,
+ uptr leaked_size, ChunkTag tag) {
+ CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
+ bool is_directly_leaked = (tag == kDirectlyLeaked);
+ uptr i;
+ for (i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].stack_trace_id == stack_trace_id &&
+ leaks_[i].is_directly_leaked == is_directly_leaked) {
+ leaks_[i].hit_count++;
+ leaks_[i].total_size += leaked_size;
+ break;
+ }
+ }
+ if (i == leaks_.size()) {
+ if (leaks_.size() == kMaxLeaksConsidered) return;
+ Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id,
+ is_directly_leaked, /* is_suppressed */ false };
+ leaks_.push_back(leak);
+ }
+ if (flags()->report_objects) {
+ LeakedObject obj = {leaks_[i].id, chunk, leaked_size};
+ leaked_objects_.push_back(obj);
+ }
+}
+
+static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
+ if (leak1.is_directly_leaked == leak2.is_directly_leaked)
+ return leak1.total_size > leak2.total_size;
+ else
+ return leak1.is_directly_leaked;
+}
+
+void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) {
+ CHECK(leaks_.size() <= kMaxLeaksConsidered);
+ Printf("\n");
+ if (leaks_.size() == kMaxLeaksConsidered)
+ Printf("Too many leaks! Only the first %zu leaks encountered will be "
+ "reported.\n",
+ kMaxLeaksConsidered);
+
+ uptr unsuppressed_count = UnsuppressedLeakCount();
+ if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count)
+ Printf("The %zu top leak(s):\n", num_leaks_to_report);
+ InternalSort(&leaks_, leaks_.size(), LeakComparator);
+ uptr leaks_reported = 0;
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].is_suppressed) continue;
+ PrintReportForLeak(i);
+ leaks_reported++;
+ if (leaks_reported == num_leaks_to_report) break;
+ }
+ if (leaks_reported < unsuppressed_count) {
+ uptr remaining = unsuppressed_count - leaks_reported;
+ Printf("Omitting %zu more leak(s).\n", remaining);
+ }
+}
+
+void LeakReport::PrintReportForLeak(uptr index) {
+ Decorator d;
+ Printf("%s", d.Leak());
+ Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
+ leaks_[index].is_directly_leaked ? "Direct" : "Indirect",
+ leaks_[index].total_size, leaks_[index].hit_count);
+ Printf("%s", d.End());
+
+ PrintStackTraceById(leaks_[index].stack_trace_id);
+
+ if (flags()->report_objects) {
+ Printf("Objects leaked above:\n");
+ PrintLeakedObjectsForLeak(index);
+ Printf("\n");
+ }
+}
+
+void LeakReport::PrintLeakedObjectsForLeak(uptr index) {
+ u32 leak_id = leaks_[index].id;
+ for (uptr j = 0; j < leaked_objects_.size(); j++) {
+ if (leaked_objects_[j].leak_id == leak_id)
+ Printf("%p (%zu bytes)\n", leaked_objects_[j].addr,
+ leaked_objects_[j].size);
+ }
+}
+
+void LeakReport::PrintSummary() {
+ CHECK(leaks_.size() <= kMaxLeaksConsidered);
+ uptr bytes = 0, allocations = 0;
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].is_suppressed) continue;
+ bytes += leaks_[i].total_size;
+ allocations += leaks_[i].hit_count;
+ }
+ InternalScopedString summary(kMaxSummaryLength);
+ summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
+ allocations);
+ ReportErrorSummary(summary.data());
+}
+
+void LeakReport::ApplySuppressions() {
+ for (uptr i = 0; i < leaks_.size(); i++) {
+ Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
+ if (s) {
+ s->weight += leaks_[i].total_size;
+ atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
+ leaks_[i].hit_count);
+ leaks_[i].is_suppressed = true;
+ }
+ }
+}
+
+uptr LeakReport::UnsuppressedLeakCount() {
+ uptr result = 0;
+ for (uptr i = 0; i < leaks_.size(); i++)
+ if (!leaks_[i].is_suppressed) result++;
+ return result;
+}
+
+} // namespace __lsan
+#endif // CAN_SANITIZE_LEAKS
+
+using namespace __lsan; // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_ignore_object(const void *p) {
+#if CAN_SANITIZE_LEAKS
+ if (!common_flags()->detect_leaks)
+ return;
+ // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
+ // locked.
+ BlockingMutexLock l(&global_mutex);
+ IgnoreObjectResult res = IgnoreObjectLocked(p);
+ if (res == kIgnoreObjectInvalid)
+ VReport(1, "__lsan_ignore_object(): no heap object found at %p", p);
+ if (res == kIgnoreObjectAlreadyIgnored)
+ VReport(1, "__lsan_ignore_object(): "
+ "heap object at %p is already being ignored\n", p);
+ if (res == kIgnoreObjectSuccess)
+ VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_register_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ RootRegion region = {begin, size};
+ root_regions->push_back(region);
+ VReport(1, "Registered root region at %p of size %llu\n", begin, size);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_unregister_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ bool removed = false;
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ if (region.begin == begin && region.size == size) {
+ removed = true;
+ uptr last_index = root_regions->size() - 1;
+ (*root_regions)[i] = (*root_regions)[last_index];
+ root_regions->pop_back();
+ VReport(1, "Unregistered root region at %p of size %llu\n", begin, size);
+ break;
+ }
+ }
+ if (!removed) {
+ Report(
+ "__lsan_unregister_root_region(): region at %p of size %llu has not "
+ "been registered.\n",
+ begin, size);
+ Die();
+ }
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_disable() {
+#if CAN_SANITIZE_LEAKS
+ __lsan::disable_counter++;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_enable() {
+#if CAN_SANITIZE_LEAKS
+ if (!__lsan::disable_counter && common_flags()->detect_leaks) {
+ Report("Unmatched call to __lsan_enable().\n");
+ Die();
+ }
+ __lsan::disable_counter--;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_do_leak_check() {
+#if CAN_SANITIZE_LEAKS
+ if (common_flags()->detect_leaks)
+ __lsan::DoLeakCheck();
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __lsan_do_recoverable_leak_check() {
+#if CAN_SANITIZE_LEAKS
+ if (common_flags()->detect_leaks)
+ return __lsan::DoRecoverableLeakCheck();
+#endif // CAN_SANITIZE_LEAKS
+ return 0;
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off() {
+ return 0;
+}
+#endif
+} // extern "C"
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
new file mode 100644
index 0000000..0dfd0d4
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -0,0 +1,186 @@
+//=-- lsan_common.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Private LSan header.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_COMMON_H
+#define LSAN_COMMON_H
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
+ && (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
+#define CAN_SANITIZE_LEAKS 1
+#else
+#define CAN_SANITIZE_LEAKS 0
+#endif
+
+namespace __sanitizer {
+class FlagParser;
+}
+
+namespace __lsan {
+
+// Chunk tags.
+enum ChunkTag {
+ kDirectlyLeaked = 0, // default
+ kIndirectlyLeaked = 1,
+ kReachable = 2,
+ kIgnored = 3
+};
+
+struct Flags {
+#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "lsan_flags.inc"
+#undef LSAN_FLAG
+
+ void SetDefaults();
+ uptr pointer_alignment() const {
+ return use_unaligned ? 1 : sizeof(uptr);
+ }
+};
+
+extern Flags lsan_flags;
+inline Flags *flags() { return &lsan_flags; }
+void RegisterLsanFlags(FlagParser *parser, Flags *f);
+
+struct Leak {
+ u32 id;
+ uptr hit_count;
+ uptr total_size;
+ u32 stack_trace_id;
+ bool is_directly_leaked;
+ bool is_suppressed;
+};
+
+struct LeakedObject {
+ u32 leak_id;
+ uptr addr;
+ uptr size;
+};
+
+// Aggregates leaks by stack trace prefix.
+class LeakReport {
+ public:
+ LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {}
+ void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size,
+ ChunkTag tag);
+ void ReportTopLeaks(uptr max_leaks);
+ void PrintSummary();
+ void ApplySuppressions();
+ uptr UnsuppressedLeakCount();
+
+
+ private:
+ void PrintReportForLeak(uptr index);
+ void PrintLeakedObjectsForLeak(uptr index);
+
+ u32 next_id_;
+ InternalMmapVector<Leak> leaks_;
+ InternalMmapVector<LeakedObject> leaked_objects_;
+};
+
+typedef InternalMmapVector<uptr> Frontier;
+
+// Platform-specific functions.
+void InitializePlatformSpecificModules();
+void ProcessGlobalRegions(Frontier *frontier);
+void ProcessPlatformSpecificAllocations(Frontier *frontier);
+// Run stoptheworld while holding any platform-specific locks.
+void DoStopTheWorld(StopTheWorldCallback callback, void* argument);
+
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
+ const char *region_type, ChunkTag tag);
+
+enum IgnoreObjectResult {
+ kIgnoreObjectSuccess,
+ kIgnoreObjectAlreadyIgnored,
+ kIgnoreObjectInvalid
+};
+
+// Functions called from the parent tool.
+void InitCommonLsan();
+void DoLeakCheck();
+bool DisabledInThisThread();
+
+// Special case for "new T[0]" where T is a type with DTOR.
+// new T[0] will allocate one word for the array size (0) and store a pointer
+// to the end of allocated chunk.
+inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
+ uptr addr) {
+ return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
+ *reinterpret_cast<uptr *>(chunk_beg) == 0;
+}
+
+// The following must be implemented in the parent tool.
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg);
+// Returns the address range occupied by the global allocator object.
+void GetAllocatorGlobalRange(uptr *begin, uptr *end);
+// Wrappers for allocator's ForceLock()/ForceUnlock().
+void LockAllocator();
+void UnlockAllocator();
+// Returns true if [addr, addr + sizeof(void *)) is poisoned.
+bool WordIsPoisoned(uptr addr);
+// Wrappers for ThreadRegistry access.
+void LockThreadRegistry();
+void UnlockThreadRegistry();
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end);
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg);
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
+// If p points into a chunk that has been allocated to the user, returns its
+// user-visible address. Otherwise, returns 0.
+uptr PointsIntoChunk(void *p);
+// Returns address of user-visible chunk contained in this allocator chunk.
+uptr GetUserBegin(uptr chunk);
+// Helper for __lsan_ignore_object().
+IgnoreObjectResult IgnoreObjectLocked(const void *p);
+// Wrapper for chunk metadata operations.
+class LsanMetadata {
+ public:
+ // Constructor accepts address of user-visible chunk.
+ explicit LsanMetadata(uptr chunk);
+ bool allocated() const;
+ ChunkTag tag() const;
+ void set_tag(ChunkTag value);
+ uptr requested_size() const;
+ u32 stack_trace_id() const;
+ private:
+ void *metadata_;
+};
+
+} // namespace __lsan
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__lsan_default_suppressions();
+} // extern "C"
+
+#endif // LSAN_COMMON_H
diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cc b/compiler-rt/lib/lsan/lsan_common_linux.cc
new file mode 100644
index 0000000..1dc0561
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_common_linux.cc
@@ -0,0 +1,179 @@
+//=-- lsan_common_linux.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality. Linux-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#include "lsan_common.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX
+#include <link.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __lsan {
+
+static const char kLinkerName[] = "ld";
+// We request 2 modules matching "ld", so we can print a warning if there's more
+// than one match. But only the first one is actually used.
+static char linker_placeholder[2 * sizeof(LoadedModule)] ALIGNED(64);
+static LoadedModule *linker = nullptr;
+
+static bool IsLinker(const char* full_name) {
+ return LibraryNameIs(full_name, kLinkerName);
+}
+
+void InitializePlatformSpecificModules() {
+ internal_memset(linker_placeholder, 0, sizeof(linker_placeholder));
+ uptr num_matches = GetListOfModules(
+ reinterpret_cast<LoadedModule *>(linker_placeholder), 2, IsLinker);
+ if (num_matches == 1) {
+ linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
+ return;
+ }
+ if (num_matches == 0)
+ VReport(1, "LeakSanitizer: Dynamic linker not found. "
+ "TLS will not be handled correctly.\n");
+ else if (num_matches > 1)
+ VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
+ "TLS will not be handled correctly.\n", kLinkerName);
+ linker = nullptr;
+}
+
+static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(data);
+ for (uptr j = 0; j < info->dlpi_phnum; j++) {
+ const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
+ // We're looking for .data and .bss sections, which reside in writeable,
+ // loadable segments.
+ if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
+ (phdr->p_memsz == 0))
+ continue;
+ uptr begin = info->dlpi_addr + phdr->p_vaddr;
+ uptr end = begin + phdr->p_memsz;
+ uptr allocator_begin = 0, allocator_end = 0;
+ GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
+ if (begin <= allocator_begin && allocator_begin < end) {
+ CHECK_LE(allocator_begin, allocator_end);
+ CHECK_LT(allocator_end, end);
+ if (begin < allocator_begin)
+ ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
+ kReachable);
+ if (allocator_end < end)
+ ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL",
+ kReachable);
+ } else {
+ ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
+ }
+ }
+ return 0;
+}
+
+// Scans global variables for heap pointers.
+void ProcessGlobalRegions(Frontier *frontier) {
+ if (!flags()->use_globals) return;
+ dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
+}
+
+static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
+ CHECK(stack_id);
+ StackTrace stack = map->Get(stack_id);
+ // The top frame is our malloc/calloc/etc. The next frame is the caller.
+ if (stack.size >= 2)
+ return stack.trace[1];
+ return 0;
+}
+
+struct ProcessPlatformAllocParam {
+ Frontier *frontier;
+ StackDepotReverseMap *stack_depot_reverse_map;
+};
+
+// ForEachChunk callback. Identifies unreachable chunks which must be treated as
+// reachable. Marks them as reachable and adds them to the frontier.
+static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ ProcessPlatformAllocParam *param =
+ reinterpret_cast<ProcessPlatformAllocParam *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) {
+ u32 stack_id = m.stack_trace_id();
+ uptr caller_pc = 0;
+ if (stack_id > 0)
+ caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
+ // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
+ // it as reachable, as we can't properly report its allocation stack anyway.
+ if (caller_pc == 0 || linker->containsAddress(caller_pc)) {
+ m.set_tag(kReachable);
+ param->frontier->push_back(chunk);
+ }
+ }
+}
+
+// Handles dynamically allocated TLS blocks by treating all chunks allocated
+// from ld-linux.so as reachable.
+// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
+// They are allocated with a __libc_memalign() call in allocate_and_init()
+// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
+// blocks, but we can make sure they come from our own allocator by intercepting
+// __libc_memalign(). On top of that, there is no easy way to reach them. Their
+// addresses are stored in a dynamically allocated array (the DTV) which is
+// referenced from the static TLS. Unfortunately, we can't just rely on the DTV
+// being reachable from the static TLS, and the dynamic TLS being reachable from
+// the DTV. This is because the initial DTV is allocated before our interception
+// mechanism kicks in, and thus we don't recognize it as allocated memory. We
+// can't special-case it either, since we don't know its size.
+// Our solution is to include in the root set all allocations made from
+// ld-linux.so (which is where allocate_and_init() is implemented). This is
+// guaranteed to include all dynamic TLS blocks (and possibly other allocations
+// which we don't care about).
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {
+ if (!flags()->use_tls) return;
+ if (!linker) return;
+ StackDepotReverseMap stack_depot_reverse_map;
+ ProcessPlatformAllocParam arg = {frontier, &stack_depot_reverse_map};
+ ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg);
+}
+
+struct DoStopTheWorldParam {
+ StopTheWorldCallback callback;
+ void *argument;
+};
+
+static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
+ StopTheWorld(param->callback, param->argument);
+ return 1;
+}
+
+// LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
+// of the threads is frozen while holding the libdl lock, the tracer will hang
+// in dl_iterate_phdr() forever.
+// Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
+// tracer task and the thread that spawned it. Thus, if we run the tracer task
+// while holding the libdl lock in the parent thread, we can safely reenter it
+// in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
+// callback in the parent thread.
+void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
+ DoStopTheWorldParam param = {callback, argument};
+ dl_iterate_phdr(DoStopTheWorldCallback, ¶m);
+}
+
+} // namespace __lsan
+
+#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX
diff --git a/compiler-rt/lib/lsan/lsan_flags.inc b/compiler-rt/lib/lsan/lsan_flags.inc
new file mode 100644
index 0000000..c405005
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_flags.inc
@@ -0,0 +1,43 @@
+//===-- lsan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LSAN_FLAG
+# error "Define LSAN_FLAG prior to including this file!"
+#endif
+
+// LSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+LSAN_FLAG(bool, report_objects, false,
+ "Print addresses of leaked objects after main leak report.")
+LSAN_FLAG(
+ int, resolution, 0,
+ "Aggregate two objects into one leak if this many stack frames match. If "
+ "zero, the entire stack trace must match.")
+LSAN_FLAG(int, max_leaks, 0, "The number of leaks reported.")
+
+// Flags controlling the root set of reachable memory.
+LSAN_FLAG(bool, use_globals, true,
+ "Root set: include global variables (.data and .bss)")
+LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks")
+LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers")
+LSAN_FLAG(bool, use_tls, true,
+ "Root set: include TLS and thread-specific storage")
+LSAN_FLAG(bool, use_root_regions, true,
+ "Root set: include regions added via __lsan_register_root_region().")
+
+LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
+LSAN_FLAG(bool, use_poisoned, false,
+ "Consider pointers found in poisoned memory to be valid.")
+LSAN_FLAG(bool, log_pointers, false, "Debug logging")
+LSAN_FLAG(bool, log_threads, false, "Debug logging")
+LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cc b/compiler-rt/lib/lsan/lsan_interceptors.cc
new file mode 100644
index 0000000..be0d0dd
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_interceptors.cc
@@ -0,0 +1,287 @@
+//=-- lsan_interceptors.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Interceptors for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+using namespace __lsan;
+
+extern "C" {
+int pthread_attr_init(void *attr);
+int pthread_attr_destroy(void *attr);
+int pthread_attr_getdetachstate(void *attr, int *v);
+int pthread_key_create(unsigned *key, void (*destructor)(void* v));
+int pthread_setspecific(unsigned key, const void *v);
+}
+
+#define ENSURE_LSAN_INITED do { \
+ CHECK(!lsan_init_is_running); \
+ if (!lsan_inited) \
+ __lsan_init(); \
+} while (0)
+
+///// Malloc/free interceptors. /////
+
+const bool kAlwaysClearMemory = true;
+
+namespace std {
+ struct nothrow_t;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, free, void *p) {
+ ENSURE_LSAN_INITED;
+ Deallocate(p);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (lsan_init_is_running) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const uptr kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ size *= nmemb;
+ return Allocate(stack, size, 1, true);
+}
+
+INTERCEPTOR(void*, realloc, void *q, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Reallocate(stack, q, size, 1);
+}
+
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
+ // FIXME: Return ENOMEM if user requested more than max alloc size.
+ return 0;
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ if (size == 0)
+ size = GetPageSizeCached();
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ ENSURE_LSAN_INITED;
+ return GetMallocUsableSize(ptr);
+}
+
+struct fake_mallinfo {
+ int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+ struct fake_mallinfo res;
+ internal_memset(&res, 0, sizeof(res));
+ return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+
+INTERCEPTOR(void*, pvalloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
+
+#define OPERATOR_NEW_BODY \
+ ENSURE_LSAN_INITED; \
+ GET_STACK_TRACE_MALLOC; \
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+ ENSURE_LSAN_INITED; \
+ Deallocate(ptr);
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const &) {
+ OPERATOR_DELETE_BODY;
+}
+
+// We need this to intercept the __libc_memalign calls that are used to
+// allocate dynamic TLS space in ld-linux.so.
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s)
+ ALIAS(WRAPPER_NAME(memalign));
+
+///// Thread initialization and finalization. /////
+
+static unsigned g_thread_finalize_key;
+
+static void thread_finalize(void *v) {
+ uptr iter = (uptr)v;
+ if (iter > 1) {
+ if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+ Report("LeakSanitizer: failed to set thread key.\n");
+ Die();
+ }
+ return;
+ }
+ ThreadFinish();
+}
+
+struct ThreadParam {
+ void *(*callback)(void *arg);
+ void *param;
+ atomic_uintptr_t tid;
+};
+
+extern "C" void *__lsan_thread_start_func(void *arg) {
+ ThreadParam *p = (ThreadParam*)arg;
+ void* (*callback)(void *arg) = p->callback;
+ void *param = p->param;
+ // Wait until the last iteration to maximize the chance that we are the last
+ // destructor to run.
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void*)GetPthreadDestructorIterations())) {
+ Report("LeakSanitizer: failed to set thread key.\n");
+ Die();
+ }
+ int tid = 0;
+ while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
+ internal_sched_yield();
+ SetCurrentThread(tid);
+ ThreadStart(tid, GetTid());
+ atomic_store(&p->tid, 0, memory_order_release);
+ return callback(param);
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr,
+ void *(*callback)(void *), void *param) {
+ ENSURE_LSAN_INITED;
+ EnsureMainThreadIDIsCorrect();
+ __sanitizer_pthread_attr_t myattr;
+ if (!attr) {
+ pthread_attr_init(&myattr);
+ attr = &myattr;
+ }
+ AdjustStackSize(attr);
+ int detached = 0;
+ pthread_attr_getdetachstate(attr, &detached);
+ ThreadParam p;
+ p.callback = callback;
+ p.param = param;
+ atomic_store(&p.tid, 0, memory_order_relaxed);
+ int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+ if (res == 0) {
+ int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
+ CHECK_NE(tid, 0);
+ atomic_store(&p.tid, tid, memory_order_release);
+ while (atomic_load(&p.tid, memory_order_acquire) != 0)
+ internal_sched_yield();
+ }
+ if (attr == &myattr)
+ pthread_attr_destroy(&myattr);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **ret) {
+ ENSURE_LSAN_INITED;
+ int tid = ThreadTid((uptr)th);
+ int res = REAL(pthread_join)(th, ret);
+ if (res == 0)
+ ThreadJoin(tid);
+ return res;
+}
+
+namespace __lsan {
+
+void InitializeInterceptors() {
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(free);
+ INTERCEPT_FUNCTION(cfree);
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(realloc);
+ INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(posix_memalign);
+ INTERCEPT_FUNCTION(__libc_memalign);
+ INTERCEPT_FUNCTION(valloc);
+ INTERCEPT_FUNCTION(pvalloc);
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ INTERCEPT_FUNCTION(mallinfo);
+ INTERCEPT_FUNCTION(mallopt);
+ INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_join);
+
+ if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+ Report("LeakSanitizer: failed to create thread key.\n");
+ Die();
+ }
+}
+
+} // namespace __lsan
diff --git a/compiler-rt/lib/lsan/lsan_preinit.cc b/compiler-rt/lib/lsan/lsan_preinit.cc
new file mode 100644
index 0000000..5a19095
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_preinit.cc
@@ -0,0 +1,22 @@
+//===-- lsan_preinit.cc ---------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+//
+// Call __lsan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+ // We force __lsan_init to be called before anyone else by placing it into
+ // .preinit_array section.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_lsan_preinit)(void) = __lsan_init;
+#endif
diff --git a/compiler-rt/lib/lsan/lsan_thread.cc b/compiler-rt/lib/lsan/lsan_thread.cc
new file mode 100644
index 0000000..10ac2c9
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_thread.cc
@@ -0,0 +1,160 @@
+//=-- lsan_thread.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// See lsan_thread.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_thread.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "lsan_allocator.h"
+
+namespace __lsan {
+
+const u32 kInvalidTid = (u32) -1;
+
+static ThreadRegistry *thread_registry;
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+
+static ThreadContextBase *CreateThreadContext(u32 tid) {
+ void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
+ return new(mem) ThreadContext(tid);
+}
+
+static const uptr kMaxThreads = 1 << 13;
+static const uptr kThreadQuarantineSize = 64;
+
+void InitializeThreadRegistry() {
+ static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64);
+ thread_registry = new(thread_registry_placeholder)
+ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+}
+
+u32 GetCurrentThread() {
+ return current_thread_tid;
+}
+
+void SetCurrentThread(u32 tid) {
+ current_thread_tid = tid;
+}
+
+ThreadContext::ThreadContext(int tid)
+ : ThreadContextBase(tid),
+ stack_begin_(0),
+ stack_end_(0),
+ cache_begin_(0),
+ cache_end_(0),
+ tls_begin_(0),
+ tls_end_(0) {}
+
+struct OnStartedArgs {
+ uptr stack_begin, stack_end,
+ cache_begin, cache_end,
+ tls_begin, tls_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
+ stack_begin_ = args->stack_begin;
+ stack_end_ = args->stack_end;
+ tls_begin_ = args->tls_begin;
+ tls_end_ = args->tls_end;
+ cache_begin_ = args->cache_begin;
+ cache_end_ = args->cache_end;
+}
+
+void ThreadContext::OnFinished() {
+ AllocatorThreadFinish();
+}
+
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
+ return thread_registry->CreateThread(user_id, detached, parent_tid,
+ /* arg */ nullptr);
+}
+
+void ThreadStart(u32 tid, uptr os_id) {
+ OnStartedArgs args;
+ uptr stack_size = 0;
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+ &args.tls_begin, &tls_size);
+ args.stack_end = args.stack_begin + stack_size;
+ args.tls_end = args.tls_begin + tls_size;
+ GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ thread_registry->StartThread(tid, os_id, &args);
+}
+
+void ThreadFinish() {
+ thread_registry->FinishThread(GetCurrentThread());
+}
+
+ThreadContext *CurrentThreadContext() {
+ if (!thread_registry) return nullptr;
+ if (GetCurrentThread() == kInvalidTid)
+ return nullptr;
+ // No lock needed when getting current thread.
+ return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
+}
+
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+ return true;
+ }
+ return false;
+}
+
+u32 ThreadTid(uptr uid) {
+ return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+}
+
+void ThreadJoin(u32 tid) {
+ CHECK_NE(tid, kInvalidTid);
+ thread_registry->JoinThread(tid, /* arg */nullptr);
+}
+
+void EnsureMainThreadIDIsCorrect() {
+ if (GetCurrentThread() == 0)
+ CurrentThreadContext()->os_id = GetTid();
+}
+
+///// Interface to the common LSan module. /////
+
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end) {
+ ThreadContext *context = static_cast<ThreadContext *>(
+ thread_registry->FindThreadContextByOsIDLocked(os_id));
+ if (!context) return false;
+ *stack_begin = context->stack_begin();
+ *stack_end = context->stack_end();
+ *tls_begin = context->tls_begin();
+ *tls_end = context->tls_end();
+ *cache_begin = context->cache_begin();
+ *cache_end = context->cache_end();
+ return true;
+}
+
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+}
+
+void LockThreadRegistry() {
+ thread_registry->Lock();
+}
+
+void UnlockThreadRegistry() {
+ thread_registry->Unlock();
+}
+
+} // namespace __lsan
diff --git a/compiler-rt/lib/lsan/lsan_thread.h b/compiler-rt/lib/lsan/lsan_thread.h
new file mode 100644
index 0000000..99e2c1d
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_thread.h
@@ -0,0 +1,53 @@
+//=-- lsan_thread.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Thread registry for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_THREAD_H
+#define LSAN_THREAD_H
+
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextBase {
+ public:
+ explicit ThreadContext(int tid);
+ void OnStarted(void *arg) override;
+ void OnFinished() override;
+ uptr stack_begin() { return stack_begin_; }
+ uptr stack_end() { return stack_end_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ uptr cache_begin() { return cache_begin_; }
+ uptr cache_end() { return cache_end_; }
+ private:
+ uptr stack_begin_, stack_end_,
+ cache_begin_, cache_end_,
+ tls_begin_, tls_end_;
+};
+
+void InitializeThreadRegistry();
+
+void ThreadStart(u32 tid, uptr os_id);
+void ThreadFinish();
+u32 ThreadCreate(u32 tid, uptr uid, bool detached);
+void ThreadJoin(u32 tid);
+u32 ThreadTid(uptr uid);
+
+u32 GetCurrentThread();
+void SetCurrentThread(u32 tid);
+ThreadContext *CurrentThreadContext();
+void EnsureMainThreadIDIsCorrect();
+} // namespace __lsan
+
+#endif // LSAN_THREAD_H
diff --git a/compiler-rt/lib/msan/.clang-format b/compiler-rt/lib/msan/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/msan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/msan/CMakeLists.txt b/compiler-rt/lib/msan/CMakeLists.txt
new file mode 100644
index 0000000..1b48def
--- /dev/null
+++ b/compiler-rt/lib/msan/CMakeLists.txt
@@ -0,0 +1,67 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+set(MSAN_RTL_SOURCES
+ msan.cc
+ msan_allocator.cc
+ msan_chained_origin_depot.cc
+ msan_interceptors.cc
+ msan_linux.cc
+ msan_report.cc
+ msan_thread.cc
+ msan_poisoning.cc
+ )
+
+set(MSAN_RTL_CXX_SOURCES
+ msan_new_delete.cc)
+
+
+set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
+
+set(MSAN_RUNTIME_LIBRARIES)
+
+# Static runtime library.
+add_custom_target(msan)
+foreach(arch ${MSAN_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.msan
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${MSAN_RTL_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ CFLAGS ${MSAN_RTL_CFLAGS}
+ PARENT_TARGET msan)
+ add_compiler_rt_runtime(clang_rt.msan_cxx
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${MSAN_RTL_CXX_SOURCES}
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
+ CFLAGS ${MSAN_RTL_CFLAGS}
+ PARENT_TARGET msan)
+ list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}
+ clang_rt.msan_cxx-${arch})
+ if(UNIX)
+ add_sanitizer_rt_symbols(clang_rt.msan
+ ARCHS ${arch}
+ EXTRA msan.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.msan_cxx
+ ARCHS ${arch}
+ EXTRA msan.syms.extra)
+ add_dependencies(msan clang_rt.msan-${arch}-symbols
+ clang_rt.msan_cxx-${arch}-symbols)
+ endif()
+endforeach()
+
+add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
+add_dependencies(msan msan_blacklist)
+add_dependencies(compiler-rt msan)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(tests)
+endif()
diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc
new file mode 100644
index 0000000..9949db4
--- /dev/null
+++ b/compiler-rt/lib/msan/msan.cc
@@ -0,0 +1,642 @@
+//===-- msan.cc -----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// MemorySanitizer runtime.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "ubsan/ubsan_flags.h"
+#include "ubsan/ubsan_init.h"
+
+// ACHTUNG! No system header includes in this file.
+
+using namespace __sanitizer;
+
+// Globals.
+static THREADLOCAL int msan_expect_umr = 0;
+static THREADLOCAL int msan_expected_umr_found = 0;
+
+// Function argument shadow. Each argument starts at the next available 8-byte
+// aligned address.
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
+
+// Function argument origin. Each argument starts at the same offset as the
+// corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
+// would break compatibility with older prebuilt binaries.
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_retval_origin_tls;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+ALIGNED(16) THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL u32 __msan_origin_tls;
+
+static THREADLOCAL int is_in_symbolizer;
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
+
+int __msan_get_track_origins() {
+ return &__msan_track_origins ? __msan_track_origins : 0;
+}
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
+
+namespace __msan {
+
+void EnterSymbolizer() { ++is_in_symbolizer; }
+void ExitSymbolizer() { --is_in_symbolizer; }
+bool IsInSymbolizer() { return is_in_symbolizer; }
+
+static Flags msan_flags;
+
+Flags *flags() {
+ return &msan_flags;
+}
+
+int msan_inited = 0;
+bool msan_init_is_running;
+
+int msan_report_count = 0;
+
+// Array of stack origins.
+// FIXME: make it resizable.
+static const uptr kNumStackOriginDescrs = 1024 * 1024;
+static const char *StackOriginDescr[kNumStackOriginDescrs];
+static uptr StackOriginPC[kNumStackOriginDescrs];
+static atomic_uint32_t NumStackOriginDescrs;
+
+void Flags::SetDefaults() {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+}
+
+// keep_going is an old name for halt_on_error,
+// and it has inverse meaning.
+class FlagHandlerKeepGoing : public FlagHandlerBase {
+ bool *halt_on_error_;
+
+ public:
+ explicit FlagHandlerKeepGoing(bool *halt_on_error)
+ : halt_on_error_(halt_on_error) {}
+ bool Parse(const char *value) final {
+ bool tmp;
+ FlagHandler<bool> h(&tmp);
+ if (!h.Parse(value)) return false;
+ *halt_on_error_ = !tmp;
+ return true;
+ }
+};
+
+static void RegisterMsanFlags(FlagParser *parser, Flags *f) {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+
+ FlagHandlerKeepGoing *fh_keep_going = new (FlagParser::Alloc) // NOLINT
+ FlagHandlerKeepGoing(&f->halt_on_error);
+ parser->RegisterHandler("keep_going", fh_keep_going,
+ "deprecated, use halt_on_error");
+}
+
+static void InitializeFlags() {
+ SetCommonFlagsDefaults();
+ {
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
+ cf.malloc_context_size = 20;
+ cf.handle_ioctl = true;
+ // FIXME: test and enable.
+ cf.check_printf = false;
+ cf.intercept_tls_get_addr = true;
+ cf.exitcode = 77;
+ OverrideCommonFlags(cf);
+ }
+
+ Flags *f = flags();
+ f->SetDefaults();
+
+ FlagParser parser;
+ RegisterMsanFlags(&parser, f);
+ RegisterCommonFlags(&parser);
+
+#if MSAN_CONTAINS_UBSAN
+ __ubsan::Flags *uf = __ubsan::flags();
+ uf->SetDefaults();
+
+ FlagParser ubsan_parser;
+ __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+ RegisterCommonFlags(&ubsan_parser);
+#endif
+
+ // Override from user-specified string.
+ if (__msan_default_options)
+ parser.ParseString(__msan_default_options());
+#if MSAN_CONTAINS_UBSAN
+ const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+ ubsan_parser.ParseString(ubsan_default_options);
+#endif
+
+ const char *msan_options = GetEnv("MSAN_OPTIONS");
+ parser.ParseString(msan_options);
+#if MSAN_CONTAINS_UBSAN
+ ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
+ VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+
+ // Check if deprecated exit_code MSan flag is set.
+ if (f->exit_code != -1) {
+ if (Verbosity())
+ Printf("MSAN_OPTIONS=exit_code is deprecated! "
+ "Please use MSAN_OPTIONS=exitcode instead.\n");
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.exitcode = f->exit_code;
+ OverrideCommonFlags(cf);
+ }
+
+ // Check flag values:
+ if (f->origin_history_size < 0 ||
+ f->origin_history_size > Origin::kMaxDepth) {
+ Printf(
+ "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] "
+ "range.\n",
+ f->origin_history_size, Origin::kMaxDepth);
+ Die();
+ }
+ // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in
+ // StackDepotHandle::inc_use_count_unsafe.
+ if (f->origin_history_per_stack_limit < 0 ||
+ f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) {
+ Printf(
+ "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, "
+ "%d] range.\n",
+ f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2);
+ Die();
+ }
+ if (f->store_context_size < 1) f->store_context_size = 1;
+}
+
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
+ bool request_fast_unwind) {
+ MsanThread *t = GetCurrentThread();
+ if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
+ // Block reports from our interceptors during _Unwind_Backtrace.
+ SymbolizerScope sym_scope;
+ return stack->Unwind(max_s, pc, bp, nullptr, 0, 0, request_fast_unwind);
+ }
+ stack->Unwind(max_s, pc, bp, nullptr, t->stack_top(), t->stack_bottom(),
+ request_fast_unwind);
+}
+
+void PrintWarning(uptr pc, uptr bp) {
+ PrintWarningWithOrigin(pc, bp, __msan_origin_tls);
+}
+
+void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
+ if (msan_expect_umr) {
+ // Printf("Expected UMR\n");
+ __msan_origin_tls = origin;
+ msan_expected_umr_found = 1;
+ return;
+ }
+
+ ++msan_report_count;
+
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
+
+ u32 report_origin =
+ (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0;
+ ReportUMR(&stack, report_origin);
+
+ if (__msan_get_track_origins() && !Origin::isValidId(origin)) {
+ Printf(
+ " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin "
+ "tracking.\n This could still be a bug in your code, too!\n",
+ origin);
+ }
+}
+
+void UnpoisonParam(uptr n) {
+ internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
+}
+
+// Backup MSan runtime TLS state.
+// Implementation must be async-signal-safe.
+// Instances of this class may live on the signal handler stack, and data size
+// may be an issue.
+void ScopedThreadLocalStateBackup::Backup() {
+ va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls;
+}
+
+void ScopedThreadLocalStateBackup::Restore() {
+ // A lame implementation that only keeps essential state and resets the rest.
+ __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls;
+
+ internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls));
+ internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
+
+ if (__msan_get_track_origins()) {
+ internal_memset(&__msan_retval_origin_tls, 0,
+ sizeof(__msan_retval_origin_tls));
+ internal_memset(__msan_param_origin_tls, 0,
+ sizeof(__msan_param_origin_tls));
+ }
+}
+
+void UnpoisonThreadLocalState() {
+}
+
+const char *GetStackOriginDescr(u32 id, uptr *pc) {
+ CHECK_LT(id, kNumStackOriginDescrs);
+ if (pc) *pc = StackOriginPC[id];
+ return StackOriginDescr[id];
+}
+
+u32 ChainOrigin(u32 id, StackTrace *stack) {
+ MsanThread *t = GetCurrentThread();
+ if (t && t->InSignalHandler())
+ return id;
+
+ Origin o = Origin::FromRawId(id);
+ stack->tag = StackTrace::TAG_UNKNOWN;
+ Origin chained = Origin::CreateChainedOrigin(o, stack);
+ return chained.raw_id();
+}
+
+} // namespace __msan
+
+// Interface.
+
+using namespace __msan;
+
+#define MSAN_MAYBE_WARNING(type, size) \
+ void __msan_maybe_warning_##size(type s, u32 o) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ if (UNLIKELY(s)) { \
+ PrintWarningWithOrigin(pc, bp, o); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ }
+
+MSAN_MAYBE_WARNING(u8, 1)
+MSAN_MAYBE_WARNING(u16, 2)
+MSAN_MAYBE_WARNING(u32, 4)
+MSAN_MAYBE_WARNING(u64, 8)
+
+#define MSAN_MAYBE_STORE_ORIGIN(type, size) \
+ void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \
+ if (UNLIKELY(s)) { \
+ if (__msan_get_track_origins() > 1) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
+ o = ChainOrigin(o, &stack); \
+ } \
+ *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \
+ } \
+ }
+
+MSAN_MAYBE_STORE_ORIGIN(u8, 1)
+MSAN_MAYBE_STORE_ORIGIN(u16, 2)
+MSAN_MAYBE_STORE_ORIGIN(u32, 4)
+MSAN_MAYBE_STORE_ORIGIN(u64, 8)
+
+void __msan_warning() {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ PrintWarning(pc, bp);
+ if (__msan::flags()->halt_on_error) {
+ if (__msan::flags()->print_stats)
+ ReportStats();
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
+void __msan_warning_noreturn() {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ PrintWarning(pc, bp);
+ if (__msan::flags()->print_stats)
+ ReportStats();
+ Printf("Exiting\n");
+ Die();
+}
+
+void __msan_init() {
+ CHECK(!msan_init_is_running);
+ if (msan_inited) return;
+ msan_init_is_running = 1;
+ SanitizerToolName = "MemorySanitizer";
+
+ InitTlsSize();
+
+ CacheBinaryName();
+ InitializeFlags();
+
+ __sanitizer_set_report_path(common_flags()->log_path);
+
+ InitializeInterceptors();
+ InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
+
+ DisableCoreDumperIfNecessary();
+ if (StackSizeIsUnlimited()) {
+ VPrintf(1, "Unlimited stack, doing reexec\n");
+ // A reasonably large stack size. It is bigger than the usual 8Mb, because,
+ // well, the program could have been run with unlimited stack for a reason.
+ SetStackSizeLimitInBytes(32 * 1024 * 1024);
+ ReExec();
+ }
+
+ __msan_clear_on_return();
+ if (__msan_get_track_origins())
+ VPrintf(1, "msan_track_origins\n");
+ if (!InitShadow(__msan_get_track_origins())) {
+ Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
+ Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
+ Printf("FATAL: Disabling ASLR is known to cause this error.\n");
+ Printf("FATAL: If running under GDB, try "
+ "'set disable-randomization off'.\n");
+ DumpProcessMap();
+ Die();
+ }
+
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+
+ MsanTSDInit(MsanTSDDtor);
+
+ MsanAllocatorInit();
+
+ MsanThread *main_thread = MsanThread::Create(nullptr, nullptr);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart();
+
+#if MSAN_CONTAINS_UBSAN
+ __ubsan::InitAsPlugin();
+#endif
+
+ VPrintf(1, "MemorySanitizer init done\n");
+
+ msan_init_is_running = 0;
+ msan_inited = 1;
+}
+
+void __msan_set_keep_going(int keep_going) {
+ flags()->halt_on_error = !keep_going;
+}
+
+void __msan_set_expect_umr(int expect_umr) {
+ if (expect_umr) {
+ msan_expected_umr_found = 0;
+ } else if (!msan_expected_umr_found) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
+ ReportExpectedUMRNotFound(&stack);
+ Die();
+ }
+ msan_expect_umr = expect_umr;
+}
+
+void __msan_print_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
+ DescribeMemoryRange(x, size);
+}
+
+void __msan_dump_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
+ unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x);
+ for (uptr i = 0; i < size; i++) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x ", s[i] & 0xf, s[i] >> 4);
+#else
+ Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
+#endif
+ }
+ Printf("\n");
+}
+
+sptr __msan_test_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) return -1;
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return i;
+ return -1;
+}
+
+void __msan_check_mem_is_initialized(const void *x, uptr size) {
+ if (!__msan::flags()->report_umrs) return;
+ sptr offset = __msan_test_shadow(x, size);
+ if (offset < 0)
+ return;
+
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ ReportUMRInsideAddressRange(__func__, x, size, offset);
+ __msan::PrintWarningWithOrigin(pc, bp,
+ __msan_get_origin(((const char *)x) + offset));
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
+int __msan_set_poison_in_malloc(int do_poison) {
+ int old = flags()->poison_in_malloc;
+ flags()->poison_in_malloc = do_poison;
+ return old;
+}
+
+int __msan_has_dynamic_component() { return false; }
+
+NOINLINE
+void __msan_clear_on_return() {
+ __msan_param_tls[0] = 0;
+}
+
+void __msan_partial_poison(const void* data, void* shadow, uptr size) {
+ internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
+}
+
+void __msan_load_unpoisoned(const void *src, uptr size, void *dst) {
+ internal_memcpy(dst, src, size);
+ __msan_unpoison(dst, size);
+}
+
+void __msan_set_origin(const void *a, uptr size, u32 origin) {
+ if (__msan_get_track_origins()) SetOrigin(a, size, origin);
+}
+
+// 'descr' is created at compile time and contains '----' in the beginning.
+// When we see descr for the first time we replace '----' with a uniq id
+// and set the origin to (id | (31-th bit)).
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
+ __msan_set_alloca_origin4(a, size, descr, 0);
+}
+
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
+ static const u32 dash = '-';
+ static const u32 first_timer =
+ dash + (dash << 8) + (dash << 16) + (dash << 24);
+ u32 *id_ptr = (u32*)descr;
+ bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0;
+ u32 id = *id_ptr;
+ if (id == first_timer) {
+ u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed);
+ CHECK_LT(idx, kNumStackOriginDescrs);
+ StackOriginDescr[idx] = descr + 4;
+ StackOriginPC[idx] = pc;
+ id = Origin::CreateStackOrigin(idx).raw_id();
+ *id_ptr = id;
+ if (print)
+ Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc);
+ }
+ if (print)
+ Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
+ __msan_set_origin(a, size, id);
+}
+
+u32 __msan_chain_origin(u32 id) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp);
+ return ChainOrigin(id, &stack);
+}
+
+u32 __msan_get_origin(const void *a) {
+ if (!__msan_get_track_origins()) return 0;
+ uptr x = (uptr)a;
+ uptr aligned = x & ~3ULL;
+ uptr origin_ptr = MEM_TO_ORIGIN(aligned);
+ return *(u32*)origin_ptr;
+}
+
+int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id) {
+ Origin o = Origin::FromRawId(this_id);
+ while (o.raw_id() != prev_id && o.isChainedOrigin())
+ o = o.getNextChainedOrigin(nullptr);
+ return o.raw_id() == prev_id;
+}
+
+u32 __msan_get_umr_origin() {
+ return __msan_origin_tls;
+}
+
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+ __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+ __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+ __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
+ return *p;
+}
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+ u16 s = __msan_param_tls[1];
+ *(uu16 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+ u32 s = __msan_param_tls[1];
+ *(uu32 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+ u64 s = __msan_param_tls[1];
+ *(uu64 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
+ *p = x;
+}
+
+void __msan_set_death_callback(void (*callback)(void)) {
+ SetUserDieCallback(callback);
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __msan_default_options() { return ""; }
+} // extern "C"
+#endif
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
+ stack.Print();
+}
+} // extern "C"
diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h
new file mode 100644
index 0000000..2079a59
--- /dev/null
+++ b/compiler-rt/lib/msan/msan.h
@@ -0,0 +1,317 @@
+//===-- msan.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Private MSan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_H
+#define MSAN_H
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "msan_interface_internal.h"
+#include "msan_flags.h"
+#include "ubsan/ubsan_platform.h"
+
+#ifndef MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
+#endif
+
+#ifndef MSAN_CONTAINS_UBSAN
+# define MSAN_CONTAINS_UBSAN CAN_SANITIZE_UB
+#endif
+
+struct MappingDesc {
+ uptr start;
+ uptr end;
+ enum Type {
+ INVALID, APP, SHADOW, ORIGIN
+ } type;
+ const char *name;
+};
+
+
+#if SANITIZER_LINUX && defined(__mips64)
+
+// Everything is above 0x00e000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x00a000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x00a000000000ULL, 0x00c000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x00c000000000ULL, 0x00e000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x00e000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app"}};
+
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x002000000000)
+
+#elif SANITIZER_LINUX && defined(__aarch64__)
+
+// The mapping describes both 39-bits and 42-bits. AArch64 maps:
+// - 0x00000000000-0x00010000000: 39/42-bits program own segments
+// - 0x05500000000-0x05600000000: 39-bits PIE program segments
+// - 0x07f80000000-0x07fffffffff: 39-bits libraries segments
+// - 0x2aa00000000-0x2ab00000000: 42-bits PIE program segments
+// - 0x3ff00000000-0x3ffffffffff: 42-bits libraries segments
+// It is fragmented in multiples segments to increase the memory available
+// on 42-bits (12.21% of total VMA available for 42-bits and 13.28 for
+// 39 bits).
+const MappingDesc kMemoryLayout[] = {
+ {0x00000000000ULL, 0x01000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x01000000000ULL, 0x02000000000ULL, MappingDesc::SHADOW, "shadow-2"},
+ {0x02000000000ULL, 0x03000000000ULL, MappingDesc::ORIGIN, "origin-2"},
+ {0x03000000000ULL, 0x04000000000ULL, MappingDesc::SHADOW, "shadow-1"},
+ {0x04000000000ULL, 0x05000000000ULL, MappingDesc::ORIGIN, "origin-1"},
+ {0x05000000000ULL, 0x06000000000ULL, MappingDesc::APP, "app-1"},
+ {0x06000000000ULL, 0x07000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x07000000000ULL, 0x08000000000ULL, MappingDesc::APP, "app-2"},
+ {0x08000000000ULL, 0x09000000000ULL, MappingDesc::INVALID, "invalid"},
+ // The mappings below are used only for 42-bits VMA.
+ {0x09000000000ULL, 0x0A000000000ULL, MappingDesc::SHADOW, "shadow-3"},
+ {0x0A000000000ULL, 0x0B000000000ULL, MappingDesc::ORIGIN, "origin-3"},
+ {0x0B000000000ULL, 0x0F000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x0F000000000ULL, 0x10000000000ULL, MappingDesc::APP, "app-3"},
+ {0x10000000000ULL, 0x11000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x11000000000ULL, 0x12000000000ULL, MappingDesc::APP, "app-4"},
+ {0x12000000000ULL, 0x17000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x17000000000ULL, 0x18000000000ULL, MappingDesc::SHADOW, "shadow-4"},
+ {0x18000000000ULL, 0x19000000000ULL, MappingDesc::ORIGIN, "origin-4"},
+ {0x19000000000ULL, 0x20000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x20000000000ULL, 0x21000000000ULL, MappingDesc::APP, "app-5"},
+ {0x21000000000ULL, 0x26000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x26000000000ULL, 0x27000000000ULL, MappingDesc::SHADOW, "shadow-5"},
+ {0x27000000000ULL, 0x28000000000ULL, MappingDesc::ORIGIN, "origin-5"},
+ {0x28000000000ULL, 0x29000000000ULL, MappingDesc::SHADOW, "shadow-7"},
+ {0x29000000000ULL, 0x2A000000000ULL, MappingDesc::ORIGIN, "origin-7"},
+ {0x2A000000000ULL, 0x2B000000000ULL, MappingDesc::APP, "app-6"},
+ {0x2B000000000ULL, 0x2C000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x2C000000000ULL, 0x2D000000000ULL, MappingDesc::SHADOW, "shadow-6"},
+ {0x2D000000000ULL, 0x2E000000000ULL, MappingDesc::ORIGIN, "origin-6"},
+ {0x2E000000000ULL, 0x2F000000000ULL, MappingDesc::APP, "app-7"},
+ {0x2F000000000ULL, 0x39000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x39000000000ULL, 0x3A000000000ULL, MappingDesc::SHADOW, "shadow-9"},
+ {0x3A000000000ULL, 0x3B000000000ULL, MappingDesc::ORIGIN, "origin-9"},
+ {0x3B000000000ULL, 0x3C000000000ULL, MappingDesc::APP, "app-8"},
+ {0x3C000000000ULL, 0x3D000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x3D000000000ULL, 0x3E000000000ULL, MappingDesc::SHADOW, "shadow-8"},
+ {0x3E000000000ULL, 0x3F000000000ULL, MappingDesc::ORIGIN, "origin-8"},
+ {0x3F000000000ULL, 0x40000000000ULL, MappingDesc::APP, "app-9"},
+};
+# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0x6000000000ULL)
+# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x1000000000ULL)
+
+#elif SANITIZER_LINUX && defined(__powerpc64__)
+
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x000100000000ULL, MappingDesc::APP, "low memory"},
+ {0x000100000000ULL, 0x080000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x080000000000ULL, 0x180100000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x180100000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x1C0000000000ULL, 0x2C0100000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x2C0100000000ULL, 0x300000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x300000000000ULL, 0x400000000000ULL, MappingDesc::APP, "high memory"}};
+
+// Maps low and high app ranges to contiguous space with zero base:
+// Low: 0000 0000 0000 - 0000 ffff ffff -> 1000 0000 0000 - 1000 ffff ffff
+// High: 3000 0000 0000 - 3fff ffff ffff -> 0000 0000 0000 - 0fff ffff ffff
+#define LINEARIZE_MEM(mem) \
+ (((uptr)(mem) & ~0x200000000000ULL) ^ 0x100000000000ULL)
+#define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x080000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL)
+
+#elif SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 64
+
+// Low memory: main binary, MAP_32BIT mappings and modules
+// High memory: heap, modules and main thread stack
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "low memory"},
+ {0x010000000000ULL, 0x100000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x100000000000ULL, 0x310000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x310000000000ULL, 0x380000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x380000000000ULL, 0x590000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x590000000000ULL, 0x600000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};
+
+// Maps low and high app ranges to contiguous space with zero base:
+// Low: 0000 0000 0000 - 00ff ffff ffff -> 2000 0000 0000 - 20ff ffff ffff
+// High: 6000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 1fff ffff ffff
+#define LINEARIZE_MEM(mem) \
+ (((uptr)(mem) & ~0xc00000000000ULL) ^ 0x200000000000ULL)
+#define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x100000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x280000000000)
+
+#elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64
+
+#ifdef MSAN_LINUX_X86_64_OLD_MAPPING
+// Requries PIE binary and ASLR enabled.
+// Main thread stack and DSOs at 0x7f0000000000 (sometimes 0x7e0000000000).
+// Heap at 0x600000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x200000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x200000000000ULL, 0x400000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x400000000000ULL, 0x600000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app"}};
+
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL)
+#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x200000000000ULL)
+#else // MSAN_LINUX_X86_64_OLD_MAPPING
+// All of the following configurations are supported.
+// ASLR disabled: main executable and DSOs at 0x555550000000
+// PIE and ASLR: main executable and DSOs at 0x7f0000000000
+// non-PIE: main executable below 0x100000000, DSOs at 0x7f0000000000
+// Heap at 0x700000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app-1"},
+ {0x010000000000ULL, 0x100000000000ULL, MappingDesc::SHADOW, "shadow-2"},
+ {0x100000000000ULL, 0x110000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x110000000000ULL, 0x200000000000ULL, MappingDesc::ORIGIN, "origin-2"},
+ {0x200000000000ULL, 0x300000000000ULL, MappingDesc::SHADOW, "shadow-3"},
+ {0x300000000000ULL, 0x400000000000ULL, MappingDesc::ORIGIN, "origin-3"},
+ {0x400000000000ULL, 0x500000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x500000000000ULL, 0x510000000000ULL, MappingDesc::SHADOW, "shadow-1"},
+ {0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
+ {0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
+ {0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
+#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL)
+#endif // MSAN_LINUX_X86_64_OLD_MAPPING
+
+#else
+#error "Unsupported platform"
+#endif
+
+const uptr kMemoryLayoutSize = sizeof(kMemoryLayout) / sizeof(kMemoryLayout[0]);
+
+#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW((mem))))
+
+#ifndef __clang__
+__attribute__((optimize("unroll-loops")))
+#endif
+inline bool addr_is_type(uptr addr, MappingDesc::Type mapping_type) {
+// It is critical for performance that this loop is unrolled (because then it is
+// simplified into just a few constant comparisons).
+#ifdef __clang__
+#pragma unroll
+#endif
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
+ if (kMemoryLayout[i].type == mapping_type &&
+ addr >= kMemoryLayout[i].start && addr < kMemoryLayout[i].end)
+ return true;
+ return false;
+}
+
+#define MEM_IS_APP(mem) addr_is_type((uptr)(mem), MappingDesc::APP)
+#define MEM_IS_SHADOW(mem) addr_is_type((uptr)(mem), MappingDesc::SHADOW)
+#define MEM_IS_ORIGIN(mem) addr_is_type((uptr)(mem), MappingDesc::ORIGIN)
+
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
+
+namespace __msan {
+extern int msan_inited;
+extern bool msan_init_is_running;
+extern int msan_report_count;
+
+bool ProtectRange(uptr beg, uptr end);
+bool InitShadow(bool init_origins);
+char *GetProcSelfMaps();
+void InitializeInterceptors();
+
+void MsanAllocatorInit();
+void MsanAllocatorThreadFinish();
+void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size);
+void *MsanReallocate(StackTrace *stack, void *oldp, uptr size,
+ uptr alignment, bool zeroise);
+void MsanDeallocate(StackTrace *stack, void *ptr);
+void InstallTrapHandler();
+void InstallAtExitHandler();
+
+const char *GetStackOriginDescr(u32 id, uptr *pc);
+
+void EnterSymbolizer();
+void ExitSymbolizer();
+bool IsInSymbolizer();
+
+struct SymbolizerScope {
+ SymbolizerScope() { EnterSymbolizer(); }
+ ~SymbolizerScope() { ExitSymbolizer(); }
+};
+
+void PrintWarning(uptr pc, uptr bp);
+void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
+
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
+ bool request_fast_unwind);
+
+void ReportUMR(StackTrace *stack, u32 origin);
+void ReportExpectedUMRNotFound(StackTrace *stack);
+void ReportStats();
+void ReportAtExitStatistics();
+void DescribeMemoryRange(const void *x, uptr size);
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset);
+
+// Unpoison first n function arguments.
+void UnpoisonParam(uptr n);
+void UnpoisonThreadLocalState();
+
+// Returns a "chained" origin id, pointing to the given stack trace followed by
+// the previous origin id.
+u32 ChainOrigin(u32 id, StackTrace *stack);
+
+const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;
+
+#define GET_MALLOC_STACK_TRACE \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() && msan_inited) \
+ GetStackTrace(&stack, common_flags()->malloc_context_size, \
+ StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() > 1 && msan_inited) \
+ GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (msan_inited) \
+ GetStackTrace(&stack, kStackTraceMax, pc, bp, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STORE_STACK_TRACE \
+ GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
+
+class ScopedThreadLocalStateBackup {
+ public:
+ ScopedThreadLocalStateBackup() { Backup(); }
+ ~ScopedThreadLocalStateBackup() { Restore(); }
+ void Backup();
+ void Restore();
+ private:
+ u64 va_arg_overflow_size_tls;
+};
+
+void MsanTSDInit(void (*destructor)(void *tsd));
+void *MsanTSDGet();
+void MsanTSDSet(void *tsd);
+void MsanTSDDtor(void *tsd);
+
+} // namespace __msan
+
+#define MSAN_MALLOC_HOOK(ptr, size) \
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
+#define MSAN_FREE_HOOK(ptr) \
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
+
+#endif // MSAN_H
diff --git a/compiler-rt/lib/msan/msan.syms.extra b/compiler-rt/lib/msan/msan.syms.extra
new file mode 100644
index 0000000..950e6f4
--- /dev/null
+++ b/compiler-rt/lib/msan/msan.syms.extra
@@ -0,0 +1,2 @@
+__msan_*
+__ubsan_*
diff --git a/compiler-rt/lib/msan/msan_allocator.cc b/compiler-rt/lib/msan/msan_allocator.cc
new file mode 100644
index 0000000..b7d3947
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_allocator.cc
@@ -0,0 +1,244 @@
+//===-- msan_allocator.cc --------------------------- ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// MemorySanitizer allocator.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "msan.h"
+#include "msan_allocator.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+
+namespace __msan {
+
+struct Metadata {
+ uptr requested_size;
+};
+
+struct MsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const {}
+ void OnUnmap(uptr p, uptr size) const {
+ __msan_unpoison((void *)p, size);
+
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededShadowMemory(MEM_TO_SHADOW(p), size);
+ if (__msan_get_track_origins())
+ FlushUnneededShadowMemory(MEM_TO_ORIGIN(p), size);
+ }
+};
+
+#if defined(__mips64)
+ static const uptr kMaxAllowedMallocSize = 2UL << 30;
+ static const uptr kRegionSizeLog = 20;
+ static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+ typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+ typedef CompactSizeClassMap SizeClassMap;
+
+ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+ SizeClassMap, kRegionSizeLog, ByteMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+
+#elif defined(__x86_64__)
+#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)
+ static const uptr kAllocatorSpace = 0x700000000000ULL;
+#else
+ static const uptr kAllocatorSpace = 0x600000000000ULL;
+#endif
+ static const uptr kAllocatorSize = 0x80000000000; // 8T.
+ static const uptr kMetadataSize = sizeof(Metadata);
+ static const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+ DefaultSizeClassMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+
+#elif defined(__powerpc64__)
+ static const uptr kAllocatorSpace = 0x300000000000;
+ static const uptr kAllocatorSize = 0x020000000000; // 2T
+ static const uptr kMetadataSize = sizeof(Metadata);
+ static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
+
+ typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+ DefaultSizeClassMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__aarch64__)
+ static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
+ static const uptr kRegionSizeLog = 20;
+ static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+ typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+ typedef CompactSizeClassMap SizeClassMap;
+
+ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+ SizeClassMap, kRegionSizeLog, ByteMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static SpinMutex fallback_mutex;
+
+void MsanAllocatorInit() {
+ allocator.Init(common_flags()->allocator_may_return_null);
+}
+
+AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
+ return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
+}
+
+void MsanThreadLocalMallocStorage::CommitBack() {
+ allocator.SwallowCache(GetAllocatorCache(this));
+}
+
+static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
+ bool zeroise) {
+ if (size > kMaxAllowedMallocSize) {
+ Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
+ (void *)size);
+ return allocator.ReturnNullOrDie();
+ }
+ MsanThread *t = GetCurrentThread();
+ void *allocated;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ }
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
+ meta->requested_size = size;
+ if (zeroise) {
+ __msan_clear_and_unpoison(allocated, size);
+ } else if (flags()->poison_in_malloc) {
+ __msan_poison(allocated, size);
+ if (__msan_get_track_origins()) {
+ stack->tag = StackTrace::TAG_ALLOC;
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(allocated, size, o.raw_id());
+ }
+ }
+ MSAN_MALLOC_HOOK(allocated, size);
+ return allocated;
+}
+
+void MsanDeallocate(StackTrace *stack, void *p) {
+ CHECK(p);
+ MSAN_FREE_HOOK(p);
+ Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
+ uptr size = meta->requested_size;
+ meta->requested_size = 0;
+ // This memory will not be reused by anyone else, so we are free to keep it
+ // poisoned.
+ if (flags()->poison_in_free) {
+ __msan_poison(p, size);
+ if (__msan_get_track_origins()) {
+ stack->tag = StackTrace::TAG_DEALLOC;
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(p, size, o.raw_id());
+ }
+ }
+ MsanThread *t = GetCurrentThread();
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocator.Deallocate(cache, p);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocator.Deallocate(cache, p);
+ }
+}
+
+void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return allocator.ReturnNullOrDie();
+ return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true);
+}
+
+void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
+ uptr alignment, bool zeroise) {
+ if (!old_p)
+ return MsanAllocate(stack, new_size, alignment, zeroise);
+ if (!new_size) {
+ MsanDeallocate(stack, old_p);
+ return nullptr;
+ }
+ Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
+ uptr old_size = meta->requested_size;
+ uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
+ if (new_size <= actually_allocated_size) {
+ // We are not reallocating here.
+ meta->requested_size = new_size;
+ if (new_size > old_size) {
+ if (zeroise) {
+ __msan_clear_and_unpoison((char *)old_p + old_size,
+ new_size - old_size);
+ } else if (flags()->poison_in_malloc) {
+ stack->tag = StackTrace::TAG_ALLOC;
+ PoisonMemory((char *)old_p + old_size, new_size - old_size, stack);
+ }
+ }
+ return old_p;
+ }
+ uptr memcpy_size = Min(new_size, old_size);
+ void *new_p = MsanAllocate(stack, new_size, alignment, zeroise);
+ // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size);
+ if (new_p) {
+ CopyMemory(new_p, old_p, memcpy_size, stack);
+ MsanDeallocate(stack, old_p);
+ }
+ return new_p;
+}
+
+static uptr AllocationSize(const void *p) {
+ if (!p) return 0;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (beg != p) return 0;
+ Metadata *b = (Metadata *)allocator.GetMetaData(p);
+ return b->requested_size;
+}
+
+} // namespace __msan
+
+using namespace __msan;
+
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+uptr __sanitizer_get_free_bytes() { return 1; }
+
+uptr __sanitizer_get_unmapped_bytes() { return 1; }
+
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
+
+int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
+
+uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/compiler-rt/lib/msan/msan_allocator.h b/compiler-rt/lib/msan/msan_allocator.h
new file mode 100644
index 0000000..407942e
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_allocator.h
@@ -0,0 +1,33 @@
+//===-- msan_allocator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_ALLOCATOR_H
+#define MSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+struct MsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ // Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
+ ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
+ void CommitBack();
+
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ MsanThreadLocalMallocStorage() {}
+};
+
+} // namespace __msan
+#endif // MSAN_ALLOCATOR_H
diff --git a/compiler-rt/lib/msan/msan_blacklist.txt b/compiler-rt/lib/msan/msan_blacklist.txt
new file mode 100644
index 0000000..44a5680
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_blacklist.txt
@@ -0,0 +1,7 @@
+# Blacklist for MemorySanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
diff --git a/compiler-rt/lib/msan/msan_chained_origin_depot.cc b/compiler-rt/lib/msan/msan_chained_origin_depot.cc
new file mode 100644
index 0000000..e2796fd
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_chained_origin_depot.cc
@@ -0,0 +1,132 @@
+//===-- msan_chained_origin_depot.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#include "msan_chained_origin_depot.h"
+
+#include "sanitizer_common/sanitizer_stackdepotbase.h"
+
+namespace __msan {
+
+struct ChainedOriginDepotDesc {
+ u32 here_id;
+ u32 prev_id;
+};
+
+struct ChainedOriginDepotNode {
+ ChainedOriginDepotNode *link;
+ u32 id;
+ u32 here_id;
+ u32 prev_id;
+
+ typedef ChainedOriginDepotDesc args_type;
+
+ bool eq(u32 hash, const args_type &args) const {
+ return here_id == args.here_id && prev_id == args.prev_id;
+ }
+
+ static uptr storage_size(const args_type &args) {
+ return sizeof(ChainedOriginDepotNode);
+ }
+
+ /* This is murmur2 hash for the 64->32 bit case.
+ It does not behave all that well because the keys have a very biased
+ distribution (I've seen 7-element buckets with the table only 14% full).
+
+ here_id is built of
+ * (1 bits) Reserved, zero.
+ * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+ * (23 bits) Sequential number (each part has each own sequence).
+
+ prev_id has either the same distribution as here_id (but with 3:8:21)
+ split, or one of two reserved values (-1) or (-2). Either case can
+ dominate depending on the workload.
+ */
+ static u32 hash(const args_type &args) {
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed;
+ u32 k = args.here_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ k = args.prev_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) { return true; }
+ void store(const args_type &args, u32 other_hash) {
+ here_id = args.here_id;
+ prev_id = args.prev_id;
+ }
+
+ args_type load() const {
+ args_type ret = {here_id, prev_id};
+ return ret;
+ }
+
+ struct Handle {
+ ChainedOriginDepotNode *node_;
+ Handle() : node_(nullptr) {}
+ explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id() { return node_->id; }
+ int here_id() { return node_->here_id; }
+ int prev_id() { return node_->prev_id; }
+ };
+
+ Handle get_handle() { return Handle(this); }
+
+ typedef Handle handle_type;
+};
+
+static StackDepotBase<ChainedOriginDepotNode, 4, 20> chainedOriginDepot;
+
+StackDepotStats *ChainedOriginDepotGetStats() {
+ return chainedOriginDepot.GetStats();
+}
+
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) {
+ ChainedOriginDepotDesc desc = {here_id, prev_id};
+ bool inserted;
+ ChainedOriginDepotNode::Handle h = chainedOriginDepot.Put(desc, &inserted);
+ *new_id = h.valid() ? h.id() : 0;
+ return inserted;
+}
+
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other) {
+ ChainedOriginDepotDesc desc = chainedOriginDepot.Get(id);
+ *other = desc.prev_id;
+ return desc.here_id;
+}
+
+void ChainedOriginDepotLockAll() {
+ chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+ chainedOriginDepot.UnlockAll();
+}
+
+} // namespace __msan
diff --git a/compiler-rt/lib/msan/msan_chained_origin_depot.h b/compiler-rt/lib/msan/msan_chained_origin_depot.h
new file mode 100644
index 0000000..f7a71ce
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_chained_origin_depot.h
@@ -0,0 +1,29 @@
+//===-- msan_chained_origin_depot.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_CHAINED_ORIGIN_DEPOT_H
+#define MSAN_CHAINED_ORIGIN_DEPOT_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+StackDepotStats *ChainedOriginDepotGetStats();
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id);
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other);
+
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
+} // namespace __msan
+
+#endif // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/compiler-rt/lib/msan/msan_flags.h b/compiler-rt/lib/msan/msan_flags.h
new file mode 100644
index 0000000..4fc6d17
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_flags.h
@@ -0,0 +1,30 @@
+//===-- msan_flags.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_FLAGS_H
+#define MSAN_FLAGS_H
+
+namespace __msan {
+
+struct Flags {
+#define MSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "msan_flags.inc"
+#undef MSAN_FLAG
+
+ void SetDefaults();
+};
+
+Flags *flags();
+
+} // namespace __msan
+
+#endif // MSAN_FLAGS_H
diff --git a/compiler-rt/lib/msan/msan_flags.inc b/compiler-rt/lib/msan/msan_flags.inc
new file mode 100644
index 0000000..a7ff6c5
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_flags.inc
@@ -0,0 +1,35 @@
+//===-- msan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_FLAG
+# error "Define MSAN_FLAG prior to including this file!"
+#endif
+
+// MSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+MSAN_FLAG(int, exit_code, -1,
+ "DEPRECATED. Use exitcode from common flags instead.")
+MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "")
+MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "")
+MSAN_FLAG(bool, poison_heap_with_zeroes, false, "")
+MSAN_FLAG(bool, poison_stack_with_zeroes, false, "")
+MSAN_FLAG(bool, poison_in_malloc, true, "")
+MSAN_FLAG(bool, poison_in_free, true, "")
+MSAN_FLAG(bool, poison_in_dtor, false, "")
+MSAN_FLAG(bool, report_umrs, true, "")
+MSAN_FLAG(bool, wrap_signals, true, "")
+MSAN_FLAG(bool, print_stats, false, "")
+MSAN_FLAG(bool, halt_on_error, !&__msan_keep_going, "")
+MSAN_FLAG(bool, atexit, false, "")
+MSAN_FLAG(int, store_context_size, 20,
+ "Like malloc_context_size, but for uninit stores.")
diff --git a/compiler-rt/lib/msan/msan_interceptors.cc b/compiler-rt/lib/msan/msan_interceptors.cc
new file mode 100644
index 0000000..fc28e08
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_interceptors.cc
@@ -0,0 +1,1643 @@
+//===-- msan_interceptors.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Interceptors for standard library functions.
+//
+// FIXME: move as many interceptors as possible into
+// sanitizer_common/sanitizer_common_interceptors.h
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
+#include "msan_poisoning.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+#include <stdarg.h>
+// ACHTUNG! No other system header includes in this file.
+// Ideally, we should get rid of stdarg.h as well.
+
+using namespace __msan;
+
+using __sanitizer::memory_order;
+using __sanitizer::atomic_load;
+using __sanitizer::atomic_store;
+using __sanitizer::atomic_uintptr_t;
+
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#endif
+
+// True if this is a nested interceptor.
+static THREADLOCAL int in_interceptor_scope;
+
+extern "C" int *__errno_location(void);
+
+struct InterceptorScope {
+ InterceptorScope() { ++in_interceptor_scope; }
+ ~InterceptorScope() { --in_interceptor_scope; }
+};
+
+bool IsInInterceptorScope() {
+ return in_interceptor_scope;
+}
+
+#define ENSURE_MSAN_INITED() do { \
+ CHECK(!msan_init_is_running); \
+ if (!msan_inited) { \
+ __msan_init(); \
+ } \
+} while (0)
+
+// Check that [x, x+n) range is unpoisoned.
+#define CHECK_UNPOISONED_0(x, n) \
+ do { \
+ sptr offset = __msan_test_shadow(x, n); \
+ if (__msan::IsInSymbolizer()) \
+ break; \
+ if (offset >= 0 && __msan::flags()->report_umrs) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ ReportUMRInsideAddressRange(__func__, x, n, offset); \
+ __msan::PrintWarningWithOrigin( \
+ pc, bp, __msan_get_origin((const char *)x + offset)); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ } while (0)
+
+// Check that [x, x+n) range is unpoisoned unless we are in a nested
+// interceptor.
+#define CHECK_UNPOISONED(x, n) \
+ do { \
+ if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
+ } while (0);
+
+#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \
+ CHECK_UNPOISONED((x), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define CHECK_UNPOISONED_STRING(x, n) \
+ CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
+
+INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
+ if (res > 0)
+ __msan_unpoison(ptr, res *size);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
+ void *file) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file);
+ if (res > 0)
+ __msan_unpoison(ptr, res *size);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
+#endif
+
+INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED_STRING(path, 0)
+ SSIZE_T res = REAL(readlink)(path, buf, bufsiz);
+ if (res > 0)
+ __msan_unpoison(buf, res);
+ return res;
+}
+
+INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
+ return __msan_memcpy(dest, src, n);
+}
+
+INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
+ return (char *)__msan_memcpy(dest, src, n) + n;
+}
+
+INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memccpy)(dest, src, c, n);
+ CHECK(!res || (res >= dest && res <= (char *)dest + n));
+ SIZE_T sz = res ? (char *)res - (char *)dest : n;
+ CHECK_UNPOISONED(src, sz);
+ __msan_unpoison(dest, sz);
+ return res;
+}
+
+INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
+INTERCEPTOR(void *, memset, void *s, int c, SIZE_T n) {
+ return __msan_memset(s, c, n);
+}
+
+INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(alignment & (alignment - 1), 0);
+ CHECK_NE(memptr, 0);
+ *memptr = MsanReallocate(&stack, nullptr, size, alignment, false);
+ CHECK_NE(*memptr, 0);
+ __msan_unpoison(memptr, sizeof(*memptr));
+ return 0;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
+ return ptr;
+}
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
+ DTLS_on_libc_memalign(ptr, size * boundary);
+ return ptr;
+}
+
+INTERCEPTOR(void *, valloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ void *ptr = MsanReallocate(&stack, nullptr, size, GetPageSizeCached(), false);
+ return ptr;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, pvalloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ void *ptr = MsanReallocate(&stack, nullptr, size, PageSize, false);
+ return ptr;
+}
+#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define MSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
+
+INTERCEPTOR(void, free, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (!ptr) return;
+ MsanDeallocate(&stack, ptr);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (!ptr) return;
+ MsanDeallocate(&stack, ptr);
+}
+#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
+#else
+#define MSAN_MAYBE_INTERCEPT_CFREE
+#endif
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ return __sanitizer_get_allocated_size(ptr);
+}
+
+#if !SANITIZER_FREEBSD
+// This function actually returns a struct by value, but we can't unpoison a
+// temporary! The following is equivalent on all supported platforms but
+// aarch64 (which uses a different register for sret value). We have a test
+// to confirm that.
+INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
+#ifdef __aarch64__
+ uptr r8;
+ asm volatile("mov %0,x8" : "=r" (r8));
+ sret = reinterpret_cast<__sanitizer_mallinfo*>(r8);
+#endif
+ REAL(memset)(sret, 0, sizeof(*sret));
+ __msan_unpoison(sret, sizeof(*sret));
+}
+#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLINFO
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOPT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, malloc_stats, void) {
+ // FIXME: implement, but don't call REAL(malloc_stats)!
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
+#endif
+
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ if (msan_init_is_running)
+ return REAL(strlen)(s);
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(strlen)(s);
+ CHECK_UNPOISONED(s, res + 1);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(strnlen)(s, n);
+ SIZE_T scan_size = (res == n) ? res : res + 1;
+ CHECK_UNPOISONED(s, scan_size);
+ return res;
+}
+
+INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
+ char *res = REAL(strcpy)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest, src, n + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ if (copy_size < n)
+ copy_size++; // trailing \0
+ char *res = REAL(strncpy)(dest, src, n); // NOLINT
+ CopyShadowAndOrigin(dest, src, copy_size, &stack);
+ __msan_unpoison(dest + copy_size, n - copy_size);
+ return res;
+}
+
+INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
+ char *res = REAL(stpcpy)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest, src, n + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strdup, char *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ // On FreeBSD strdup() leverages strlen().
+ InterceptorScope interceptor_scope;
+ SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
+ char *res = REAL(strdup)(src);
+ CopyShadowAndOrigin(res, src, n + 1, &stack);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, __strdup, char *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
+ char *res = REAL(__strdup)(src);
+ CopyShadowAndOrigin(res, src, n + 1, &stack);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRDUP
+#endif
+
+INTERCEPTOR(char *, strndup, char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ // On FreeBSD strndup() leverages strnlen().
+ InterceptorScope interceptor_scope;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ char *res = REAL(strndup)(src, n);
+ CopyShadowAndOrigin(res, src, copy_size, &stack);
+ __msan_unpoison(res + copy_size, 1); // \0
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ char *res = REAL(__strndup)(src, n);
+ CopyShadowAndOrigin(res, src, copy_size, &stack);
+ __msan_unpoison(res + copy_size, 1); // \0
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRNDUP
+#endif
+
+INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(gcvt)(number, ndigit, buf);
+ SIZE_T n = REAL(strlen)(buf);
+ __msan_unpoison(buf, n + 1);
+ return res;
+}
+
+INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T src_size = REAL(strlen)(src);
+ SIZE_T dest_size = REAL(strlen)(dest);
+ CHECK_UNPOISONED_STRING(src + src_size, 0);
+ CHECK_UNPOISONED_STRING(dest + dest_size, 0);
+ char *res = REAL(strcat)(dest, src); // NOLINT
+ CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
+ return res;
+}
+
+INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ SIZE_T dest_size = REAL(strlen)(dest);
+ SIZE_T copy_size = REAL(strnlen)(src, n);
+ CHECK_UNPOISONED_STRING(dest + dest_size, 0);
+ char *res = REAL(strncat)(dest, src, n); // NOLINT
+ CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
+ __msan_unpoison(dest + dest_size + copy_size, 1); // \0
+ return res;
+}
+
+// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
+// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
+#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(__VA_ARGS__); \
+ __msan_unpoison(endptr, sizeof(*endptr)); \
+ return res;
+
+#define INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \
+ }
+
+#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \
+ }
+
+#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \
+ }
+
+#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base, void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \
+ }
+
+#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
+
+#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
+
+INTERCEPTORS_STRTO(double, strtod, char) // NOLINT
+INTERCEPTORS_STRTO(float, strtof, char) // NOLINT
+INTERCEPTORS_STRTO(long double, strtold, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, strtol, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, strtoll, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) // NOLINT
+
+INTERCEPTORS_STRTO(double, wcstod, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(float, wcstof, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(long double, wcstold, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) // NOLINT
+
+#define INTERCEPT_STRTO(func) \
+ INTERCEPT_FUNCTION(func); \
+ INTERCEPT_FUNCTION(func##_l); \
+ INTERCEPT_FUNCTION(__##func##_l); \
+ INTERCEPT_FUNCTION(__##func##_internal);
+
+
+// FIXME: support *wprintf in common format interceptors.
+INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(vswprintf)(str, size, format, ap);
+ if (res >= 0) {
+ __msan_unpoison(str, 4 * (res + 1));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
+ ENSURE_MSAN_INITED();
+ va_list ap;
+ va_start(ap, format);
+ int res = vswprintf(str, size, format, ap);
+ va_end(ap);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm)(dest, src, n);
+ if (res < n) __msan_unpoison(dest, res + 1);
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n,
+ void *loc) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc);
+ if (res < n) __msan_unpoison(dest, res + 1);
+ return res;
+}
+
+#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(s, __VA_ARGS__); \
+ if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \
+ return res;
+
+INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
+ loc);
+}
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
+#endif
+
+INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
+ loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
+ loc);
+}
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
+#endif
+
+INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(mbtowc)(dest, src, n);
+ if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
+ if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ ENSURE_MSAN_INITED();
+ SIZE_T res = REAL(wcslen)(s);
+ CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1));
+ return res;
+}
+
+// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
+INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wcschr)(s, wc, ps);
+ return res;
+}
+
+// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
+INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wcscpy)(dest, src);
+ CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1),
+ &stack);
+ return res;
+}
+
+// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
+INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmemcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmempcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
+ CHECK(MEM_IS_APP(s));
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wmemset)(s, c, n);
+ __msan_unpoison(s, n * sizeof(wchar_t));
+ return res;
+}
+
+INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ wchar_t *res = REAL(wmemmove)(dest, src, n);
+ MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack);
+ return res;
+}
+
+INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(wcscmp)(s1, s2);
+ return res;
+}
+
+INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(gettimeofday)(tv, tz);
+ if (tv)
+ __msan_unpoison(tv, 16);
+ if (tz)
+ __msan_unpoison(tz, 8);
+ return res;
+}
+
+INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fcvt)(x, a, b, c);
+ __msan_unpoison(b, sizeof(*b));
+ __msan_unpoison(c, sizeof(*c));
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+INTERCEPTOR(char *, getenv, char *name) {
+ if (msan_init_is_running)
+ return REAL(getenv)(name);
+ ENSURE_MSAN_INITED();
+ char *res = REAL(getenv)(name);
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+extern char **environ;
+
+static void UnpoisonEnviron() {
+ char **envp = environ;
+ for (; *envp; ++envp) {
+ __msan_unpoison(envp, sizeof(*envp));
+ __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
+ }
+ // Trailing NULL pointer.
+ __msan_unpoison(envp, sizeof(*envp));
+}
+
+INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
+ ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED_STRING(name, 0)
+ int res = REAL(setenv)(name, value, overwrite);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+INTERCEPTOR(int, putenv, char *string) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(putenv)(string);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstat)(magic, fd, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstat64)(magic, fd, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+
+#if SANITIZER_FREEBSD
+INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(fstatat)(fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(fstatat)
+#else
+INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(__fxstatat)
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64
+#endif
+
+#if SANITIZER_FREEBSD
+INTERCEPTOR(int, stat, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(stat)(path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(stat)
+#else
+INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xstat)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+# define MSAN_INTERCEPT_STAT INTERCEPT_FUNCTION(__xstat)
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xstat64)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___XSTAT64 INTERCEPT_FUNCTION(__xstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__lxstat)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT INTERCEPT_FUNCTION(__lxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__lxstat64)(magic, path, buf);
+ if (!res)
+ __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64 INTERCEPT_FUNCTION(__lxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
+
+INTERCEPTOR(int, pipe, int pipefd[2]) {
+ if (msan_init_is_running)
+ return REAL(pipe)(pipefd);
+ ENSURE_MSAN_INITED();
+ int res = REAL(pipe)(pipefd);
+ if (!res)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pipe2)(pipefd, flags);
+ if (!res)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(socketpair)(domain, type, protocol, sv);
+ if (!res)
+ __msan_unpoison(sv, sizeof(int[2]));
+ return res;
+}
+
+INTERCEPTOR(char *, fgets, char *s, int size, void *stream) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fgets)(s, size, stream);
+ if (res)
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(fgets_unlocked)(s, size, stream);
+ if (res)
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
+#endif
+
+INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
+ if (msan_init_is_running)
+ return REAL(getrlimit)(resource, rlim);
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrlimit)(resource, rlim);
+ if (!res)
+ __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz);
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
+ if (msan_init_is_running)
+ return REAL(getrlimit64)(resource, rlim);
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrlimit64)(resource, rlim);
+ if (!res)
+ __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
+#else
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
+#endif
+
+#if SANITIZER_FREEBSD
+// FreeBSD's <sys/utsname.h> define uname() as
+// static __inline int uname(struct utsname *name) {
+// return __xuname(SYS_NMLN, (void*)name);
+// }
+INTERCEPTOR(int, __xuname, int size, void *utsname) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__xuname)(size, utsname);
+ if (!res)
+ __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname)
+#else
+INTERCEPTOR(int, uname, struct utsname *utsname) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(uname)(utsname);
+ if (!res)
+ __msan_unpoison(utsname, __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname)
+#endif
+
+INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(gethostname)(name, len);
+ if (!res) {
+ SIZE_T real_len = REAL(strnlen)(name, len);
+ if (real_len < len)
+ ++real_len;
+ __msan_unpoison(name, real_len);
+ }
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
+ int timeout) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(epoll_wait)(epfd, events, maxevents, timeout);
+ if (res > 0) {
+ __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
+ }
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
+ int timeout, void *sigmask) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask);
+ if (res > 0) {
+ __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res);
+ }
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
+#endif
+
+INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
+ ENSURE_MSAN_INITED();
+ SSIZE_T res = REAL(recv)(fd, buf, len, flags);
+ if (res > 0)
+ __msan_unpoison(buf, res);
+ return res;
+}
+
+INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
+ void *srcaddr, int *addrlen) {
+ ENSURE_MSAN_INITED();
+ SIZE_T srcaddr_sz;
+ if (srcaddr) srcaddr_sz = *addrlen;
+ SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
+ if (res > 0) {
+ __msan_unpoison(buf, res);
+ if (srcaddr) {
+ SIZE_T sz = *addrlen;
+ __msan_unpoison(srcaddr, Min(sz, srcaddr_sz));
+ }
+ }
+ return res;
+}
+
+INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ if (UNLIKELY(!msan_inited)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const SIZE_T kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static SIZE_T allocated;
+ SIZE_T size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ return MsanCalloc(&stack, nmemb, size);
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ return MsanReallocate(&stack, ptr, size, sizeof(u64), false);
+}
+
+INTERCEPTOR(void *, malloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ return MsanReallocate(&stack, nullptr, size, sizeof(u64), false);
+}
+
+void __msan_allocated_memory(const void *data, uptr size) {
+ GET_MALLOC_STACK_TRACE;
+ if (flags()->poison_in_malloc) {
+ stack.tag = STACK_TRACE_TAG_POISON;
+ PoisonMemory(data, size, &stack);
+ }
+}
+
+void __msan_copy_shadow(void *dest, const void *src, uptr n) {
+ GET_STORE_STACK_TRACE;
+ MoveShadowAndOrigin(dest, src, n, &stack);
+}
+
+void __sanitizer_dtor_callback(const void *data, uptr size) {
+ GET_MALLOC_STACK_TRACE;
+ if (flags()->poison_in_dtor) {
+ stack.tag = STACK_TRACE_TAG_POISON;
+ PoisonMemory(data, size, &stack);
+ }
+}
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF_T offset) {
+ if (msan_init_is_running)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = nullptr;
+ }
+ }
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF64_T offset) {
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = nullptr;
+ }
+ }
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ __msan_unpoison(res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
+#else
+#define MSAN_MAYBE_INTERCEPT_MMAP64
+#endif
+
+struct dlinfo {
+ char *dli_fname;
+ void *dli_fbase;
+ char *dli_sname;
+ void *dli_saddr;
+};
+
+INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(dladdr)(addr, info);
+ if (res != 0) {
+ __msan_unpoison(info, sizeof(*info));
+ if (info->dli_fname)
+ __msan_unpoison(info->dli_fname, REAL(strlen)(info->dli_fname) + 1);
+ if (info->dli_sname)
+ __msan_unpoison(info->dli_sname, REAL(strlen)(info->dli_sname) + 1);
+ }
+ return res;
+}
+
+INTERCEPTOR(char *, dlerror, int fake) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(dlerror)(fake);
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
+ void *data);
+struct dl_iterate_phdr_data {
+ dl_iterate_phdr_cb callback;
+ void *data;
+};
+
+static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
+ void *data) {
+ if (info) {
+ __msan_unpoison(info, size);
+ if (info->dlpi_phdr && info->dlpi_phnum)
+ __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum);
+ if (info->dlpi_name)
+ __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
+ }
+ dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
+ UnpoisonParam(3);
+ return cbdata->callback(info, size, cbdata->data);
+}
+
+INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
+ ENSURE_MSAN_INITED();
+ dl_iterate_phdr_data cbdata;
+ cbdata.callback = callback;
+ cbdata.data = data;
+ int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
+ return res;
+}
+
+INTERCEPTOR(int, getrusage, int who, void *usage) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(getrusage)(who, usage);
+ if (res == 0) {
+ __msan_unpoison(usage, __sanitizer::struct_rusage_sz);
+ }
+ return res;
+}
+
+class SignalHandlerScope {
+ public:
+ SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->EnterSignalHandler();
+ }
+ ~SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->LeaveSignalHandler();
+ }
+};
+
+// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
+// Access to sigactions[] is gone with relaxed atomics to avoid data race with
+// the signal handler.
+const int kMaxSignals = 1024;
+static atomic_uintptr_t sigactions[kMaxSignals];
+static StaticSpinMutex sigactions_mu;
+
+static void SignalHandler(int signo) {
+ SignalHandlerScope signal_handler_scope;
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(1);
+
+ typedef void (*signal_cb)(int x);
+ signal_cb cb =
+ (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
+ cb(signo);
+}
+
+static void SignalAction(int signo, void *si, void *uc) {
+ SignalHandlerScope signal_handler_scope;
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(3);
+ __msan_unpoison(si, sizeof(__sanitizer_sigaction));
+ __msan_unpoison(uc, __sanitizer::ucontext_t_sz);
+
+ typedef void (*sigaction_cb)(int, void *, void *);
+ sigaction_cb cb =
+ (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
+ cb(signo, si, uc);
+}
+
+INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
+ __sanitizer_sigaction *oldact) {
+ ENSURE_MSAN_INITED();
+ // FIXME: check that *act is unpoisoned.
+ // That requires intercepting all of sigemptyset, sigfillset, etc.
+ int res;
+ if (flags()->wrap_signals) {
+ SpinMutexLock lock(&sigactions_mu);
+ CHECK_LT(signo, kMaxSignals);
+ uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
+ __sanitizer_sigaction new_act;
+ __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
+ if (act) {
+ REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sigaction;
+ uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
+ ? (uptr)SignalAction
+ : (uptr)SignalHandler;
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ pnew_act->sigaction = (void (*)(int, void *, void *))new_cb;
+ }
+ }
+ res = REAL(sigaction)(signo, pnew_act, oldact);
+ if (res == 0 && oldact) {
+ uptr cb = (uptr)oldact->sigaction;
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ oldact->sigaction = (void (*)(int, void *, void *))old_cb;
+ }
+ }
+ } else {
+ res = REAL(sigaction)(signo, act, oldact);
+ }
+
+ if (res == 0 && oldact) {
+ __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, signal, int signo, uptr cb) {
+ ENSURE_MSAN_INITED();
+ if (flags()->wrap_signals) {
+ CHECK_LT(signo, kMaxSignals);
+ SpinMutexLock lock(&sigactions_mu);
+ if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ cb = (uptr) SignalHandler;
+ }
+ return REAL(signal)(signo, cb);
+ } else {
+ return REAL(signal)(signo, cb);
+ }
+}
+
+extern "C" int pthread_attr_init(void *attr);
+extern "C" int pthread_attr_destroy(void *attr);
+
+static void *MsanThreadStartFunc(void *arg) {
+ MsanThread *t = (MsanThread *)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart();
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
+ void * param) {
+ ENSURE_MSAN_INITED(); // for GetTlsSize()
+ __sanitizer_pthread_attr_t myattr;
+ if (!attr) {
+ pthread_attr_init(&myattr);
+ attr = &myattr;
+ }
+
+ AdjustStackSize(attr);
+
+ MsanThread *t = MsanThread::Create(callback, param);
+
+ int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
+
+ if (attr == &myattr)
+ pthread_attr_destroy(&myattr);
+ if (!res) {
+ __msan_unpoison(th, __sanitizer::pthread_t_sz);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
+ void (*dtor)(void *value)) {
+ if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_key_create)(key, dtor);
+ if (!res && key)
+ __msan_unpoison(key, sizeof(*key));
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **retval) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_join)(th, retval);
+ if (!res && retval)
+ __msan_unpoison(retval, sizeof(*retval));
+ return res;
+}
+
+extern char *tzname[2];
+
+INTERCEPTOR(void, tzset, int fake) {
+ ENSURE_MSAN_INITED();
+ REAL(tzset)(fake);
+ if (tzname[0])
+ __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
+ if (tzname[1])
+ __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1);
+ return;
+}
+
+struct MSanAtExitRecord {
+ void (*func)(void *arg);
+ void *arg;
+};
+
+void MSanAtExitWrapper(void *arg) {
+ UnpoisonParam(1);
+ MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
+ r->func(r->arg);
+ InternalFree(r);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+ if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ ENSURE_MSAN_INITED();
+ MSanAtExitRecord *r =
+ (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
+ r->func = func;
+ r->arg = arg;
+ return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+}
+
+DECLARE_REAL(int, shmctl, int shmid, int cmd, void *buf)
+
+INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
+ ENSURE_MSAN_INITED();
+ void *p = REAL(shmat)(shmid, shmaddr, shmflg);
+ if (p != (void *)-1) {
+ __sanitizer_shmid_ds ds;
+ int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
+ if (!res) {
+ __msan_unpoison(p, ds.shm_segsz);
+ }
+ }
+ return p;
+}
+
+static void BeforeFork() {
+ StackDepotLockAll();
+ ChainedOriginDepotLockAll();
+}
+
+static void AfterFork() {
+ ChainedOriginDepotUnlockAll();
+ StackDepotUnlockAll();
+}
+
+INTERCEPTOR(int, fork, void) {
+ ENSURE_MSAN_INITED();
+ BeforeFork();
+ int pid = REAL(fork)();
+ AfterFork();
+ return pid;
+}
+
+INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name,
+ const void *termp, const void *winp) {
+ ENSURE_MSAN_INITED();
+ InterceptorScope interceptor_scope;
+ int res = REAL(openpty)(amaster, aslave, name, termp, winp);
+ if (!res) {
+ __msan_unpoison(amaster, sizeof(*amaster));
+ __msan_unpoison(aslave, sizeof(*aslave));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp,
+ const void *winp) {
+ ENSURE_MSAN_INITED();
+ InterceptorScope interceptor_scope;
+ int res = REAL(forkpty)(amaster, name, termp, winp);
+ if (res != -1)
+ __msan_unpoison(amaster, sizeof(*amaster));
+ return res;
+}
+
+struct MSanInterceptorContext {
+ bool in_interceptor_scope;
+};
+
+namespace __msan {
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // namespace __msan
+
+// A version of CHECK_UNPOISONED using a saved scope value. Used in common
+// interceptors.
+#define CHECK_UNPOISONED_CTX(ctx, x, n) \
+ do { \
+ if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
+ CHECK_UNPOISONED_0(x, n); \
+ } while (0)
+
+#define MSAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "MemorySanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+
+#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \
+ UnpoisonParam(count)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ CHECK_UNPOISONED_CTX(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
+ MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
+ ctx = (void *)&msan_ctx; \
+ (void)ctx; \
+ InterceptorScope interceptor_scope; \
+ __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */ \
+ ENSURE_MSAN_INITED();
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ do { \
+ link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \
+ if (filename && map) \
+ ForEachMappedRegion(map, __msan_unpoison); \
+ } while (false)
+
+#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
+ if (MsanThread *t = GetCurrentThread()) { \
+ *begin = t->tls_begin(); \
+ *end = t->tls_end(); \
+ } else { \
+ *begin = *end = 0; \
+ }
+
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+// These interface functions reside here so that they can use
+// REAL(memset), etc.
+void __msan_unpoison(const void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, 0);
+}
+
+void __msan_poison(const void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
+}
+
+void __msan_poison_stack(void *a, uptr size) {
+ if (!MEM_IS_APP(a)) return;
+ SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
+}
+
+void __msan_clear_and_unpoison(void *a, uptr size) {
+ REAL(memset)(a, 0, size);
+ SetShadow(a, size, 0);
+}
+
+void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memcpy(dest, src, n);
+ if (msan_init_is_running || __msan::IsInSymbolizer())
+ return REAL(memcpy)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memcpy)(dest, src, n);
+ CopyShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+
+void *__msan_memset(void *s, int c, SIZE_T n) {
+ if (!msan_inited) return internal_memset(s, c, n);
+ if (msan_init_is_running) return REAL(memset)(s, c, n);
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memset)(s, c, n);
+ __msan_unpoison(s, n);
+ return res;
+}
+
+void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memmove(dest, src, n);
+ if (msan_init_is_running) return REAL(memmove)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memmove)(dest, src, n);
+ MoveShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+
+void __msan_unpoison_string(const char* s) {
+ if (!MEM_IS_APP(s)) return;
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
+}
+
+namespace __msan {
+
+void InitializeInterceptors() {
+ static int inited = 0;
+ CHECK_EQ(inited, 0);
+ InitializeCommonInterceptors();
+
+ INTERCEPT_FUNCTION(mmap);
+ MSAN_MAYBE_INTERCEPT_MMAP64;
+ INTERCEPT_FUNCTION(posix_memalign);
+ MSAN_MAYBE_INTERCEPT_MEMALIGN;
+ INTERCEPT_FUNCTION(__libc_memalign);
+ INTERCEPT_FUNCTION(valloc);
+ MSAN_MAYBE_INTERCEPT_PVALLOC;
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(realloc);
+ INTERCEPT_FUNCTION(free);
+ MSAN_MAYBE_INTERCEPT_CFREE;
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ MSAN_MAYBE_INTERCEPT_MALLINFO;
+ MSAN_MAYBE_INTERCEPT_MALLOPT;
+ MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
+ INTERCEPT_FUNCTION(fread);
+ MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
+ INTERCEPT_FUNCTION(readlink);
+ INTERCEPT_FUNCTION(memcpy);
+ INTERCEPT_FUNCTION(memccpy);
+ INTERCEPT_FUNCTION(mempcpy);
+ INTERCEPT_FUNCTION(memset);
+ INTERCEPT_FUNCTION(memmove);
+ INTERCEPT_FUNCTION(bcopy);
+ INTERCEPT_FUNCTION(wmemset);
+ INTERCEPT_FUNCTION(wmemcpy);
+ INTERCEPT_FUNCTION(wmempcpy);
+ INTERCEPT_FUNCTION(wmemmove);
+ INTERCEPT_FUNCTION(strcpy); // NOLINT
+ INTERCEPT_FUNCTION(stpcpy); // NOLINT
+ INTERCEPT_FUNCTION(strdup);
+ MSAN_MAYBE_INTERCEPT___STRDUP;
+ INTERCEPT_FUNCTION(strndup);
+ MSAN_MAYBE_INTERCEPT___STRNDUP;
+ INTERCEPT_FUNCTION(strncpy); // NOLINT
+ INTERCEPT_FUNCTION(strlen);
+ INTERCEPT_FUNCTION(strnlen);
+ INTERCEPT_FUNCTION(gcvt);
+ INTERCEPT_FUNCTION(strcat); // NOLINT
+ INTERCEPT_FUNCTION(strncat); // NOLINT
+ INTERCEPT_STRTO(strtod);
+ INTERCEPT_STRTO(strtof);
+ INTERCEPT_STRTO(strtold);
+ INTERCEPT_STRTO(strtol);
+ INTERCEPT_STRTO(strtoul);
+ INTERCEPT_STRTO(strtoll);
+ INTERCEPT_STRTO(strtoull);
+ INTERCEPT_STRTO(wcstod);
+ INTERCEPT_STRTO(wcstof);
+ INTERCEPT_STRTO(wcstold);
+ INTERCEPT_STRTO(wcstol);
+ INTERCEPT_STRTO(wcstoul);
+ INTERCEPT_STRTO(wcstoll);
+ INTERCEPT_STRTO(wcstoull);
+ INTERCEPT_FUNCTION(vswprintf);
+ INTERCEPT_FUNCTION(swprintf);
+ INTERCEPT_FUNCTION(strxfrm);
+ INTERCEPT_FUNCTION(strxfrm_l);
+ INTERCEPT_FUNCTION(strftime);
+ INTERCEPT_FUNCTION(strftime_l);
+ MSAN_MAYBE_INTERCEPT___STRFTIME_L;
+ INTERCEPT_FUNCTION(wcsftime);
+ INTERCEPT_FUNCTION(wcsftime_l);
+ MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
+ INTERCEPT_FUNCTION(mbtowc);
+ INTERCEPT_FUNCTION(mbrtowc);
+ INTERCEPT_FUNCTION(wcslen);
+ INTERCEPT_FUNCTION(wcschr);
+ INTERCEPT_FUNCTION(wcscpy);
+ INTERCEPT_FUNCTION(wcscmp);
+ INTERCEPT_FUNCTION(getenv);
+ INTERCEPT_FUNCTION(setenv);
+ INTERCEPT_FUNCTION(putenv);
+ INTERCEPT_FUNCTION(gettimeofday);
+ INTERCEPT_FUNCTION(fcvt);
+ MSAN_MAYBE_INTERCEPT___FXSTAT;
+ MSAN_INTERCEPT_FSTATAT;
+ MSAN_INTERCEPT_STAT;
+ MSAN_MAYBE_INTERCEPT___LXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTAT64;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT64;
+ MSAN_MAYBE_INTERCEPT___XSTAT64;
+ MSAN_MAYBE_INTERCEPT___LXSTAT64;
+ INTERCEPT_FUNCTION(pipe);
+ INTERCEPT_FUNCTION(pipe2);
+ INTERCEPT_FUNCTION(socketpair);
+ INTERCEPT_FUNCTION(fgets);
+ MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
+ INTERCEPT_FUNCTION(getrlimit);
+ MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
+ MSAN_INTERCEPT_UNAME;
+ INTERCEPT_FUNCTION(gethostname);
+ MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
+ MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
+ INTERCEPT_FUNCTION(recv);
+ INTERCEPT_FUNCTION(recvfrom);
+ INTERCEPT_FUNCTION(dladdr);
+ INTERCEPT_FUNCTION(dlerror);
+ INTERCEPT_FUNCTION(dl_iterate_phdr);
+ INTERCEPT_FUNCTION(getrusage);
+ INTERCEPT_FUNCTION(sigaction);
+ INTERCEPT_FUNCTION(signal);
+ INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_key_create);
+ INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(tzset);
+ INTERCEPT_FUNCTION(__cxa_atexit);
+ INTERCEPT_FUNCTION(shmat);
+ INTERCEPT_FUNCTION(fork);
+ INTERCEPT_FUNCTION(openpty);
+ INTERCEPT_FUNCTION(forkpty);
+
+ inited = 1;
+}
+} // namespace __msan
diff --git a/compiler-rt/lib/msan/msan_interface_internal.h b/compiler-rt/lib/msan/msan_interface_internal.h
new file mode 100644
index 0000000..c1e02ce
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_interface_internal.h
@@ -0,0 +1,169 @@
+//===-- msan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Private MSan interface header.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_INTERFACE_INTERNAL_H
+#define MSAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+extern "C" {
+// FIXME: document all interface functions.
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_get_track_origins();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_init();
+
+// Print a warning and maybe return.
+// This function can die based on common_flags()->exitcode.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_warning();
+
+// Print a warning and die.
+// Intrumentation inserts calls to this function when building in "fast" mode
+// (i.e. -mllvm -msan-keep-going)
+SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn))
+void __msan_warning_noreturn();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_1(u8 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_2(u16 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_4(u32 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_8(u64 s, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_1(u8 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_2(u16 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_4(u32 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_8(u64 s, void *p, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison(const void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison_string(const char *s);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_clear_and_unpoison(void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memcpy(void *dst, const void *src, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memset(void *s, int c, uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+void* __msan_memmove(void* dest, const void* src, uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_poison(const void *a, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_poison_stack(void *a, uptr size);
+
+// Copy size bytes from src to dst and unpoison the result.
+// Useful to implement unsafe loads.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_load_unpoisoned(void *src, uptr size, void *dst);
+
+// Returns the offset of the first (at least partially) poisoned byte,
+// or -1 if the whole range is good.
+SANITIZER_INTERFACE_ATTRIBUTE
+sptr __msan_test_shadow(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_check_mem_is_initialized(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_origin(const void *a, uptr size, u32 origin);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_chain_origin(u32 id);
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_get_origin(const void *a);
+
+// Test that this_id is a descendant of prev_id (or they are simply equal).
+// "descendant" here means that are part of the same chain, created with
+// __msan_chain_origin.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id);
+
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_clear_on_return();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_keep_going(int keep_going);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_set_poison_in_malloc(int do_poison);
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+/* OPTIONAL */ const char* __msan_default_options();
+
+// For testing.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_expect_umr(int expect_umr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_print_shadow(const void *x, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_dump_shadow(const void *x, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __msan_has_dynamic_component();
+
+// For testing.
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __msan_get_umr_origin();
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_partial_poison(const void* data, void* shadow, uptr size);
+
+// Tell MSan about newly allocated memory (ex.: custom allocator).
+// Memory will be marked uninitialized, with origin at the call site.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_allocated_memory(const void* data, uptr size);
+
+// Tell MSan about newly destroyed memory. Memory will be marked
+// uninitialized.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_dtor_callback(const void* data, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_death_callback(void (*callback)(void));
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_copy_shadow(void *dst, const void *src, uptr size);
+} // extern "C"
+
+#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/compiler-rt/lib/msan/msan_linux.cc b/compiler-rt/lib/msan/msan_linux.cc
new file mode 100644
index 0000000..ab3be91
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_linux.cc
@@ -0,0 +1,215 @@
+//===-- msan_linux.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Linux- and FreeBSD-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "msan.h"
+#include "msan_thread.h"
+
+#include <elf.h>
+#include <link.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <unwind.h>
+#include <execinfo.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+namespace __msan {
+
+void ReportMapRange(const char *descr, uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ VPrintf(1, "%s : %p - %p\n", descr, beg, end);
+ }
+}
+
+static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!MemoryRangeIsAvailable(beg, end)) {
+ Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
+ if (size > 0) {
+ void *addr = MmapNoAccess(beg, size, name);
+ if (beg == 0 && addr) {
+ // Depending on the kernel configuration, we may not be able to protect
+ // the page at address zero.
+ uptr gap = 16 * GetPageSizeCached();
+ beg += gap;
+ size -= gap;
+ addr = MmapNoAccess(beg, size, name);
+ }
+ if ((uptr)addr != beg) {
+ uptr end = beg + size - 1;
+ Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void CheckMemoryLayoutSanity() {
+ uptr prev_end = 0;
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
+ uptr start = kMemoryLayout[i].start;
+ uptr end = kMemoryLayout[i].end;
+ MappingDesc::Type type = kMemoryLayout[i].type;
+ CHECK_LT(start, end);
+ CHECK_EQ(prev_end, start);
+ CHECK(addr_is_type(start, type));
+ CHECK(addr_is_type((start + end) / 2, type));
+ CHECK(addr_is_type(end - 1, type));
+ if (type == MappingDesc::APP) {
+ uptr addr = start;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+
+ addr = (start + end) / 2;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+
+ addr = end - 1;
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
+ CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
+ }
+ prev_end = end;
+ }
+}
+
+bool InitShadow(bool init_origins) {
+ // Let user know mapping parameters first.
+ VPrintf(1, "__msan_init %p\n", &__msan_init);
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
+ VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
+ kMemoryLayout[i].end - 1);
+
+ CheckMemoryLayoutSanity();
+
+ if (!MEM_IS_APP(&__msan_init)) {
+ Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
+ (uptr)&__msan_init);
+ return false;
+ }
+
+ const uptr maxVirtualAddress = GetMaxVirtualAddress();
+
+ for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
+ uptr start = kMemoryLayout[i].start;
+ uptr end = kMemoryLayout[i].end;
+ uptr size= end - start;
+ MappingDesc::Type type = kMemoryLayout[i].type;
+
+ // Check if the segment should be mapped based on platform constraints.
+ if (start >= maxVirtualAddress)
+ continue;
+
+ bool map = type == MappingDesc::SHADOW ||
+ (init_origins && type == MappingDesc::ORIGIN);
+ bool protect = type == MappingDesc::INVALID ||
+ (!init_origins && type == MappingDesc::ORIGIN);
+ CHECK(!(map && protect));
+ if (!map && !protect)
+ CHECK(type == MappingDesc::APP);
+ if (map) {
+ if (!CheckMemoryRangeAvailability(start, size))
+ return false;
+ if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start)
+ return false;
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(start, size);
+ }
+ if (protect) {
+ if (!CheckMemoryRangeAvailability(start, size))
+ return false;
+ if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void MsanAtExit(void) {
+ if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
+ ReportStats();
+ if (msan_report_count > 0) {
+ ReportAtExitStatistics();
+ if (common_flags()->exitcode)
+ internal__exit(common_flags()->exitcode);
+ }
+}
+
+void InstallAtExitHandler() {
+ atexit(MsanAtExit);
+}
+
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+static THREADLOCAL MsanThread* msan_current_thread;
+
+MsanThread *GetCurrentThread() {
+ return msan_current_thread;
+}
+
+void SetCurrentThread(MsanThread *t) {
+ // Make sure we do not reset the current MsanThread.
+ CHECK_EQ(0, msan_current_thread);
+ msan_current_thread = t;
+ // Make sure that MsanTSDDtor gets called at the end.
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, (void *)t);
+}
+
+void MsanTSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ if (t->destructor_iterations_ > 1) {
+ t->destructor_iterations_--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ msan_current_thread = nullptr;
+ // Make sure that signal handler can not see a stale current thread pointer.
+ atomic_signal_fence(memory_order_seq_cst);
+ MsanThread::TSDDtor(tsd);
+}
+
+} // namespace __msan
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/compiler-rt/lib/msan/msan_new_delete.cc b/compiler-rt/lib/msan/msan_new_delete.cc
new file mode 100644
index 0000000..5401003
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_new_delete.cc
@@ -0,0 +1,58 @@
+//===-- msan_new_delete.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Interceptors for operators new and delete.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "interception/interception.h"
+
+#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+
+#include <stddef.h>
+
+using namespace __msan; // NOLINT
+
+// Fake std::nothrow_t to avoid including <new>.
+namespace std {
+ struct nothrow_t {};
+} // namespace std
+
+
+#define OPERATOR_NEW_BODY \
+ GET_MALLOC_STACK_TRACE; \
+ return MsanReallocate(&stack, 0, size, sizeof(u64), false)
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+ GET_MALLOC_STACK_TRACE; \
+ if (ptr) MsanDeallocate(&stack, ptr)
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY;
+}
+
+#endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
diff --git a/compiler-rt/lib/msan/msan_origin.h b/compiler-rt/lib/msan/msan_origin.h
new file mode 100644
index 0000000..36c168b
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_origin.h
@@ -0,0 +1,169 @@
+//===-- msan_origin.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Origin id utils.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_ORIGIN_H
+#define MSAN_ORIGIN_H
+
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "msan_chained_origin_depot.h"
+
+namespace __msan {
+
+// Origin handling.
+//
+// Origin is a 32-bit identifier that is attached to any uninitialized value in
+// the program and describes, more or less exactly, how this memory came to be
+// uninitialized.
+//
+// There are 3 kinds of origin ids:
+// 1xxx xxxx xxxx xxxx heap origin id
+// 0000 xxxx xxxx xxxx stack origin id
+// 0zzz xxxx xxxx xxxx chained origin id
+//
+// Heap origin id describes a heap memory allocation and contains (in the xxx
+// part) a value of StackDepot.
+//
+// Stack origin id describes a stack memory allocation and contains (in the xxx
+// part) an index into StackOriginDescr and StackOriginPC. We don't store a
+// stack trace for such origins for performance reasons.
+//
+// Chained origin id describes an event of storing an uninitialized value to
+// memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
+// (stack_id, prev_id) -> id, where
+// * stack_id describes the event.
+// StackDepot keeps a mapping between those and corresponding stack traces.
+// * prev_id is another origin id that describes the earlier part of the
+// uninitialized value history.
+// Following a chain of prev_id provides the full recorded history of an
+// uninitialized value.
+//
+// This, effectively, defines a tree (or 2 trees, see below) where nodes are
+// points in value history marked with origin ids, and edges are events that are
+// marked with stack_id.
+//
+// The "zzz" bits of chained origin id are used to store the length (or depth)
+// of the origin chain.
+
+class Origin {
+ public:
+ static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; }
+
+ u32 raw_id() const { return raw_id_; }
+ bool isHeapOrigin() const {
+ // 1xxx xxxx xxxx xxxx
+ return raw_id_ >> kHeapShift == 0;
+ }
+ bool isStackOrigin() const {
+ // 1000 xxxx xxxx xxxx
+ return (raw_id_ >> kDepthShift) == (1 << kDepthBits);
+ }
+ bool isChainedOrigin() const {
+ // 1zzz xxxx xxxx xxxx, zzz != 000
+ return (raw_id_ >> kDepthShift) > (1 << kDepthBits);
+ }
+ u32 getChainedId() const {
+ CHECK(isChainedOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getStackId() const {
+ CHECK(isStackOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getHeapId() const {
+ CHECK(isHeapOrigin());
+ return raw_id_ & kHeapIdMask;
+ }
+
+ // Returns the next origin in the chain and the current stack trace.
+ Origin getNextChainedOrigin(StackTrace *stack) const {
+ CHECK(isChainedOrigin());
+ u32 prev_id;
+ u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id);
+ if (stack) *stack = StackDepotGet(stack_id);
+ return Origin(prev_id);
+ }
+
+ StackTrace getStackTraceForHeapOrigin() const {
+ return StackDepotGet(getHeapId());
+ }
+
+ static Origin CreateStackOrigin(u32 id) {
+ CHECK((id & kStackIdMask) == id);
+ return Origin((1 << kHeapShift) | id);
+ }
+
+ static Origin CreateHeapOrigin(StackTrace *stack) {
+ u32 stack_id = StackDepotPut(*stack);
+ CHECK(stack_id);
+ CHECK((stack_id & kHeapIdMask) == stack_id);
+ return Origin(stack_id);
+ }
+
+ static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) {
+ int depth = prev.isChainedOrigin() ? prev.depth() : 0;
+ // depth is the length of the chain minus 1.
+ // origin_history_size of 0 means unlimited depth.
+ if (flags()->origin_history_size > 0) {
+ if (depth + 1 >= flags()->origin_history_size) {
+ return prev;
+ } else {
+ ++depth;
+ CHECK(depth < (1 << kDepthBits));
+ }
+ }
+
+ StackDepotHandle h = StackDepotPut_WithHandle(*stack);
+ if (!h.valid()) return prev;
+
+ if (flags()->origin_history_per_stack_limit > 0) {
+ int use_count = h.use_count();
+ if (use_count > flags()->origin_history_per_stack_limit) return prev;
+ }
+
+ u32 chained_id;
+ bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id);
+ CHECK((chained_id & kChainedIdMask) == chained_id);
+
+ if (inserted && flags()->origin_history_per_stack_limit > 0)
+ h.inc_use_count_unsafe();
+
+ return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id);
+ }
+
+ static Origin FromRawId(u32 id) {
+ return Origin(id);
+ }
+
+ private:
+ static const int kDepthBits = 3;
+ static const int kDepthShift = 32 - kDepthBits - 1;
+
+ static const int kHeapShift = 31;
+ static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift);
+
+ u32 raw_id_;
+
+ explicit Origin(u32 raw_id) : raw_id_(raw_id) {}
+
+ int depth() const {
+ CHECK(isChainedOrigin());
+ return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1);
+ }
+
+ public:
+ static const int kMaxDepth = (1 << kDepthBits) - 1;
+};
+
+} // namespace __msan
+
+#endif // MSAN_ORIGIN_H
diff --git a/compiler-rt/lib/msan/msan_poisoning.cc b/compiler-rt/lib/msan/msan_poisoning.cc
new file mode 100644
index 0000000..92134f6
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_poisoning.cc
@@ -0,0 +1,174 @@
+//===-- msan_poisoning.cc ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "msan_poisoning.h"
+
+#include "interception/interception.h"
+#include "msan_origin.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
+DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
+DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)
+
+namespace __msan {
+
+u32 GetOriginIfPoisoned(uptr addr, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
+ return 0;
+}
+
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
+ u32 src_origin) {
+ uptr dst_s = MEM_TO_SHADOW(addr);
+ uptr src_s = src_shadow;
+ uptr src_s_end = src_s + size;
+
+ for (; src_s < src_s_end; ++dst_s, ++src_s)
+ if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin;
+}
+
+void CopyOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
+
+ uptr d = (uptr)dst;
+ uptr beg = d & ~3UL;
+ // Copy left unaligned origin if that memory is poisoned.
+ if (beg < d) {
+ u32 o = GetOriginIfPoisoned((uptr)src, d - beg);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(beg) = o;
+ }
+ beg += 4;
+ }
+
+ uptr end = (d + size) & ~3UL;
+ // If both ends fall into the same 4-byte slot, we are done.
+ if (end < beg) return;
+
+ // Copy right unaligned origin if that memory is poisoned.
+ if (end < d + size) {
+ u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(end) = o;
+ }
+ }
+
+ if (beg < end) {
+ // Align src up.
+ uptr s = ((uptr)src + 3) & ~3UL;
+ // FIXME: factor out to msan_copy_origin_aligned
+ if (__msan_get_track_origins() > 1) {
+ u32 *src = (u32 *)MEM_TO_ORIGIN(s);
+ u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
+ u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
+ u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
+ u32 src_o = 0;
+ u32 dst_o = 0;
+ for (; src < src_end; ++src, ++src_s, ++dst) {
+ if (!*src_s) continue;
+ if (*src != src_o) {
+ src_o = *src;
+ dst_o = ChainOrigin(src_o, stack);
+ }
+ *dst = dst_o;
+ }
+ } else {
+ REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+ end - beg);
+ }
+ }
+}
+
+void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst)) return;
+ if (!MEM_IS_APP(src)) return;
+ if (src == dst) return;
+ REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
+}
+
+void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack) {
+ if (!MEM_IS_APP(dst)) return;
+ if (!MEM_IS_APP(src)) return;
+ REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
+}
+
+void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
+ REAL(memcpy)(dst, src, size);
+ CopyShadowAndOrigin(dst, src, size, stack);
+}
+
+void SetShadow(const void *ptr, uptr size, u8 value) {
+ uptr PageSize = GetPageSizeCached();
+ uptr shadow_beg = MEM_TO_SHADOW(ptr);
+ uptr shadow_end = shadow_beg + size;
+ if (value ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_beg = RoundUpTo(shadow_beg, PageSize);
+ uptr page_end = RoundDownTo(shadow_end, PageSize);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ MmapFixedNoReserve(page_beg, page_end - page_beg);
+ }
+ }
+}
+
+void SetOrigin(const void *dst, uptr size, u32 origin) {
+ // Origin mapping is 4 bytes per 4 bytes of application memory.
+ // Here we extend the range such that its left and right bounds are both
+ // 4 byte aligned.
+ uptr x = MEM_TO_ORIGIN((uptr)dst);
+ uptr beg = x & ~3UL; // align down.
+ uptr end = (x + size + 3) & ~3UL; // align up.
+ u64 origin64 = ((u64)origin << 32) | origin;
+ // This is like memset, but the value is 32-bit. We unroll by 2 to write
+ // 64 bits at once. May want to unroll further to get 128-bit stores.
+ if (beg & 7ULL) {
+ *(u32 *)beg = origin;
+ beg += 4;
+ }
+ for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64;
+ if (end & 7ULL) *(u32 *)(end - 4) = origin;
+}
+
+void PoisonMemory(const void *dst, uptr size, StackTrace *stack) {
+ SetShadow(dst, size, (u8)-1);
+
+ if (__msan_get_track_origins()) {
+ Origin o = Origin::CreateHeapOrigin(stack);
+ SetOrigin(dst, size, o.raw_id());
+ }
+}
+
+} // namespace __msan
diff --git a/compiler-rt/lib/msan/msan_poisoning.h b/compiler-rt/lib/msan/msan_poisoning.h
new file mode 100644
index 0000000..edacbee
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_poisoning.h
@@ -0,0 +1,59 @@
+//===-- msan_poisoning.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_POISONING_H
+#define MSAN_POISONING_H
+
+#include "msan.h"
+
+namespace __msan {
+
+// Return origin for the first poisoned byte in the memory range, or 0.
+u32 GetOriginIfPoisoned(uptr addr, uptr size);
+
+// Walk [addr, addr+size) app memory region, copying origin tags from the
+// corresponding positions in [src_origin, src_origin+size) where the
+// corresponding shadow in [src_shadow, src_shadow+size) is non-zero.
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, u32 src_origin);
+
+// Copy origin from src (app address) to dst (app address), creating chained
+// origin ids as necessary, without overriding origin for fully initialized
+// quads.
+void CopyOrigin(const void *dst, const void *src, uptr size, StackTrace *stack);
+
+// memmove() shadow and origin. Dst and src are application addresses.
+// See CopyOrigin() for the origin copying logic.
+void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack);
+
+// memcpy() shadow and origin. Dst and src are application addresses.
+// See CopyOrigin() for the origin copying logic.
+void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
+ StackTrace *stack);
+
+// memcpy() app memory, and do "the right thing" to the corresponding shadow and
+// origin regions.
+void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack);
+
+// Fill shadow will value. Ptr is an application address.
+void SetShadow(const void *ptr, uptr size, u8 value);
+
+// Set origin for the memory region.
+void SetOrigin(const void *dst, uptr size, u32 origin);
+
+// Mark memory region uninitialized, with origins.
+void PoisonMemory(const void *dst, uptr size, StackTrace *stack);
+
+} // namespace __msan
+
+#endif // MSAN_POISONING_H
diff --git a/compiler-rt/lib/msan/msan_report.cc b/compiler-rt/lib/msan/msan_report.cc
new file mode 100644
index 0000000..ddb8070
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_report.cc
@@ -0,0 +1,277 @@
+//===-- msan_report.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+using namespace __sanitizer;
+
+namespace __msan {
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() { }
+ const char *Warning() { return Red(); }
+ const char *Origin() { return Magenta(); }
+ const char *Name() { return Green(); }
+ const char *End() { return Default(); }
+};
+
+static void DescribeStackOrigin(const char *so, uptr pc) {
+ Decorator d;
+ char *s = internal_strdup(so);
+ char *sep = internal_strchr(s, '@');
+ CHECK(sep);
+ *sep = '\0';
+ Printf("%s", d.Origin());
+ Printf(
+ " %sUninitialized value was created by an allocation of '%s%s%s'"
+ " in the stack frame of function '%s%s%s'%s\n",
+ d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+ d.End());
+ InternalFree(s);
+
+ if (pc) {
+ // For some reason function address in LLVM IR is 1 less then the address
+ // of the first instruction.
+ pc = StackTrace::GetNextInstructionPc(pc);
+ StackTrace(&pc, 1).Print();
+ }
+}
+
+static void DescribeOrigin(u32 id) {
+ VPrintf(1, " raw origin id: %d\n", id);
+ Decorator d;
+ Origin o = Origin::FromRawId(id);
+ while (o.isChainedOrigin()) {
+ StackTrace stack;
+ o = o.getNextChainedOrigin(&stack);
+ Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),
+ d.End());
+ stack.Print();
+ }
+ if (o.isStackOrigin()) {
+ uptr pc;
+ const char *so = GetStackOriginDescr(o.getStackId(), &pc);
+ DescribeStackOrigin(so, pc);
+ } else {
+ StackTrace stack = o.getStackTraceForHeapOrigin();
+ switch (stack.tag) {
+ case StackTrace::TAG_ALLOC:
+ Printf(" %sUninitialized value was created by a heap allocation%s\n",
+ d.Origin(), d.End());
+ break;
+ case StackTrace::TAG_DEALLOC:
+ Printf(" %sUninitialized value was created by a heap deallocation%s\n",
+ d.Origin(), d.End());
+ break;
+ case STACK_TRACE_TAG_POISON:
+ Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(),
+ d.End());
+ break;
+ default:
+ Printf(" %sUninitialized value was created%s\n", d.Origin(), d.End());
+ break;
+ }
+ stack.Print();
+ }
+}
+
+void ReportUMR(StackTrace *stack, u32 origin) {
+ if (!__msan::flags()->report_umrs) return;
+
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
+ Printf("%s", d.End());
+ stack->Print();
+ if (origin) {
+ DescribeOrigin(origin);
+ }
+ ReportErrorSummary("use-of-uninitialized-value", stack);
+}
+
+void ReportExpectedUMRNotFound(StackTrace *stack) {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ Printf("WARNING: Expected use of uninitialized value not found\n");
+ stack->Print();
+}
+
+void ReportStats() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (__msan_get_track_origins() > 0) {
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ // FIXME: we want this at normal exit, too!
+ // FIXME: but only with verbosity=1 or something
+ Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
+ Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
+
+ StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
+ Printf("Unique origin histories: %zu\n",
+ chained_origin_depot_stats->n_uniq_ids);
+ Printf("History depot allocated bytes: %zu\n",
+ chained_origin_depot_stats->allocated);
+ }
+}
+
+void ReportAtExitStatistics() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (msan_report_count > 0) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("%s", d.End());
+ }
+}
+
+class OriginSet {
+ public:
+ OriginSet() : next_id_(0) {}
+ int insert(u32 o) {
+ // Scan from the end for better locality.
+ for (int i = next_id_ - 1; i >= 0; --i)
+ if (origins_[i] == o) return i;
+ if (next_id_ == kMaxSize_) return OVERFLOW;
+ int id = next_id_++;
+ origins_[id] = o;
+ return id;
+ }
+ int size() { return next_id_; }
+ u32 get(int id) { return origins_[id]; }
+ static char asChar(int id) {
+ switch (id) {
+ case MISSING:
+ return '.';
+ case OVERFLOW:
+ return '*';
+ default:
+ return 'A' + id;
+ }
+ }
+ static const int OVERFLOW = -1;
+ static const int MISSING = -2;
+
+ private:
+ static const int kMaxSize_ = 'Z' - 'A' + 1;
+ u32 origins_[kMaxSize_];
+ int next_id_;
+};
+
+void DescribeMemoryRange(const void *x, uptr size) {
+ // Real limits.
+ uptr start = MEM_TO_SHADOW(x);
+ uptr end = start + size;
+ // Scan limits: align start down to 4; align size up to 16.
+ uptr s = start & ~3UL;
+ size = end - s;
+ size = (size + 15) & ~15UL;
+ uptr e = s + size;
+
+ // Single letter names to origin id mapping.
+ OriginSet origin_set;
+
+ uptr pos = 0; // Offset from aligned start.
+ bool with_origins = __msan_get_track_origins();
+ // True if there is at least 1 poisoned bit in the last 4-byte group.
+ bool last_quad_poisoned;
+ int origin_ids[4]; // Single letter origin ids for the current line.
+
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
+ Printf("%s", d.End());
+ while (s < e) {
+ // Line start.
+ if (pos % 16 == 0) {
+ for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
+ Printf("%p:", s);
+ }
+ // Group start.
+ if (pos % 4 == 0) {
+ Printf(" ");
+ last_quad_poisoned = false;
+ }
+ // Print shadow byte.
+ if (s < start || s >= end) {
+ Printf("..");
+ } else {
+ unsigned char v = *(unsigned char *)s;
+ if (v) last_quad_poisoned = true;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x", v & 0xf, v >> 4);
+#else
+ Printf("%x%x", v >> 4, v & 0xf);
+#endif
+ }
+ // Group end.
+ if (pos % 4 == 3 && with_origins) {
+ int id = OriginSet::MISSING;
+ if (last_quad_poisoned) {
+ u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
+ id = origin_set.insert(o);
+ }
+ origin_ids[(pos % 16) / 4] = id;
+ }
+ // Line end.
+ if (pos % 16 == 15) {
+ if (with_origins) {
+ Printf(" |");
+ for (int i = 0; i < 4; ++i) {
+ char c = OriginSet::asChar(origin_ids[i]);
+ Printf("%c", c);
+ if (i != 3) Printf(" ");
+ }
+ Printf("|");
+ }
+ Printf("\n");
+ }
+ size--;
+ s++;
+ pos++;
+ }
+
+ Printf("\n");
+
+ for (int i = 0; i < origin_set.size(); ++i) {
+ u32 o = origin_set.get(i);
+ Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
+ DescribeOrigin(o);
+ }
+}
+
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
+ d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
+ d.End());
+ if (__sanitizer::Verbosity())
+ DescribeMemoryRange(start, size);
+}
+
+} // namespace __msan
diff --git a/compiler-rt/lib/msan/msan_thread.cc b/compiler-rt/lib/msan/msan_thread.cc
new file mode 100644
index 0000000..0ba4993
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_thread.cc
@@ -0,0 +1,82 @@
+
+#include "msan.h"
+#include "msan_thread.h"
+#include "msan_interface_internal.h"
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __msan {
+
+MsanThread *MsanThread::Create(thread_callback_t start_routine,
+ void *arg) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(MsanThread), PageSize);
+ MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ thread->destructor_iterations_ = GetPthreadDestructorIterations();
+
+ return thread;
+}
+
+void MsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ uptr stack_size = 0;
+ GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size,
+ &tls_begin_, &tls_size);
+ stack_top_ = stack_bottom_ + stack_size;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void MsanThread::ClearShadowForThreadStackAndTLS() {
+ __msan_unpoison((void *)stack_bottom_, stack_top_ - stack_bottom_);
+ if (tls_begin_ != tls_end_)
+ __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_);
+ DTLS *dtls = DTLS_Get();
+ CHECK_NE(dtls, 0);
+ for (uptr i = 0; i < dtls->dtv_size; ++i)
+ __msan_unpoison((void *)(dtls->dtv[i].beg), dtls->dtv[i].size);
+}
+
+void MsanThread::Init() {
+ SetThreadStackAndTls();
+ CHECK(MEM_IS_APP(stack_bottom_));
+ CHECK(MEM_IS_APP(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+}
+
+void MsanThread::TSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ t->Destroy();
+}
+
+void MsanThread::Destroy() {
+ malloc_storage().CommitBack();
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+thread_return_t MsanThread::ThreadStart() {
+ Init();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ return res;
+}
+
+} // namespace __msan
diff --git a/compiler-rt/lib/msan/msan_thread.h b/compiler-rt/lib/msan/msan_thread.h
new file mode 100644
index 0000000..ed22e67
--- /dev/null
+++ b/compiler-rt/lib/msan/msan_thread.h
@@ -0,0 +1,71 @@
+//===-- msan_thread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_THREAD_H
+#define MSAN_THREAD_H
+
+#include "msan_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+class MsanThread {
+ public:
+ static MsanThread *Create(thread_callback_t start_routine, void *arg);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart();
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ bool IsMainThread() { return start_routine_ == nullptr; }
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ bool InSignalHandler() { return in_signal_handler_; }
+ void EnterSignalHandler() { in_signal_handler_++; }
+ void LeaveSignalHandler() { in_signal_handler_--; }
+
+ MsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+
+ int destructor_iterations_;
+
+ private:
+ // NOTE: There is no MsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ unsigned in_signal_handler_;
+
+ MsanThreadLocalMallocStorage malloc_storage_;
+};
+
+MsanThread *GetCurrentThread();
+void SetCurrentThread(MsanThread *t);
+
+} // namespace __msan
+
+#endif // MSAN_THREAD_H
diff --git a/compiler-rt/lib/msan/tests/CMakeLists.txt b/compiler-rt/lib/msan/tests/CMakeLists.txt
new file mode 100644
index 0000000..087b1af
--- /dev/null
+++ b/compiler-rt/lib/msan/tests/CMakeLists.txt
@@ -0,0 +1,144 @@
+include(CheckCXXCompilerFlag)
+include(CompilerRTCompile)
+include(CompilerRTLink)
+
+include_directories(..)
+include_directories(../..)
+
+set(MSAN_LIBCXX_CFLAGS
+ -fsanitize=memory
+ -fsanitize-memory-track-origins
+ -Wno-pedantic)
+
+# Unittest sources and build flags.
+set(MSAN_UNITTEST_SOURCES msan_test.cc msan_test_main.cc)
+set(MSAN_LOADABLE_SOURCE msan_loadable.cc)
+set(MSAN_UNITTEST_HEADERS
+ msan_test_config.h
+ ../../../include/sanitizer/msan_interface.h
+)
+set(MSAN_UNITTEST_COMMON_CFLAGS
+ -nostdinc++
+ -isystem ${COMPILER_RT_LIBCXX_PATH}/include
+ ${COMPILER_RT_TEST_CFLAGS}
+ ${COMPILER_RT_GTEST_CFLAGS}
+ -I${COMPILER_RT_SOURCE_DIR}/include
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${COMPILER_RT_SOURCE_DIR}/lib/msan
+ -g
+ -O2
+ -fno-exceptions
+ -fno-omit-frame-pointer
+ -mno-omit-leaf-frame-pointer
+ -Wno-deprecated-declarations
+ -Wno-unused-variable
+ -Wno-zero-length-array
+ -Wno-uninitialized
+ -Werror=sign-compare
+)
+set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
+ ${MSAN_UNITTEST_COMMON_CFLAGS}
+ -fsanitize=memory
+ -fsanitize-memory-track-origins
+ -mllvm -msan-keep-going=1
+)
+set(MSAN_UNITTEST_LINK_FLAGS
+ -fsanitize=memory
+ # Don't need -stdlib=libc++ because we explicitly list libc++.so in the linker
+ # inputs.
+ # FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
+ -lstdc++
+)
+
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
+
+# Compile source for the given architecture, using compiler
+# options in ${ARGN}, and add it to the object list.
+macro(msan_compile obj_list source arch kind)
+ get_filename_component(basename ${source} NAME)
+ set(output_obj "${basename}.${arch}${kind}.o")
+ get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${MSAN_UNITTEST_HEADERS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest msan)
+ endif()
+ clang_compile(${output_obj} ${source}
+ CFLAGS ${ARGN} ${TARGET_CFLAGS}
+ DEPS ${COMPILE_DEPS})
+ list(APPEND ${obj_list} ${output_obj})
+endmacro()
+
+macro(msan_link_shared so_list so_name arch kind)
+ cmake_parse_arguments(SOURCE "" "" "OBJECTS;LINKFLAGS;DEPS" ${ARGN})
+ set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}${kind}.so")
+ get_target_flags_for_arch(${arch} TARGET_LINKFLAGS)
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SOURCE_DEPS msan)
+ endif()
+ clang_link_shared(${output_so}
+ OBJECTS ${SOURCE_OBJECTS}
+ LINKFLAGS ${TARGET_LINKFLAGS} ${SOURCE_LINKFLAGS}
+ DEPS ${SOURCE_DEPS})
+ list(APPEND ${so_list} ${output_so})
+endmacro()
+
+# Main MemorySanitizer unit tests.
+add_custom_target(MsanUnitTests)
+set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests")
+
+# Adds MSan unit tests and benchmarks for architecture.
+macro(add_msan_tests_for_arch arch kind)
+ # Build gtest instrumented with MSan.
+ set(MSAN_INST_GTEST)
+ msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
+
+ # Instrumented tests.
+ set(MSAN_INST_TEST_OBJECTS)
+ foreach (SOURCE ${MSAN_UNITTEST_SOURCES})
+ msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
+ endforeach(SOURCE)
+
+ # Instrumented loadable module objects.
+ set(MSAN_INST_LOADABLE_OBJECTS)
+ msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} "-fPIC" ${ARGN})
+
+ # Instrumented loadable library tests.
+ set(MSAN_LOADABLE_SO)
+ msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch} "${kind}"
+ OBJECTS ${MSAN_INST_LOADABLE_OBJECTS}
+ DEPS ${MSAN_INST_LOADABLE_OBJECTS})
+
+ set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST})
+ set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}
+ ${MSAN_LOADABLE_SO})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND MSAN_TEST_DEPS msan)
+ endif()
+ get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ add_compiler_rt_test(MsanUnitTests "Msan-${arch}${kind}-Test" ${arch}
+ OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
+ DEPS ${MSAN_TEST_DEPS}
+ LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
+ ${TARGET_LINK_FLAGS}
+ "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
+ "-Wl,-rpath=${LIBCXX_PREFIX}/lib")
+endmacro()
+
+# We should only build MSan unit tests if we can build instrumented libcxx.
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
+ foreach(arch ${MSAN_SUPPORTED_ARCH})
+ get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch})
+ add_custom_libcxx(libcxx_msan_${arch} ${LIBCXX_PREFIX}
+ DEPS ${MSAN_RUNTIME_LIBRARIES}
+ CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS})
+ set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
+
+ add_msan_tests_for_arch(${arch} "")
+ add_msan_tests_for_arch(${arch} "-with-call"
+ -mllvm -msan-instrumentation-with-call-threshold=0)
+ endforeach()
+endif()
diff --git a/compiler-rt/lib/msan/tests/msan_loadable.cc b/compiler-rt/lib/msan/tests/msan_loadable.cc
new file mode 100644
index 0000000..06e880f
--- /dev/null
+++ b/compiler-rt/lib/msan/tests/msan_loadable.cc
@@ -0,0 +1,27 @@
+//===-- msan_loadable.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#include "msan/msan_interface_internal.h"
+#include <stdlib.h>
+
+static void *dso_global;
+
+// No name mangling.
+extern "C" {
+
+void **get_dso_global() {
+ return &dso_global;
+}
+
+}
diff --git a/compiler-rt/lib/msan/tests/msan_test.cc b/compiler-rt/lib/msan/tests/msan_test.cc
new file mode 100644
index 0000000..b7162b3
--- /dev/null
+++ b/compiler-rt/lib/msan/tests/msan_test.cc
@@ -0,0 +1,4307 @@
+//===-- msan_test.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
+#include "sanitizer_common/tests/sanitizer_test_utils.h"
+
+#include "sanitizer/allocator_interface.h"
+#include "sanitizer/msan_interface.h"
+
+#if defined(__FreeBSD__)
+# define _KERNEL // To declare 'shminfo' structure.
+# include <sys/shm.h>
+# undef _KERNEL
+extern "C" {
+// <sys/shm.h> doesn't declare these functions in _KERNEL mode.
+void *shmat(int, const void *, int);
+int shmget(key_t, size_t, int);
+int shmctl(int, int, struct shmid_ds *);
+int shmdt(const void *);
+}
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <math.h>
+
+#include <arpa/inet.h>
+#include <dlfcn.h>
+#include <grp.h>
+#include <unistd.h>
+#include <link.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/statvfs.h>
+#include <sys/utsname.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <wordexp.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#if !defined(__FreeBSD__)
+# include <malloc.h>
+# include <sys/sysinfo.h>
+# include <sys/vfs.h>
+# include <mntent.h>
+# include <netinet/ether.h>
+#else
+# include <signal.h>
+# include <netinet/in.h>
+# include <pthread_np.h>
+# include <sys/uio.h>
+# include <sys/mount.h>
+# include <sys/sysctl.h>
+# include <net/ethernet.h>
+# define f_namelen f_namemax // FreeBSD names this statfs field so.
+# define cpu_set_t cpuset_t
+extern "C" {
+// FreeBSD's <ssp/string.h> defines mempcpy() to be a macro expanding into
+// a __builtin___mempcpy_chk() call, but since Msan RTL defines it as an
+// ordinary function, we can declare it here to complete the tests.
+void *mempcpy(void *dest, const void *src, size_t n);
+}
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+# include <emmintrin.h>
+# define MSAN_HAS_M128 1
+#else
+# define MSAN_HAS_M128 0
+#endif
+
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+
+// On FreeBSD procfs is not enabled by default.
+#if defined(__FreeBSD__)
+# define FILE_TO_READ "/bin/cat"
+# define DIR_TO_READ "/bin"
+# define SUBFILE_TO_READ "cat"
+# define SYMLINK_TO_READ "/usr/bin/tar"
+# define SUPERUSER_GROUP "wheel"
+#else
+# define FILE_TO_READ "/proc/self/stat"
+# define DIR_TO_READ "/proc/self"
+# define SUBFILE_TO_READ "stat"
+# define SYMLINK_TO_READ "/proc/self/exe"
+# define SUPERUSER_GROUP "root"
+#endif
+
+const size_t kPageSize = 4096;
+const size_t kMaxPathLength = 4096;
+
+typedef unsigned char U1;
+typedef unsigned short U2; // NOLINT
+typedef unsigned int U4;
+typedef unsigned long long U8; // NOLINT
+typedef signed char S1;
+typedef signed short S2; // NOLINT
+typedef signed int S4;
+typedef signed long long S8; // NOLINT
+#define NOINLINE __attribute__((noinline))
+#define INLINE __attribute__((always_inline))
+
+static bool TrackingOrigins() {
+ S8 x;
+ __msan_set_origin(&x, sizeof(x), 0x1234);
+ U4 origin = __msan_get_origin(&x);
+ __msan_set_origin(&x, sizeof(x), 0);
+ return __msan_origin_is_descendant_or_same(origin, 0x1234);
+}
+
+#define EXPECT_ORIGIN(expected, origin) \
+ EXPECT_TRUE(__msan_origin_is_descendant_or_same((origin), (expected)))
+
+#define EXPECT_UMR(action) \
+ do { \
+ __msan_set_expect_umr(1); \
+ action; \
+ __msan_set_expect_umr(0); \
+ } while (0)
+
+#define EXPECT_UMR_O(action, origin) \
+ do { \
+ __msan_set_expect_umr(1); \
+ action; \
+ __msan_set_expect_umr(0); \
+ if (TrackingOrigins()) EXPECT_ORIGIN(origin, __msan_get_umr_origin()); \
+ } while (0)
+
+#define EXPECT_POISONED(x) ExpectPoisoned(x)
+
+template<typename T>
+void ExpectPoisoned(const T& t) {
+ EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
+}
+
+#define EXPECT_POISONED_O(x, origin) \
+ ExpectPoisonedWithOrigin(x, origin)
+
+template<typename T>
+void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
+ EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
+ if (TrackingOrigins()) EXPECT_ORIGIN(origin, __msan_get_origin((void *)&t));
+}
+
+#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x)))
+
+template<typename T>
+bool TestForNotPoisoned(const T& t) {
+ return __msan_test_shadow((void*)&t, sizeof(t)) == -1;
+}
+
+static U8 poisoned_array[100];
+template<class T>
+T *GetPoisoned(int i = 0, T val = 0) {
+ T *res = (T*)&poisoned_array[i];
+ *res = val;
+ __msan_poison(&poisoned_array[i], sizeof(T));
+ return res;
+}
+
+template<class T>
+T *GetPoisonedO(int i, U4 origin, T val = 0) {
+ T *res = (T*)&poisoned_array[i];
+ *res = val;
+ __msan_poison(&poisoned_array[i], sizeof(T));
+ __msan_set_origin(&poisoned_array[i], sizeof(T), origin);
+ return res;
+}
+
+template<typename T>
+T Poisoned(T v = 0, T s = (T)(-1)) {
+ __msan_partial_poison(&v, &s, sizeof(T));
+ return v;
+}
+
+template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); }
+
+static volatile int g_one = 1;
+static volatile int g_zero = 0;
+static volatile int g_0 = 0;
+static volatile int g_1 = 1;
+
+S4 a_s4[100];
+S8 a_s8[100];
+
+// Check that malloc poisons memory.
+// A lot of tests below depend on this.
+TEST(MemorySanitizerSanity, PoisonInMalloc) {
+ int *x = (int*)malloc(sizeof(int));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, NegativeTest1) {
+ S4 *x = GetPoisoned<S4>();
+ if (g_one)
+ *x = 0;
+ EXPECT_NOT_POISONED(*x);
+}
+
+TEST(MemorySanitizer, PositiveTest1) {
+ // Load to store.
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+
+ // S->S conversions.
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S1>());
+ EXPECT_POISONED(*GetPoisoned<S1>());
+
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+ EXPECT_POISONED(*GetPoisoned<S2>());
+
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+ EXPECT_POISONED(*GetPoisoned<S4>());
+
+ EXPECT_POISONED(*GetPoisoned<S8>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+ EXPECT_POISONED(*GetPoisoned<S8>());
+
+ // ZExt
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U1>());
+ EXPECT_POISONED(*GetPoisoned<U2>());
+ EXPECT_POISONED(*GetPoisoned<U2>());
+ EXPECT_POISONED(*GetPoisoned<U4>());
+
+ // Unary ops.
+ EXPECT_POISONED(- *GetPoisoned<S4>());
+
+ EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1));
+
+
+ a_s4[g_zero] = 1 - *GetPoisoned<S4>();
+ a_s4[g_zero] = 1 + *GetPoisoned<S4>();
+}
+
+TEST(MemorySanitizer, Phi1) {
+ S4 c;
+ if (g_one) {
+ c = *GetPoisoned<S4>();
+ } else {
+ break_optimization(0);
+ c = 0;
+ }
+ EXPECT_POISONED(c);
+}
+
+TEST(MemorySanitizer, Phi2) {
+ S4 i = *GetPoisoned<S4>();
+ S4 n = g_one;
+ EXPECT_UMR(for (; i < g_one; i++););
+ EXPECT_POISONED(i);
+}
+
+NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(a1); }
+NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(a2); }
+NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(a3); }
+
+TEST(MemorySanitizer, ArgTest) {
+ Arg1ExpectUMR(*GetPoisoned<S4>());
+ Arg2ExpectUMR(0, *GetPoisoned<S4>());
+ Arg3ExpectUMR(0, 1, *GetPoisoned<S8>());
+}
+
+
+TEST(MemorySanitizer, CallAndRet) {
+ ReturnPoisoned<S1>();
+ ReturnPoisoned<S2>();
+ ReturnPoisoned<S4>();
+ ReturnPoisoned<S8>();
+
+ EXPECT_POISONED(ReturnPoisoned<S1>());
+ EXPECT_POISONED(ReturnPoisoned<S2>());
+ EXPECT_POISONED(ReturnPoisoned<S4>());
+ EXPECT_POISONED(ReturnPoisoned<S8>());
+}
+
+// malloc() in the following test may be optimized to produce a compile-time
+// undef value. Check that we trap on the volatile assignment anyway.
+TEST(MemorySanitizer, DISABLED_MallocNoIdent) {
+ S4 *x = (int*)malloc(sizeof(S4));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, Malloc) {
+ S4 *x = (int*)Ident(malloc(sizeof(S4)));
+ EXPECT_POISONED(*x);
+ free(x);
+}
+
+TEST(MemorySanitizer, Realloc) {
+ S4 *x = (int*)Ident(realloc(0, sizeof(S4)));
+ EXPECT_POISONED(x[0]);
+ x[0] = 1;
+ x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[1]);
+ x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[2]);
+ EXPECT_POISONED(x[1]);
+ x[2] = 1; // Init this here. Check that after realloc it is poisoned again.
+ x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
+ EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
+ EXPECT_POISONED(x[1]);
+ x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
+ EXPECT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ free(x);
+}
+
+TEST(MemorySanitizer, Calloc) {
+ S4 *x = (int*)Ident(calloc(1, sizeof(S4)));
+ EXPECT_NOT_POISONED(*x); // Should not be poisoned.
+ EXPECT_EQ(0, *x);
+ free(x);
+}
+
+TEST(MemorySanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ }
+ }
+}
+
+TEST(MemorySanitizer, AndOr) {
+ U4 *p = GetPoisoned<U4>();
+ // We poison two bytes in the midle of a 4-byte word to make the test
+ // correct regardless of endianness.
+ ((U1*)p)[1] = 0;
+ ((U1*)p)[2] = 0xff;
+ EXPECT_NOT_POISONED(*p & 0x00ffff00);
+ EXPECT_NOT_POISONED(*p & 0x00ff0000);
+ EXPECT_NOT_POISONED(*p & 0x0000ff00);
+ EXPECT_POISONED(*p & 0xff000000);
+ EXPECT_POISONED(*p & 0x000000ff);
+ EXPECT_POISONED(*p & 0x0000ffff);
+ EXPECT_POISONED(*p & 0xffff0000);
+
+ EXPECT_NOT_POISONED(*p | 0xff0000ff);
+ EXPECT_NOT_POISONED(*p | 0xff00ffff);
+ EXPECT_NOT_POISONED(*p | 0xffff00ff);
+ EXPECT_POISONED(*p | 0xff000000);
+ EXPECT_POISONED(*p | 0x000000ff);
+ EXPECT_POISONED(*p | 0x0000ffff);
+ EXPECT_POISONED(*p | 0xffff0000);
+
+ EXPECT_POISONED(*GetPoisoned<bool>() & *GetPoisoned<bool>());
+}
+
+template<class T>
+static bool applyNot(T value, T shadow) {
+ __msan_partial_poison(&value, &shadow, sizeof(T));
+ return !value;
+}
+
+TEST(MemorySanitizer, Not) {
+ EXPECT_NOT_POISONED(applyNot<U4>(0x0, 0x0));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFFFFFFFF, 0x0));
+ EXPECT_POISONED(applyNot<U4>(0xFFFFFFFF, 0xFFFFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0FFFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00FFFFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0000FFFF));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00000000));
+ EXPECT_POISONED(applyNot<U4>(0xFF000000, 0xFF000000));
+ EXPECT_NOT_POISONED(applyNot<U4>(0xFF800000, 0xFF000000));
+ EXPECT_POISONED(applyNot<U4>(0x00008000, 0x00008000));
+
+ EXPECT_NOT_POISONED(applyNot<U1>(0x0, 0x0));
+ EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0xFE));
+ EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0x0));
+ EXPECT_POISONED(applyNot<U1>(0xFF, 0xFF));
+
+ EXPECT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-1)));
+ EXPECT_NOT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-2)));
+}
+
+TEST(MemorySanitizer, Shift) {
+ U4 *up = GetPoisoned<U4>();
+ ((U1*)up)[0] = 0;
+ ((U1*)up)[3] = 0xff;
+ EXPECT_NOT_POISONED(*up >> 30);
+ EXPECT_NOT_POISONED(*up >> 24);
+ EXPECT_POISONED(*up >> 23);
+ EXPECT_POISONED(*up >> 10);
+
+ EXPECT_NOT_POISONED(*up << 30);
+ EXPECT_NOT_POISONED(*up << 24);
+ EXPECT_POISONED(*up << 23);
+ EXPECT_POISONED(*up << 10);
+
+ S4 *sp = (S4*)up;
+ EXPECT_NOT_POISONED(*sp >> 30);
+ EXPECT_NOT_POISONED(*sp >> 24);
+ EXPECT_POISONED(*sp >> 23);
+ EXPECT_POISONED(*sp >> 10);
+
+ sp = GetPoisoned<S4>();
+ ((S1*)sp)[1] = 0;
+ ((S1*)sp)[2] = 0;
+ EXPECT_POISONED(*sp >> 31);
+
+ EXPECT_POISONED(100 >> *GetPoisoned<S4>());
+ EXPECT_POISONED(100U >> *GetPoisoned<S4>());
+}
+
+NOINLINE static int GetPoisonedZero() {
+ int *zero = new int;
+ *zero = 0;
+ __msan_poison(zero, sizeof(*zero));
+ int res = *zero;
+ delete zero;
+ return res;
+}
+
+TEST(MemorySanitizer, LoadFromDirtyAddress) {
+ int *a = new int;
+ *a = 0;
+ EXPECT_UMR(break_optimization((void*)(U8)a[GetPoisonedZero()]));
+ delete a;
+}
+
+TEST(MemorySanitizer, StoreToDirtyAddress) {
+ int *a = new int;
+ EXPECT_UMR(a[GetPoisonedZero()] = 0);
+ break_optimization(a);
+ delete a;
+}
+
+
+NOINLINE void StackTestFunc() {
+ S4 p4;
+ S4 ok4 = 1;
+ S2 p2;
+ S2 ok2 = 1;
+ S1 p1;
+ S1 ok1 = 1;
+ break_optimization(&p4);
+ break_optimization(&ok4);
+ break_optimization(&p2);
+ break_optimization(&ok2);
+ break_optimization(&p1);
+ break_optimization(&ok1);
+
+ EXPECT_POISONED(p4);
+ EXPECT_POISONED(p2);
+ EXPECT_POISONED(p1);
+ EXPECT_NOT_POISONED(ok1);
+ EXPECT_NOT_POISONED(ok2);
+ EXPECT_NOT_POISONED(ok4);
+}
+
+TEST(MemorySanitizer, StackTest) {
+ StackTestFunc();
+}
+
+NOINLINE void StackStressFunc() {
+ int foo[10000];
+ break_optimization(foo);
+}
+
+TEST(MemorySanitizer, DISABLED_StackStressTest) {
+ for (int i = 0; i < 1000000; i++)
+ StackStressFunc();
+}
+
+template<class T>
+void TestFloatingPoint() {
+ static volatile T v;
+ static T g[100];
+ break_optimization(&g);
+ T *x = GetPoisoned<T>();
+ T *y = GetPoisoned<T>(1);
+ EXPECT_POISONED(*x);
+ EXPECT_POISONED((long long)*x);
+ EXPECT_POISONED((int)*x);
+ g[0] = *x;
+ g[1] = *x + *y;
+ g[2] = *x - *y;
+ g[3] = *x * *y;
+}
+
+TEST(MemorySanitizer, FloatingPointTest) {
+ TestFloatingPoint<float>();
+ TestFloatingPoint<double>();
+}
+
+TEST(MemorySanitizer, DynMem) {
+ S4 x = 0;
+ S4 *y = GetPoisoned<S4>();
+ memcpy(y, &x, g_one * sizeof(S4));
+ EXPECT_NOT_POISONED(*y);
+}
+
+static char *DynRetTestStr;
+
+TEST(MemorySanitizer, DynRet) {
+ ReturnPoisoned<S8>();
+ EXPECT_NOT_POISONED(atoi("0"));
+}
+
+TEST(MemorySanitizer, DynRet1) {
+ ReturnPoisoned<S8>();
+}
+
+struct LargeStruct {
+ S4 x[10];
+};
+
+NOINLINE
+LargeStruct LargeRetTest() {
+ LargeStruct res;
+ res.x[0] = *GetPoisoned<S4>();
+ res.x[1] = *GetPoisoned<S4>();
+ res.x[2] = *GetPoisoned<S4>();
+ res.x[3] = *GetPoisoned<S4>();
+ res.x[4] = *GetPoisoned<S4>();
+ res.x[5] = *GetPoisoned<S4>();
+ res.x[6] = *GetPoisoned<S4>();
+ res.x[7] = *GetPoisoned<S4>();
+ res.x[8] = *GetPoisoned<S4>();
+ res.x[9] = *GetPoisoned<S4>();
+ return res;
+}
+
+TEST(MemorySanitizer, strcmp) {
+ char s1[10];
+ char s2[10];
+ strncpy(s1, "foo", 10);
+ s2[0] = 'f';
+ s2[1] = 'n';
+ EXPECT_GT(strcmp(s1, s2), 0);
+ s2[1] = 'o';
+ int res;
+ EXPECT_UMR(res = strcmp(s1, s2));
+ EXPECT_NOT_POISONED(res);
+ EXPECT_EQ(strncmp(s1, s2, 1), 0);
+}
+
+TEST(MemorySanitizer, LargeRet) {
+ LargeStruct a = LargeRetTest();
+ EXPECT_POISONED(a.x[0]);
+ EXPECT_POISONED(a.x[9]);
+}
+
+TEST(MemorySanitizer, strerror) {
+ char *buf = strerror(EINVAL);
+ EXPECT_NOT_POISONED(strlen(buf));
+ buf = strerror(123456);
+ EXPECT_NOT_POISONED(strlen(buf));
+}
+
+TEST(MemorySanitizer, strerror_r) {
+ errno = 0;
+ char buf[1000];
+ char *res = (char*) (size_t) strerror_r(EINVAL, buf, sizeof(buf));
+ ASSERT_EQ(0, errno);
+ if (!res) res = buf; // POSIX version success.
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
+TEST(MemorySanitizer, fread) {
+ char *x = new char[32];
+ FILE *f = fopen(FILE_TO_READ, "r");
+ ASSERT_TRUE(f != NULL);
+ fread(x, 1, 32, f);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ fclose(f);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, read) {
+ char *x = new char[32];
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = read(fd, x, 32);
+ ASSERT_EQ(sz, 32);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ close(fd);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, pread) {
+ char *x = new char[32];
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = pread(fd, x, 32, 0);
+ ASSERT_EQ(sz, 32);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[16]);
+ EXPECT_NOT_POISONED(x[31]);
+ close(fd);
+ delete[] x;
+}
+
+TEST(MemorySanitizer, readv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = readv(fd, iov, 2);
+ ASSERT_GE(sz, 0);
+ ASSERT_LE(sz, 5 + 2000);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
+TEST(MemorySanitizer, preadv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open(FILE_TO_READ, O_RDONLY);
+ ASSERT_GT(fd, 0);
+ int sz = preadv(fd, iov, 2, 3);
+ ASSERT_GE(sz, 0);
+ ASSERT_LE(sz, 5 + 2000);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
+// FIXME: fails now.
+TEST(MemorySanitizer, DISABLED_ioctl) {
+ struct winsize ws;
+ EXPECT_EQ(ioctl(2, TIOCGWINSZ, &ws), 0);
+ EXPECT_NOT_POISONED(ws.ws_col);
+}
+
+TEST(MemorySanitizer, readlink) {
+ char *x = new char[1000];
+ readlink(SYMLINK_TO_READ, x, 1000);
+ EXPECT_NOT_POISONED(x[0]);
+ delete [] x;
+}
+
+TEST(MemorySanitizer, stat) {
+ struct stat* st = new struct stat;
+ int res = stat(FILE_TO_READ, st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st->st_dev);
+ EXPECT_NOT_POISONED(st->st_mode);
+ EXPECT_NOT_POISONED(st->st_size);
+}
+
+TEST(MemorySanitizer, fstatat) {
+ struct stat* st = new struct stat;
+ int dirfd = open(DIR_TO_READ, O_RDONLY);
+ ASSERT_GT(dirfd, 0);
+ int res = fstatat(dirfd, SUBFILE_TO_READ, st, 0);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st->st_dev);
+ EXPECT_NOT_POISONED(st->st_mode);
+ EXPECT_NOT_POISONED(st->st_size);
+ close(dirfd);
+}
+
+TEST(MemorySanitizer, statfs) {
+ struct statfs st;
+ int res = statfs("/", &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_type);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namelen);
+}
+
+TEST(MemorySanitizer, statvfs) {
+ struct statvfs st;
+ int res = statvfs("/", &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+}
+
+TEST(MemorySanitizer, fstatvfs) {
+ struct statvfs st;
+ int fd = open("/", O_RDONLY | O_DIRECTORY);
+ int res = fstatvfs(fd, &st);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+ close(fd);
+}
+
+TEST(MemorySanitizer, pipe) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pipefd[0]);
+ EXPECT_NOT_POISONED(pipefd[1]);
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, pipe2) {
+ int* pipefd = new int[2];
+ int res = pipe2(pipefd, O_NONBLOCK);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pipefd[0]);
+ EXPECT_NOT_POISONED(pipefd[1]);
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, socketpair) {
+ int sv[2];
+ int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(sv[0]);
+ EXPECT_NOT_POISONED(sv[1]);
+ close(sv[0]);
+ close(sv[1]);
+}
+
+TEST(MemorySanitizer, poll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ res = poll(fds, 2, 500);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+// There is no ppoll() on FreeBSD.
+#if !defined (__FreeBSD__)
+TEST(MemorySanitizer, ppoll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ sigset_t ss;
+ sigemptyset(&ss);
+ res = ppoll(fds, 2, NULL, &ss);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+#endif
+
+TEST(MemorySanitizer, poll_positive) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ // fds[1].fd uninitialized
+ fds[1].events = POLLIN;
+ EXPECT_UMR(poll(fds, 2, 0));
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, bind_getsockname) {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_UNIX;
+ int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
+
+ ASSERT_EQ(0, res);
+ char buf[200];
+ socklen_t addrlen;
+ EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
+
+ addrlen = sizeof(buf);
+ res = getsockname(sock, (struct sockaddr *)&buf, &addrlen);
+ EXPECT_NOT_POISONED(addrlen);
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[addrlen - 1]);
+ EXPECT_POISONED(buf[addrlen]);
+ close(sock);
+}
+
+TEST(MemorySanitizer, accept) {
+ int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, listen_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ res = listen(listen_socket, 1);
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+ int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, connect_socket);
+ res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
+ ASSERT_EQ(0, res);
+ res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
+ // On FreeBSD this connection completes immediately.
+ if (res != 0) {
+ ASSERT_EQ(-1, res);
+ ASSERT_EQ(EINPROGRESS, errno);
+ }
+
+ __msan_poison(&sai, sizeof(sai));
+ int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_LT(0, new_sock);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ __msan_poison(&sai, sizeof(sai));
+ res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ close(new_sock);
+ close(connect_socket);
+ close(listen_socket);
+}
+
+TEST(MemorySanitizer, getaddrinfo) {
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ int res = getaddrinfo("localhost", NULL, &hints, &ai);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(*ai);
+ ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
+ EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr);
+}
+
+TEST(MemorySanitizer, getnameinfo) {
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 80;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ char host[500];
+ char serv[500];
+ int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
+ sizeof(host), serv, sizeof(serv), 0);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(host[0]);
+ EXPECT_POISONED(host[sizeof(host) - 1]);
+
+ ASSERT_NE(0U, strlen(host));
+ EXPECT_NOT_POISONED(serv[0]);
+ EXPECT_POISONED(serv[sizeof(serv) - 1]);
+ ASSERT_NE(0U, strlen(serv));
+}
+
+#define EXPECT_HOSTENT_NOT_POISONED(he) \
+ do { \
+ EXPECT_NOT_POISONED(*(he)); \
+ ASSERT_NE((void *) 0, (he)->h_name); \
+ ASSERT_NE((void *) 0, (he)->h_aliases); \
+ ASSERT_NE((void *) 0, (he)->h_addr_list); \
+ EXPECT_NOT_POISONED(strlen((he)->h_name)); \
+ char **p = (he)->h_aliases; \
+ while (*p) { \
+ EXPECT_NOT_POISONED(strlen(*p)); \
+ ++p; \
+ } \
+ char **q = (he)->h_addr_list; \
+ while (*q) { \
+ EXPECT_NOT_POISONED(*q[0]); \
+ ++q; \
+ } \
+ EXPECT_NOT_POISONED(*q); \
+ } while (0)
+
+TEST(MemorySanitizer, gethostent) {
+ struct hostent *he = gethostent();
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, gethostbyname) {
+ struct hostent *he = gethostbyname("localhost");
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, recvmsg) {
+ int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, server_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(server_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+
+ int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, client_socket);
+
+ struct sockaddr_in client_sai;
+ memset(&client_sai, 0, sizeof(client_sai));
+ client_sai.sin_family = AF_INET;
+ client_sai.sin_port = 0;
+ client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai));
+ ASSERT_EQ(0, res);
+
+ sz = sizeof(client_sai);
+ res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(client_sai), sz);
+
+ const char *s = "message text";
+ struct iovec iov;
+ iov.iov_base = (void *)s;
+ iov.iov_len = strlen(s) + 1;
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &sai;
+ msg.msg_namelen = sizeof(sai);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ res = sendmsg(client_socket, &msg, 0);
+ ASSERT_LT(0, res);
+
+
+ char buf[1000];
+ struct iovec recv_iov;
+ recv_iov.iov_base = (void *)&buf;
+ recv_iov.iov_len = sizeof(buf);
+ struct sockaddr_in recv_sai;
+ struct msghdr recv_msg;
+ memset(&recv_msg, 0, sizeof(recv_msg));
+ recv_msg.msg_name = &recv_sai;
+ recv_msg.msg_namelen = sizeof(recv_sai);
+ recv_msg.msg_iov = &recv_iov;
+ recv_msg.msg_iovlen = 1;
+ res = recvmsg(server_socket, &recv_msg, 0);
+ ASSERT_LT(0, res);
+
+ ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen);
+ EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name);
+ EXPECT_STREQ(s, buf);
+
+ close(server_socket);
+ close(client_socket);
+}
+
+TEST(MemorySanitizer, gethostbyname2) {
+ struct hostent *he = gethostbyname2("localhost", AF_INET);
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostbyaddr) {
+ in_addr_t addr = inet_addr("127.0.0.1");
+ EXPECT_NOT_POISONED(addr);
+ struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+ ASSERT_NE((void *)NULL, he);
+ EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostent_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostent_r(&he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ((struct hostent *)0, result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_erange) {
+ char buf[5];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(ERANGE, res);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname2_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf),
+ &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyaddr_r) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ in_addr_t addr = inet_addr("127.0.0.1");
+ EXPECT_NOT_POISONED(addr);
+ int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf),
+ &result, &err);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(result);
+ ASSERT_NE((void *)NULL, result);
+ EXPECT_HOSTENT_NOT_POISONED(result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, getsockopt) {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ struct linger l[2];
+ socklen_t sz = sizeof(l[0]);
+ int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(l[0]), sz);
+ EXPECT_NOT_POISONED(l[0]);
+ EXPECT_POISONED(*(char *)(l + 1));
+}
+
+TEST(MemorySanitizer, getcwd) {
+ char path[PATH_MAX + 1];
+ char* res = getcwd(path, sizeof(path));
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(path[0]);
+}
+
+TEST(MemorySanitizer, getcwd_gnu) {
+ char* res = getcwd(NULL, 0);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+// There's no get_current_dir_name() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, get_current_dir_name) {
+ char* res = get_current_dir_name();
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+#endif
+
+TEST(MemorySanitizer, shmctl) {
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ struct shmid_ds ds;
+ int res = shmctl(id, IPC_STAT, &ds);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(ds);
+
+ // FreeBSD does not support shmctl(IPC_INFO) and shmctl(SHM_INFO).
+#if !defined(__FreeBSD__)
+ struct shminfo si;
+ res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(si);
+
+ struct shm_info s_i;
+ res = shmctl(id, SHM_INFO, (struct shmid_ds *)&s_i);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(s_i);
+#endif
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+TEST(MemorySanitizer, shmat) {
+ void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, p);
+
+ ((char *)p)[10] = *GetPoisoned<U1>();
+ ((char *)p)[4095] = *GetPoisoned<U1>();
+
+ int res = munmap(p, 4096);
+ ASSERT_EQ(0, res);
+
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ void *q = shmat(id, p, 0);
+ ASSERT_EQ(p, q);
+
+ EXPECT_NOT_POISONED(((char *)q)[0]);
+ EXPECT_NOT_POISONED(((char *)q)[10]);
+ EXPECT_NOT_POISONED(((char *)q)[4095]);
+
+ res = shmdt(q);
+ ASSERT_EQ(0, res);
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+// There's no random_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, random_r) {
+ int32_t x;
+ char z[64];
+ memset(z, 0, sizeof(z));
+
+ struct random_data buf;
+ memset(&buf, 0, sizeof(buf));
+
+ int res = initstate_r(0, z, sizeof(z), &buf);
+ ASSERT_EQ(0, res);
+
+ res = random_r(&buf, &x);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(x);
+}
+#endif
+
+TEST(MemorySanitizer, confstr) {
+ char buf[3];
+ size_t res = confstr(_CS_PATH, buf, sizeof(buf));
+ ASSERT_GT(res, sizeof(buf));
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]);
+
+ char buf2[1000];
+ res = confstr(_CS_PATH, buf2, sizeof(buf2));
+ ASSERT_LT(res, sizeof(buf2));
+ EXPECT_NOT_POISONED(buf2[0]);
+ EXPECT_NOT_POISONED(buf2[res - 1]);
+ EXPECT_POISONED(buf2[res]);
+ ASSERT_EQ(res, strlen(buf2) + 1);
+}
+
+TEST(MemorySanitizer, opendir) {
+ DIR *dir = opendir(".");
+ closedir(dir);
+
+ char name[10] = ".";
+ __msan_poison(name, sizeof(name));
+ EXPECT_UMR(dir = opendir(name));
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, readdir) {
+ DIR *dir = opendir(".");
+ struct dirent *d = readdir(dir);
+ ASSERT_TRUE(d != NULL);
+ EXPECT_NOT_POISONED(d->d_name[0]);
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, readdir_r) {
+ DIR *dir = opendir(".");
+ struct dirent d;
+ struct dirent *pd;
+ int res = readdir_r(dir, &d, &pd);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pd);
+ EXPECT_NOT_POISONED(d.d_name[0]);
+ closedir(dir);
+}
+
+TEST(MemorySanitizer, realpath) {
+ const char* relpath = ".";
+ char path[PATH_MAX + 1];
+ char* res = realpath(relpath, path);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(path[0]);
+}
+
+TEST(MemorySanitizer, realpath_null) {
+ const char* relpath = ".";
+ char* res = realpath(relpath, NULL);
+ printf("%d, %s\n", errno, strerror(errno));
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+// There's no canonicalize_file_name() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, canonicalize_file_name) {
+ const char* relpath = ".";
+ char* res = canonicalize_file_name(relpath);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+#endif
+
+extern char **environ;
+
+TEST(MemorySanitizer, setenv) {
+ setenv("AAA", "BBB", 1);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
+TEST(MemorySanitizer, putenv) {
+ char s[] = "AAA=BBB";
+ putenv(s);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
+TEST(MemorySanitizer, memcpy) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ memcpy(y, x, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned,
+ bool src_is_poisoned, bool dst_is_poisoned) {
+ fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right,
+ src_is_aligned, src_is_poisoned, dst_is_poisoned);
+
+ const unsigned sz = 20;
+ U4 dst_origin, src_origin;
+ char *dst = (char *)malloc(sz);
+ if (dst_is_poisoned)
+ dst_origin = __msan_get_origin(dst);
+ else
+ memset(dst, 0, sz);
+
+ char *src = (char *)malloc(sz);
+ if (src_is_poisoned)
+ src_origin = __msan_get_origin(src);
+ else
+ memset(src, 0, sz);
+
+ memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
+
+ for (unsigned i = 0; i < (left & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[i], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ for (unsigned i = 0; i < (right & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[sz - i - 1], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[sz - i - 1]);
+
+ for (unsigned i = left; i < sz - right; ++i)
+ if (src_is_poisoned)
+ EXPECT_POISONED_O(dst[i], src_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ free(dst);
+ free(src);
+}
+
+TEST(MemorySanitizer, memcpy_unaligned) {
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ for (int aligned = 0; aligned < 2; ++aligned)
+ for (int srcp = 0; srcp < 2; ++srcp)
+ for (int dstp = 0; dstp < 2; ++dstp)
+ TestUnalignedMemcpy(i, j, aligned, srcp, dstp);
+}
+
+TEST(MemorySanitizer, memmove) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ memmove(y, x, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+TEST(MemorySanitizer, memccpy_nomatch) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'd', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'b', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_POISONED(y[2]);
+ EXPECT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_nomatch_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ EXPECT_UMR(memccpy(y, x, 'd', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ x[0] = 'a';
+ x[2] = 'b';
+ EXPECT_UMR(memccpy(y, x, 'b', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, bcopy) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ bcopy(x, y, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
+TEST(MemorySanitizer, strdup) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strdup(buf);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+ free(x);
+}
+
+TEST(MemorySanitizer, strndup) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strndup(buf, 3);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+ free(x);
+}
+
+TEST(MemorySanitizer, strndup_short) {
+ char buf[4] = "abc";
+ __msan_poison(buf + 1, sizeof(*buf));
+ __msan_poison(buf + 2, sizeof(*buf));
+ char *x = strndup(buf, 2);
+ EXPECT_NOT_POISONED(x[0]);
+ EXPECT_POISONED(x[1]);
+ EXPECT_NOT_POISONED(x[2]);
+ free(x);
+}
+
+
+template<class T, int size>
+void TestOverlapMemmove() {
+ T *x = new T[size];
+ ASSERT_GE(size, 3);
+ x[2] = 0;
+ memmove(x, x + 1, (size - 1) * sizeof(T));
+ EXPECT_NOT_POISONED(x[1]);
+ EXPECT_POISONED(x[0]);
+ EXPECT_POISONED(x[2]);
+ delete [] x;
+}
+
+TEST(MemorySanitizer, overlap_memmove) {
+ TestOverlapMemmove<U1, 10>();
+ TestOverlapMemmove<U1, 1000>();
+ TestOverlapMemmove<U8, 4>();
+ TestOverlapMemmove<U8, 1000>();
+}
+
+TEST(MemorySanitizer, strcpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[3];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = 0;
+ strcpy(y, x); // NOLINT
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+}
+
+TEST(MemorySanitizer, strncpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[5];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = '\0';
+ strncpy(y, x, 4); // NOLINT
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+}
+
+TEST(MemorySanitizer, stpcpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[3];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = 0;
+ char *res = stpcpy(y, x); // NOLINT
+ ASSERT_EQ(res, y + 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+}
+
+TEST(MemorySanitizer, strcat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strcat(a, b);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 5);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat_overflow) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 2);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+#define TEST_STRTO_INT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
+
+#define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
+
+#define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+#define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+TEST_STRTO_INT(strtol, char, )
+TEST_STRTO_INT(strtoll, char, )
+TEST_STRTO_INT(strtoul, char, )
+TEST_STRTO_INT(strtoull, char, )
+
+TEST_STRTO_FLOAT(strtof, char, )
+TEST_STRTO_FLOAT(strtod, char, )
+TEST_STRTO_FLOAT(strtold, char, )
+
+TEST_STRTO_FLOAT_LOC(strtof_l, char, )
+TEST_STRTO_FLOAT_LOC(strtod_l, char, )
+TEST_STRTO_FLOAT_LOC(strtold_l, char, )
+
+TEST_STRTO_INT_LOC(strtol_l, char, )
+TEST_STRTO_INT_LOC(strtoll_l, char, )
+TEST_STRTO_INT_LOC(strtoul_l, char, )
+TEST_STRTO_INT_LOC(strtoull_l, char, )
+
+TEST_STRTO_INT(wcstol, wchar_t, L)
+TEST_STRTO_INT(wcstoll, wchar_t, L)
+TEST_STRTO_INT(wcstoul, wchar_t, L)
+TEST_STRTO_INT(wcstoull, wchar_t, L)
+
+TEST_STRTO_FLOAT(wcstof, wchar_t, L)
+TEST_STRTO_FLOAT(wcstod, wchar_t, L)
+TEST_STRTO_FLOAT(wcstold, wchar_t, L)
+
+TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
+
+TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
+
+
+TEST(MemorySanitizer, strtoimax) {
+ char *e;
+ ASSERT_EQ(1, strtoimax("1", &e, 10));
+ EXPECT_NOT_POISONED((S8) e);
+}
+
+TEST(MemorySanitizer, strtoumax) {
+ char *e;
+ ASSERT_EQ(1U, strtoumax("1", &e, 10));
+ EXPECT_NOT_POISONED((S8) e);
+}
+
+#ifdef __GLIBC__
+extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtof_l, char, )
+extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtod_l, char, )
+extern "C" long double __strtold_l(const char *nptr, char **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtold_l, char, )
+
+extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L)
+extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L)
+extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L)
+#endif // __GLIBC__
+
+TEST(MemorySanitizer, modf) {
+ double x, y;
+ x = modf(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modff) {
+ float x, y;
+ x = modff(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modfl) {
+ long double x, y;
+ x = modfl(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+// There's no sincos() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincos) {
+ double s, c;
+ sincos(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+// There's no sincosf() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincosf) {
+ float s, c;
+ sincosf(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+// There's no sincosl() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sincosl) {
+ long double s, c;
+ sincosl(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+#endif
+
+TEST(MemorySanitizer, remquo) {
+ int quo;
+ double res = remquo(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquof) {
+ int quo;
+ float res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquol) {
+ int quo;
+ long double res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, lgamma) {
+ double res = lgamma(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammaf) {
+ float res = lgammaf(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammal) {
+ long double res = lgammal(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgamma_r) {
+ int sgn;
+ double res = lgamma_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+TEST(MemorySanitizer, lgammaf_r) {
+ int sgn;
+ float res = lgammaf_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+// There's no lgammal_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, lgammal_r) {
+ int sgn;
+ long double res = lgammal_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+#endif
+
+// There's no drand48_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, drand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ double d;
+ drand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+#endif
+
+// There's no lrand48_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, lrand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ long d;
+ lrand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+#endif
+
+TEST(MemorySanitizer, sprintf) { // NOLINT
+ char buff[10];
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = sprintf(buff, "%d", 1234567); // NOLINT
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, snprintf) {
+ char buff[10];
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = snprintf(buff, sizeof(buff), "%d", 1234567);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, swprintf) {
+ wchar_t buff[10];
+ ASSERT_EQ(4U, sizeof(wchar_t));
+ break_optimization(buff);
+ EXPECT_POISONED(buff[0]);
+ int res = swprintf(buff, 9, L"%d", 1234567);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], L'\0');
+ EXPECT_POISONED(buff[8]);
+}
+
+TEST(MemorySanitizer, asprintf) { // NOLINT
+ char *pbuf;
+ EXPECT_POISONED(pbuf);
+ int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
+ ASSERT_EQ(res, 7);
+ EXPECT_NOT_POISONED(pbuf);
+ ASSERT_EQ(pbuf[0], '1');
+ ASSERT_EQ(pbuf[1], '2');
+ ASSERT_EQ(pbuf[2], '3');
+ ASSERT_EQ(pbuf[6], '7');
+ ASSERT_EQ(pbuf[7], 0);
+ free(pbuf);
+}
+
+TEST(MemorySanitizer, mbstowcs) {
+ const char *x = "abc";
+ wchar_t buff[10];
+ int res = mbstowcs(buff, x, 2);
+ EXPECT_EQ(2, res);
+ EXPECT_EQ(L'a', buff[0]);
+ EXPECT_EQ(L'b', buff[1]);
+ EXPECT_POISONED(buff[2]);
+ res = mbstowcs(buff, x, 10);
+ EXPECT_EQ(3, res);
+ EXPECT_NOT_POISONED(buff[3]);
+}
+
+TEST(MemorySanitizer, wcstombs) {
+ const wchar_t *x = L"abc";
+ char buff[10];
+ int res = wcstombs(buff, x, 4);
+ EXPECT_EQ(res, 3);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_EQ(buff[2], 'c');
+}
+
+TEST(MemorySanitizer, wcsrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsrtombs(buff, &p, 4, &mbs);
+ EXPECT_EQ(res, 3);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_EQ(buff[2], 'c');
+ EXPECT_EQ(buff[3], '\0');
+ EXPECT_POISONED(buff[4]);
+}
+
+TEST(MemorySanitizer, wcsnrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsnrtombs(buff, &p, 2, 4, &mbs);
+ EXPECT_EQ(res, 2);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_POISONED(buff[2]);
+}
+
+TEST(MemorySanitizer, wcrtomb) {
+ wchar_t x = L'a';
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ size_t res = wcrtomb(buff, x, &mbs);
+ EXPECT_EQ(res, (size_t)1);
+ EXPECT_EQ(buff[0], 'a');
+}
+
+TEST(MemorySanitizer, wmemset) {
+ wchar_t x[25];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ wmemset(x, L'A', 10);
+ EXPECT_EQ(x[0], L'A');
+ EXPECT_EQ(x[9], L'A');
+ EXPECT_POISONED(x[10]);
+}
+
+TEST(MemorySanitizer, mbtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ int res = mbtowc(&wx, x, 3);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, mbrtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = mbrtowc(&wx, x, 3, &mbs);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, wcsftime) {
+ wchar_t x[100];
+ time_t t = time(NULL);
+ struct tm tms;
+ struct tm *tmres = localtime_r(&t, &tms);
+ ASSERT_NE((void *)0, tmres);
+ size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres);
+ EXPECT_GT(res, 0UL);
+ EXPECT_EQ(res, wcslen(x));
+}
+
+TEST(MemorySanitizer, gettimeofday) {
+ struct timeval tv;
+ struct timezone tz;
+ break_optimization(&tv);
+ break_optimization(&tz);
+ ASSERT_EQ(16U, sizeof(tv));
+ ASSERT_EQ(8U, sizeof(tz));
+ EXPECT_POISONED(tv.tv_sec);
+ EXPECT_POISONED(tv.tv_usec);
+ EXPECT_POISONED(tz.tz_minuteswest);
+ EXPECT_POISONED(tz.tz_dsttime);
+ ASSERT_EQ(0, gettimeofday(&tv, &tz));
+ EXPECT_NOT_POISONED(tv.tv_sec);
+ EXPECT_NOT_POISONED(tv.tv_usec);
+ EXPECT_NOT_POISONED(tz.tz_minuteswest);
+ EXPECT_NOT_POISONED(tz.tz_dsttime);
+}
+
+TEST(MemorySanitizer, clock_gettime) {
+ struct timespec tp;
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
+ EXPECT_NOT_POISONED(tp.tv_sec);
+ EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, clock_getres) {
+ struct timespec tp;
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0));
+ EXPECT_POISONED(tp.tv_sec);
+ EXPECT_POISONED(tp.tv_nsec);
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp));
+ EXPECT_NOT_POISONED(tp.tv_sec);
+ EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, getitimer) {
+ struct itimerval it1, it2;
+ int res;
+ EXPECT_POISONED(it1.it_interval.tv_sec);
+ EXPECT_POISONED(it1.it_interval.tv_usec);
+ EXPECT_POISONED(it1.it_value.tv_sec);
+ EXPECT_POISONED(it1.it_value.tv_usec);
+ res = getitimer(ITIMER_VIRTUAL, &it1);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
+ EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
+ EXPECT_NOT_POISONED(it1.it_value.tv_sec);
+ EXPECT_NOT_POISONED(it1.it_value.tv_usec);
+
+ it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000;
+ it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
+
+ res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
+ EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
+ EXPECT_NOT_POISONED(it2.it_value.tv_sec);
+ EXPECT_NOT_POISONED(it2.it_value.tv_usec);
+
+ // Check that old_value can be 0, and disable the timer.
+ memset(&it1, 0, sizeof(it1));
+ res = setitimer(ITIMER_VIRTUAL, &it1, 0);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, setitimer_null) {
+ setitimer(ITIMER_VIRTUAL, 0, 0);
+ // Not testing the return value, since it the behaviour seems to differ
+ // between libc implementations and POSIX.
+ // Should never crash, though.
+}
+
+TEST(MemorySanitizer, time) {
+ time_t t;
+ EXPECT_POISONED(t);
+ time_t t2 = time(&t);
+ ASSERT_NE(t2, (time_t)-1);
+ EXPECT_NOT_POISONED(t);
+}
+
+TEST(MemorySanitizer, strptime) {
+ struct tm time;
+ char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(time.tm_sec);
+ EXPECT_NOT_POISONED(time.tm_hour);
+ EXPECT_NOT_POISONED(time.tm_year);
+}
+
+TEST(MemorySanitizer, localtime) {
+ time_t t = 123;
+ struct tm *time = localtime(&t);
+ ASSERT_TRUE(time != NULL);
+ EXPECT_NOT_POISONED(time->tm_sec);
+ EXPECT_NOT_POISONED(time->tm_hour);
+ EXPECT_NOT_POISONED(time->tm_year);
+ EXPECT_NOT_POISONED(time->tm_isdst);
+ EXPECT_NE(0U, strlen(time->tm_zone));
+}
+
+TEST(MemorySanitizer, localtime_r) {
+ time_t t = 123;
+ struct tm time;
+ struct tm *res = localtime_r(&t, &time);
+ ASSERT_TRUE(res != NULL);
+ EXPECT_NOT_POISONED(time.tm_sec);
+ EXPECT_NOT_POISONED(time.tm_hour);
+ EXPECT_NOT_POISONED(time.tm_year);
+ EXPECT_NOT_POISONED(time.tm_isdst);
+ EXPECT_NE(0U, strlen(time.tm_zone));
+}
+
+// There's no getmntent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, getmntent) {
+ FILE *fp = setmntent("/etc/fstab", "r");
+ struct mntent *mnt = getmntent(fp);
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+#endif
+
+// There's no getmntent_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, getmntent_r) {
+ FILE *fp = setmntent("/etc/fstab", "r");
+ struct mntent mntbuf;
+ char buf[1000];
+ struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, ether) {
+ const char *asc = "11:22:33:44:55:66";
+ struct ether_addr *paddr = ether_aton(asc);
+ EXPECT_NOT_POISONED(*paddr);
+
+ struct ether_addr addr;
+ paddr = ether_aton_r(asc, &addr);
+ ASSERT_EQ(paddr, &addr);
+ EXPECT_NOT_POISONED(addr);
+
+ char *s = ether_ntoa(&addr);
+ ASSERT_NE(0U, strlen(s));
+
+ char buf[100];
+ s = ether_ntoa_r(&addr, buf);
+ ASSERT_EQ(s, buf);
+ ASSERT_NE(0U, strlen(buf));
+}
+
+TEST(MemorySanitizer, mmap) {
+ const int size = 4096;
+ void *p1, *p2;
+ p1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ __msan_poison(p1, size);
+ munmap(p1, size);
+ for (int i = 0; i < 1000; i++) {
+ p2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p2 == p1)
+ break;
+ else
+ munmap(p2, size);
+ }
+ if (p1 == p2) {
+ EXPECT_NOT_POISONED(*(char*)p2);
+ munmap(p2, size);
+ }
+}
+
+// There's no fcvt() on FreeBSD.
+#if !defined(__FreeBSD__)
+// FIXME: enable and add ecvt.
+// FIXME: check why msandr does nt handle fcvt.
+TEST(MemorySanitizer, fcvt) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(12345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+#endif
+
+// There's no fcvt_long() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fcvt_long) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(111111112345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+#endif
+
+TEST(MemorySanitizer, memchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[2] = '2';
+ void *res;
+ EXPECT_UMR(res = memchr(x, '2', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memchr(x, '2', 10);
+ EXPECT_EQ(&x[2], res);
+ EXPECT_UMR(res = memchr(x, '3', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, memrchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[9] = '9';
+ void *res;
+ EXPECT_UMR(res = memrchr(x, '9', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memrchr(x, '0', 2);
+ EXPECT_EQ(&x[0], res);
+ EXPECT_UMR(res = memrchr(x, '7', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, frexp) {
+ int x;
+ x = *GetPoisoned<int>();
+ double r = frexp(1.1, &x);
+ EXPECT_NOT_POISONED(r);
+ EXPECT_NOT_POISONED(x);
+
+ x = *GetPoisoned<int>();
+ float rf = frexpf(1.1, &x);
+ EXPECT_NOT_POISONED(rf);
+ EXPECT_NOT_POISONED(x);
+
+ x = *GetPoisoned<int>();
+ double rl = frexpl(1.1, &x);
+ EXPECT_NOT_POISONED(rl);
+ EXPECT_NOT_POISONED(x);
+}
+
+namespace {
+
+static int cnt;
+
+void SigactionHandler(int signo, siginfo_t* si, void* uc) {
+ ASSERT_EQ(signo, SIGPROF);
+ ASSERT_TRUE(si != NULL);
+ EXPECT_NOT_POISONED(si->si_errno);
+ EXPECT_NOT_POISONED(si->si_pid);
+#if __linux__
+# if defined(__x86_64__)
+ EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]);
+# elif defined(__i386__)
+ EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]);
+# endif
+#endif
+ ++cnt;
+}
+
+TEST(MemorySanitizer, sigaction) {
+ struct sigaction act = {};
+ struct sigaction oldact = {};
+ struct sigaction origact = {};
+
+ sigaction(SIGPROF, 0, &origact);
+
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction = &SigactionHandler;
+ sigaction(SIGPROF, &act, 0);
+
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGPROF, &act, 0);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(SIG_DFL, oldact.sa_handler);
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction = &SigactionHandler;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(SIG_IGN, oldact.sa_handler);
+ kill(getpid(), SIGPROF);
+
+ act.sa_flags &= ~SA_SIGINFO;
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGPROF, &act, &oldact);
+ EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO);
+ EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction);
+ EXPECT_EQ(2, cnt);
+
+ sigaction(SIGPROF, &origact, 0);
+}
+
+} // namespace
+
+
+TEST(MemorySanitizer, sigemptyset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigemptyset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigfillset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigfillset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigpending) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigpending(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigprocmask) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigprocmask(SIG_BLOCK, 0, &s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+struct StructWithDtor {
+ ~StructWithDtor();
+};
+
+NOINLINE StructWithDtor::~StructWithDtor() {
+ break_optimization(0);
+}
+
+TEST(MemorySanitizer, Invoke) {
+ StructWithDtor s; // Will cause the calls to become invokes.
+ EXPECT_NOT_POISONED(0);
+ EXPECT_POISONED(*GetPoisoned<int>());
+ EXPECT_NOT_POISONED(0);
+ EXPECT_POISONED(*GetPoisoned<int>());
+ EXPECT_POISONED(ReturnPoisoned<S4>());
+}
+
+TEST(MemorySanitizer, ptrtoint) {
+ // Test that shadow is propagated through pointer-to-integer conversion.
+ void* p = (void*)0xABCD;
+ __msan_poison(((char*)&p) + 1, sizeof(p));
+ EXPECT_NOT_POISONED((((uintptr_t)p) & 0xFF) == 0);
+
+ void* q = (void*)0xABCD;
+ __msan_poison(&q, sizeof(q) - 1);
+ EXPECT_POISONED((((uintptr_t)q) & 0xFF) == 0);
+}
+
+static void vaargsfn2(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ va_end(vl);
+}
+
+static void vaargsfn(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ // The following call will overwrite __msan_param_tls.
+ // Checks after it test that arg shadow was somehow saved across the call.
+ vaargsfn2(1, 2, 3, 4, *GetPoisoned<double>());
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgTest) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn(1, 13, *x, 42, *y);
+}
+
+static void vaargsfn_many(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgManyTest) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_many(1, 2, *x, 3, 4, 5, 6, 7, 8, 9, *y);
+}
+
+static void vaargsfn_pass2(va_list vl) {
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+}
+
+static void vaargsfn_pass(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_POISONED(va_arg(vl, int));
+ vaargsfn_pass2(vl);
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgPass) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_pass(1, *x, 2, 3, *y);
+}
+
+static void vaargsfn_copy2(va_list vl) {
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+}
+
+static void vaargsfn_copy(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_list vl2;
+ va_copy(vl2, vl);
+ vaargsfn_copy2(vl2);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgCopy) {
+ int* x = GetPoisoned<int>();
+ int* y = GetPoisoned<int>(4);
+ vaargsfn_copy(1, 2, *x, 3, *y);
+}
+
+static void vaargsfn_ptr(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+ EXPECT_POISONED(va_arg(vl, int*));
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+ EXPECT_POISONED(va_arg(vl, double*));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgPtr) {
+ int** x = GetPoisoned<int*>();
+ double** y = GetPoisoned<double*>(8);
+ int z;
+ vaargsfn_ptr(1, &z, *x, &z, *y);
+}
+
+static void vaargsfn_overflow(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ EXPECT_NOT_POISONED(va_arg(vl, double));
+ EXPECT_NOT_POISONED(va_arg(vl, int*));
+
+ EXPECT_POISONED(va_arg(vl, int));
+ EXPECT_POISONED(va_arg(vl, double));
+ EXPECT_POISONED(va_arg(vl, int*));
+
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgOverflow) {
+ int* x = GetPoisoned<int>();
+ double* y = GetPoisoned<double>(8);
+ int** p = GetPoisoned<int*>(16);
+ int z;
+ vaargsfn_overflow(1,
+ 1, 2, *x, 4, 5, 6,
+ 1.1, 2.2, 3.3, *y, 5.5, *p, 7.7, 8.8,
+ // the following args will overflow for sure
+ *x, *y, *p,
+ 7, 9.9, &z,
+ *x, *y, *p);
+}
+
+static void vaargsfn_tlsoverwrite2(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ for (int i = 0; i < 20; ++i)
+ EXPECT_NOT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+static void vaargsfn_tlsoverwrite(int guard, ...) {
+ // This call will overwrite TLS contents unless it's backed up somewhere.
+ vaargsfn_tlsoverwrite2(2,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42); // 20x
+ va_list vl;
+ va_start(vl, guard);
+ for (int i = 0; i < 20; ++i)
+ EXPECT_POISONED(va_arg(vl, int));
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgTLSOverwrite) {
+ int* x = GetPoisoned<int>();
+ vaargsfn_tlsoverwrite(1,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x); // 20x
+
+}
+
+struct StructByVal {
+ int a, b, c, d, e, f;
+};
+
+static void vaargsfn_structbyval(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgStructByVal) {
+ StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ vaargsfn_structbyval(0, s, s);
+}
+
+NOINLINE void StructByValTestFunc(struct StructByVal s) {
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+}
+
+NOINLINE void StructByValTestFunc1(struct StructByVal s) {
+ StructByValTestFunc(s);
+}
+
+NOINLINE void StructByValTestFunc2(int z, struct StructByVal s) {
+ StructByValTestFunc(s);
+}
+
+TEST(MemorySanitizer, StructByVal) {
+ // Large aggregates are passed as "byval" pointer argument in LLVM.
+ struct StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ StructByValTestFunc(s);
+ StructByValTestFunc1(s);
+ StructByValTestFunc2(0, s);
+}
+
+
+#if MSAN_HAS_M128
+NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); }
+NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); }
+TEST(MemorySanitizer, m128) {
+ __m128i a = _mm_set1_epi16(0x1234);
+ __m128i b = _mm_set1_epi16(0x7890);
+ EXPECT_NOT_POISONED(m128Eq(&a, &b));
+ EXPECT_NOT_POISONED(m128Lt(&a, &b));
+}
+// FIXME: add more tests for __m128i.
+#endif // MSAN_HAS_M128
+
+// We should not complain when copying this poisoned hole.
+struct StructWithHole {
+ U4 a;
+ // 4-byte hole.
+ U8 b;
+};
+
+NOINLINE StructWithHole ReturnStructWithHole() {
+ StructWithHole res;
+ __msan_poison(&res, sizeof(res));
+ res.a = 1;
+ res.b = 2;
+ return res;
+}
+
+TEST(MemorySanitizer, StructWithHole) {
+ StructWithHole a = ReturnStructWithHole();
+ break_optimization(&a);
+}
+
+template <class T>
+NOINLINE T ReturnStruct() {
+ T res;
+ __msan_poison(&res, sizeof(res));
+ res.a = 1;
+ return res;
+}
+
+template <class T>
+NOINLINE void TestReturnStruct() {
+ T s1 = ReturnStruct<T>();
+ EXPECT_NOT_POISONED(s1.a);
+ EXPECT_POISONED(s1.b);
+}
+
+struct SSS1 {
+ int a, b, c;
+};
+struct SSS2 {
+ int b, a, c;
+};
+struct SSS3 {
+ int b, c, a;
+};
+struct SSS4 {
+ int c, b, a;
+};
+
+struct SSS5 {
+ int a;
+ float b;
+};
+struct SSS6 {
+ int a;
+ double b;
+};
+struct SSS7 {
+ S8 b;
+ int a;
+};
+struct SSS8 {
+ S2 b;
+ S8 a;
+};
+
+TEST(MemorySanitizer, IntStruct3) {
+ TestReturnStruct<SSS1>();
+ TestReturnStruct<SSS2>();
+ TestReturnStruct<SSS3>();
+ TestReturnStruct<SSS4>();
+ TestReturnStruct<SSS5>();
+ TestReturnStruct<SSS6>();
+ TestReturnStruct<SSS7>();
+ TestReturnStruct<SSS8>();
+}
+
+struct LongStruct {
+ U1 a1, b1;
+ U2 a2, b2;
+ U4 a4, b4;
+ U8 a8, b8;
+};
+
+NOINLINE LongStruct ReturnLongStruct1() {
+ LongStruct res;
+ __msan_poison(&res, sizeof(res));
+ res.a1 = res.a2 = res.a4 = res.a8 = 111;
+ // leaves b1, .., b8 poisoned.
+ return res;
+}
+
+NOINLINE LongStruct ReturnLongStruct2() {
+ LongStruct res;
+ __msan_poison(&res, sizeof(res));
+ res.b1 = res.b2 = res.b4 = res.b8 = 111;
+ // leaves a1, .., a8 poisoned.
+ return res;
+}
+
+TEST(MemorySanitizer, LongStruct) {
+ LongStruct s1 = ReturnLongStruct1();
+ __msan_print_shadow(&s1, sizeof(s1));
+ EXPECT_NOT_POISONED(s1.a1);
+ EXPECT_NOT_POISONED(s1.a2);
+ EXPECT_NOT_POISONED(s1.a4);
+ EXPECT_NOT_POISONED(s1.a8);
+
+ EXPECT_POISONED(s1.b1);
+ EXPECT_POISONED(s1.b2);
+ EXPECT_POISONED(s1.b4);
+ EXPECT_POISONED(s1.b8);
+
+ LongStruct s2 = ReturnLongStruct2();
+ __msan_print_shadow(&s2, sizeof(s2));
+ EXPECT_NOT_POISONED(s2.b1);
+ EXPECT_NOT_POISONED(s2.b2);
+ EXPECT_NOT_POISONED(s2.b4);
+ EXPECT_NOT_POISONED(s2.b8);
+
+ EXPECT_POISONED(s2.a1);
+ EXPECT_POISONED(s2.a2);
+ EXPECT_POISONED(s2.a4);
+ EXPECT_POISONED(s2.a8);
+}
+
+TEST(MemorySanitizer, getrlimit) {
+ struct rlimit limit;
+ __msan_poison(&limit, sizeof(limit));
+ int result = getrlimit(RLIMIT_DATA, &limit);
+ ASSERT_EQ(result, 0);
+ EXPECT_NOT_POISONED(limit.rlim_cur);
+ EXPECT_NOT_POISONED(limit.rlim_max);
+}
+
+TEST(MemorySanitizer, getrusage) {
+ struct rusage usage;
+ __msan_poison(&usage, sizeof(usage));
+ int result = getrusage(RUSAGE_SELF, &usage);
+ ASSERT_EQ(result, 0);
+ EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
+ EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
+ EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
+ EXPECT_NOT_POISONED(usage.ru_stime.tv_usec);
+ EXPECT_NOT_POISONED(usage.ru_maxrss);
+ EXPECT_NOT_POISONED(usage.ru_minflt);
+ EXPECT_NOT_POISONED(usage.ru_majflt);
+ EXPECT_NOT_POISONED(usage.ru_inblock);
+ EXPECT_NOT_POISONED(usage.ru_oublock);
+ EXPECT_NOT_POISONED(usage.ru_nvcsw);
+ EXPECT_NOT_POISONED(usage.ru_nivcsw);
+}
+
+#if defined(__FreeBSD__)
+static void GetProgramPath(char *buf, size_t sz) {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ int res = sysctl(mib, 4, buf, &sz, NULL, 0);
+ ASSERT_EQ(0, res);
+}
+#elif defined(__GLIBC__)
+static void GetProgramPath(char *buf, size_t sz) {
+ extern char *program_invocation_name;
+ int res = snprintf(buf, sz, "%s", program_invocation_name);
+ ASSERT_GE(res, 0);
+ ASSERT_LT((size_t)res, sz);
+}
+#else
+# error "TODO: port this"
+#endif
+
+static void dladdr_testfn() {}
+
+TEST(MemorySanitizer, dladdr) {
+ Dl_info info;
+ __msan_poison(&info, sizeof(info));
+ int result = dladdr((const void*)dladdr_testfn, &info);
+ ASSERT_NE(result, 0);
+ EXPECT_NOT_POISONED((unsigned long)info.dli_fname);
+ if (info.dli_fname)
+ EXPECT_NOT_POISONED(strlen(info.dli_fname));
+ EXPECT_NOT_POISONED((unsigned long)info.dli_fbase);
+ EXPECT_NOT_POISONED((unsigned long)info.dli_sname);
+ if (info.dli_sname)
+ EXPECT_NOT_POISONED(strlen(info.dli_sname));
+ EXPECT_NOT_POISONED((unsigned long)info.dli_saddr);
+}
+
+#ifndef MSAN_TEST_DISABLE_DLOPEN
+
+static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
+ (*(int *)data)++;
+ EXPECT_NOT_POISONED(info->dlpi_addr);
+ EXPECT_NOT_POISONED(strlen(info->dlpi_name));
+ EXPECT_NOT_POISONED(info->dlpi_phnum);
+ for (int i = 0; i < info->dlpi_phnum; ++i)
+ EXPECT_NOT_POISONED(info->dlpi_phdr[i]);
+ return 0;
+}
+
+// Compute the path to our loadable DSO. We assume it's in the same
+// directory. Only use string routines that we intercept so far to do this.
+static void GetPathToLoadable(char *buf, size_t sz) {
+ char program_path[kMaxPathLength];
+ GetProgramPath(program_path, sizeof(program_path));
+
+ const char *last_slash = strrchr(program_path, '/');
+ ASSERT_NE(nullptr, last_slash);
+ size_t dir_len = (size_t)(last_slash - program_path);
+#if defined(__x86_64__)
+ static const char basename[] = "libmsan_loadable.x86_64.so";
+#elif defined(__MIPSEB__) || defined(MIPSEB)
+ static const char basename[] = "libmsan_loadable.mips64.so";
+#elif defined(__mips64)
+ static const char basename[] = "libmsan_loadable.mips64el.so";
+#elif defined(__aarch64__)
+ static const char basename[] = "libmsan_loadable.aarch64.so";
+#endif
+ int res = snprintf(buf, sz, "%.*s/%s",
+ (int)dir_len, program_path, basename);
+ ASSERT_GE(res, 0);
+ ASSERT_LT((size_t)res, sz);
+}
+
+TEST(MemorySanitizer, dl_iterate_phdr) {
+ char path[kMaxPathLength];
+ GetPathToLoadable(path, sizeof(path));
+
+ // Having at least one dlopen'ed library in the process makes this more
+ // entertaining.
+ void *lib = dlopen(path, RTLD_LAZY);
+ ASSERT_NE((void*)0, lib);
+
+ int count = 0;
+ int result = dl_iterate_phdr(dl_phdr_callback, &count);
+ ASSERT_GT(count, 0);
+
+ dlclose(lib);
+}
+
+TEST(MemorySanitizer, dlopen) {
+ char path[kMaxPathLength];
+ GetPathToLoadable(path, sizeof(path));
+
+ // We need to clear shadow for globals when doing dlopen. In order to test
+ // this, we have to poison the shadow for the DSO before we load it. In
+ // general this is difficult, but the loader tends to reload things in the
+ // same place, so we open, close, and then reopen. The global should always
+ // start out clean after dlopen.
+ for (int i = 0; i < 2; i++) {
+ void *lib = dlopen(path, RTLD_LAZY);
+ if (lib == NULL) {
+ printf("dlerror: %s\n", dlerror());
+ ASSERT_TRUE(lib != NULL);
+ }
+ void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global");
+ ASSERT_TRUE(get_dso_global != NULL);
+ void **dso_global = get_dso_global();
+ EXPECT_NOT_POISONED(*dso_global);
+ __msan_poison(dso_global, sizeof(*dso_global));
+ EXPECT_POISONED(*dso_global);
+ dlclose(lib);
+ }
+}
+
+// Regression test for a crash in dlopen() interceptor.
+TEST(MemorySanitizer, dlopenFailed) {
+ const char *path = "/libmsan_loadable_does_not_exist.so";
+ void *lib = dlopen(path, RTLD_LAZY);
+ ASSERT_TRUE(lib == NULL);
+}
+
+#endif // MSAN_TEST_DISABLE_DLOPEN
+
+// There's no sched_getaffinity() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sched_getaffinity) {
+ cpu_set_t mask;
+ int res = sched_getaffinity(getpid(), sizeof(mask), &mask);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(mask);
+}
+#endif
+
+TEST(MemorySanitizer, scanf) {
+ const char *input = "42 hello";
+ int* d = new int;
+ char* s = new char[7];
+ int res = sscanf(input, "%d %5s", d, s);
+ printf("res %d\n", res);
+ ASSERT_EQ(res, 2);
+ EXPECT_NOT_POISONED(*d);
+ EXPECT_NOT_POISONED(s[0]);
+ EXPECT_NOT_POISONED(s[1]);
+ EXPECT_NOT_POISONED(s[2]);
+ EXPECT_NOT_POISONED(s[3]);
+ EXPECT_NOT_POISONED(s[4]);
+ EXPECT_NOT_POISONED(s[5]);
+ EXPECT_POISONED(s[6]);
+ delete[] s;
+ delete d;
+}
+
+static void *SimpleThread_threadfn(void* data) {
+ return new int;
+}
+
+TEST(MemorySanitizer, SimpleThread) {
+ pthread_t t;
+ void *p;
+ int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(t);
+ res = pthread_join(t, &p);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(p);
+ delete (int*)p;
+}
+
+static void *SmallStackThread_threadfn(void* data) {
+ return 0;
+}
+
+#ifdef PTHREAD_STACK_MIN
+# define SMALLSTACKSIZE PTHREAD_STACK_MIN
+# define SMALLPRESTACKSIZE PTHREAD_STACK_MIN
+#else
+# define SMALLSTACKSIZE 64 * 1024
+# define SMALLPRESTACKSIZE 16 * 1024
+#endif
+
+TEST(MemorySanitizer, SmallStackThread) {
+ pthread_attr_t attr;
+ pthread_t t;
+ void *p;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_setstacksize(&attr, SMALLSTACKSIZE);
+ ASSERT_EQ(0, res);
+ res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
+ ASSERT_EQ(0, res);
+ res = pthread_join(t, &p);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
+ pthread_attr_t attr;
+ pthread_t t;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ void *stack;
+ const size_t kStackSize = SMALLPRESTACKSIZE;
+ res = posix_memalign(&stack, 4096, kStackSize);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_setstack(&attr, stack, kStackSize);
+ ASSERT_EQ(0, res);
+ res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
+ EXPECT_EQ(0, res);
+ res = pthread_join(t, NULL);
+ ASSERT_EQ(0, res);
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, pthread_attr_get) {
+ pthread_attr_t attr;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ {
+ int v;
+ res = pthread_attr_getdetachstate(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getguardsize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ struct sched_param v;
+ res = pthread_attr_getschedparam(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getschedpolicy(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getinheritsched(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getscope(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getstacksize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ void *v;
+ size_t w;
+ res = pthread_attr_getstack(&attr, &v, &w);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ EXPECT_NOT_POISONED(w);
+ }
+ {
+ cpu_set_t v;
+ res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, pthread_getschedparam) {
+ int policy;
+ struct sched_param param;
+ int res = pthread_getschedparam(pthread_self(), &policy, ¶m);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(policy);
+ EXPECT_NOT_POISONED(param.sched_priority);
+}
+
+TEST(MemorySanitizer, pthread_key_create) {
+ pthread_key_t key;
+ int res = pthread_key_create(&key, NULL);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(key);
+ res = pthread_key_delete(key);
+ ASSERT_EQ(0, res);
+}
+
+namespace {
+struct SignalCondArg {
+ pthread_cond_t* cond;
+ pthread_mutex_t* mu;
+ bool broadcast;
+};
+
+void *SignalCond(void *param) {
+ SignalCondArg *arg = reinterpret_cast<SignalCondArg *>(param);
+ pthread_mutex_lock(arg->mu);
+ if (arg->broadcast)
+ pthread_cond_broadcast(arg->cond);
+ else
+ pthread_cond_signal(arg->cond);
+ pthread_mutex_unlock(arg->mu);
+ return 0;
+}
+} // namespace
+
+TEST(MemorySanitizer, pthread_cond_wait) {
+ pthread_cond_t cond;
+ pthread_mutex_t mu;
+ SignalCondArg args = {&cond, &mu, false};
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&mu, 0);
+ pthread_mutex_lock(&mu);
+
+ // signal
+ pthread_t thr;
+ pthread_create(&thr, 0, SignalCond, &args);
+ int res = pthread_cond_wait(&cond, &mu);
+ ASSERT_EQ(0, res);
+ pthread_join(thr, 0);
+
+ // broadcast
+ args.broadcast = true;
+ pthread_create(&thr, 0, SignalCond, &args);
+ res = pthread_cond_wait(&cond, &mu);
+ ASSERT_EQ(0, res);
+ pthread_join(thr, 0);
+
+ pthread_mutex_unlock(&mu);
+ pthread_mutex_destroy(&mu);
+ pthread_cond_destroy(&cond);
+}
+
+TEST(MemorySanitizer, tmpnam) {
+ char s[L_tmpnam];
+ char *res = tmpnam(s);
+ ASSERT_EQ(s, res);
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
+TEST(MemorySanitizer, tempnam) {
+ char *res = tempnam(NULL, "zzz");
+ EXPECT_NOT_POISONED(strlen(res));
+ free(res);
+}
+
+TEST(MemorySanitizer, posix_memalign) {
+ void *p;
+ EXPECT_POISONED(p);
+ int res = posix_memalign(&p, 4096, 13);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(p);
+ EXPECT_EQ(0U, (uintptr_t)p % 4096);
+ free(p);
+}
+
+// There's no memalign() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, memalign) {
+ void *p = memalign(4096, 13);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ free(p);
+}
+#endif
+
+TEST(MemorySanitizer, valloc) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+
+// There's no pvalloc() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, pvalloc) {
+ void *p = pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p));
+ free(p);
+
+ p = pvalloc(0); // pvalloc(0) should allocate at least one page.
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p));
+ free(p);
+}
+#endif
+
+TEST(MemorySanitizer, inet_pton) {
+ const char *s = "1:0:0:0:0:0:0:8";
+ unsigned char buf[sizeof(struct in6_addr)];
+ int res = inet_pton(AF_INET6, s, buf);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]);
+
+ char s_out[INET6_ADDRSTRLEN];
+ EXPECT_POISONED(s_out[3]);
+ const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN);
+ ASSERT_NE((void*)0, q);
+ EXPECT_NOT_POISONED(s_out[3]);
+}
+
+TEST(MemorySanitizer, inet_aton) {
+ const char *s = "127.0.0.1";
+ struct in_addr in[2];
+ int res = inet_aton(s, in);
+ ASSERT_NE(0, res);
+ EXPECT_NOT_POISONED(in[0]);
+ EXPECT_POISONED(*(char *)(in + 1));
+}
+
+TEST(MemorySanitizer, uname) {
+ struct utsname u;
+ int res = uname(&u);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(strlen(u.sysname));
+ EXPECT_NOT_POISONED(strlen(u.nodename));
+ EXPECT_NOT_POISONED(strlen(u.release));
+ EXPECT_NOT_POISONED(strlen(u.version));
+ EXPECT_NOT_POISONED(strlen(u.machine));
+}
+
+TEST(MemorySanitizer, gethostname) {
+ char buf[100];
+ int res = gethostname(buf, 100);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(strlen(buf));
+}
+
+// There's no sysinfo() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, sysinfo) {
+ struct sysinfo info;
+ int res = sysinfo(&info);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(info);
+}
+#endif
+
+TEST(MemorySanitizer, getpwuid) {
+ struct passwd *p = getpwuid(0); // root
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ ASSERT_EQ(0U, p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwuid_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, getpwnam_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, getpwnam_r_positive) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char s[5];
+ strncpy(s, "abcd", 5);
+ __msan_poison(s, 5);
+ char buf[10000];
+ int res;
+ EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres));
+}
+
+TEST(MemorySanitizer, getgrnam_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ int res = getgrnam_r(SUPERUSER_GROUP, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ // Note that getgrnam_r() returns 0 if the matching group is not found.
+ ASSERT_NE(nullptr, grpres);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, getpwent) {
+ setpwent();
+ struct passwd *p = getpwent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwent_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ setpwent();
+ int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+// There's no fgetpwent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetpwent) {
+ FILE *fp = fopen("/etc/passwd", "r");
+ struct passwd *p = fgetpwent(fp);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgrent) {
+ setgrent();
+ struct group *p = getgrent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->gr_name);
+ ASSERT_TRUE(p->gr_name != NULL);
+ EXPECT_NOT_POISONED(p->gr_name[0]);
+ EXPECT_NOT_POISONED(p->gr_gid);
+}
+
+// There's no fgetgrent() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetgrent) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group *grp = fgetgrent(fp);
+ ASSERT_TRUE(grp != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name);
+ ASSERT_TRUE(grp->gr_name != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name[0]);
+ EXPECT_NOT_POISONED(grp->gr_gid);
+ for (char **p = grp->gr_mem; *p; ++p) {
+ EXPECT_NOT_POISONED((*p)[0]);
+ EXPECT_TRUE(strlen(*p) > 0);
+ }
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgrent_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = getgrent_r(&grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+// There's no fgetgrent_r() on FreeBSD.
+#if !defined(__FreeBSD__)
+TEST(MemorySanitizer, fgetgrent_r) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+ fclose(fp);
+}
+#endif
+
+TEST(MemorySanitizer, getgroups) {
+ int n = getgroups(0, 0);
+ gid_t *gids = new gid_t[n];
+ int res = getgroups(n, gids);
+ ASSERT_EQ(n, res);
+ for (int i = 0; i < n; ++i)
+ EXPECT_NOT_POISONED(gids[i]);
+}
+
+TEST(MemorySanitizer, wordexp) {
+ wordexp_t w;
+ int res = wordexp("a b c", &w, 0);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(3U, w.we_wordc);
+ ASSERT_STREQ("a", w.we_wordv[0]);
+ ASSERT_STREQ("b", w.we_wordv[1]);
+ ASSERT_STREQ("c", w.we_wordv[2]);
+}
+
+template<class T>
+static bool applySlt(T value, T shadow) {
+ __msan_partial_poison(&value, &shadow, sizeof(T));
+ volatile bool zzz = true;
+ // This "|| zzz" trick somehow makes LLVM emit "icmp slt" instead of
+ // a shift-and-trunc to get at the highest bit.
+ volatile bool v = value < 0 || zzz;
+ return v;
+}
+
+TEST(MemorySanitizer, SignedCompareWithZero) {
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFFFFFF));
+ EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0x7FFFFFF));
+ EXPECT_UMR(applySlt<S4>(0xF, 0x80FFFFFF));
+ EXPECT_UMR(applySlt<S4>(0xF, 0xFFFFFFFF));
+}
+
+template <class T, class S>
+static T poisoned(T Va, S Sa) {
+ char SIZE_CHECK1[(ssize_t)sizeof(T) - (ssize_t)sizeof(S)];
+ char SIZE_CHECK2[(ssize_t)sizeof(S) - (ssize_t)sizeof(T)];
+ T a;
+ a = Va;
+ __msan_partial_poison(&a, &Sa, sizeof(T));
+ return a;
+}
+
+TEST(MemorySanitizer, ICmpRelational) {
+ EXPECT_NOT_POISONED(poisoned(0, 0) < poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) < poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) < poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) < poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) < poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) <= poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) <= poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) <= poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) <= poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) <= poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <=
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <=
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) > poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) > poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) > poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) > poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) > poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_NOT_POISONED(poisoned(0, 0) >= poisoned(0, 0));
+ EXPECT_NOT_POISONED(poisoned(0U, 0) >= poisoned(0U, 0));
+ EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) >= poisoned(0LL, 0LLU));
+ EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) >= poisoned(0LLU, 0LLU));
+ EXPECT_POISONED(poisoned(0xFF, 0xFF) >= poisoned(0xFF, 0xFF));
+ EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >=
+ poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
+ EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >=
+ poisoned(-1, 0xFFFFFFFFU));
+
+ EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0));
+ EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0));
+
+ EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U));
+}
+
+#if MSAN_HAS_M128
+TEST(MemorySanitizer, ICmpVectorRelational) {
+ EXPECT_NOT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)),
+ poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0))));
+ EXPECT_NOT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)),
+ poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0))));
+ EXPECT_POISONED(
+ _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)),
+ poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF))));
+ EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)),
+ poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0))));
+}
+#endif
+
+// Volatile bitfield store is implemented as load-mask-store
+// Test that we don't warn on the store of (uninitialized) padding.
+struct VolatileBitfieldStruct {
+ volatile unsigned x : 1;
+ unsigned y : 1;
+};
+
+TEST(MemorySanitizer, VolatileBitfield) {
+ VolatileBitfieldStruct *S = new VolatileBitfieldStruct;
+ S->x = 1;
+ EXPECT_NOT_POISONED((unsigned)S->x);
+ EXPECT_POISONED((unsigned)S->y);
+}
+
+TEST(MemorySanitizer, UnalignedLoad) {
+ char x[32] __attribute__((aligned(8)));
+ U4 origin = __LINE__;
+ for (unsigned i = 0; i < sizeof(x) / 4; ++i)
+ __msan_set_origin(x + 4 * i, 4, origin + i);
+
+ memset(x + 8, 0, 16);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6);
+}
+
+TEST(MemorySanitizer, UnalignedStore16) {
+ char x[5] __attribute__((aligned(4)));
+ U2 y2 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y2, 1);
+ __msan_set_origin(&y2, 1, origin);
+
+ __sanitizer_unaligned_store16(x + 1, y2);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore32) {
+ char x[8] __attribute__((aligned(4)));
+ U4 y4 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y4, 2);
+ __msan_set_origin(&y4, 2, origin);
+
+ __sanitizer_unaligned_store32(x + 3, y4);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_POISONED_O(x[7], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore64) {
+ char x[16] __attribute__((aligned(8)));
+ U8 y8 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y8, 3);
+ __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1);
+ __msan_set_origin(&y8, 8, origin);
+
+ __sanitizer_unaligned_store64(x + 3, y8);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_POISONED_O(x[5], origin);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], origin);
+ EXPECT_NOT_POISONED(x[10]);
+ EXPECT_POISONED_O(x[11], origin);
+}
+
+TEST(MemorySanitizer, UnalignedStore16_precise) {
+ char x[8] __attribute__((aligned(4)));
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_POISONED_O(x[2], originx1);
+ EXPECT_NOT_POISONED(x[3]);
+ EXPECT_POISONED_O(x[4], originy);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+}
+
+TEST(MemorySanitizer, UnalignedStore16_precise2) {
+ char x[8] __attribute__((aligned(4)));
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y), 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_POISONED_O(x[2], originy);
+ EXPECT_POISONED_O(x[3], originy);
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originx2);
+ EXPECT_POISONED_O(x[6], originx2);
+ EXPECT_POISONED_O(x[7], originx2);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise) {
+ char x[12] __attribute__((aligned(8)));
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_poison(((char *)&y) + 7, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], originy);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], originy);
+ EXPECT_POISONED_O(x[10], originy);
+ EXPECT_POISONED_O(x[11], originy);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise2) {
+ char x[12] __attribute__((aligned(8)));
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 3, 3);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_NOT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[10], originx3);
+ EXPECT_POISONED_O(x[11], originx3);
+}
+
+#if (defined(__x86_64__) && defined(__clang__))
+namespace {
+typedef U1 V16x8 __attribute__((__vector_size__(16)));
+typedef U2 V8x16 __attribute__((__vector_size__(16)));
+typedef U4 V4x32 __attribute__((__vector_size__(16)));
+typedef U8 V2x64 __attribute__((__vector_size__(16)));
+typedef U4 V8x32 __attribute__((__vector_size__(32)));
+typedef U8 V4x64 __attribute__((__vector_size__(32)));
+typedef U4 V2x32 __attribute__((__vector_size__(8)));
+typedef U2 V4x16 __attribute__((__vector_size__(8)));
+typedef U1 V8x8 __attribute__((__vector_size__(8)));
+
+
+V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {
+ return _mm_slli_epi16(x, y);
+}
+
+V8x16 shift_sse2_left(V8x16 x, V8x16 y) {
+ return _mm_sll_epi16(x, y);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, 2);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar_by_uninit) {
+ V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, Poisoned<U4>());
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+TEST(VectorShiftTest, sse2_left) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ // Top 64 bits of shift count don't affect the result.
+ V2x64 s = {2, Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_by_uninit) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V2x64 s = {Poisoned<U8>(), Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+#ifdef __AVX2__
+V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+ return _mm_sllv_epi32(x, y);
+}
+// This is variable vector shift that's only available starting with AVX2.
+// V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+TEST(VectorShiftTest, avx2_left) {
+ V4x32 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3};
+ V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()};
+ V4x32 u = shift_avx2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_NOT_POISONED(u[0] | (~7U));
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[1] | (~31U));
+ EXPECT_NOT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[3] | (~31U));
+}
+#endif // __AVX2__
+} // namespace
+
+TEST(VectorPackTest, sse2_packssdw_128) {
+ const unsigned S2_max = (1 << 15) - 1;
+ V4x32 a = {Poisoned<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000),
+ S2_max + 100, 4};
+ V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(0, 0xFF00),
+ S2_max};
+
+ V8x16 c = _mm_packs_epi32(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], S2_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], S2_max);
+ EXPECT_EQ(c[7], S2_max);
+}
+
+TEST(VectorPackTest, mmx_packuswb) {
+ const unsigned U1_max = (1 << 8) - 1;
+ V4x16 a = {Poisoned<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100,
+ 4};
+ V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(0, 0xF), U1_max};
+ V8x8 c = _mm_packs_pu16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], U1_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], U1_max - 1);
+ EXPECT_EQ(c[7], U1_max);
+}
+
+TEST(VectorSadTest, sse2_psad_bw) {
+ V16x8 a = {Poisoned<U1>(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115};
+ V2x64 c = _mm_sad_epu8(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ(800U, c[1]);
+}
+
+TEST(VectorMaddTest, mmx_pmadd_wd) {
+ V4x16 a = {Poisoned<U2>(), 1, 2, 3};
+ V4x16 b = {100, 101, 102, 103};
+ V2x32 c = _mm_madd_pi16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]);
+}
+#endif // defined(__clang__)
+
+TEST(MemorySanitizerOrigins, SetGet) {
+ EXPECT_EQ(TrackingOrigins(), !!__msan_get_track_origins());
+ if (!TrackingOrigins()) return;
+ int x;
+ __msan_set_origin(&x, sizeof(x), 1234);
+ EXPECT_ORIGIN(1234U, __msan_get_origin(&x));
+ __msan_set_origin(&x, sizeof(x), 5678);
+ EXPECT_ORIGIN(5678U, __msan_get_origin(&x));
+ __msan_set_origin(&x, sizeof(x), 0);
+ EXPECT_ORIGIN(0U, __msan_get_origin(&x));
+}
+
+namespace {
+struct S {
+ U4 dummy;
+ U2 a;
+ U2 b;
+};
+
+TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) {
+ if (!TrackingOrigins()) return;
+
+ S s;
+ U4 origin = rand(); // NOLINT
+ s.a = *GetPoisonedO<U2>(0, origin);
+ EXPECT_ORIGIN(origin, __msan_get_origin(&s.a));
+ EXPECT_ORIGIN(origin, __msan_get_origin(&s.b));
+
+ s.b = 42;
+ EXPECT_ORIGIN(origin, __msan_get_origin(&s.a));
+ EXPECT_ORIGIN(origin, __msan_get_origin(&s.b));
+}
+} // namespace
+
+template<class T, class BinaryOp>
+INLINE
+void BinaryOpOriginTest(BinaryOp op) {
+ U4 ox = rand(); //NOLINT
+ U4 oy = rand(); //NOLINT
+ T *x = GetPoisonedO<T>(0, ox, 0);
+ T *y = GetPoisonedO<T>(1, oy, 0);
+ T *z = GetPoisonedO<T>(2, 0, 0);
+
+ *z = op(*x, *y);
+ U4 origin = __msan_get_origin(z);
+ EXPECT_POISONED_O(*z, origin);
+ EXPECT_EQ(true, __msan_origin_is_descendant_or_same(origin, ox) ||
+ __msan_origin_is_descendant_or_same(origin, oy));
+
+ // y is poisoned, x is not.
+ *x = 10101;
+ *y = *GetPoisonedO<T>(1, oy);
+ break_optimization(x);
+ __msan_set_origin(z, sizeof(*z), 0);
+ *z = op(*x, *y);
+ EXPECT_POISONED_O(*z, oy);
+ EXPECT_ORIGIN(oy, __msan_get_origin(z));
+
+ // x is poisoned, y is not.
+ *x = *GetPoisonedO<T>(0, ox);
+ *y = 10101010;
+ break_optimization(y);
+ __msan_set_origin(z, sizeof(*z), 0);
+ *z = op(*x, *y);
+ EXPECT_POISONED_O(*z, ox);
+ EXPECT_ORIGIN(ox, __msan_get_origin(z));
+}
+
+template<class T> INLINE T XOR(const T &a, const T&b) { return a ^ b; }
+template<class T> INLINE T ADD(const T &a, const T&b) { return a + b; }
+template<class T> INLINE T SUB(const T &a, const T&b) { return a - b; }
+template<class T> INLINE T MUL(const T &a, const T&b) { return a * b; }
+template<class T> INLINE T AND(const T &a, const T&b) { return a & b; }
+template<class T> INLINE T OR (const T &a, const T&b) { return a | b; }
+
+TEST(MemorySanitizerOrigins, BinaryOp) {
+ if (!TrackingOrigins()) return;
+ BinaryOpOriginTest<S8>(XOR<S8>);
+ BinaryOpOriginTest<U8>(ADD<U8>);
+ BinaryOpOriginTest<S4>(SUB<S4>);
+ BinaryOpOriginTest<S4>(MUL<S4>);
+ BinaryOpOriginTest<U4>(OR<U4>);
+ BinaryOpOriginTest<U4>(AND<U4>);
+ BinaryOpOriginTest<double>(ADD<U4>);
+ BinaryOpOriginTest<float>(ADD<S4>);
+ BinaryOpOriginTest<double>(ADD<double>);
+ BinaryOpOriginTest<float>(ADD<double>);
+}
+
+TEST(MemorySanitizerOrigins, Unary) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+
+ EXPECT_POISONED_O((void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O((U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, EQ) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, DIV) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__);
+ unsigned o = __LINE__;
+ EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO<S4>(0, o, 1), o);
+}
+
+TEST(MemorySanitizerOrigins, SHIFT) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__);
+ EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__);
+ EXPECT_POISONED_O(10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(-10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__);
+ EXPECT_POISONED_O(-10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__);
+}
+
+template<class T, int N>
+void MemCpyTest() {
+ int ox = __LINE__;
+ T *x = new T[N];
+ T *y = new T[N];
+ T *z = new T[N];
+ T *q = new T[N];
+ __msan_poison(x, N * sizeof(T));
+ __msan_set_origin(x, N * sizeof(T), ox);
+ __msan_set_origin(y, N * sizeof(T), 777777);
+ __msan_set_origin(z, N * sizeof(T), 888888);
+ EXPECT_NOT_POISONED(x);
+ memcpy(y, x, N * sizeof(T));
+ EXPECT_POISONED_O(y[0], ox);
+ EXPECT_POISONED_O(y[N/2], ox);
+ EXPECT_POISONED_O(y[N-1], ox);
+ EXPECT_NOT_POISONED(x);
+ void *res = mempcpy(q, x, N * sizeof(T));
+ ASSERT_EQ(q + N, res);
+ EXPECT_POISONED_O(q[0], ox);
+ EXPECT_POISONED_O(q[N/2], ox);
+ EXPECT_POISONED_O(q[N-1], ox);
+ EXPECT_NOT_POISONED(x);
+ memmove(z, x, N * sizeof(T));
+ EXPECT_POISONED_O(z[0], ox);
+ EXPECT_POISONED_O(z[N/2], ox);
+ EXPECT_POISONED_O(z[N-1], ox);
+}
+
+TEST(MemorySanitizerOrigins, LargeMemCpy) {
+ if (!TrackingOrigins()) return;
+ MemCpyTest<U1, 10000>();
+ MemCpyTest<U8, 10000>();
+}
+
+TEST(MemorySanitizerOrigins, SmallMemCpy) {
+ if (!TrackingOrigins()) return;
+ MemCpyTest<U8, 1>();
+ MemCpyTest<U8, 2>();
+ MemCpyTest<U8, 3>();
+}
+
+TEST(MemorySanitizerOrigins, Select) {
+ if (!TrackingOrigins()) return;
+ EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__));
+ EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
+ S4 x;
+ break_optimization(&x);
+ x = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 0;
+
+ EXPECT_POISONED_O(g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__);
+ EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__);
+}
+
+NOINLINE int RetvalOriginTest(U4 origin) {
+ int *a = new int;
+ break_optimization(a);
+ __msan_set_origin(a, sizeof(*a), origin);
+ int res = *a;
+ delete a;
+ return res;
+}
+
+TEST(MemorySanitizerOrigins, Retval) {
+ if (!TrackingOrigins()) return;
+ EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
+}
+
+NOINLINE void ParamOriginTest(int param, U4 origin) {
+ EXPECT_POISONED_O(param, origin);
+}
+
+TEST(MemorySanitizerOrigins, Param) {
+ if (!TrackingOrigins()) return;
+ int *a = new int;
+ U4 origin = __LINE__;
+ break_optimization(a);
+ __msan_set_origin(a, sizeof(*a), origin);
+ ParamOriginTest(*a, origin);
+ delete a;
+}
+
+TEST(MemorySanitizerOrigins, Invoke) {
+ if (!TrackingOrigins()) return;
+ StructWithDtor s; // Will cause the calls to become invokes.
+ EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
+}
+
+TEST(MemorySanitizerOrigins, strlen) {
+ S8 alignment;
+ break_optimization(&alignment);
+ char x[4] = {'a', 'b', 0, 0};
+ __msan_poison(&x[2], 1);
+ U4 origin = __LINE__;
+ __msan_set_origin(x, sizeof(x), origin);
+ EXPECT_UMR_O(volatile unsigned y = strlen(x), origin);
+}
+
+TEST(MemorySanitizerOrigins, wcslen) {
+ wchar_t w[3] = {'a', 'b', 0};
+ U4 origin = __LINE__;
+ __msan_set_origin(w, sizeof(w), origin);
+ __msan_poison(&w[2], sizeof(wchar_t));
+ EXPECT_UMR_O(volatile unsigned y = wcslen(w), origin);
+}
+
+#if MSAN_HAS_M128
+TEST(MemorySanitizerOrigins, StoreIntrinsic) {
+ __m128 x, y;
+ U4 origin = __LINE__;
+ __msan_set_origin(&x, sizeof(x), origin);
+ __msan_poison(&x, sizeof(x));
+ __builtin_ia32_storeups((float*)&y, x);
+ EXPECT_POISONED_O(y, origin);
+}
+#endif
+
+NOINLINE void RecursiveMalloc(int depth) {
+ static int count;
+ count++;
+ if ((count % (1024 * 1024)) == 0)
+ printf("RecursiveMalloc: %d\n", count);
+ int *x1 = new int;
+ int *x2 = new int;
+ break_optimization(x1);
+ break_optimization(x2);
+ if (depth > 0) {
+ RecursiveMalloc(depth-1);
+ RecursiveMalloc(depth-1);
+ }
+ delete x1;
+ delete x2;
+}
+
+TEST(MemorySanitizer, Select) {
+ int x;
+ int volatile* p = &x;
+ int z = *p ? 1 : 0;
+ EXPECT_POISONED(z);
+}
+
+TEST(MemorySanitizer, SelectPartial) {
+ // Precise instrumentation of select.
+ // Some bits of the result do not depend on select condition, and must stay
+ // initialized even if select condition is not. These are the bits that are
+ // equal and initialized in both left and right select arguments.
+ U4 x = 0xFFFFABCDU;
+ U4 x_s = 0xFFFF0000U;
+ __msan_partial_poison(&x, &x_s, sizeof(x));
+ U4 y = 0xAB00U;
+ U1 cond = true;
+ __msan_poison(&cond, sizeof(cond));
+ U4 z = cond ? x : y;
+ __msan_print_shadow(&z, sizeof(z));
+ EXPECT_POISONED(z & 0xFFU);
+ EXPECT_NOT_POISONED(z & 0xFF00U);
+ EXPECT_POISONED(z & 0xFF0000U);
+ EXPECT_POISONED(z & 0xFF000000U);
+ EXPECT_EQ(0xAB00U, z & 0xFF00U);
+}
+
+TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
+ RecursiveMalloc(22);
+}
+
+TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
+ size_t sizes[] = {0, 20, 5000, 1<<20};
+ for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
+ size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]);
+ EXPECT_EQ(alloc_size, sizes[i]);
+ }
+}
+
+TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
+ char *array = reinterpret_cast<char*>(malloc(100));
+ int *int_ptr = new int;
+
+ EXPECT_TRUE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(100U, __sanitizer_get_allocated_size(array));
+
+ EXPECT_TRUE(__sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr));
+
+ void *wild_addr = reinterpret_cast<void*>(0x1);
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr));
+
+ EXPECT_FALSE(__sanitizer_get_ownership(array + 50));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50));
+
+ // NULL is a valid argument for GetAllocatedSize but is not owned.
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
+
+ free(array);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array));
+
+ delete int_ptr;
+}
+
+TEST(MemorySanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+
+// Test that LargeAllocator unpoisons memory before releasing it to the OS.
+TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
+ void *p = malloc(1024 * 1024);
+ free(p);
+
+ typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t);
+ mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap");
+
+ // Allocate the page that was released to the OS in free() with the real mmap,
+ // bypassing the interceptor.
+ char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE((char *)0, q);
+
+ ASSERT_TRUE(q <= p);
+ ASSERT_TRUE(q + 4096 > p);
+
+ EXPECT_NOT_POISONED(q[0]);
+ EXPECT_NOT_POISONED(q[10]);
+ EXPECT_NOT_POISONED(q[100]);
+
+ munmap(q, 4096);
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+TEST(MemorySanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ free(array);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
diff --git a/compiler-rt/lib/msan/tests/msan_test_config.h b/compiler-rt/lib/msan/tests/msan_test_config.h
new file mode 100644
index 0000000..5404c43
--- /dev/null
+++ b/compiler-rt/lib/msan/tests/msan_test_config.h
@@ -0,0 +1,20 @@
+//===-- msan_test_config.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_TEST_CONFIG_H
+#define MSAN_TEST_CONFIG_H
+
+#include "gtest/gtest.h"
+
+#endif // MSAN_TEST_CONFIG_H
diff --git a/compiler-rt/lib/msan/tests/msan_test_main.cc b/compiler-rt/lib/msan/tests/msan_test_main.cc
new file mode 100644
index 0000000..c8c5fef
--- /dev/null
+++ b/compiler-rt/lib/msan/tests/msan_test_main.cc
@@ -0,0 +1,21 @@
+//===-- msan_test_main.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/compiler-rt/lib/profile/Android.bp b/compiler-rt/lib/profile/Android.bp
new file mode 100644
index 0000000..a0059e5
--- /dev/null
+++ b/compiler-rt/lib/profile/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//=====================================================================
+// Static Library: libprofile_rt
+//=====================================================================
+
+cc_library_static {
+ name: "libprofile_rt",
+ host_supported: true,
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ clang: true,
+ srcs: [
+ "GCDAProfiling.c",
+ "InstrProfiling.c",
+ "InstrProfilingBuffer.c",
+ "InstrProfilingFile.c",
+ "InstrProfilingPlatformDarwin.c",
+ "InstrProfilingPlatformOther.c",
+ "InstrProfilingRuntime.cc",
+ "InstrProfilingUtil.c",
+ ],
+
+ sanitize: {
+ never: true,
+ },
+ compile_multilib: "both",
+ stl: "none",
+ sdk_version: "21",
+}
diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt
new file mode 100644
index 0000000..1b10ade
--- /dev/null
+++ b/compiler-rt/lib/profile/CMakeLists.txt
@@ -0,0 +1,71 @@
+
+CHECK_CXX_SOURCE_COMPILES("
+#ifdef _MSC_VER
+#include <Intrin.h> /* Workaround for PR19898. */
+#include <windows.h>
+#endif
+int main() {
+#ifdef _MSC_VER
+ volatile LONG val = 1;
+ MemoryBarrier();
+ InterlockedCompareExchange(&val, 0, 1);
+ InterlockedIncrement(&val);
+ InterlockedDecrement(&val);
+#else
+ volatile unsigned long val = 1;
+ __sync_synchronize();
+ __sync_val_compare_and_swap(&val, 1, 0);
+ __sync_add_and_fetch(&val, 1);
+ __sync_sub_and_fetch(&val, 1);
+#endif
+ return 0;
+ }
+" COMPILER_RT_TARGET_HAS_ATOMICS)
+
+add_custom_target(profile)
+
+set(PROFILE_SOURCES
+ GCDAProfiling.c
+ InstrProfiling.c
+ InstrProfilingValue.c
+ InstrProfilingBuffer.c
+ InstrProfilingFile.c
+ InstrProfilingWriter.c
+ InstrProfilingPlatformDarwin.c
+ InstrProfilingPlatformLinux.c
+ InstrProfilingPlatformOther.c
+ InstrProfilingRuntime.cc
+ InstrProfilingUtil.c)
+
+if(UNIX)
+ set(EXTRA_FLAGS
+ -fPIC
+ -Wno-pedantic)
+else()
+ set(EXTRA_FLAGS
+ -fPIC)
+endif()
+
+if(COMPILER_RT_TARGET_HAS_ATOMICS)
+ set(EXTRA_FLAGS
+ ${EXTRA_FLAGS}
+ -DCOMPILER_RT_HAS_ATOMICS=1)
+endif()
+
+if(APPLE)
+ add_compiler_rt_runtime(clang_rt.profile
+ STATIC
+ OS ${PROFILE_SUPPORTED_OS}
+ ARCHS ${PROFILE_SUPPORTED_ARCH}
+ SOURCES ${PROFILE_SOURCES}
+ PARENT_TARGET profile)
+else()
+ add_compiler_rt_runtime(clang_rt.profile
+ STATIC
+ ARCHS ${PROFILE_SUPPORTED_ARCH}
+ CFLAGS ${EXTRA_FLAGS}
+ SOURCES ${PROFILE_SOURCES}
+ PARENT_TARGET profile)
+endif()
+
+add_dependencies(compiler-rt profile)
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
new file mode 100644
index 0000000..aec2328
--- /dev/null
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -0,0 +1,572 @@
+/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the gcov profiling
+|* instrumentation pass. Link against this library when running code through
+|* the -insert-gcov-profiling LLVM pass.
+|*
+|* We emit files in a corrupt version of GCOV's "gcda" file format. These files
+|* are only close enough that LCOV will happily parse them. Anything that lcov
+|* ignores is missing.
+|*
+|* TODO: gcov is multi-process safe by having each exit open the existing file
+|* and append to it. We'd like to achieve that and be thread-safe too.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfilingUtil.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
+
+#if !defined(_MSC_VER) && !I386_FREEBSD
+#include <stdint.h>
+#endif
+
+#if defined(_MSC_VER)
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#elif I386_FREEBSD
+/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
+ * FreeBSD 10, r232261) when compiled in 32-bit mode.
+ */
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+/* #define DEBUG_GCDAPROFILING */
+
+/*
+ * --- GCOV file format I/O primitives ---
+ */
+
+/*
+ * The current file name we're outputting. Used primarily for error logging.
+ */
+static char *filename = NULL;
+
+/*
+ * The current file we're outputting.
+ */
+static FILE *output_file = NULL;
+
+/*
+ * Buffer that we write things into.
+ */
+#define WRITE_BUFFER_SIZE (128 * 1024)
+static char *write_buffer = NULL;
+static uint64_t cur_buffer_size = 0;
+static uint64_t cur_pos = 0;
+static uint64_t file_size = 0;
+static int new_file = 0;
+static int fd = -1;
+
+/*
+ * A list of functions to write out the data.
+ */
+typedef void (*writeout_fn)();
+
+struct writeout_fn_node {
+ writeout_fn fn;
+ struct writeout_fn_node *next;
+};
+
+static struct writeout_fn_node *writeout_fn_head = NULL;
+static struct writeout_fn_node *writeout_fn_tail = NULL;
+
+/*
+ * A list of flush functions that our __gcov_flush() function should call.
+ */
+typedef void (*flush_fn)();
+
+struct flush_fn_node {
+ flush_fn fn;
+ struct flush_fn_node *next;
+};
+
+static struct flush_fn_node *flush_fn_head = NULL;
+static struct flush_fn_node *flush_fn_tail = NULL;
+
+static void resize_write_buffer(uint64_t size) {
+ if (!new_file) return;
+ size += cur_pos;
+ if (size <= cur_buffer_size) return;
+ size = (size - 1) / WRITE_BUFFER_SIZE + 1;
+ size *= WRITE_BUFFER_SIZE;
+ write_buffer = realloc(write_buffer, size);
+ cur_buffer_size = size;
+}
+
+static void write_bytes(const char *s, size_t len) {
+ resize_write_buffer(len);
+ memcpy(&write_buffer[cur_pos], s, len);
+ cur_pos += len;
+}
+
+static void write_32bit_value(uint32_t i) {
+ write_bytes((char*)&i, 4);
+}
+
+static void write_64bit_value(uint64_t i) {
+ write_bytes((char*)&i, 8);
+}
+
+static uint32_t length_of_string(const char *s) {
+ return (strlen(s) / 4) + 1;
+}
+
+static void write_string(const char *s) {
+ uint32_t len = length_of_string(s);
+ write_32bit_value(len);
+ write_bytes(s, strlen(s));
+ write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
+}
+
+static uint32_t read_32bit_value() {
+ uint32_t val;
+
+ if (new_file)
+ return (uint32_t)-1;
+
+ val = *(uint32_t*)&write_buffer[cur_pos];
+ cur_pos += 4;
+ return val;
+}
+
+static uint64_t read_64bit_value() {
+ uint64_t val;
+
+ if (new_file)
+ return (uint64_t)-1;
+
+ val = *(uint64_t*)&write_buffer[cur_pos];
+ cur_pos += 8;
+ return val;
+}
+
+static char *mangle_filename(const char *orig_filename) {
+ char *new_filename;
+ size_t filename_len, prefix_len;
+ int prefix_strip;
+ int level = 0;
+ const char *fname, *ptr;
+ const char *prefix = getenv("GCOV_PREFIX");
+ const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");
+
+ if (prefix == NULL || prefix[0] == '\0')
+ return strdup(orig_filename);
+
+ if (prefix_strip_str) {
+ prefix_strip = atoi(prefix_strip_str);
+
+ /* Negative GCOV_PREFIX_STRIP values are ignored */
+ if (prefix_strip < 0)
+ prefix_strip = 0;
+ } else {
+ prefix_strip = 0;
+ }
+
+ fname = orig_filename;
+ for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) {
+ if (*ptr == '\0')
+ break;
+ if (*ptr != '/')
+ continue;
+ fname = ptr;
+ ++level;
+ }
+
+ filename_len = strlen(fname);
+ prefix_len = strlen(prefix);
+ new_filename = malloc(prefix_len + 1 + filename_len + 1);
+ memcpy(new_filename, prefix, prefix_len);
+
+ if (prefix[prefix_len - 1] != '/')
+ new_filename[prefix_len++] = '/';
+ memcpy(new_filename + prefix_len, fname, filename_len + 1);
+
+ return new_filename;
+}
+
+static int map_file() {
+ fseek(output_file, 0L, SEEK_END);
+ file_size = ftell(output_file);
+
+ /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an
+ * error message because it should "just work" for the user. */
+ if (file_size == 0)
+ return -1;
+
+ write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd, 0);
+ if (write_buffer == (void *)-1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot map: %s\n", filename,
+ strerror(errnum));
+ return -1;
+ }
+ return 0;
+}
+
+static void unmap_file() {
+ if (msync(write_buffer, file_size, MS_SYNC) == -1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
+ strerror(errnum));
+ }
+
+ /* We explicitly ignore errors from unmapping because at this point the data
+ * is written and we don't care.
+ */
+ (void)munmap(write_buffer, file_size);
+ write_buffer = NULL;
+ file_size = 0;
+}
+
+/*
+ * --- LLVM line counter API ---
+ */
+
+/* A file in this case is a translation unit. Each .o file built with line
+ * profiling enabled will emit to a different file. Only one file may be
+ * started at a time.
+ */
+void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+ uint32_t checksum) {
+ const char *mode = "r+b";
+ filename = mangle_filename(orig_filename);
+
+ /* Try just opening the file. */
+ new_file = 0;
+ fd = open(filename, O_RDWR);
+
+ if (fd == -1) {
+ /* Try opening the file, creating it if necessary. */
+ new_file = 1;
+ mode = "w+b";
+ fd = open(filename, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) {
+ /* Try creating the directories first then opening the file. */
+ __llvm_profile_recursive_mkdir(filename);
+ fd = open(filename, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) {
+ /* Bah! It's hopeless. */
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+ strerror(errnum));
+ return;
+ }
+ }
+ }
+
+ /* Try to flock the file to serialize concurrent processes writing out to the
+ * same GCDA. This can fail if the filesystem doesn't support it, but in that
+ * case we'll just carry on with the old racy behaviour and hope for the best.
+ */
+ flock(fd, LOCK_EX);
+ output_file = fdopen(fd, mode);
+
+ /* Initialize the write buffer. */
+ write_buffer = NULL;
+ cur_buffer_size = 0;
+ cur_pos = 0;
+
+ if (new_file) {
+ resize_write_buffer(WRITE_BUFFER_SIZE);
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ } else {
+ if (map_file() == -1) {
+ /* mmap failed, try to recover by clobbering */
+ new_file = 1;
+ write_buffer = NULL;
+ cur_buffer_size = 0;
+ resize_write_buffer(WRITE_BUFFER_SIZE);
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ }
+ }
+
+ /* gcda file, version, stamp checksum. */
+ write_bytes("adcg", 4);
+ write_bytes(version, 4);
+ write_32bit_value(checksum);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
+#endif
+}
+
+/* Given an array of pointers to counters (counters), increment the n-th one,
+ * where we're also given a pointer to n (predecessor).
+ */
+void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
+ uint64_t **counters) {
+ uint64_t *counter;
+ uint32_t pred;
+
+ pred = *predecessor;
+ if (pred == 0xffffffff)
+ return;
+ counter = counters[pred];
+
+ /* Don't crash if the pred# is out of sync. This can happen due to threads,
+ or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
+ if (counter)
+ ++*counter;
+#ifdef DEBUG_GCDAPROFILING
+ else
+ fprintf(stderr,
+ "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n",
+ *counter, *predecessor);
+#endif
+}
+
+void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
+ uint32_t func_checksum, uint8_t use_extra_checksum,
+ uint32_t cfg_checksum) {
+ uint32_t len = 2;
+
+ if (use_extra_checksum)
+ len++;
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident,
+ function_name ? function_name : "NULL");
+#endif
+ if (!output_file) return;
+
+ /* function tag */
+ write_bytes("\0\0\0\1", 4);
+ if (function_name)
+ len += 1 + length_of_string(function_name);
+ write_32bit_value(len);
+ write_32bit_value(ident);
+ write_32bit_value(func_checksum);
+ if (use_extra_checksum)
+ write_32bit_value(cfg_checksum);
+ if (function_name)
+ write_string(function_name);
+}
+
+void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
+ uint32_t i;
+ uint64_t *old_ctrs = NULL;
+ uint32_t val = 0;
+ uint64_t save_cur_pos = cur_pos;
+
+ if (!output_file) return;
+
+ val = read_32bit_value();
+
+ if (val != (uint32_t)-1) {
+ /* There are counters present in the file. Merge them. */
+ if (val != 0x01a10000) {
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "corrupt arc tag (0x%08x)\n",
+ filename, val);
+ return;
+ }
+
+ val = read_32bit_value();
+ if (val == (uint32_t)-1 || val / 2 != num_counters) {
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "mismatched number of counters (%d)\n",
+ filename, val);
+ return;
+ }
+
+ old_ctrs = malloc(sizeof(uint64_t) * num_counters);
+ for (i = 0; i < num_counters; ++i)
+ old_ctrs[i] = read_64bit_value();
+ }
+
+ cur_pos = save_cur_pos;
+
+ /* Counter #1 (arcs) tag */
+ write_bytes("\0\0\xa1\1", 4);
+ write_32bit_value(num_counters * 2);
+ for (i = 0; i < num_counters; ++i) {
+ counters[i] += (old_ctrs ? old_ctrs[i] : 0);
+ write_64bit_value(counters[i]);
+ }
+
+ free(old_ctrs);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: %u arcs\n", num_counters);
+ for (i = 0; i < num_counters; ++i)
+ fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]);
+#endif
+}
+
+void llvm_gcda_summary_info() {
+ const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
+ uint32_t i;
+ uint32_t runs = 1;
+ uint32_t val = 0;
+ uint64_t save_cur_pos = cur_pos;
+
+ if (!output_file) return;
+
+ val = read_32bit_value();
+
+ if (val != (uint32_t)-1) {
+ /* There are counters present in the file. Merge them. */
+ if (val != 0xa1000000) {
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "corrupt object tag (0x%08x)\n",
+ filename, val);
+ return;
+ }
+
+ val = read_32bit_value(); /* length */
+ if (val != obj_summary_len) {
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "mismatched object length (%d)\n",
+ filename, val);
+ return;
+ }
+
+ read_32bit_value(); /* checksum, unused */
+ read_32bit_value(); /* num, unused */
+ runs += read_32bit_value(); /* Add previous run count to new counter. */
+ }
+
+ cur_pos = save_cur_pos;
+
+ /* Object summary tag */
+ write_bytes("\0\0\0\xa1", 4);
+ write_32bit_value(obj_summary_len);
+ write_32bit_value(0); /* checksum, unused */
+ write_32bit_value(0); /* num, unused */
+ write_32bit_value(runs);
+ for (i = 3; i < obj_summary_len; ++i)
+ write_32bit_value(0);
+
+ /* Program summary tag */
+ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
+ write_32bit_value(0); /* 0 length */
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: %u runs\n", runs);
+#endif
+}
+
+void llvm_gcda_end_file() {
+ /* Write out EOF record. */
+ if (output_file) {
+ write_bytes("\0\0\0\0\0\0\0\0", 8);
+
+ if (new_file) {
+ fwrite(write_buffer, cur_pos, 1, output_file);
+ free(write_buffer);
+ } else {
+ unmap_file();
+ }
+
+ fclose(output_file);
+ flock(fd, LOCK_UN);
+ output_file = NULL;
+ write_buffer = NULL;
+ }
+ free(filename);
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: -----\n");
+#endif
+}
+
+void llvm_register_writeout_function(writeout_fn fn) {
+ struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
+ new_node->fn = fn;
+ new_node->next = NULL;
+
+ if (!writeout_fn_head) {
+ writeout_fn_head = writeout_fn_tail = new_node;
+ } else {
+ writeout_fn_tail->next = new_node;
+ writeout_fn_tail = new_node;
+ }
+}
+
+void llvm_writeout_files() {
+ struct writeout_fn_node *curr = writeout_fn_head;
+
+ while (curr) {
+ curr->fn();
+ curr = curr->next;
+ }
+}
+
+void llvm_delete_writeout_function_list() {
+ while (writeout_fn_head) {
+ struct writeout_fn_node *node = writeout_fn_head;
+ writeout_fn_head = writeout_fn_head->next;
+ free(node);
+ }
+
+ writeout_fn_head = writeout_fn_tail = NULL;
+}
+
+void llvm_register_flush_function(flush_fn fn) {
+ struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node));
+ new_node->fn = fn;
+ new_node->next = NULL;
+
+ if (!flush_fn_head) {
+ flush_fn_head = flush_fn_tail = new_node;
+ } else {
+ flush_fn_tail->next = new_node;
+ flush_fn_tail = new_node;
+ }
+}
+
+void __gcov_flush() {
+ struct flush_fn_node *curr = flush_fn_head;
+
+ while (curr) {
+ curr->fn();
+ curr = curr->next;
+ }
+}
+
+void llvm_delete_flush_function_list() {
+ while (flush_fn_head) {
+ struct flush_fn_node *node = flush_fn_head;
+ flush_fn_head = flush_fn_head->next;
+ free(node);
+ }
+
+ flush_fn_head = flush_fn_tail = NULL;
+}
+
+void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) {
+ static int atexit_ran = 0;
+
+ if (wfn)
+ llvm_register_writeout_function(wfn);
+
+ if (ffn)
+ llvm_register_flush_function(ffn);
+
+ if (atexit_ran == 0) {
+ atexit_ran = 1;
+
+ /* Make sure we write out the data and delete the data structures. */
+ atexit(llvm_delete_flush_function_list);
+ atexit(llvm_delete_writeout_function_list);
+ atexit(llvm_writeout_files);
+ }
+}
diff --git a/compiler-rt/lib/profile/InstrProfData.inc b/compiler-rt/lib/profile/InstrProfData.inc
new file mode 100644
index 0000000..48dae50
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfData.inc
@@ -0,0 +1,735 @@
+/*===-- InstrProfData.inc - instr profiling runtime structures -----------=== *\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+/*
+ * This is the master file that defines all the data structure, signature,
+ * constant literals that are shared across profiling runtime library,
+ * compiler (instrumentation), and host tools (reader/writer). The entities
+ * defined in this file affect the profile runtime ABI, the raw profile format,
+ * or both.
+ *
+ * The file has two identical copies. The master copy lives in LLVM and
+ * the other one sits in compiler-rt/lib/profile directory. To make changes
+ * in this file, first modify the master copy and copy it over to compiler-rt.
+ * Testing of any change in this file can start only after the two copies are
+ * synced up.
+ *
+ * The first part of the file includes macros that defines types, names, and
+ * initializers for the member fields of the core data structures. The field
+ * declarations for one structure is enabled by defining the field activation
+ * macro associated with that structure. Only one field activation record
+ * can be defined at one time and the rest definitions will be filtered out by
+ * the preprocessor.
+ *
+ * Examples of how the template is used to instantiate structure definition:
+ * 1. To declare a structure:
+ *
+ * struct ProfData {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Type Name;
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 2. To construct LLVM type arrays for the struct type:
+ *
+ * Type *DataTypes[] = {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * LLVMType,
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 4. To construct constant array for the initializers:
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Initializer,
+ * Constant *ConstantVals[] = {
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ *
+ * The second part of the file includes definitions all other entities that
+ * are related to runtime ABI and format. When no field activation macro is
+ * defined, this file can be included to introduce the definitions.
+ *
+\*===----------------------------------------------------------------------===*/
+
+/* INSTR_PROF_DATA start. */
+/* Definition of member fields of the per-function control structure. */
+#ifndef INSTR_PROF_DATA
+#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \
+ NamePtr->getType()->getPointerElementType()->getArrayNumElements()))
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
+INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
+ Inc->getHash()->getZExtValue()))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \
+ ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \
+ ConstantExpr::getBitCast(CounterPtr, \
+ llvm::Type::getInt64PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \
+ FunctionAddr)
+INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
+ ConstantPointerNull::get(Int8PtrTy))
+INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
+ ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
+#undef INSTR_PROF_DATA
+/* INSTR_PROF_DATA end. */
+
+/* INSTR_PROF_RAW_HEADER start */
+/* Definition of member fields of the raw profile header data structure. */
+#ifndef INSTR_PROF_RAW_HEADER
+#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
+INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
+INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin)
+#undef INSTR_PROF_RAW_HEADER
+/* INSTR_PROF_RAW_HEADER end */
+
+/* VALUE_PROF_FUNC_PARAM start */
+/* Definition of parameter types of the runtime API used to do value profiling
+ * for a given value site.
+ */
+#ifndef VALUE_PROF_FUNC_PARAM
+#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType)
+#define INSTR_PROF_COMMA
+#else
+#define INSTR_PROF_DATA_DEFINED
+#define INSTR_PROF_COMMA ,
+#endif
+VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \
+ INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
+#undef VALUE_PROF_FUNC_PARAM
+#undef INSTR_PROF_COMMA
+/* VALUE_PROF_FUNC_PARAM end */
+
+/* VALUE_PROF_KIND start */
+#ifndef VALUE_PROF_KIND
+#define VALUE_PROF_KIND(Enumerator, Value)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0)
+/* These two kinds must be the last to be
+ * declared. This is to make sure the string
+ * array created with the template can be
+ * indexed with the kind value.
+ */
+VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget)
+VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
+
+#undef VALUE_PROF_KIND
+/* VALUE_PROF_KIND end */
+
+/* COVMAP_FUNC_RECORD start */
+/* Definition of member fields of the function record structure in coverage
+ * map.
+ */
+#ifndef COVMAP_FUNC_RECORD
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
+ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
+ llvm::Type::getInt8PtrTy(Ctx)))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ NameValue.size()))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ CoverageMapping.size()))
+COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash))
+#undef COVMAP_FUNC_RECORD
+/* COVMAP_FUNC_RECORD end. */
+
+
+#ifdef INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_DATA_DEFINED
+
+/*!
+ * This is the header of the data structure that defines the on-disk
+ * layout of the value profile data of a particular kind for one function.
+ */
+typedef struct ValueProfRecord {
+ /* The kind of the value profile record. */
+ uint32_t Kind;
+ /*
+ * The number of value profile sites. It is guaranteed to be non-zero;
+ * otherwise the record for this kind won't be emitted.
+ */
+ uint32_t NumValueSites;
+ /*
+ * The first element of the array that stores the number of profiled
+ * values for each value site. The size of the array is NumValueSites.
+ * Since NumValueSites is greater than zero, there is at least one
+ * element in the array.
+ */
+ uint8_t SiteCountArray[1];
+
+ /*
+ * The fake declaration is for documentation purpose only.
+ * Align the start of next field to be on 8 byte boundaries.
+ uint8_t Padding[X];
+ */
+
+ /* The array of value profile data. The size of the array is the sum
+ * of all elements in SiteCountArray[].
+ InstrProfValueData ValueData[];
+ */
+
+#ifdef __cplusplus
+ /*!
+ * \brief Return the number of value sites.
+ */
+ uint32_t getNumValueSites() const { return NumValueSites; }
+ /*!
+ * \brief Read data from this record and save it to Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ /*
+ * In-place byte swap:
+ * Do byte swap for this instance. \c Old is the original order before
+ * the swap, and \c New is the New byte order.
+ */
+ void swapBytes(support::endianness Old, support::endianness New);
+#endif
+} ValueProfRecord;
+
+/*!
+ * Per-function header/control data structure for value profiling
+ * data in indexed format.
+ */
+typedef struct ValueProfData {
+ /*
+ * Total size in bytes including this field. It must be a multiple
+ * of sizeof(uint64_t).
+ */
+ uint32_t TotalSize;
+ /*
+ *The number of value profile kinds that has value profile data.
+ * In this implementation, a value profile kind is considered to
+ * have profile data if the number of value profile sites for the
+ * kind is not zero. More aggressively, the implementation can
+ * choose to check the actual data value: if none of the value sites
+ * has any profiled values, the kind can be skipped.
+ */
+ uint32_t NumValueKinds;
+
+ /*
+ * Following are a sequence of variable length records. The prefix/header
+ * of each record is defined by ValueProfRecord type. The number of
+ * records is NumValueKinds.
+ * ValueProfRecord Record_1;
+ * ValueProfRecord Record_N;
+ */
+
+#if __cplusplus
+ /*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+ static uint32_t getSize(const InstrProfRecord &Record);
+ /*!
+ * Return a pointer to \c ValueProfData instance ready to be streamed.
+ */
+ static std::unique_ptr<ValueProfData>
+ serializeFrom(const InstrProfRecord &Record);
+ /*!
+ * Check the integrity of the record. Return the error code when
+ * an error is detected, otherwise return instrprof_error::success.
+ */
+ instrprof_error checkIntegrity();
+ /*!
+ * Return a pointer to \c ValueProfileData instance ready to be read.
+ * All data in the instance are properly byte swapped. The input
+ * data is assumed to be in little endian order.
+ */
+ static ErrorOr<std::unique_ptr<ValueProfData>>
+ getValueProfData(const unsigned char *SrcBuffer,
+ const unsigned char *const SrcBufferEnd,
+ support::endianness SrcDataEndianness);
+ /*!
+ * Swap byte order from \c Endianness order to host byte order.
+ */
+ void swapBytesToHost(support::endianness Endianness);
+ /*!
+ * Swap byte order from host byte order to \c Endianness order.
+ */
+ void swapBytesFromHost(support::endianness Endianness);
+ /*!
+ * Return the total size of \c ValueProfileData.
+ */
+ uint32_t getSize() const { return TotalSize; }
+ /*!
+ * Read data from this data and save it to \c Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ void operator delete(void *ptr) { ::operator delete(ptr); }
+#endif
+} ValueProfData;
+
+/*
+ * The closure is designed to abstact away two types of value profile data:
+ * - InstrProfRecord which is the primary data structure used to
+ * represent profile data in host tools (reader, writer, and profile-use)
+ * - value profile runtime data structure suitable to be used by C
+ * runtime library.
+ *
+ * Both sources of data need to serialize to disk/memory-buffer in common
+ * format: ValueProfData. The abstraction allows compiler-rt's raw profiler
+ * writer to share the same format and code with indexed profile writer.
+ *
+ * For documentation of the member methods below, refer to corresponding methods
+ * in class InstrProfRecord.
+ */
+typedef struct ValueProfRecordClosure {
+ const void *Record;
+ uint32_t (*GetNumValueKinds)(const void *Record);
+ uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
+
+ /*
+ * After extracting the value profile data from the value profile record,
+ * this method is used to map the in-memory value to on-disk value. If
+ * the method is null, value will be written out untranslated.
+ */
+ uint64_t (*RemapValueData)(uint32_t, uint64_t Value);
+ void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t));
+ ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
+} ValueProfRecordClosure;
+
+/*
+ * A wrapper struct that represents value profile runtime data.
+ * Like InstrProfRecord class which is used by profiling host tools,
+ * ValueProfRuntimeRecord also implements the abstract intefaces defined in
+ * ValueProfRecordClosure so that the runtime data can be serialized using
+ * shared C implementation. In this structure, NumValueSites and Nodes
+ * members are the primary fields while other fields hold the derived
+ * information for fast implementation of closure interfaces.
+ */
+typedef struct ValueProfRuntimeRecord {
+ /* Number of sites for each value profile kind. */
+ const uint16_t *NumValueSites;
+ /* An array of linked-list headers. The size of of the array is the
+ * total number of value profile sites : sum(NumValueSites[*])). Each
+ * linked-list stores the values profiled for a value profile site. */
+ ValueProfNode **Nodes;
+
+ /* Total number of value profile kinds which have at least one
+ * value profile sites. */
+ uint32_t NumValueKinds;
+ /* An array recording the number of values tracked at each site.
+ * The size of the array is TotalNumValueSites. */
+ uint8_t *SiteCountArray[IPVK_Last + 1];
+ ValueProfNode **NodesKind[IPVK_Last + 1];
+} ValueProfRuntimeRecord;
+
+/* Forward declarations of C interfaces. */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes);
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord);
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record);
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *Dst);
+uint32_t getNumValueKindsRT(const void *R);
+
+#undef INSTR_PROF_VALUE_PROF_DATA
+#endif /* INSTR_PROF_VALUE_PROF_DATA */
+
+
+#ifdef INSTR_PROF_COMMON_API_IMPL
+#define INSTR_PROF_DATA_DEFINED
+#ifdef __cplusplus
+#define INSTR_PROF_INLINE inline
+#else
+#define INSTR_PROF_INLINE
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/*!
+ * \brief Return the \c ValueProfRecord header size including the
+ * padding bytes.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
+ uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) +
+ sizeof(uint8_t) * NumValueSites;
+ /* Round the size to multiple of 8 bytes. */
+ Size = (Size + 7) & ~7;
+ return Size;
+}
+
+/*!
+ * \brief Return the total size of the value profile record including the
+ * header and the value data.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordSize(uint32_t NumValueSites,
+ uint32_t NumValueData) {
+ return getValueProfRecordHeaderSize(NumValueSites) +
+ sizeof(InstrProfValueData) * NumValueData;
+}
+
+/*!
+ * \brief Return the pointer to the start of value data array.
+ */
+INSTR_PROF_INLINE
+InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
+ return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize(
+ This->NumValueSites));
+}
+
+/*!
+ * \brief Return the total number of value data for \c This record.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
+ uint32_t NumValueData = 0;
+ uint32_t I;
+ for (I = 0; I < This->NumValueSites; I++)
+ NumValueData += This->SiteCountArray[I];
+ return NumValueData;
+}
+
+/*!
+ * \brief Use this method to advance to the next \c This \c ValueProfRecord.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
+ uint32_t NumValueData = getValueProfRecordNumValueData(This);
+ return (ValueProfRecord *)((char *)This +
+ getValueProfRecordSize(This->NumValueSites,
+ NumValueData));
+}
+
+/*!
+ * \brief Return the first \c ValueProfRecord instance.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
+ return (ValueProfRecord *)((char *)This + sizeof(ValueProfData));
+}
+
+/* Closure based interfaces. */
+
+/*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) {
+ uint32_t Kind;
+ uint32_t TotalSize = sizeof(ValueProfData);
+ const void *Record = Closure->Record;
+ uint32_t NumValueKinds = Closure->GetNumValueKinds(Record);
+ if (NumValueKinds == 0)
+ return TotalSize;
+
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind);
+ if (!NumValueSites)
+ continue;
+ TotalSize += getValueProfRecordSize(NumValueSites,
+ Closure->GetNumValueData(Record, Kind));
+ }
+ return TotalSize;
+}
+
+/*!
+ * Extract value profile data of a function for the profile kind \c ValueKind
+ * from the \c Closure and serialize the data into \c This record instance.
+ */
+void serializeValueProfRecordFrom(ValueProfRecord *This,
+ ValueProfRecordClosure *Closure,
+ uint32_t ValueKind, uint32_t NumValueSites) {
+ uint32_t S;
+ const void *Record = Closure->Record;
+ This->Kind = ValueKind;
+ This->NumValueSites = NumValueSites;
+ InstrProfValueData *DstVD = getValueProfRecordValueData(This);
+
+ for (S = 0; S < NumValueSites; S++) {
+ uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S);
+ This->SiteCountArray[S] = ND;
+ Closure->GetValueForSite(Record, DstVD, ValueKind, S,
+ Closure->RemapValueData);
+ DstVD += ND;
+ }
+}
+
+/*!
+ * Extract value profile data of a function from the \c Closure
+ * and serialize the data into \c DstData if it is not NULL or heap
+ * memory allocated by the \c Closure's allocator method.
+ */
+ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
+ ValueProfData *DstData) {
+ uint32_t Kind;
+ uint32_t TotalSize = getValueProfDataSize(Closure);
+
+ ValueProfData *VPD =
+ DstData ? DstData : Closure->AllocValueProfData(TotalSize);
+
+ VPD->TotalSize = TotalSize;
+ VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record);
+ ValueProfRecord *VR = getFirstValueProfRecord(VPD);
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind);
+ if (!NumValueSites)
+ continue;
+ serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites);
+ VR = getValueProfRecordNext(VR);
+ }
+ return VPD;
+}
+
+/*
+ * The value profiler runtime library stores the value profile data
+ * for a given function in \c NumValueSites and \c Nodes structures.
+ * \c ValueProfRuntimeRecord class is used to encapsulate the runtime
+ * profile data and provides fast interfaces to retrieve the profile
+ * information. This interface is used to initialize the runtime record
+ * and pre-compute the information needed for efficient implementation
+ * of callbacks required by ValueProfRecordClosure class.
+ */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes) {
+ unsigned I, J, S = 0, NumValueKinds = 0;
+ RuntimeRecord->NumValueSites = NumValueSites;
+ RuntimeRecord->Nodes = Nodes;
+ for (I = 0; I <= IPVK_Last; I++) {
+ uint16_t N = NumValueSites[I];
+ if (!N) {
+ RuntimeRecord->SiteCountArray[I] = 0;
+ continue;
+ }
+ NumValueKinds++;
+ RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1);
+ if (!RuntimeRecord->SiteCountArray[I])
+ return 1;
+ RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : NULL;
+ for (J = 0; J < N; J++) {
+ /* Compute value count for each site. */
+ uint32_t C = 0;
+ ValueProfNode *Site = Nodes ? RuntimeRecord->NodesKind[I][J] : NULL;
+ while (Site) {
+ C++;
+ Site = Site->Next;
+ }
+ if (C > UCHAR_MAX)
+ C = UCHAR_MAX;
+ RuntimeRecord->SiteCountArray[I][J] = C;
+ }
+ S += N;
+ }
+ RuntimeRecord->NumValueKinds = NumValueKinds;
+ return 0;
+}
+
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) {
+ unsigned I;
+ for (I = 0; I <= IPVK_Last; I++) {
+ if (RuntimeRecord->SiteCountArray[I])
+ free(RuntimeRecord->SiteCountArray[I]);
+ }
+}
+
+/* ValueProfRecordClosure Interface implementation for
+ * ValueProfDataRuntimeRecord. */
+uint32_t getNumValueKindsRT(const void *R) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueKinds;
+}
+
+uint32_t getNumValueSitesRT(const void *R, uint32_t VK) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK];
+}
+
+uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) {
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ return Record->SiteCountArray[VK][S];
+}
+
+uint32_t getNumValueDataRT(const void *R, uint32_t VK) {
+ unsigned I, S = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ if (Record->SiteCountArray[VK] == 0)
+ return 0;
+ for (I = 0; I < Record->NumValueSites[VK]; I++)
+ S += Record->SiteCountArray[VK][I];
+ return S;
+}
+
+void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)) {
+ unsigned I, N = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ N = getNumValueDataForSiteRT(R, VK, S);
+ if (N == 0)
+ return;
+ ValueProfNode *VNode = Record->NodesKind[VK][S];
+ for (I = 0; I < N; I++) {
+ Dst[I] = VNode->VData;
+ VNode = VNode->Next;
+ }
+}
+
+ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) {
+ return (ValueProfData *)calloc(TotalSizeInBytes, 1);
+}
+
+static ValueProfRecordClosure RTRecordClosure = {0,
+ getNumValueKindsRT,
+ getNumValueSitesRT,
+ getNumValueDataRT,
+ getNumValueDataForSiteRT,
+ 0,
+ getValueForSiteRT,
+ allocValueProfDataRT};
+
+/*
+ * Return the size of ValueProfData structure to store data
+ * recorded in the runtime record.
+ */
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
+ RTRecordClosure.Record = Record;
+ return getValueProfDataSize(&RTRecordClosure);
+}
+
+/*
+ * Return a ValueProfData instance that stores the data collected
+ * from runtime. If \c DstData is provided by the caller, the value
+ * profile data will be store in *DstData and DstData is returned,
+ * otherwise the method will allocate space for the value data and
+ * return pointer to the newly allocated space.
+ */
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *DstData) {
+ RTRecordClosure.Record = Record;
+ return serializeValueProfDataFrom(&RTRecordClosure, DstData);
+}
+
+
+#undef INSTR_PROF_COMMON_API_IMPL
+#endif /* INSTR_PROF_COMMON_API_IMPL */
+
+/*============================================================================*/
+
+
+#ifndef INSTR_PROF_DATA_DEFINED
+
+#ifndef INSTR_PROF_DATA_INC_
+#define INSTR_PROF_DATA_INC_
+
+/* Helper macros. */
+#define INSTR_PROF_SIMPLE_QUOTE(x) #x
+#define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x)
+#define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y
+#define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y)
+
+/* Magic number to detect file format and endianness.
+ * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
+ * so that utilities, like strings, don't grab it as a string. 129 is also
+ * invalid UTF-8, and high enough to be interesting.
+ * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR"
+ * for 32-bit platforms.
+ */
+#define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
+ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \
+ (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129
+#define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
+ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \
+ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
+
+/* Raw profile format version. */
+#define INSTR_PROF_RAW_VERSION 2
+
+/* Runtime section names and name strings. */
+#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
+#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
+#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
+
+#define INSTR_PROF_DATA_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
+#define INSTR_PROF_NAME_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
+#define INSTR_PROF_CNTS_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
+
+/* Macros to define start/stop section symbol for a given
+ * section on Linux. For instance
+ * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will
+ * expand to __start___llvm_prof_data
+ */
+#define INSTR_PROF_SECT_START(Sect) \
+ INSTR_PROF_CONCAT(__start_,Sect)
+#define INSTR_PROF_SECT_STOP(Sect) \
+ INSTR_PROF_CONCAT(__stop_,Sect)
+
+/* Value Profiling API linkage name. */
+#define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target
+#define INSTR_PROF_VALUE_PROF_FUNC_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC)
+
+/* InstrProfile per-function control data alignment. */
+#define INSTR_PROF_DATA_ALIGNMENT 8
+
+/* The data structure that represents a tracked value by the
+ * value profiler.
+ */
+typedef struct InstrProfValueData {
+ /* Profiled value. */
+ uint64_t Value;
+ /* Number of times the value appears in the training run. */
+ uint64_t Count;
+} InstrProfValueData;
+
+/* This is an internal data structure used by value profiler. It
+ * is defined here to allow serialization code sharing by LLVM
+ * to be used in unit test.
+ */
+typedef struct ValueProfNode {
+ InstrProfValueData VData;
+ struct ValueProfNode *Next;
+} ValueProfNode;
+
+#endif /* INSTR_PROF_DATA_INC_ */
+
+#else
+#undef INSTR_PROF_DATA_DEFINED
+#endif
+
diff --git a/compiler-rt/lib/profile/InstrProfiling.c b/compiler-rt/lib/profile/InstrProfiling.c
new file mode 100644
index 0000000..58778ae
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfiling.c
@@ -0,0 +1,68 @@
+/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define INSTR_PROF_VALUE_PROF_DATA
+#include "InstrProfData.inc"
+
+char *(*GetEnvHook)(const char *) = 0;
+
+COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
+ return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
+ : (INSTR_PROF_RAW_MAGIC_32);
+}
+
+/* Return the number of bytes needed to add to SizeInBytes to make it
+ * the result a multiple of 8.
+ */
+COMPILER_RT_VISIBILITY uint8_t
+__llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) {
+ return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
+}
+
+COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) {
+ return INSTR_PROF_RAW_VERSION;
+}
+
+COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
+ uint64_t *I = __llvm_profile_begin_counters();
+ uint64_t *E = __llvm_profile_end_counters();
+
+ memset(I, 0, sizeof(uint64_t) * (E - I));
+
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const __llvm_profile_data *DI;
+ for (DI = DataBegin; DI != DataEnd; ++DI) {
+ uint64_t CurrentVSiteCount = 0;
+ uint32_t VKI, i;
+ if (!DI->Values)
+ continue;
+
+ ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values;
+
+ for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
+ CurrentVSiteCount += DI->NumValueSites[VKI];
+
+ for (i = 0; i < CurrentVSiteCount; ++i) {
+ ValueProfNode *CurrentVNode = ValueCounters[i];
+
+ while (CurrentVNode) {
+ CurrentVNode->VData.Count = 0;
+ CurrentVNode = CurrentVNode->Next;
+ }
+ }
+ }
+}
+
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
new file mode 100644
index 0000000..c924a42
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -0,0 +1,133 @@
+/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_H_
+#define PROFILE_INSTRPROFILING_H_
+
+#include "InstrProfilingPort.h"
+#include "InstrProfData.inc"
+
+enum ValueKind {
+#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
+#include "InstrProfData.inc"
+};
+
+typedef void *IntPtrT;
+typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT)
+ __llvm_profile_data {
+#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name;
+#include "InstrProfData.inc"
+} __llvm_profile_data;
+
+typedef struct __llvm_profile_header {
+#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name;
+#include "InstrProfData.inc"
+} __llvm_profile_header;
+
+/*!
+ * \brief Get number of bytes necessary to pad the argument to eight
+ * byte boundary.
+ */
+uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes);
+
+/*!
+ * \brief Get required size for profile buffer.
+ */
+uint64_t __llvm_profile_get_size_for_buffer(void);
+
+/*!
+ * \brief Write instrumentation data to the given buffer.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer().
+ */
+int __llvm_profile_write_buffer(char *Buffer);
+
+const __llvm_profile_data *__llvm_profile_begin_data(void);
+const __llvm_profile_data *__llvm_profile_end_data(void);
+const char *__llvm_profile_begin_names(void);
+const char *__llvm_profile_end_names(void);
+uint64_t *__llvm_profile_begin_counters(void);
+uint64_t *__llvm_profile_end_counters(void);
+
+/*!
+ * \brief Clear profile counters to zero.
+ *
+ */
+void __llvm_profile_reset_counters(void);
+
+/*!
+ * \brief Counts the number of times a target value is seen.
+ *
+ * Records the target value for the CounterIndex if not seen before. Otherwise,
+ * increments the counter associated w/ the target value.
+ * void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
+ * uint32_t CounterIndex);
+ */
+void INSTR_PROF_VALUE_PROF_FUNC(
+#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName
+#include "InstrProfData.inc"
+);
+
+/*!
+ * \brief Prepares the value profiling data for output.
+ *
+ * Prepares a single __llvm_profile_value_data array out of the many
+ * ValueProfNode trees (one per instrumented function).
+ */
+uint64_t __llvm_profile_gather_value_data(uint8_t **DataArray);
+
+/*!
+ * \brief Write instrumentation data to the current file.
+ *
+ * Writes to the file with the last name given to \a __llvm_profile_set_filename(),
+ * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
+ * or if that's not set, the last name given to
+ * \a __llvm_profile_override_default_filename(), or if that's not set,
+ * \c "default.profraw".
+ */
+int __llvm_profile_write_file(void);
+
+/*!
+ * \brief Set the filename for writing instrumentation data.
+ *
+ * Sets the filename to be used for subsequent calls to
+ * \a __llvm_profile_write_file().
+ *
+ * \c Name is not copied, so it must remain valid. Passing NULL resets the
+ * filename logic to the default behaviour.
+ */
+void __llvm_profile_set_filename(const char *Name);
+
+/*!
+ * \brief Set the filename for writing instrumentation data, unless the
+ * \c LLVM_PROFILE_FILE environment variable was set.
+ *
+ * Unless overridden, sets the filename to be used for subsequent calls to
+ * \a __llvm_profile_write_file().
+ *
+ * \c Name is not copied, so it must remain valid. Passing NULL resets the
+ * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE
+ * was set in which case it has no effect).
+ */
+void __llvm_profile_override_default_filename(const char *Name);
+
+/*! \brief Register to write instrumentation data to file at exit. */
+int __llvm_profile_register_write_file_atexit(void);
+
+/*! \brief Initialize file handling. */
+void __llvm_profile_initialize_file(void);
+
+/*! \brief Get the magic token for the file format. */
+uint64_t __llvm_profile_get_magic(void);
+
+/*! \brief Get the version of the file format. */
+uint64_t __llvm_profile_get_version(void);
+
+#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/compiler-rt/lib/profile/InstrProfilingBuffer.c b/compiler-rt/lib/profile/InstrProfilingBuffer.c
new file mode 100644
index 0000000..8bade76
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -0,0 +1,69 @@
+/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+
+#include <string.h>
+
+COMPILER_RT_VISIBILITY
+uint64_t __llvm_profile_get_size_for_buffer(void) {
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+
+ return __llvm_profile_get_size_for_buffer_internal(
+ DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
+}
+
+#define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin)
+
+COMPILER_RT_VISIBILITY
+uint64_t __llvm_profile_get_size_for_buffer_internal(
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ const char *NamesBegin, const char *NamesEnd) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char);
+ const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
+ return sizeof(__llvm_profile_header) +
+ PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
+ PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + NamesSize + Padding;
+}
+
+/* The buffer writer is reponsponsible in keeping writer state
+ * across the call.
+ */
+static uint32_t bufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+ void **WriterCtx) {
+ uint32_t I;
+ char **Buffer = (char **)WriterCtx;
+ for (I = 0; I < NumIOVecs; I++) {
+ size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
+ memcpy(*Buffer, IOVecs[I].Data, Length);
+ *Buffer += Length;
+ }
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
+ return llvmWriteProfData(bufferWriter, Buffer, 0, 0);
+}
+
+COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
+ char *Buffer, const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
+ return llvmWriteProfDataImpl(bufferWriter, Buffer, DataBegin, DataEnd,
+ CountersBegin, CountersEnd, 0, 0, NamesBegin,
+ NamesEnd);
+}
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c
new file mode 100644
index 0000000..7f2923c
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -0,0 +1,221 @@
+/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include "InstrProfilingUtil.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
+
+/* Return 1 if there is an error, otherwise return 0. */
+static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+ void **WriterCtx) {
+ uint32_t I;
+ FILE *File = (FILE *)*WriterCtx;
+ for (I = 0; I < NumIOVecs; I++) {
+ if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
+ IOVecs[I].NumElm)
+ return 1;
+ }
+ return 0;
+}
+
+static int writeFile(FILE *File) {
+ uint8_t *ValueDataBegin = NULL;
+ const uint64_t ValueDataSize =
+ __llvm_profile_gather_value_data(&ValueDataBegin);
+ int r = llvmWriteProfData(fileWriter, File, ValueDataBegin, ValueDataSize);
+ free(ValueDataBegin);
+ return r;
+}
+
+static int writeFileWithName(const char *OutputName) {
+ int RetVal;
+ FILE *OutputFile;
+ if (!OutputName || !OutputName[0])
+ return -1;
+
+ /* Append to the file to support profiling multiple shared objects. */
+ OutputFile = fopen(OutputName, "ab");
+ if (!OutputFile)
+ return -1;
+
+ RetVal = writeFile(OutputFile);
+
+ fclose(OutputFile);
+ return RetVal;
+}
+
+COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
+COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
+
+static void truncateCurrentFile(void) {
+ const char *Filename;
+ FILE *File;
+
+ Filename = __llvm_profile_CurrentFilename;
+ if (!Filename || !Filename[0])
+ return;
+
+ /* Create the directory holding the file, if needed. */
+ if (strchr(Filename, '/')) {
+ char *Copy = malloc(strlen(Filename) + 1);
+ strcpy(Copy, Filename);
+ __llvm_profile_recursive_mkdir(Copy);
+ free(Copy);
+ }
+
+ /* Truncate the file. Later we'll reopen and append. */
+ File = fopen(Filename, "w");
+ if (!File)
+ return;
+ fclose(File);
+}
+
+static void setFilename(const char *Filename, int OwnsFilename) {
+ /* Check if this is a new filename and therefore needs truncation. */
+ int NewFile = !__llvm_profile_CurrentFilename ||
+ (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
+ if (__llvm_profile_OwnsFilename)
+ free(UNCONST(__llvm_profile_CurrentFilename));
+
+ __llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
+
+ /* If not a new file, append to support profiling multiple shared objects. */
+ if (NewFile)
+ truncateCurrentFile();
+}
+
+static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenamePossiblyWithPid(const char *Filename) {
+#define MAX_PID_SIZE 16
+ char PidChars[MAX_PID_SIZE] = {0};
+ int NumPids = 0, PidLength = 0;
+ char *Allocated;
+ int I, J;
+
+ /* Reset filename on NULL, except with env var which is checked by caller. */
+ if (!Filename) {
+ resetFilenameToDefault();
+ return 0;
+ }
+
+ /* Check the filename for "%p", which indicates a pid-substitution. */
+ for (I = 0; Filename[I]; ++I)
+ if (Filename[I] == '%' && Filename[++I] == 'p')
+ if (!NumPids++) {
+ PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
+ if (PidLength <= 0)
+ return -1;
+ }
+ if (!NumPids) {
+ setFilename(Filename, 0);
+ return 0;
+ }
+
+ /* Allocate enough space for the substituted filename. */
+ Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
+ if (!Allocated)
+ return -1;
+
+ /* Construct the new filename. */
+ for (I = 0, J = 0; Filename[I]; ++I)
+ if (Filename[I] == '%') {
+ if (Filename[++I] == 'p') {
+ memcpy(Allocated + J, PidChars, PidLength);
+ J += PidLength;
+ }
+ /* Drop any unknown substitutions. */
+ } else
+ Allocated[J++] = Filename[I];
+ Allocated[J] = 0;
+
+ /* Use the computed name. */
+ setFilename(Allocated, 1);
+ return 0;
+}
+
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+
+ if (!Filename || !Filename[0])
+ return -1;
+
+ return setFilenamePossiblyWithPid(Filename);
+}
+
+static void setFilenameAutomatically(void) {
+ if (!setFilenameFromEnvironment())
+ return;
+
+ resetFilenameToDefault();
+}
+
+COMPILER_RT_VISIBILITY
+void __llvm_profile_initialize_file(void) {
+ /* Check if the filename has been initialized. */
+ if (__llvm_profile_CurrentFilename)
+ return;
+
+ /* Detect the filename and truncate. */
+ setFilenameAutomatically();
+}
+
+COMPILER_RT_VISIBILITY
+void __llvm_profile_set_filename(const char *Filename) {
+ setFilenamePossiblyWithPid(Filename);
+}
+
+COMPILER_RT_VISIBILITY
+void __llvm_profile_override_default_filename(const char *Filename) {
+ /* If the env var is set, skip setting filename from argument. */
+ const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
+ if (Env_Filename && Env_Filename[0])
+ return;
+ setFilenamePossiblyWithPid(Filename);
+}
+
+COMPILER_RT_VISIBILITY
+int __llvm_profile_write_file(void) {
+ int rc;
+
+ GetEnvHook = &getenv;
+ /* Check the filename. */
+ if (!__llvm_profile_CurrentFilename) {
+ PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
+ return -1;
+ }
+
+ /* Write the file. */
+ rc = writeFileWithName(__llvm_profile_CurrentFilename);
+ if (rc)
+ PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
+ __llvm_profile_CurrentFilename, strerror(errno));
+ return rc;
+}
+
+static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
+
+COMPILER_RT_VISIBILITY
+int __llvm_profile_register_write_file_atexit(void) {
+ static int HasBeenRegistered = 0;
+
+ if (HasBeenRegistered)
+ return 0;
+
+ HasBeenRegistered = 1;
+ return atexit(writeFileWithoutReturn);
+}
diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.h b/compiler-rt/lib/profile/InstrProfilingInternal.h
new file mode 100644
index 0000000..d247ca4
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingInternal.h
@@ -0,0 +1,66 @@
+/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_INTERNALH_
+#define PROFILE_INSTRPROFILING_INTERNALH_
+
+#include "InstrProfiling.h"
+#include "stddef.h"
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if
+ * your program has a custom memory layout.
+ */
+uint64_t __llvm_profile_get_size_for_buffer_internal(
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ const char *NamesBegin, const char *NamesEnd);
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_write_buffer instead. Use this function if your
+ * program has a custom memory layout.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer_internal().
+ */
+int __llvm_profile_write_buffer_internal(
+ char *Buffer, const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd);
+
+/*!
+ * This is an internal function not intended to be used externally.
+ */
+typedef struct ProfDataIOVec {
+ const void *Data;
+ size_t ElmSize;
+ size_t NumElm;
+} ProfDataIOVec;
+
+typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs,
+ void **WriterCtx);
+int llvmWriteProfData(WriterCallback Writer, void *WriterCtx,
+ const uint8_t *ValueDataBegin,
+ const uint64_t ValueDataSize);
+int llvmWriteProfDataImpl(WriterCallback Writer, void *WriterCtx,
+ const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd,
+ const uint8_t *ValueDataBegin,
+ const uint64_t ValueDataSize, const char *NamesBegin,
+ const char *NamesEnd);
+
+extern char *(*GetEnvHook)(const char *);
+
+#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c b/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
new file mode 100644
index 0000000..30ddbd2
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
@@ -0,0 +1,46 @@
+/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if defined(__APPLE__)
+/* Use linker magic to find the bounds of the Data section. */
+COMPILER_RT_VISIBILITY
+extern __llvm_profile_data
+ DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern __llvm_profile_data
+ DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern char
+ NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern uint64_t
+ CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern uint64_t
+ CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
+
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_begin_data(void) {
+ return &DataStart;
+}
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; }
+COMPILER_RT_VISIBILITY
+const char *__llvm_profile_begin_names(void) { return &NamesStart; }
+COMPILER_RT_VISIBILITY
+const char *__llvm_profile_end_names(void) { return &NamesEnd; }
+COMPILER_RT_VISIBILITY
+uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
+COMPILER_RT_VISIBILITY
+uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
+#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
new file mode 100644
index 0000000..7843f47
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -0,0 +1,59 @@
+/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if defined(__linux__) || defined(__FreeBSD__)
+#include <stdlib.h>
+
+#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME)
+#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME)
+#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME)
+#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME)
+#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME)
+#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME)
+
+/* Declare section start and stop symbols for various sections
+ * generated by compiler instrumentation.
+ */
+extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY;
+extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY;
+extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY;
+extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY;
+extern char PROF_NAME_START COMPILER_RT_VISIBILITY;
+extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY;
+
+/* Add dummy data to ensure the section is always created. */
+__llvm_profile_data
+ __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR);
+uint64_t
+ __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR);
+char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR);
+
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_begin_data(void) {
+ return &PROF_DATA_START;
+}
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_end_data(void) {
+ return &PROF_DATA_STOP;
+}
+COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
+ return &PROF_NAME_START;
+}
+COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
+ return &PROF_NAME_STOP;
+}
+COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) {
+ return &PROF_CNTS_START;
+}
+COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) {
+ return &PROF_CNTS_STOP;
+}
+#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
new file mode 100644
index 0000000..58ceb34
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
@@ -0,0 +1,68 @@
+/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__)
+#include <stdlib.h>
+
+static const __llvm_profile_data *DataFirst = NULL;
+static const __llvm_profile_data *DataLast = NULL;
+static const char *NamesFirst = NULL;
+static const char *NamesLast = NULL;
+static uint64_t *CountersFirst = NULL;
+static uint64_t *CountersLast = NULL;
+
+/*!
+ * \brief Register an instrumented function.
+ *
+ * Calls to this are emitted by clang with -fprofile-instr-generate. Such
+ * calls are only required (and only emitted) on targets where we haven't
+ * implemented linker magic to find the bounds of the sections.
+ */
+COMPILER_RT_VISIBILITY
+void __llvm_profile_register_function(void *Data_) {
+ /* TODO: Only emit this function if we can't use linker magic. */
+ const __llvm_profile_data *Data = (__llvm_profile_data *)Data_;
+ if (!DataFirst) {
+ DataFirst = Data;
+ DataLast = Data + 1;
+ NamesFirst = Data->NamePtr;
+ NamesLast = (const char *)Data->NamePtr + Data->NameSize;
+ CountersFirst = Data->CounterPtr;
+ CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters;
+ return;
+ }
+
+#define UPDATE_FIRST(First, New) First = New < First ? New : First
+ UPDATE_FIRST(DataFirst, Data);
+ UPDATE_FIRST(NamesFirst, (const char *)Data->NamePtr);
+ UPDATE_FIRST(CountersFirst, (uint64_t *)Data->CounterPtr);
+#undef UPDATE_FIRST
+
+#define UPDATE_LAST(Last, New) Last = New > Last ? New : Last
+ UPDATE_LAST(DataLast, Data + 1);
+ UPDATE_LAST(NamesLast, (const char *)Data->NamePtr + Data->NameSize);
+ UPDATE_LAST(CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters);
+#undef UPDATE_LAST
+}
+
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; }
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; }
+COMPILER_RT_VISIBILITY
+const char *__llvm_profile_begin_names(void) { return NamesFirst; }
+COMPILER_RT_VISIBILITY
+const char *__llvm_profile_end_names(void) { return NamesLast; }
+COMPILER_RT_VISIBILITY
+uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
+COMPILER_RT_VISIBILITY
+uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
+#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h
new file mode 100644
index 0000000..da4f18f
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingPort.h
@@ -0,0 +1,76 @@
+/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_PORT_H_
+#define PROFILE_INSTRPROFILING_PORT_H_
+
+#ifdef _MSC_VER
+#define COMPILER_RT_ALIGNAS(x) __declspec(align(x))
+#define COMPILER_RT_VISIBILITY
+#define COMPILER_RT_WEAK __declspec(selectany)
+#elif __GNUC__
+#define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x)))
+#define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden")))
+#define COMPILER_RT_WEAK __attribute__((weak))
+#endif
+
+#define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect)))
+
+#if COMPILER_RT_HAS_ATOMICS == 1
+#ifdef _MSC_VER
+#include <windows.h>
+#if defined(_WIN64)
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ (InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \
+ (LONGLONG)OldV) == (LONGLONG)OldV)
+#else
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \
+ (LONG)OldV)
+#endif
+#else
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ __sync_bool_compare_and_swap(Ptr, OldV, NewV)
+#endif
+#else
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ BoolCmpXchg((void **)Ptr, OldV, NewV)
+#endif
+
+#define PROF_ERR(Format, ...) \
+ if (GetEnvHook && GetEnvHook("LLVM_PROFILE_VERBOSE_ERRORS")) \
+ fprintf(stderr, Format, __VA_ARGS__);
+
+#if defined(__FreeBSD__) && defined(__i386__)
+
+/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
+ * FreeBSD 10, r232261) when compiled in 32-bit mode.
+ */
+#define PRIu64 "llu"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef uint32_t uintptr_t;
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+#define PRIu64 "lu"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned long int uintptr_t;
+
+#else /* defined(__FreeBSD__) && defined(__i386__) */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#endif /* defined(__FreeBSD__) && defined(__i386__) */
+
+#endif /* PROFILE_INSTRPROFILING_PORT_H_ */
diff --git a/compiler-rt/lib/profile/InstrProfilingRuntime.cc b/compiler-rt/lib/profile/InstrProfilingRuntime.cc
new file mode 100644
index 0000000..12ad9f1
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingRuntime.cc
@@ -0,0 +1,29 @@
+//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+#include "InstrProfiling.h"
+
+COMPILER_RT_VISIBILITY int __llvm_profile_runtime;
+}
+
+namespace {
+
+class RegisterRuntime {
+public:
+ RegisterRuntime() {
+ __llvm_profile_register_write_file_atexit();
+ __llvm_profile_initialize_file();
+ }
+};
+
+RegisterRuntime Registration;
+
+}
diff --git a/compiler-rt/lib/profile/InstrProfilingUtil.c b/compiler-rt/lib/profile/InstrProfilingUtil.c
new file mode 100644
index 0000000..6f0443d
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingUtil.c
@@ -0,0 +1,36 @@
+/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfilingUtil.h"
+#include "InstrProfiling.h"
+
+#ifdef _WIN32
+#include <direct.h>
+#elif I386_FREEBSD
+int mkdir(const char*, unsigned short);
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+COMPILER_RT_VISIBILITY
+void __llvm_profile_recursive_mkdir(char *path) {
+ int i;
+
+ for (i = 1; path[i] != '\0'; ++i) {
+ if (path[i] != '/') continue;
+ path[i] = '\0';
+#ifdef _WIN32
+ _mkdir(path);
+#else
+ mkdir(path, 0755); /* Some of these will fail, ignore it. */
+#endif
+ path[i] = '/';
+ }
+}
diff --git a/compiler-rt/lib/profile/InstrProfilingUtil.h b/compiler-rt/lib/profile/InstrProfilingUtil.h
new file mode 100644
index 0000000..756b18e
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingUtil.h
@@ -0,0 +1,16 @@
+/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILINGUTIL_H
+#define PROFILE_INSTRPROFILINGUTIL_H
+
+/*! \brief Create a directory tree. */
+void __llvm_profile_recursive_mkdir(char *Pathname);
+
+#endif /* PROFILE_INSTRPROFILINGUTIL_H */
diff --git a/compiler-rt/lib/profile/InstrProfilingValue.c b/compiler-rt/lib/profile/InstrProfilingValue.c
new file mode 100644
index 0000000..4888eec
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingValue.c
@@ -0,0 +1,238 @@
+/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_COMMON_API_IMPL
+#include "InstrProfData.inc"
+
+#define PROF_OOM(Msg) PROF_ERR(Msg ":%s\n", "Out of memory");
+#define PROF_OOM_RETURN(Msg) \
+ { \
+ PROF_OOM(Msg) \
+ return 0; \
+ }
+
+#if COMPILER_RT_HAS_ATOMICS != 1
+COMPILER_RT_VISIBILITY
+uint32_t BoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
+ void *R = *Ptr;
+ if (R == OldV) {
+ *Ptr = NewV;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY void
+__llvm_profile_set_num_value_sites(__llvm_profile_data *Data,
+ uint32_t ValueKind, uint16_t NumValueSites) {
+ *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites;
+}
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_iterate_data(const __llvm_profile_data *Data) {
+ return Data + 1;
+}
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY void *
+__llvm_get_function_addr(const __llvm_profile_data *Data) {
+ return Data->FunctionPointer;
+}
+
+/* Allocate an array that holds the pointers to the linked lists of
+ * value profile counter nodes. The number of element of the array
+ * is the total number of value profile sites instrumented. Returns
+ * 0 if allocation fails.
+ */
+
+static int allocateValueProfileCounters(__llvm_profile_data *Data) {
+ uint64_t NumVSites = 0;
+ uint32_t VKI;
+ for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
+ NumVSites += Data->NumValueSites[VKI];
+
+ ValueProfNode **Mem =
+ (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *));
+ if (!Mem)
+ return 0;
+ if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) {
+ free(Mem);
+ return 0;
+ }
+ return 1;
+}
+
+static void deallocateValueProfileCounters(__llvm_profile_data *Data) {
+ uint64_t NumVSites = 0, I;
+ uint32_t VKI;
+ if (!Data->Values)
+ return;
+ for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
+ NumVSites += Data->NumValueSites[VKI];
+ for (I = 0; I < NumVSites; I++) {
+ ValueProfNode *Node = ((ValueProfNode **)Data->Values)[I];
+ while (Node) {
+ ValueProfNode *Next = Node->Next;
+ free(Node);
+ Node = Next;
+ }
+ }
+ free(Data->Values);
+}
+
+COMPILER_RT_VISIBILITY void
+__llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
+ uint32_t CounterIndex) {
+
+ __llvm_profile_data *PData = (__llvm_profile_data *)Data;
+ if (!PData)
+ return;
+
+ if (!PData->Values) {
+ if (!allocateValueProfileCounters(PData))
+ return;
+ }
+
+ ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values;
+ ValueProfNode *PrevVNode = NULL;
+ ValueProfNode *CurrentVNode = ValueCounters[CounterIndex];
+
+ uint8_t VDataCount = 0;
+ while (CurrentVNode) {
+ if (TargetValue == CurrentVNode->VData.Value) {
+ CurrentVNode->VData.Count++;
+ return;
+ }
+ PrevVNode = CurrentVNode;
+ CurrentVNode = CurrentVNode->Next;
+ ++VDataCount;
+ }
+
+ if (VDataCount >= UCHAR_MAX)
+ return;
+
+ CurrentVNode = (ValueProfNode *)calloc(1, sizeof(ValueProfNode));
+ if (!CurrentVNode)
+ return;
+
+ CurrentVNode->VData.Value = TargetValue;
+ CurrentVNode->VData.Count++;
+
+ uint32_t Success = 0;
+ if (!ValueCounters[CounterIndex])
+ Success =
+ COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurrentVNode);
+ else if (PrevVNode && !PrevVNode->Next)
+ Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurrentVNode);
+
+ if (!Success) {
+ free(CurrentVNode);
+ return;
+ }
+}
+
+/* For multi-threaded programs, while the profile is being dumped, other
+ threads may still be updating the value profile data and creating new
+ value entries. To accommadate this, we need to add extra bytes to the
+ data buffer. The size of the extra space is controlled by an environment
+ variable. */
+static unsigned getVprofExtraBytes() {
+ const char *ExtraStr =
+ GetEnvHook ? GetEnvHook("LLVM_VALUE_PROF_BUFFER_EXTRA") : 0;
+ if (!ExtraStr || !ExtraStr[0])
+ return 1024;
+ return (unsigned)atoi(ExtraStr);
+}
+
+/* Extract the value profile data info from the runtime. */
+#define DEF_VALUE_RECORD(R, NS, V) \
+ ValueProfRuntimeRecord R; \
+ if (initializeValueProfRuntimeRecord(&R, NS, V)) \
+ PROF_OOM_RETURN("Failed to write value profile data ");
+
+#define DTOR_VALUE_RECORD(R) finalizeValueProfRuntimeRecord(&R);
+
+COMPILER_RT_VISIBILITY uint64_t
+__llvm_profile_gather_value_data(uint8_t **VDataArray) {
+ size_t S = 0, RealSize = 0, BufferCapacity = 0, Extra = 0;
+ __llvm_profile_data *I;
+ if (!VDataArray)
+ PROF_OOM_RETURN("Failed to write value profile data ");
+
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+
+ /*
+ * Compute the total Size of the buffer to hold ValueProfData
+ * structures for functions with value profile data.
+ */
+ for (I = (__llvm_profile_data *)DataBegin; I != DataEnd; ++I) {
+
+ DEF_VALUE_RECORD(R, I->NumValueSites, I->Values);
+
+ /* Compute the size of ValueProfData from this runtime record. */
+ if (getNumValueKindsRT(&R) != 0)
+ S += getValueProfDataSizeRT(&R);
+
+ DTOR_VALUE_RECORD(R);
+ }
+ /* No value sites or no value profile data is collected. */
+ if (!S)
+ return 0;
+
+ Extra = getVprofExtraBytes();
+ BufferCapacity = S + Extra;
+ *VDataArray = calloc(BufferCapacity, sizeof(uint8_t));
+ if (!*VDataArray)
+ PROF_OOM_RETURN("Failed to write value profile data ");
+
+ ValueProfData *VD = (ValueProfData *)(*VDataArray);
+ /*
+ * Extract value profile data and write into ValueProfData structure
+ * one by one. Note that new value profile data added to any value
+ * site (from another thread) after the ValueProfRuntimeRecord is
+ * initialized (when the profile data snapshot is taken) won't be
+ * collected. This is not a problem as those dropped value will have
+ * very low taken count.
+ */
+ for (I = (__llvm_profile_data *)DataBegin; I != DataEnd; ++I) {
+ DEF_VALUE_RECORD(R, I->NumValueSites, I->Values);
+ if (getNumValueKindsRT(&R) == 0)
+ continue;
+
+ /* Record R has taken a snapshot of the VP data at this point. Newly
+ added VP data for this function will be dropped. */
+ /* Check if there is enough space. */
+ if (BufferCapacity - RealSize < getValueProfDataSizeRT(&R)) {
+ PROF_ERR("Value profile data is dropped :%s \n",
+ "Out of buffer space. Use environment "
+ " LLVM_VALUE_PROF_BUFFER_EXTRA to allocate more");
+ I->Values = 0;
+ }
+
+ serializeValueProfDataFromRT(&R, VD);
+ deallocateValueProfileCounters(I);
+ I->Values = VD;
+ RealSize += VD->TotalSize;
+ VD = (ValueProfData *)((char *)VD + VD->TotalSize);
+ DTOR_VALUE_RECORD(R);
+ }
+
+ return RealSize;
+}
diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c
new file mode 100644
index 0000000..4c9e679
--- /dev/null
+++ b/compiler-rt/lib/profile/InstrProfilingWriter.c
@@ -0,0 +1,70 @@
+/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+
+COMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer,
+ void *WriterCtx,
+ const uint8_t *ValueDataBegin,
+ const uint64_t ValueDataSize) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+ return llvmWriteProfDataImpl(Writer, WriterCtx, DataBegin, DataEnd,
+ CountersBegin, CountersEnd, ValueDataBegin,
+ ValueDataSize, NamesBegin, NamesEnd);
+}
+
+COMPILER_RT_VISIBILITY int llvmWriteProfDataImpl(
+ WriterCallback Writer, void *WriterCtx,
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ const uint8_t *ValueDataBegin, const uint64_t ValueDataSize,
+ const char *NamesBegin, const char *NamesEnd) {
+
+ /* Calculate size of sections. */
+ const uint64_t DataSize = DataEnd - DataBegin;
+ const uint64_t CountersSize = CountersEnd - CountersBegin;
+ const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
+
+ /* Create the header. */
+ __llvm_profile_header Header;
+
+ if (!DataSize)
+ return 0;
+
+ /* Initialize header struture. */
+#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
+#include "InstrProfData.inc"
+
+ /* Write the data. */
+ ProfDataIOVec IOVec[] = {
+ {&Header, sizeof(__llvm_profile_header), 1},
+ {DataBegin, sizeof(__llvm_profile_data), DataSize},
+ {CountersBegin, sizeof(uint64_t), CountersSize},
+ {NamesBegin, sizeof(char), NamesSize},
+ {Zeroes, sizeof(char), Padding}};
+ if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx))
+ return -1;
+ if (ValueDataBegin) {
+ ProfDataIOVec IOVec2[] = {{ValueDataBegin, sizeof(char), ValueDataSize}};
+ if (Writer(IOVec2, sizeof(IOVec2) / sizeof(*IOVec2), &WriterCtx))
+ return -1;
+ }
+ return 0;
+}
diff --git a/compiler-rt/lib/profile/Makefile.mk b/compiler-rt/lib/profile/Makefile.mk
new file mode 100644
index 0000000..dd3a36f
--- /dev/null
+++ b/compiler-rt/lib/profile/Makefile.mk
@@ -0,0 +1,18 @@
+#===- lib/profile/Makefile.mk ------------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := profile
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.c $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(Sources)))
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
diff --git a/compiler-rt/lib/safestack/.clang-format b/compiler-rt/lib/safestack/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/safestack/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/safestack/CMakeLists.txt b/compiler-rt/lib/safestack/CMakeLists.txt
new file mode 100644
index 0000000..9c11bb6
--- /dev/null
+++ b/compiler-rt/lib/safestack/CMakeLists.txt
@@ -0,0 +1,34 @@
+add_custom_target(safestack)
+
+set(SAFESTACK_SOURCES safestack.cc)
+
+include_directories(..)
+
+set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+
+if(APPLE)
+ # Build universal binary on APPLE.
+ add_compiler_rt_runtime(clang_rt.safestack
+ STATIC
+ OS osx
+ ARCHS ${SAFESTACK_SUPPORTED_ARCH}
+ SOURCES ${SAFESTACK_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.osx>
+ CFLAGS ${SAFESTACK_CFLAGS}
+ PARENT_TARGET safestack)
+else()
+ # Otherwise, build separate libraries for each target.
+ foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.safestack
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${SAFESTACK_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.${arch}>
+ CFLAGS ${SAFESTACK_CFLAGS}
+ PARENT_TARGET safestack)
+ endforeach()
+endif()
diff --git a/compiler-rt/lib/safestack/safestack.cc b/compiler-rt/lib/safestack/safestack.cc
new file mode 100644
index 0000000..92c24b3
--- /dev/null
+++ b/compiler-rt/lib/safestack/safestack.cc
@@ -0,0 +1,251 @@
+//===-- safestack.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the runtime support for the safe stack protection
+// mechanism. The runtime manages allocation/deallocation of the unsafe stack
+// for the main thread, as well as all pthreads that are created/destroyed
+// during program execution.
+//
+//===----------------------------------------------------------------------===//
+
+#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/user.h>
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+// TODO: The runtime library does not currently protect the safe stack beyond
+// relying on the system-enforced ASLR. The protection of the (safe) stack can
+// be provided by three alternative features:
+//
+// 1) Protection via hardware segmentation on x86-32 and some x86-64
+// architectures: the (safe) stack segment (implicitly accessed via the %ss
+// segment register) can be separated from the data segment (implicitly
+// accessed via the %ds segment register). Dereferencing a pointer to the safe
+// segment would result in a segmentation fault.
+//
+// 2) Protection via software fault isolation: memory writes that are not meant
+// to access the safe stack can be prevented from doing so through runtime
+// instrumentation. One way to do it is to allocate the safe stack(s) in the
+// upper half of the userspace and bitmask the corresponding upper bit of the
+// memory addresses of memory writes that are not meant to access the safe
+// stack.
+//
+// 3) Protection via information hiding on 64 bit architectures: the location
+// of the safe stack(s) can be randomized through secure mechanisms, and the
+// leakage of the stack pointer can be prevented. Currently, libc can leak the
+// stack pointer in several ways (e.g. in longjmp, signal handling, user-level
+// context switching related functions, etc.). These can be fixed in libc and
+// in other low-level libraries, by either eliminating the escaping/dumping of
+// the stack pointer (i.e., %rsp) when that's possible, or by using
+// encryption/PTR_MANGLE (XOR-ing the dumped stack pointer with another secret
+// we control and protect better, as is already done for setjmp in glibc.)
+// Furthermore, a static machine code level verifier can be ran after code
+// generation to make sure that the stack pointer is never written to memory,
+// or if it is, its written on the safe stack.
+//
+// Finally, while the Unsafe Stack pointer is currently stored in a thread
+// local variable, with libc support it could be stored in the TCB (thread
+// control block) as well, eliminating another level of indirection and making
+// such accesses faster. Alternatively, dedicating a separate register for
+// storing it would also be possible.
+
+/// Minimum stack alignment for the unsafe stack.
+const unsigned kStackAlign = 16;
+
+/// Default size of the unsafe stack. This value is only used if the stack
+/// size rlimit is set to infinity.
+const unsigned kDefaultUnsafeStackSize = 0x2800000;
+
+/// Runtime page size obtained through sysconf
+static unsigned pageSize;
+
+// TODO: To make accessing the unsafe stack pointer faster, we plan to
+// eventually store it directly in the thread control block data structure on
+// platforms where this structure is pointed to by %fs or %gs. This is exactly
+// the same mechanism as currently being used by the traditional stack
+// protector pass to store the stack guard (see getStackCookieLocation()
+// function above). Doing so requires changing the tcbhead_t struct in glibc
+// on Linux and tcb struct in libc on FreeBSD.
+//
+// For now, store it in a thread-local variable.
+extern "C" {
+__attribute__((visibility(
+ "default"))) __thread void *__safestack_unsafe_stack_ptr = nullptr;
+}
+
+// Per-thread unsafe stack information. It's not frequently accessed, so there
+// it can be kept out of the tcb in normal thread-local variables.
+static __thread void *unsafe_stack_start = nullptr;
+static __thread size_t unsafe_stack_size = 0;
+static __thread size_t unsafe_stack_guard = 0;
+
+static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
+ CHECK_GE(size + guard, size);
+ void *addr = MmapOrDie(size + guard, "unsafe_stack_alloc");
+ MprotectNoAccess((uptr)addr, (uptr)guard);
+ return (char *)addr + guard;
+}
+
+static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
+ CHECK_GE((char *)start + size, (char *)start);
+ CHECK_GE((char *)start + guard, (char *)start);
+ void *stack_ptr = (char *)start + size;
+ CHECK_EQ((((size_t)stack_ptr) & (kStackAlign - 1)), 0);
+
+ __safestack_unsafe_stack_ptr = stack_ptr;
+ unsafe_stack_start = start;
+ unsafe_stack_size = size;
+ unsafe_stack_guard = guard;
+}
+
+static void unsafe_stack_free() {
+ if (unsafe_stack_start) {
+ UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
+ unsafe_stack_size + unsafe_stack_guard);
+ }
+ unsafe_stack_start = nullptr;
+}
+
+/// Thread data for the cleanup handler
+static pthread_key_t thread_cleanup_key;
+
+/// Safe stack per-thread information passed to the thread_start function
+struct tinfo {
+ void *(*start_routine)(void *);
+ void *start_routine_arg;
+
+ void *unsafe_stack_start;
+ size_t unsafe_stack_size;
+ size_t unsafe_stack_guard;
+};
+
+/// Wrap the thread function in order to deallocate the unsafe stack when the
+/// thread terminates by returning from its main function.
+static void *thread_start(void *arg) {
+ struct tinfo *tinfo = (struct tinfo *)arg;
+
+ void *(*start_routine)(void *) = tinfo->start_routine;
+ void *start_routine_arg = tinfo->start_routine_arg;
+
+ // Setup the unsafe stack; this will destroy tinfo content
+ unsafe_stack_setup(tinfo->unsafe_stack_start, tinfo->unsafe_stack_size,
+ tinfo->unsafe_stack_guard);
+
+ // Make sure out thread-specific destructor will be called
+ // FIXME: we can do this only any other specific key is set by
+ // intercepting the pthread_setspecific function itself
+ pthread_setspecific(thread_cleanup_key, (void *)1);
+
+ return start_routine(start_routine_arg);
+}
+
+/// Thread-specific data destructor
+static void thread_cleanup_handler(void *_iter) {
+ // We want to free the unsafe stack only after all other destructors
+ // have already run. We force this function to be called multiple times.
+ // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
+ // times might still end up executing after the unsafe stack is deallocated.
+ size_t iter = (size_t)_iter;
+ if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
+ pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
+ } else {
+ // This is the last iteration
+ unsafe_stack_free();
+ }
+}
+
+/// Intercept thread creation operation to allocate and setup the unsafe stack
+INTERCEPTOR(int, pthread_create, pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void*), void *arg) {
+
+ size_t size = 0;
+ size_t guard = 0;
+
+ if (attr) {
+ pthread_attr_getstacksize(attr, &size);
+ pthread_attr_getguardsize(attr, &guard);
+ } else {
+ // get pthread default stack size
+ pthread_attr_t tmpattr;
+ pthread_attr_init(&tmpattr);
+ pthread_attr_getstacksize(&tmpattr, &size);
+ pthread_attr_getguardsize(&tmpattr, &guard);
+ pthread_attr_destroy(&tmpattr);
+ }
+
+ CHECK_NE(size, 0);
+ CHECK_EQ((size & (kStackAlign - 1)), 0);
+ CHECK_EQ((guard & (pageSize - 1)), 0);
+
+ void *addr = unsafe_stack_alloc(size, guard);
+ struct tinfo *tinfo =
+ (struct tinfo *)(((char *)addr) + size - sizeof(struct tinfo));
+ tinfo->start_routine = start_routine;
+ tinfo->start_routine_arg = arg;
+ tinfo->unsafe_stack_start = addr;
+ tinfo->unsafe_stack_size = size;
+ tinfo->unsafe_stack_guard = guard;
+
+ return REAL(pthread_create)(thread, attr, thread_start, tinfo);
+}
+
+extern "C" __attribute__((visibility("default")))
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, the constructor is invoked using .preinit_array (see below)
+__attribute__((constructor(0)))
+#endif
+void __safestack_init() {
+ // Determine the stack size for the main thread.
+ size_t size = kDefaultUnsafeStackSize;
+ size_t guard = 4096;
+
+ struct rlimit limit;
+ if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
+ size = limit.rlim_cur;
+
+ // Allocate unsafe stack for main thread
+ void *addr = unsafe_stack_alloc(size, guard);
+
+ unsafe_stack_setup(addr, size, guard);
+ pageSize = sysconf(_SC_PAGESIZE);
+
+ // Initialize pthread interceptors for thread allocation
+ INTERCEPT_FUNCTION(pthread_create);
+
+ // Setup the cleanup handler
+ pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, run safestack initialization before any other constructors.
+// On other platforms we use the constructor attribute to arrange to run our
+// initialization early.
+extern "C" {
+__attribute__((section(".preinit_array"),
+ used)) void (*__safestack_preinit)(void) = __safestack_init;
+}
+#endif
+
+extern "C"
+ __attribute__((visibility("default"))) void *__get_unsafe_stack_start() {
+ return unsafe_stack_start;
+}
+
+extern "C"
+ __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
+ return __safestack_unsafe_stack_ptr;
+}
diff --git a/compiler-rt/lib/sanitizer_common/.clang-format b/compiler-rt/lib/sanitizer_common/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/compiler-rt/lib/sanitizer_common/Android.bp b/compiler-rt/lib/sanitizer_common/Android.bp
new file mode 100644
index 0000000..2de4ff1
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/Android.bp
@@ -0,0 +1,100 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//###############################################################################
+// Host modules
+
+cc_library_static {
+ name: "libsan",
+ host_supported: true,
+ clang: true,
+ sdk_version: "19",
+
+ include_dirs: ["external/compiler-rt/lib"],
+ cppflags: [
+ "-fvisibility=hidden",
+ "-fno-exceptions",
+ "-std=c++11",
+ "-Wall",
+ "-Werror",
+ "-Wno-non-virtual-dtor",
+ "-Wno-unused-parameter",
+ ],
+ srcs: [
+ // rtl
+ "sanitizer_allocator.cc",
+ "sanitizer_common.cc",
+ "sanitizer_deadlock_detector1.cc",
+ "sanitizer_deadlock_detector2.cc",
+ "sanitizer_flags.cc",
+ "sanitizer_flag_parser.cc",
+ "sanitizer_libc.cc",
+ "sanitizer_libignore.cc",
+ "sanitizer_linux.cc",
+ "sanitizer_mac.cc",
+ "sanitizer_persistent_allocator.cc",
+ "sanitizer_platform_limits_linux.cc",
+ "sanitizer_platform_limits_posix.cc",
+ "sanitizer_posix.cc",
+ "sanitizer_printf.cc",
+ "sanitizer_procmaps_common.cc",
+ "sanitizer_procmaps_freebsd.cc",
+ "sanitizer_procmaps_linux.cc",
+ "sanitizer_procmaps_mac.cc",
+ "sanitizer_stackdepot.cc",
+ "sanitizer_stacktrace.cc",
+ "sanitizer_stacktrace_printer.cc",
+ "sanitizer_suppressions.cc",
+ "sanitizer_symbolizer.cc",
+ "sanitizer_symbolizer_libbacktrace.cc",
+ "sanitizer_symbolizer_win.cc",
+ "sanitizer_tls_get_addr.cc",
+ "sanitizer_thread_registry.cc",
+ "sanitizer_win.cc",
+
+ // cdep
+ "sanitizer_common_libcdep.cc",
+ "sanitizer_coverage_libcdep.cc",
+ "sanitizer_coverage_mapping_libcdep.cc",
+ "sanitizer_linux_libcdep.cc",
+ "sanitizer_posix_libcdep.cc",
+ "sanitizer_stacktrace_libcdep.cc",
+ "sanitizer_stoptheworld_linux_libcdep.cc",
+ "sanitizer_symbolizer_libcdep.cc",
+ "sanitizer_symbolizer_posix_libcdep.cc",
+ "sanitizer_unwind_linux_libcdep.cc",
+ ],
+ stl: "none",
+ sanitize: {
+ never: true,
+ },
+ compile_multilib: "both",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+subdirs = ["tests"]
+
+// ANDROIDMK TRANSLATION ERROR: unsupported conditional
+// ifndef SANITIZE_HOST
+// ANDROIDMK TRANSLATION ERROR: unsupported include
+// include $(LOCAL_PATH)/tests/Android.mk
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// endif
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
new file mode 100644
index 0000000..6a20f02
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -0,0 +1,158 @@
+# Build system for the common Sanitizer runtime support library components.
+# These components are shared between AddressSanitizer and ThreadSanitizer.
+
+set(SANITIZER_SOURCES
+ sanitizer_allocator.cc
+ sanitizer_common.cc
+ sanitizer_deadlock_detector1.cc
+ sanitizer_deadlock_detector2.cc
+ sanitizer_flags.cc
+ sanitizer_flag_parser.cc
+ sanitizer_libc.cc
+ sanitizer_libignore.cc
+ sanitizer_linux.cc
+ sanitizer_mac.cc
+ sanitizer_persistent_allocator.cc
+ sanitizer_platform_limits_linux.cc
+ sanitizer_platform_limits_posix.cc
+ sanitizer_posix.cc
+ sanitizer_printf.cc
+ sanitizer_procmaps_common.cc
+ sanitizer_procmaps_freebsd.cc
+ sanitizer_procmaps_linux.cc
+ sanitizer_procmaps_mac.cc
+ sanitizer_stackdepot.cc
+ sanitizer_stacktrace.cc
+ sanitizer_stacktrace_printer.cc
+ sanitizer_suppressions.cc
+ sanitizer_symbolizer.cc
+ sanitizer_symbolizer_libbacktrace.cc
+ sanitizer_symbolizer_mac.cc
+ sanitizer_symbolizer_win.cc
+ sanitizer_tls_get_addr.cc
+ sanitizer_thread_registry.cc
+ sanitizer_win.cc)
+
+# Libc functions stubs. These sources should be linked instead of
+# SANITIZER_LIBCDEP_SOURCES when sanitizer_common library must not depend on
+# libc.
+set(SANITIZER_NOLIBC_SOURCES
+ sanitizer_common_nolibc.cc)
+
+set(SANITIZER_LIBCDEP_SOURCES
+ sanitizer_common_libcdep.cc
+ sanitizer_coverage_libcdep.cc
+ sanitizer_coverage_mapping_libcdep.cc
+ sanitizer_linux_libcdep.cc
+ sanitizer_posix_libcdep.cc
+ sanitizer_stacktrace_libcdep.cc
+ sanitizer_stoptheworld_linux_libcdep.cc
+ sanitizer_symbolizer_libcdep.cc
+ sanitizer_symbolizer_posix_libcdep.cc
+ sanitizer_unwind_linux_libcdep.cc)
+
+# Explicitly list all sanitizer_common headers. Not all of these are
+# included in sanitizer_common source files, but we need to depend on
+# headers when building our custom unit tests.
+set(SANITIZER_HEADERS
+ sanitizer_addrhashmap.h
+ sanitizer_allocator.h
+ sanitizer_allocator_interface.h
+ sanitizer_allocator_internal.h
+ sanitizer_atomic.h
+ sanitizer_atomic_clang.h
+ sanitizer_atomic_msvc.h
+ sanitizer_bitvector.h
+ sanitizer_bvgraph.h
+ sanitizer_common.h
+ sanitizer_common_interceptors.inc
+ sanitizer_common_interceptors_ioctl.inc
+ sanitizer_common_interceptors_format.inc
+ sanitizer_common_syscalls.inc
+ sanitizer_deadlock_detector.h
+ sanitizer_deadlock_detector_interface.h
+ sanitizer_flag_parser.h
+ sanitizer_flags.h
+ sanitizer_flags.inc
+ sanitizer_interface_internal.h
+ sanitizer_internal_defs.h
+ sanitizer_lfstack.h
+ sanitizer_libc.h
+ sanitizer_libignore.h
+ sanitizer_linux.h
+ sanitizer_list.h
+ sanitizer_mac.h
+ sanitizer_mutex.h
+ sanitizer_persistent_allocator.h
+ sanitizer_placement_new.h
+ sanitizer_platform.h
+ sanitizer_platform_interceptors.h
+ sanitizer_platform_limits_posix.h
+ sanitizer_posix.h
+ sanitizer_procmaps.h
+ sanitizer_quarantine.h
+ sanitizer_report_decorator.h
+ sanitizer_stackdepot.h
+ sanitizer_stackdepotbase.h
+ sanitizer_stacktrace.h
+ sanitizer_stacktrace_printer.h
+ sanitizer_stoptheworld.h
+ sanitizer_suppressions.h
+ sanitizer_symbolizer.h
+ sanitizer_symbolizer_internal.h
+ sanitizer_symbolizer_libbacktrace.h
+ sanitizer_symbolizer_mac.h
+ sanitizer_syscall_generic.inc
+ sanitizer_syscall_linux_x86_64.inc
+ sanitizer_syscall_linux_aarch64.inc
+ sanitizer_thread_registry.h)
+
+set(SANITIZER_COMMON_DEFINITIONS)
+
+if(MSVC)
+ list(APPEND SANITIZER_COMMON_DEFINITIONS
+ SANITIZER_NEEDS_SEGV=0)
+else()
+ list(APPEND SANITIZER_COMMON_DEFINITIONS
+ SANITIZER_NEEDS_SEGV=1)
+endif()
+
+include(CheckIncludeFile)
+append_have_file_definition(rpc/xdr.h HAVE_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+append_have_file_definition(tirpc/rpc/xdr.h HAVE_TIRPC_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+
+set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(SANITIZER_CFLAGS)
+
+append_list_if(SANITIZER_LIMIT_FRAME_SIZE -Wframe-larger-than=570
+ SANITIZER_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors
+ SANITIZER_CFLAGS)
+
+if(APPLE)
+ set(OS_OPTION OS ${SANITIZER_COMMON_SUPPORTED_OS})
+endif()
+
+add_compiler_rt_object_libraries(RTSanitizerCommon
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTSanitizerCommonNoLibc
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_NOLIBC_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTSanitizerCommonLibc
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_LIBCDEP_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+
+# Unit tests for common sanitizer runtime.
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(tests)
+endif()
diff --git a/compiler-rt/lib/sanitizer_common/Makefile.mk b/compiler-rt/lib/sanitizer_common/Makefile.mk
new file mode 100644
index 0000000..5bb20d0
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/Makefile.mk
@@ -0,0 +1,24 @@
+#===- lib/sanitizer_common/Makefile.mk ---------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := sanitizer_common
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+NolibcSources := $(foreach file,$(wildcard $(Dir)/*_nolibc.cc),$(notdir $(file)))
+Sources := $(filter-out $(NolibcSources),$(Sources))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+
+# Define a convenience variable for all the sanitizer_common functions.
+SanitizerCommonFunctions := $(Sources:%.cc=%)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h b/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
new file mode 100644
index 0000000..e55fc4f
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -0,0 +1,342 @@
+//===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Concurrent uptr->T hashmap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ADDRHASHMAP_H
+#define SANITIZER_ADDRHASHMAP_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_allocator_internal.h"
+
+namespace __sanitizer {
+
+// Concurrent uptr->T hashmap.
+// T must be a POD type, kSize is preferably a prime but can be any number.
+// Usage example:
+//
+// typedef AddrHashMap<uptr, 11> Map;
+// Map m;
+// {
+// Map::Handle h(&m, addr);
+// use h.operator->() to access the data
+// if h.created() then the element was just created, and the current thread
+// has exclusive access to it
+// otherwise the current thread has only read access to the data
+// }
+// {
+// Map::Handle h(&m, addr, true);
+// this will remove the data from the map in Handle dtor
+// the current thread has exclusive access to the data
+// if !h.exists() then the element never existed
+// }
+template<typename T, uptr kSize>
+class AddrHashMap {
+ private:
+ struct Cell {
+ atomic_uintptr_t addr;
+ T val;
+ };
+
+ struct AddBucket {
+ uptr cap;
+ uptr size;
+ Cell cells[1]; // variable len
+ };
+
+ static const uptr kBucketSize = 3;
+
+ struct Bucket {
+ RWMutex mtx;
+ atomic_uintptr_t add;
+ Cell cells[kBucketSize];
+ };
+
+ public:
+ AddrHashMap();
+
+ class Handle {
+ public:
+ Handle(AddrHashMap<T, kSize> *map, uptr addr);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create);
+
+ ~Handle();
+ T *operator->();
+ bool created() const;
+ bool exists() const;
+
+ private:
+ friend AddrHashMap<T, kSize>;
+ AddrHashMap<T, kSize> *map_;
+ Bucket *bucket_;
+ Cell *cell_;
+ uptr addr_;
+ uptr addidx_;
+ bool created_;
+ bool remove_;
+ bool create_;
+ };
+
+ private:
+ friend class Handle;
+ Bucket *table_;
+
+ void acquire(Handle *h);
+ void release(Handle *h);
+ uptr calcHash(uptr addr);
+};
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = false;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove, bool create) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = create;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::~Handle() {
+ map_->release(this);
+}
+
+template <typename T, uptr kSize>
+T *AddrHashMap<T, kSize>::Handle::operator->() {
+ return &cell_->val;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::created() const {
+ return created_;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::exists() const {
+ return cell_ != nullptr;
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::AddrHashMap() {
+ table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap");
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::acquire(Handle *h) {
+ uptr addr = h->addr_;
+ uptr hash = calcHash(addr);
+ Bucket *b = &table_[hash];
+
+ h->created_ = false;
+ h->addidx_ = -1U;
+ h->bucket_ = b;
+ h->cell_ = nullptr;
+
+ // If we want to remove the element, we need exclusive access to the bucket,
+ // so skip the lock-free phase.
+ if (h->remove_)
+ goto locked;
+
+ retry:
+ // First try to find an existing element w/o read mutex.
+ CHECK(!h->remove_);
+ // Check the embed cells.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+ if (addr1 == addr) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Check the add cells with read lock.
+ if (atomic_load(&b->add, memory_order_relaxed)) {
+ b->mtx.ReadLock();
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ }
+ b->mtx.ReadUnlock();
+ }
+
+ locked:
+ // Re-check existence under write lock.
+ // Embed cells.
+ b->mtx.Lock();
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+
+ // Add cells.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (add) {
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+ }
+
+ // The element does not exist, no need to create it if we want to remove.
+ if (h->remove_ || !h->create_) {
+ b->mtx.Unlock();
+ return;
+ }
+
+ // Now try to create it under the mutex.
+ h->created_ = true;
+ // See if we have a free embed cell.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == 0) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Store in the add cells.
+ if (!add) {
+ // Allocate a new add array.
+ const uptr kInitSize = 64;
+ add = (AddBucket*)InternalAlloc(kInitSize);
+ internal_memset(add, 0, kInitSize);
+ add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add->size = 0;
+ atomic_store(&b->add, (uptr)add, memory_order_relaxed);
+ }
+ if (add->size == add->cap) {
+ // Grow existing add array.
+ uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]);
+ uptr newsize = oldsize * 2;
+ AddBucket *add1 = (AddBucket*)InternalAlloc(newsize);
+ internal_memset(add1, 0, newsize);
+ add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add1->size = add->size;
+ internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0]));
+ InternalFree(add);
+ atomic_store(&b->add, (uptr)add1, memory_order_relaxed);
+ add = add1;
+ }
+ // Store.
+ uptr i = add->size++;
+ Cell *c = &add->cells[i];
+ CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0);
+ h->addidx_ = i;
+ h->cell_ = c;
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::release(Handle *h) {
+ if (!h->cell_)
+ return;
+ Bucket *b = h->bucket_;
+ Cell *c = h->cell_;
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (h->created_) {
+ // Denote completion of insertion.
+ CHECK_EQ(addr1, 0);
+ // After the following store, the element becomes available
+ // for lock-free reads.
+ atomic_store(&c->addr, h->addr_, memory_order_release);
+ b->mtx.Unlock();
+ } else if (h->remove_) {
+ // Denote that the cell is empty now.
+ CHECK_EQ(addr1, h->addr_);
+ atomic_store(&c->addr, 0, memory_order_release);
+ // See if we need to compact the bucket.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (h->addidx_ == -1U) {
+ // Removed from embed array, move an add element into the freed cell.
+ if (add && add->size != 0) {
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ c->val = c1->val;
+ uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed);
+ atomic_store(&c->addr, addr1, memory_order_release);
+ atomic_store(&c1->addr, 0, memory_order_release);
+ }
+ } else {
+ // Removed from add array, compact it.
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ if (c != c1) {
+ *c = *c1;
+ atomic_store(&c1->addr, 0, memory_order_relaxed);
+ }
+ }
+ if (add && add->size == 0) {
+ // FIXME(dvyukov): free add?
+ }
+ b->mtx.Unlock();
+ } else {
+ CHECK_EQ(addr1, h->addr_);
+ if (h->addidx_ != -1U)
+ b->mtx.ReadUnlock();
+ }
+}
+
+template<typename T, uptr kSize>
+uptr AddrHashMap<T, kSize>::calcHash(uptr addr) {
+ addr += addr << 10;
+ addr ^= addr >> 6;
+ return addr % kSize;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ADDRHASHMAP_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
new file mode 100644
index 0000000..538e2db
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
@@ -0,0 +1,151 @@
+//===-- sanitizer_allocator.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// This allocator is used inside run-times.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// ThreadSanitizer for Go uses libc malloc/free.
+#if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
+# if SANITIZER_LINUX && !SANITIZER_ANDROID
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void __libc_free(void *ptr);
+# define LIBC_MALLOC __libc_malloc
+# define LIBC_FREE __libc_free
+# else
+# include <stdlib.h>
+# define LIBC_MALLOC malloc
+# define LIBC_FREE free
+# endif
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ (void)cache;
+ return LIBC_MALLOC(size);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ (void)cache;
+ LIBC_FREE(ptr);
+}
+
+InternalAllocator *internal_allocator() {
+ return 0;
+}
+
+#else // SANITIZER_GO
+
+static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
+static atomic_uint8_t internal_allocator_initialized;
+static StaticSpinMutex internal_alloc_init_mu;
+
+static InternalAllocatorCache internal_allocator_cache;
+static StaticSpinMutex internal_allocator_cache_mu;
+
+InternalAllocator *internal_allocator() {
+ InternalAllocator *internal_allocator_instance =
+ reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder);
+ if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) {
+ SpinMutexLock l(&internal_alloc_init_mu);
+ if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
+ 0) {
+ internal_allocator_instance->Init(/* may_return_null*/ false);
+ atomic_store(&internal_allocator_initialized, 1, memory_order_release);
+ }
+ }
+ return internal_allocator_instance;
+}
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Allocate(&internal_allocator_cache, size, 8,
+ false);
+ }
+ return internal_allocator()->Allocate(cache, size, 8, false);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ if (!cache) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
+ }
+ internal_allocator()->Deallocate(cache, ptr);
+}
+
+#endif // SANITIZER_GO
+
+const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ if (size + sizeof(u64) < size)
+ return nullptr;
+ void *p = RawInternalAlloc(size + sizeof(u64), cache);
+ if (!p)
+ return nullptr;
+ ((u64*)p)[0] = kBlockMagic;
+ return (char*)p + sizeof(u64);
+}
+
+void InternalFree(void *addr, InternalAllocatorCache *cache) {
+ if (!addr)
+ return;
+ addr = (char*)addr - sizeof(u64);
+ CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
+ ((u64*)addr)[0] = 0;
+ RawInternalFree(addr, cache);
+}
+
+// LowLevelAllocator
+static LowLevelAllocateCallback low_level_alloc_callback;
+
+void *LowLevelAllocator::Allocate(uptr size) {
+ // Align allocation size.
+ size = RoundUpTo(size, 8);
+ if (allocated_end_ - allocated_current_ < (sptr)size) {
+ uptr size_to_allocate = Max(size, GetPageSizeCached());
+ allocated_current_ =
+ (char*)MmapOrDie(size_to_allocate, __func__);
+ allocated_end_ = allocated_current_ + size_to_allocate;
+ if (low_level_alloc_callback) {
+ low_level_alloc_callback((uptr)allocated_current_,
+ size_to_allocate);
+ }
+ }
+ CHECK(allocated_end_ - allocated_current_ >= (sptr)size);
+ void *res = allocated_current_;
+ allocated_current_ += size;
+ return res;
+}
+
+void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
+ low_level_alloc_callback = callback;
+}
+
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
+ if (!size) return false;
+ uptr max = (uptr)-1L;
+ return (max / size) < n;
+}
+
+void NORETURN ReportAllocatorCannotReturnNull() {
+ Report("%s's allocator is terminating the process instead of returning 0\n",
+ SanitizerToolName);
+ Report("If you don't like this behavior set allocator_may_return_null=1\n");
+ CHECK(0);
+ Die();
+}
+
+} // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
new file mode 100644
index 0000000..44d6fce
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
@@ -0,0 +1,1455 @@
+//===-- sanitizer_allocator.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specialized memory allocator for ThreadSanitizer, MemorySanitizer, etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_H
+#define SANITIZER_ALLOCATOR_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_lfstack.h"
+
+namespace __sanitizer {
+
+// Prints error message and kills the program.
+void NORETURN ReportAllocatorCannotReturnNull();
+
+// SizeClassMap maps allocation sizes into size classes and back.
+// Class 0 corresponds to size 0.
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
+// Next 4 classes: 256 + i * 64 (i = 1 to 4).
+// Next 4 classes: 512 + i * 128 (i = 1 to 4).
+// ...
+// Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4).
+// Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
+//
+// This structure of the size class map gives us:
+// - Efficient table-free class-to-size and size-to-class functions.
+// - Difference between two consequent size classes is betweed 14% and 25%
+//
+// This class also gives a hint to a thread-caching allocator about the amount
+// of chunks that need to be cached per-thread:
+// - kMaxNumCached is the maximal number of chunks per size class.
+// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
+//
+// Part of output of SizeClassMap::Print():
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
+//
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
+//
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17
+// c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18
+// c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19
+//
+// c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20
+// c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21
+// c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22
+// c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23
+//
+// c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24
+// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25
+// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26
+// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27
+//
+// ...
+//
+// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48
+// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49
+// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50
+// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51
+//
+// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
+
+template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog>
+class SizeClassMap {
+ static const uptr kMinSizeLog = 4;
+ static const uptr kMidSizeLog = kMinSizeLog + 4;
+ static const uptr kMinSize = 1 << kMinSizeLog;
+ static const uptr kMidSize = 1 << kMidSizeLog;
+ static const uptr kMidClass = kMidSize / kMinSize;
+ static const uptr S = 2;
+ static const uptr M = (1 << S) - 1;
+
+ public:
+ static const uptr kMaxNumCached = kMaxNumCachedT;
+ // We transfer chunks between central and thread-local free lists in batches.
+ // For small size classes we allocate batches separately.
+ // For large size classes we use one of the chunks to store the batch.
+ struct TransferBatch {
+ TransferBatch *next;
+ uptr count;
+ void *batch[kMaxNumCached];
+ };
+
+ static const uptr kMaxSize = 1UL << kMaxSizeLog;
+ static const uptr kNumClasses =
+ kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
+ COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
+ static const uptr kNumClassesRounded =
+ kNumClasses == 32 ? 32 :
+ kNumClasses <= 64 ? 64 :
+ kNumClasses <= 128 ? 128 : 256;
+
+ static uptr Size(uptr class_id) {
+ if (class_id <= kMidClass)
+ return kMinSize * class_id;
+ class_id -= kMidClass;
+ uptr t = kMidSize << (class_id >> S);
+ return t + (t >> S) * (class_id & M);
+ }
+
+ static uptr ClassID(uptr size) {
+ if (size <= kMidSize)
+ return (size + kMinSize - 1) >> kMinSizeLog;
+ if (size > kMaxSize) return 0;
+ uptr l = MostSignificantSetBitIndex(size);
+ uptr hbits = (size >> (l - S)) & M;
+ uptr lbits = size & ((1 << (l - S)) - 1);
+ uptr l1 = l - kMidSizeLog;
+ return kMidClass + (l1 << S) + hbits + (lbits > 0);
+ }
+
+ static uptr MaxCached(uptr class_id) {
+ if (class_id == 0) return 0;
+ uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
+ return Max<uptr>(1, Min(kMaxNumCached, n));
+ }
+
+ static void Print() {
+ uptr prev_s = 0;
+ uptr total_cached = 0;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ uptr s = Size(i);
+ if (s >= kMidSize / 2 && (s & (s - 1)) == 0)
+ Printf("\n");
+ uptr d = s - prev_s;
+ uptr p = prev_s ? (d * 100 / prev_s) : 0;
+ uptr l = s ? MostSignificantSetBitIndex(s) : 0;
+ uptr cached = MaxCached(i) * s;
+ Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
+ "cached: %zd %zd; id %zd\n",
+ i, Size(i), d, p, l, MaxCached(i), cached, ClassID(s));
+ total_cached += cached;
+ prev_s = s;
+ }
+ Printf("Total cached: %zd\n", total_cached);
+ }
+
+ static bool SizeClassRequiresSeparateTransferBatch(uptr class_id) {
+ return Size(class_id) < sizeof(TransferBatch) -
+ sizeof(uptr) * (kMaxNumCached - MaxCached(class_id));
+ }
+
+ static void Validate() {
+ for (uptr c = 1; c < kNumClasses; c++) {
+ // Printf("Validate: c%zd\n", c);
+ uptr s = Size(c);
+ CHECK_NE(s, 0U);
+ CHECK_EQ(ClassID(s), c);
+ if (c != kNumClasses - 1)
+ CHECK_EQ(ClassID(s + 1), c + 1);
+ CHECK_EQ(ClassID(s - 1), c);
+ if (c)
+ CHECK_GT(Size(c), Size(c-1));
+ }
+ CHECK_EQ(ClassID(kMaxSize + 1), 0);
+
+ for (uptr s = 1; s <= kMaxSize; s++) {
+ uptr c = ClassID(s);
+ // Printf("s%zd => c%zd\n", s, c);
+ CHECK_LT(c, kNumClasses);
+ CHECK_GE(Size(c), s);
+ if (c > 0)
+ CHECK_LT(Size(c-1), s);
+ }
+ }
+};
+
+typedef SizeClassMap<17, 128, 16> DefaultSizeClassMap;
+typedef SizeClassMap<17, 64, 14> CompactSizeClassMap;
+template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
+
+// Memory allocator statistics
+enum AllocatorStat {
+ AllocatorStatAllocated,
+ AllocatorStatMapped,
+ AllocatorStatCount
+};
+
+typedef uptr AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+ void InitLinkerInitialized() {}
+
+ void Add(AllocatorStat i, uptr v) {
+ v += atomic_load(&stats_[i], memory_order_relaxed);
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Sub(AllocatorStat i, uptr v) {
+ v = atomic_load(&stats_[i], memory_order_relaxed) - v;
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Set(AllocatorStat i, uptr v) {
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ uptr Get(AllocatorStat i) const {
+ return atomic_load(&stats_[i], memory_order_relaxed);
+ }
+
+ private:
+ friend class AllocatorGlobalStats;
+ AllocatorStats *next_;
+ AllocatorStats *prev_;
+ atomic_uintptr_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+ void InitLinkerInitialized() {
+ next_ = this;
+ prev_ = this;
+ }
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized();
+ }
+
+ void Register(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->next_ = next_;
+ s->prev_ = this;
+ next_->prev_ = s;
+ next_ = s;
+ }
+
+ void Unregister(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->prev_->next_ = s->next_;
+ s->next_->prev_ = s->prev_;
+ for (int i = 0; i < AllocatorStatCount; i++)
+ Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+ }
+
+ void Get(AllocatorStatCounters s) const {
+ internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
+ SpinMutexLock l(&mu_);
+ const AllocatorStats *stats = this;
+ for (;;) {
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] += stats->Get(AllocatorStat(i));
+ stats = stats->next_;
+ if (stats == this)
+ break;
+ }
+ // All stats must be non-negative.
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
+ }
+
+ private:
+ mutable SpinMutex mu_;
+};
+
+// Allocators call these callbacks on mmap/munmap.
+struct NoOpMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const { }
+ void OnUnmap(uptr p, uptr size) const { }
+};
+
+// Callback type for iterating over chunks.
+typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
+
+// SizeClassAllocator64 -- allocator for 64-bit address space.
+//
+// Space: a portion of address space of kSpaceSize bytes starting at
+// a fixed address (kSpaceBeg). Both constants are powers of two and
+// kSpaceBeg is kSpaceSize-aligned.
+// At the beginning the entire space is mprotect-ed, then small parts of it
+// are mapped on demand.
+//
+// Region: a part of Space dedicated to a single size class.
+// There are kNumClasses Regions of equal size.
+//
+// UserChunk: a piece of memory returned to user.
+// MetaChunk: kMetadataSize bytes of metadata associated with a UserChunk.
+//
+// A Region looks like this:
+// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1
+template <const uptr kSpaceBeg, const uptr kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
+class SizeClassAllocator64 {
+ public:
+ typedef typename SizeClassMap::TransferBatch Batch;
+ typedef SizeClassAllocator64<kSpaceBeg, kSpaceSize, kMetadataSize,
+ SizeClassMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
+
+ void Init() {
+ CHECK_EQ(kSpaceBeg,
+ reinterpret_cast<uptr>(MmapNoAccess(kSpaceBeg, kSpaceSize)));
+ MapWithCallback(kSpaceEnd, AdditionalSize());
+ }
+
+ void MapWithCallback(uptr beg, uptr size) {
+ CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
+ MapUnmapCallback().OnMap(beg, size);
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *region = GetRegionInfo(class_id);
+ Batch *b = region->free_list.Pop();
+ if (!b)
+ b = PopulateFreeList(stat, c, class_id, region);
+ region->n_allocated += b->count;
+ return b;
+ }
+
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ CHECK_GT(b->count, 0);
+ region->free_list.Push(b);
+ region->n_freed += b->count;
+ }
+
+ static bool PointerIsMine(const void *p) {
+ return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
+ }
+
+ static uptr GetSizeClass(const void *p) {
+ return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
+ }
+
+ void *GetBlockBegin(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = SizeClassMap::Size(class_id);
+ if (!size) return nullptr;
+ uptr chunk_idx = GetChunkIdx((uptr)p, size);
+ uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
+ uptr beg = chunk_idx * size;
+ uptr next_beg = beg + size;
+ if (class_id >= kNumClasses) return nullptr;
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user >= next_beg)
+ return reinterpret_cast<void*>(reg_beg + beg);
+ return nullptr;
+ }
+
+ static uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return SizeClassMap::Size(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ void *GetMetaData(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = SizeClassMap::Size(class_id);
+ uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
+ return reinterpret_cast<void*>(kSpaceBeg + (kRegionSize * (class_id + 1)) -
+ (1 + chunk_idx) * kMetadataSize);
+ }
+
+ uptr TotalMemoryUsed() {
+ uptr res = 0;
+ for (uptr i = 0; i < kNumClasses; i++)
+ res += GetRegionInfo(i)->allocated_user;
+ return res;
+ }
+
+ // Test-only.
+ void TestOnlyUnmap() {
+ UnmapWithCallback(kSpaceBeg, kSpaceSize + AdditionalSize());
+ }
+
+ void PrintStats() {
+ uptr total_mapped = 0;
+ uptr n_allocated = 0;
+ uptr n_freed = 0;
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ total_mapped += region->mapped_user;
+ n_allocated += region->n_allocated;
+ n_freed += region->n_freed;
+ }
+ Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
+ "remains %zd\n",
+ total_mapped >> 20, n_allocated, n_allocated - n_freed);
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user == 0) continue;
+ Printf(" %02zd (%zd): total: %zd K allocs: %zd remains: %zd\n",
+ class_id,
+ SizeClassMap::Size(class_id),
+ region->mapped_user >> 10,
+ region->n_allocated,
+ region->n_allocated - region->n_freed);
+ }
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetRegionInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+ GetRegionInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr chunk_size = SizeClassMap::Size(class_id);
+ uptr region_beg = kSpaceBeg + class_id * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + region->allocated_user;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ static uptr AdditionalSize() {
+ return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+ GetPageSizeCached());
+ }
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+ static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
+
+ private:
+ static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
+ static const uptr kSpaceEnd = kSpaceBeg + kSpaceSize;
+ COMPILER_CHECK(kSpaceBeg % kSpaceSize == 0);
+ // kRegionSize must be >= 2^32.
+ COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2)));
+ // Populate the free list with at most this number of bytes at once
+ // or with one element if its size is greater.
+ static const uptr kPopulateSize = 1 << 14;
+ // Call mmap for user memory with at least this size.
+ static const uptr kUserMapSize = 1 << 16;
+ // Call mmap for metadata memory with at least this size.
+ static const uptr kMetaMapSize = 1 << 16;
+
+ struct RegionInfo {
+ BlockingMutex mutex;
+ LFStack<Batch> free_list;
+ uptr allocated_user; // Bytes allocated for user memory.
+ uptr allocated_meta; // Bytes allocated for metadata.
+ uptr mapped_user; // Bytes mapped for user memory.
+ uptr mapped_meta; // Bytes mapped for metadata.
+ uptr n_allocated, n_freed; // Just stats.
+ };
+ COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
+
+ RegionInfo *GetRegionInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
+ return ®ions[class_id];
+ }
+
+ static uptr GetChunkIdx(uptr chunk, uptr size) {
+ uptr offset = chunk % kRegionSize;
+ // Here we divide by a non-constant. This is costly.
+ // size always fits into 32-bits. If the offset fits too, use 32-bit div.
+ if (offset >> (SANITIZER_WORDSIZE / 2))
+ return offset / size;
+ return (u32)offset / (u32)size;
+ }
+
+ NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id, RegionInfo *region) {
+ BlockingMutexLock l(®ion->mutex);
+ Batch *b = region->free_list.Pop();
+ if (b)
+ return b;
+ uptr size = SizeClassMap::Size(class_id);
+ uptr count = size < kPopulateSize ? SizeClassMap::MaxCached(class_id) : 1;
+ uptr beg_idx = region->allocated_user;
+ uptr end_idx = beg_idx + count * size;
+ uptr region_beg = kSpaceBeg + kRegionSize * class_id;
+ if (end_idx + size > region->mapped_user) {
+ // Do the mmap for the user memory.
+ uptr map_size = kUserMapSize;
+ while (end_idx + size > region->mapped_user + map_size)
+ map_size += kUserMapSize;
+ CHECK_GE(region->mapped_user + map_size, end_idx);
+ MapWithCallback(region_beg + region->mapped_user, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ region->mapped_user += map_size;
+ }
+ uptr total_count = (region->mapped_user - beg_idx - size)
+ / size / count * count;
+ region->allocated_meta += total_count * kMetadataSize;
+ if (region->allocated_meta > region->mapped_meta) {
+ uptr map_size = kMetaMapSize;
+ while (region->allocated_meta > region->mapped_meta + map_size)
+ map_size += kMetaMapSize;
+ // Do the mmap for the metadata.
+ CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
+ MapWithCallback(region_beg + kRegionSize -
+ region->mapped_meta - map_size, map_size);
+ region->mapped_meta += map_size;
+ }
+ CHECK_LE(region->allocated_meta, region->mapped_meta);
+ if (region->mapped_user + region->mapped_meta > kRegionSize) {
+ Printf("%s: Out of memory. Dying. ", SanitizerToolName);
+ Printf("The process has exhausted %zuMB for size class %zu.\n",
+ kRegionSize / 1024 / 1024, size);
+ Die();
+ }
+ for (;;) {
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)(region_beg + beg_idx);
+ b->count = count;
+ for (uptr i = 0; i < count; i++)
+ b->batch[i] = (void*)(region_beg + beg_idx + i * size);
+ region->allocated_user += count * size;
+ CHECK_LE(region->allocated_user, region->mapped_user);
+ beg_idx += count * size;
+ if (beg_idx + count * size + size > region->mapped_user)
+ break;
+ CHECK_GT(b->count, 0);
+ region->free_list.Push(b);
+ }
+ return b;
+ }
+};
+
+// Maps integers in rage [0, kSize) to u8 values.
+template<u64 kSize>
+class FlatByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map_, 0, sizeof(map_));
+ }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize);
+ CHECK_EQ(0U, map_[idx]);
+ map_[idx] = val;
+ }
+ u8 operator[] (uptr idx) {
+ CHECK_LT(idx, kSize);
+ // FIXME: CHECK may be too expensive here.
+ return map_[idx];
+ }
+ private:
+ u8 map_[kSize];
+};
+
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map1_, 0, sizeof(map1_));
+ mu_.Init();
+ }
+
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kSize1; i++) {
+ u8 *p = Get(i);
+ if (!p) continue;
+ MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+ UnmapOrDie(p, kSize2);
+ }
+ }
+
+ uptr size() const { return kSize1 * kSize2; }
+ uptr size1() const { return kSize1; }
+ uptr size2() const { return kSize2; }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = GetOrCreate(idx / kSize2);
+ CHECK_EQ(0U, map2[idx % kSize2]);
+ map2[idx % kSize2] = val;
+ }
+
+ u8 operator[] (uptr idx) const {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = Get(idx / kSize2);
+ if (!map2) return 0;
+ return map2[idx % kSize2];
+ }
+
+ private:
+ u8 *Get(uptr idx) const {
+ CHECK_LT(idx, kSize1);
+ return reinterpret_cast<u8 *>(
+ atomic_load(&map1_[idx], memory_order_acquire));
+ }
+
+ u8 *GetOrCreate(uptr idx) {
+ u8 *res = Get(idx);
+ if (!res) {
+ SpinMutexLock l(&mu_);
+ if (!(res = Get(idx))) {
+ res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+ MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+ atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+ memory_order_release);
+ }
+ }
+ return res;
+ }
+
+ atomic_uintptr_t map1_[kSize1];
+ StaticSpinMutex mu_;
+};
+
+// SizeClassAllocator32 -- allocator for 32-bit address space.
+// This allocator can theoretically be used on 64-bit arch, but there it is less
+// efficient than SizeClassAllocator64.
+//
+// [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can
+// be returned by MmapOrDie().
+//
+// Region:
+// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
+// Since the regions are aligned by kRegionSize, there are exactly
+// kNumPossibleRegions possible regions in the address space and so we keep
+// a ByteMap possible_regions to store the size classes of each Region.
+// 0 size class means the region is not used by the allocator.
+//
+// One Region is used to allocate chunks of a single size class.
+// A Region looks like this:
+// UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1
+//
+// In order to avoid false sharing the objects of this class should be
+// chache-line aligned.
+template <const uptr kSpaceBeg, const u64 kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap,
+ const uptr kRegionSizeLog,
+ class ByteMap,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
+class SizeClassAllocator32 {
+ public:
+ typedef typename SizeClassMap::TransferBatch Batch;
+ typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
+ SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
+
+ void Init() {
+ possible_regions.TestOnlyInit();
+ internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
+ }
+
+ void *MapWithCallback(uptr size) {
+ size = RoundUpTo(size, GetPageSizeCached());
+ void *res = MmapOrDie(size, "SizeClassAllocator32");
+ MapUnmapCallback().OnMap((uptr)res, size);
+ return res;
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ void *GetMetaData(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = SizeClassMap::Size(GetSizeClass(p));
+ u32 offset = mem - beg;
+ uptr n = offset / (u32)size; // 32-bit division
+ uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize;
+ return reinterpret_cast<void*>(meta);
+ }
+
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ if (sci->free_list.empty())
+ PopulateFreeList(stat, c, sci, class_id);
+ CHECK(!sci->free_list.empty());
+ Batch *b = sci->free_list.front();
+ sci->free_list.pop_front();
+ return b;
+ }
+
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_front(b);
+ }
+
+ bool PointerIsMine(const void *p) {
+ return GetSizeClass(p) != 0;
+ }
+
+ uptr GetSizeClass(const void *p) {
+ return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
+ }
+
+ void *GetBlockBegin(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = SizeClassMap::Size(GetSizeClass(p));
+ u32 offset = mem - beg;
+ u32 n = offset / (u32)size; // 32-bit division
+ uptr res = beg + (n * (u32)size);
+ return reinterpret_cast<void*>(res);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return SizeClassMap::Size(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ uptr TotalMemoryUsed() {
+ // No need to lock here.
+ uptr res = 0;
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ res += kRegionSize;
+ return res;
+ }
+
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ UnmapWithCallback((i * kRegionSize), kRegionSize);
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetSizeClassInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = kNumClasses - 1; i >= 0; i--) {
+ GetSizeClassInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr region = 0; region < kNumPossibleRegions; region++)
+ if (possible_regions[region]) {
+ uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
+ uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
+ uptr region_beg = region * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + max_chunks_in_region * chunk_size;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ void PrintStats() {
+ }
+
+ static uptr AdditionalSize() {
+ return 0;
+ }
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+
+ private:
+ static const uptr kRegionSize = 1 << kRegionSizeLog;
+ static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
+
+ struct SizeClassInfo {
+ SpinMutex mutex;
+ IntrusiveList<Batch> free_list;
+ char padding[kCacheLineSize - sizeof(uptr) - sizeof(IntrusiveList<Batch>)];
+ };
+ COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize);
+
+ uptr ComputeRegionId(uptr mem) {
+ uptr res = mem >> kRegionSizeLog;
+ CHECK_LT(res, kNumPossibleRegions);
+ return res;
+ }
+
+ uptr ComputeRegionBeg(uptr mem) {
+ return mem & ~(kRegionSize - 1);
+ }
+
+ uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
+ "SizeClassAllocator32"));
+ MapUnmapCallback().OnMap(res, kRegionSize);
+ stat->Add(AllocatorStatMapped, kRegionSize);
+ CHECK_EQ(0U, (res & (kRegionSize - 1)));
+ possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
+ return res;
+ }
+
+ SizeClassInfo *GetSizeClassInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ return &size_class_info_array[class_id];
+ }
+
+ void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ SizeClassInfo *sci, uptr class_id) {
+ uptr size = SizeClassMap::Size(class_id);
+ uptr reg = AllocateRegion(stat, class_id);
+ uptr n_chunks = kRegionSize / (size + kMetadataSize);
+ uptr max_count = SizeClassMap::MaxCached(class_id);
+ Batch *b = nullptr;
+ for (uptr i = reg; i < reg + n_chunks * size; i += size) {
+ if (!b) {
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)i;
+ b->count = 0;
+ }
+ b->batch[b->count++] = (void*)i;
+ if (b->count == max_count) {
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_back(b);
+ b = nullptr;
+ }
+ }
+ if (b) {
+ CHECK_GT(b->count, 0);
+ sci->free_list.push_back(b);
+ }
+ }
+
+ ByteMap possible_regions;
+ SizeClassInfo size_class_info_array[kNumClasses];
+};
+
+// Objects of this type should be used as local caches for SizeClassAllocator64
+// or SizeClassAllocator32. Since the typical use of this class is to have one
+// object per thread in TLS, is has to be POD.
+template<class SizeClassAllocator>
+struct SizeClassAllocatorLocalCache {
+ typedef SizeClassAllocator Allocator;
+ static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
+
+ void Init(AllocatorGlobalStats *s) {
+ stats_.Init();
+ if (s)
+ s->Register(&stats_);
+ }
+
+ void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+ Drain(allocator);
+ if (s)
+ s->Unregister(&stats_);
+ }
+
+ void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatAllocated, SizeClassMap::Size(class_id));
+ PerClass *c = &per_class_[class_id];
+ if (UNLIKELY(c->count == 0))
+ Refill(allocator, class_id);
+ void *res = c->batch[--c->count];
+ PREFETCH(c->batch[c->count - 1]);
+ return res;
+ }
+
+ void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ // If the first allocator call on a new thread is a deallocation, then
+ // max_count will be zero, leading to check failure.
+ InitCache();
+ stats_.Sub(AllocatorStatAllocated, SizeClassMap::Size(class_id));
+ PerClass *c = &per_class_[class_id];
+ CHECK_NE(c->max_count, 0UL);
+ if (UNLIKELY(c->count == c->max_count))
+ Drain(allocator, class_id);
+ c->batch[c->count++] = p;
+ }
+
+ void Drain(SizeClassAllocator *allocator) {
+ for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
+ PerClass *c = &per_class_[class_id];
+ while (c->count > 0)
+ Drain(allocator, class_id);
+ }
+ }
+
+ // private:
+ typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
+ typedef typename SizeClassMap::TransferBatch Batch;
+ struct PerClass {
+ uptr count;
+ uptr max_count;
+ void *batch[2 * SizeClassMap::kMaxNumCached];
+ };
+ PerClass per_class_[kNumClasses];
+ AllocatorStats stats_;
+
+ void InitCache() {
+ if (per_class_[1].max_count)
+ return;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
+ c->max_count = 2 * SizeClassMap::MaxCached(i);
+ }
+ }
+
+ NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
+ CHECK_GT(b->count, 0);
+ for (uptr i = 0; i < b->count; i++)
+ c->batch[i] = b->batch[i];
+ c->count = b->count;
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
+ }
+
+ NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ Batch *b;
+ if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
+ b = (Batch*)Allocate(allocator, SizeClassMap::ClassID(sizeof(Batch)));
+ else
+ b = (Batch*)c->batch[0];
+ uptr cnt = Min(c->max_count / 2, c->count);
+ for (uptr i = 0; i < cnt; i++) {
+ b->batch[i] = c->batch[i];
+ c->batch[i] = c->batch[i + c->max_count / 2];
+ }
+ b->count = cnt;
+ c->count -= cnt;
+ CHECK_GT(b->count, 0);
+ allocator->DeallocateBatch(&stats_, class_id, b);
+ }
+};
+
+// This class can (de)allocate only large chunks of memory using mmap/unmap.
+// The main purpose of this allocator is to cover large and rare allocation
+// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
+template <class MapUnmapCallback = NoOpMapUnmapCallback>
+class LargeMmapAllocator {
+ public:
+ void InitLinkerInitialized(bool may_return_null) {
+ page_size_ = GetPageSizeCached();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void Init(bool may_return_null) {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized(may_return_null);
+ }
+
+ void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = RoundUpMapSize(size);
+ if (alignment > page_size_)
+ map_size += alignment;
+ // Overflow.
+ if (map_size < size)
+ return ReturnNullOrDie();
+ uptr map_beg = reinterpret_cast<uptr>(
+ MmapOrDie(map_size, "LargeMmapAllocator"));
+ CHECK(IsAligned(map_beg, page_size_));
+ MapUnmapCallback().OnMap(map_beg, map_size);
+ uptr map_end = map_beg + map_size;
+ uptr res = map_beg + page_size_;
+ if (res & (alignment - 1)) // Align.
+ res += alignment - (res & (alignment - 1));
+ CHECK(IsAligned(res, alignment));
+ CHECK(IsAligned(res, page_size_));
+ CHECK_GE(res + size, map_beg);
+ CHECK_LE(res + size, map_end);
+ Header *h = GetHeader(res);
+ h->size = size;
+ h->map_beg = map_beg;
+ h->map_size = map_size;
+ uptr size_log = MostSignificantSetBitIndex(map_size);
+ CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = n_chunks_++;
+ chunks_sorted_ = false;
+ CHECK_LT(idx, kMaxNumChunks);
+ h->chunk_idx = idx;
+ chunks_[idx] = h;
+ stats.n_allocs++;
+ stats.currently_allocated += map_size;
+ stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
+ stats.by_size_log[size_log]++;
+ stat->Add(AllocatorStatAllocated, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ }
+ return reinterpret_cast<void*>(res);
+ }
+
+ void *ReturnNullOrDie() {
+ if (atomic_load(&may_return_null_, memory_order_acquire))
+ return nullptr;
+ ReportAllocatorCannotReturnNull();
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ void Deallocate(AllocatorStats *stat, void *p) {
+ Header *h = GetHeader(p);
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = h->chunk_idx;
+ CHECK_EQ(chunks_[idx], h);
+ CHECK_LT(idx, n_chunks_);
+ chunks_[idx] = chunks_[n_chunks_ - 1];
+ chunks_[idx]->chunk_idx = idx;
+ n_chunks_--;
+ chunks_sorted_ = false;
+ stats.n_frees++;
+ stats.currently_allocated -= h->map_size;
+ stat->Sub(AllocatorStatAllocated, h->map_size);
+ stat->Sub(AllocatorStatMapped, h->map_size);
+ }
+ MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
+ UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
+ }
+
+ uptr TotalMemoryUsed() {
+ SpinMutexLock l(&mutex_);
+ uptr res = 0;
+ for (uptr i = 0; i < n_chunks_; i++) {
+ Header *h = chunks_[i];
+ CHECK_EQ(h->chunk_idx, i);
+ res += RoundUpMapSize(h->size);
+ }
+ return res;
+ }
+
+ bool PointerIsMine(const void *p) {
+ return GetBlockBegin(p) != nullptr;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ return RoundUpTo(GetHeader(p)->size, page_size_);
+ }
+
+ // At least page_size_/2 metadata bytes is available.
+ void *GetMetaData(const void *p) {
+ // Too slow: CHECK_EQ(p, GetBlockBegin(p));
+ if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) {
+ Printf("%s: bad pointer %p\n", SanitizerToolName, p);
+ CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+ }
+ return GetHeader(p) + 1;
+ }
+
+ void *GetBlockBegin(const void *ptr) {
+ uptr p = reinterpret_cast<uptr>(ptr);
+ SpinMutexLock l(&mutex_);
+ uptr nearest_chunk = 0;
+ // Cache-friendly linear search.
+ for (uptr i = 0; i < n_chunks_; i++) {
+ uptr ch = reinterpret_cast<uptr>(chunks_[i]);
+ if (p < ch) continue; // p is at left to this chunk, skip it.
+ if (p - ch < p - nearest_chunk)
+ nearest_chunk = ch;
+ }
+ if (!nearest_chunk)
+ return nullptr;
+ Header *h = reinterpret_cast<Header *>(nearest_chunk);
+ CHECK_GE(nearest_chunk, h->map_beg);
+ CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
+ CHECK_LE(nearest_chunk, p);
+ if (h->map_beg + h->map_size <= p)
+ return nullptr;
+ return GetUser(h);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *ptr) {
+ mutex_.CheckLocked();
+ uptr p = reinterpret_cast<uptr>(ptr);
+ uptr n = n_chunks_;
+ if (!n) return nullptr;
+ if (!chunks_sorted_) {
+ // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
+ SortArray(reinterpret_cast<uptr*>(chunks_), n);
+ for (uptr i = 0; i < n; i++)
+ chunks_[i]->chunk_idx = i;
+ chunks_sorted_ = true;
+ min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+ max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
+ chunks_[n - 1]->map_size;
+ }
+ if (p < min_mmap_ || p >= max_mmap_)
+ return nullptr;
+ uptr beg = 0, end = n - 1;
+ // This loop is a log(n) lower_bound. It does not check for the exact match
+ // to avoid expensive cache-thrashing loads.
+ while (end - beg >= 2) {
+ uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1
+ if (p < reinterpret_cast<uptr>(chunks_[mid]))
+ end = mid - 1; // We are not interested in chunks_[mid].
+ else
+ beg = mid; // chunks_[mid] may still be what we want.
+ }
+
+ if (beg < end) {
+ CHECK_EQ(beg + 1, end);
+ // There are 2 chunks left, choose one.
+ if (p >= reinterpret_cast<uptr>(chunks_[end]))
+ beg = end;
+ }
+
+ Header *h = chunks_[beg];
+ if (h->map_beg + h->map_size <= p || p < h->map_beg)
+ return nullptr;
+ return GetUser(h);
+ }
+
+ void PrintStats() {
+ Printf("Stats: LargeMmapAllocator: allocated %zd times, "
+ "remains %zd (%zd K) max %zd M; by size logs: ",
+ stats.n_allocs, stats.n_allocs - stats.n_frees,
+ stats.currently_allocated >> 10, stats.max_allocated >> 20);
+ for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) {
+ uptr c = stats.by_size_log[i];
+ if (!c) continue;
+ Printf("%zd:%zd; ", i, c);
+ }
+ Printf("\n");
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ mutex_.Lock();
+ }
+
+ void ForceUnlock() {
+ mutex_.Unlock();
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr i = 0; i < n_chunks_; i++)
+ callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
+ }
+
+ private:
+ static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
+ struct Header {
+ uptr map_beg;
+ uptr map_size;
+ uptr size;
+ uptr chunk_idx;
+ };
+
+ Header *GetHeader(uptr p) {
+ CHECK(IsAligned(p, page_size_));
+ return reinterpret_cast<Header*>(p - page_size_);
+ }
+ Header *GetHeader(const void *p) {
+ return GetHeader(reinterpret_cast<uptr>(p));
+ }
+
+ void *GetUser(Header *h) {
+ CHECK(IsAligned((uptr)h, page_size_));
+ return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
+ }
+
+ uptr RoundUpMapSize(uptr size) {
+ return RoundUpTo(size, page_size_) + page_size_;
+ }
+
+ uptr page_size_;
+ Header *chunks_[kMaxNumChunks];
+ uptr n_chunks_;
+ uptr min_mmap_, max_mmap_;
+ bool chunks_sorted_;
+ struct Stats {
+ uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
+ } stats;
+ atomic_uint8_t may_return_null_;
+ SpinMutex mutex_;
+};
+
+// This class implements a complete memory allocator by using two
+// internal allocators:
+// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
+// When allocating 2^x bytes it should return 2^x aligned chunk.
+// PrimaryAllocator is used via a local AllocatorCache.
+// SecondaryAllocator can allocate anything, but is not efficient.
+template <class PrimaryAllocator, class AllocatorCache,
+ class SecondaryAllocator> // NOLINT
+class CombinedAllocator {
+ public:
+ void InitCommon(bool may_return_null) {
+ primary_.Init();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void InitLinkerInitialized(bool may_return_null) {
+ secondary_.InitLinkerInitialized(may_return_null);
+ stats_.InitLinkerInitialized();
+ InitCommon(may_return_null);
+ }
+
+ void Init(bool may_return_null) {
+ secondary_.Init(may_return_null);
+ stats_.Init();
+ InitCommon(may_return_null);
+ }
+
+ void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
+ bool cleared = false, bool check_rss_limit = false) {
+ // Returning 0 on malloc(0) may break a lot of code.
+ if (size == 0)
+ size = 1;
+ if (size + alignment < size)
+ return ReturnNullOrDie();
+ if (check_rss_limit && RssLimitIsExceeded())
+ return ReturnNullOrDie();
+ if (alignment > 8)
+ size = RoundUpTo(size, alignment);
+ void *res;
+ bool from_primary = primary_.CanAllocate(size, alignment);
+ if (from_primary)
+ res = cache->Allocate(&primary_, primary_.ClassID(size));
+ else
+ res = secondary_.Allocate(&stats_, size, alignment);
+ if (alignment > 8)
+ CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+ if (cleared && res && from_primary)
+ internal_bzero_aligned16(res, RoundUpTo(size, 16));
+ return res;
+ }
+
+ bool MayReturnNull() const {
+ return atomic_load(&may_return_null_, memory_order_acquire);
+ }
+
+ void *ReturnNullOrDie() {
+ if (MayReturnNull())
+ return nullptr;
+ ReportAllocatorCannotReturnNull();
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ secondary_.SetMayReturnNull(may_return_null);
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ bool RssLimitIsExceeded() {
+ return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire);
+ }
+
+ void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) {
+ atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded,
+ memory_order_release);
+ }
+
+ void Deallocate(AllocatorCache *cache, void *p) {
+ if (!p) return;
+ if (primary_.PointerIsMine(p))
+ cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
+ else
+ secondary_.Deallocate(&stats_, p);
+ }
+
+ void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
+ uptr alignment) {
+ if (!p)
+ return Allocate(cache, new_size, alignment);
+ if (!new_size) {
+ Deallocate(cache, p);
+ return nullptr;
+ }
+ CHECK(PointerIsMine(p));
+ uptr old_size = GetActuallyAllocatedSize(p);
+ uptr memcpy_size = Min(new_size, old_size);
+ void *new_p = Allocate(cache, new_size, alignment);
+ if (new_p)
+ internal_memcpy(new_p, p, memcpy_size);
+ Deallocate(cache, p);
+ return new_p;
+ }
+
+ bool PointerIsMine(void *p) {
+ if (primary_.PointerIsMine(p))
+ return true;
+ return secondary_.PointerIsMine(p);
+ }
+
+ bool FromPrimary(void *p) {
+ return primary_.PointerIsMine(p);
+ }
+
+ void *GetMetaData(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetMetaData(p);
+ return secondary_.GetMetaData(p);
+ }
+
+ void *GetBlockBegin(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBegin(p);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBeginFastLocked(p);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetActuallyAllocatedSize(p);
+ return secondary_.GetActuallyAllocatedSize(p);
+ }
+
+ uptr TotalMemoryUsed() {
+ return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
+ }
+
+ void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
+
+ void InitCache(AllocatorCache *cache) {
+ cache->Init(&stats_);
+ }
+
+ void DestroyCache(AllocatorCache *cache) {
+ cache->Destroy(&primary_, &stats_);
+ }
+
+ void SwallowCache(AllocatorCache *cache) {
+ cache->Drain(&primary_);
+ }
+
+ void GetStats(AllocatorStatCounters s) const {
+ stats_.Get(s);
+ }
+
+ void PrintStats() {
+ primary_.PrintStats();
+ secondary_.PrintStats();
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ primary_.ForceLock();
+ secondary_.ForceLock();
+ }
+
+ void ForceUnlock() {
+ secondary_.ForceUnlock();
+ primary_.ForceUnlock();
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ primary_.ForEachChunk(callback, arg);
+ secondary_.ForEachChunk(callback, arg);
+ }
+
+ private:
+ PrimaryAllocator primary_;
+ SecondaryAllocator secondary_;
+ AllocatorGlobalStats stats_;
+ atomic_uint8_t may_return_null_;
+ atomic_uint8_t rss_limit_is_exceeded_;
+};
+
+// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ALLOCATOR_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
new file mode 100644
index 0000000..2cd924c
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_interface.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Re-declaration of functions from public sanitizer allocator interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
+#define SANITIZER_ALLOCATOR_INTERFACE_H
+
+#include "sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr
+__sanitizer_get_allocated_size(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
+} // extern "C"
+
+#endif // SANITIZER_ALLOCATOR_INTERFACE_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
new file mode 100644
index 0000000..3dcfccd
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -0,0 +1,63 @@
+//===-- sanitizer_allocator_internal.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This allocator is used inside run-times.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERNAL_H
+#define SANITIZER_ALLOCATOR_INTERNAL_H
+
+#include "sanitizer_allocator.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// FIXME: Check if we may use even more compact size class map for internal
+// purposes.
+typedef CompactSizeClassMap InternalSizeClassMap;
+
+static const uptr kInternalAllocatorSpace = 0;
+static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
+static const uptr kInternalAllocatorRegionSizeLog = 20;
+#if SANITIZER_WORDSIZE == 32
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
+#else
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
+#endif
+typedef SizeClassAllocator32<
+ kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
+ kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
+
+typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
+ InternalAllocatorCache;
+
+typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
+ LargeMmapAllocator<> > InternalAllocator;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr);
+void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
+InternalAllocator *internal_allocator();
+
+enum InternalAllocEnum {
+ INTERNAL_ALLOC
+};
+
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ InternalAllocEnum) {
+ return InternalAlloc(size);
+}
+
+#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_asm.h b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
new file mode 100644
index 0000000..47c2b12
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
@@ -0,0 +1,58 @@
+//===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various support for assemebler.
+//
+//===----------------------------------------------------------------------===//
+
+// Some toolchains do not support .cfi asm directives, so we have to hide
+// them inside macros.
+#if defined(__clang__) || \
+ (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM))
+ // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI.
+ // Clang seems to support CFI by default (or not?).
+ // We need two versions of macros: for inline asm and standalone asm files.
+# define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";"
+
+# define CFI_STARTPROC .cfi_startproc
+# define CFI_ENDPROC .cfi_endproc
+# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
+# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n
+# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
+# define CFI_OFFSET(reg, n) .cfi_offset reg, n
+# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
+# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n
+# define CFI_RESTORE(reg) .cfi_restore reg
+
+#else // No CFI
+# define CFI_INL_ADJUST_CFA_OFFSET(n)
+# define CFI_STARTPROC
+# define CFI_ENDPROC
+# define CFI_ADJUST_CFA_OFFSET(n)
+# define CFI_DEF_CFA_OFFSET(n)
+# define CFI_REL_OFFSET(reg, n)
+# define CFI_OFFSET(reg, n)
+# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_DEF_CFA(reg, n)
+# define CFI_RESTORE(reg)
+#endif
+
+#if !defined(__APPLE__)
+# define ASM_HIDDEN(symbol) .hidden symbol
+# define ASM_TYPE_FUNCTION(symbol) .type symbol, @function
+# define ASM_SIZE(symbol) .size symbol, .-symbol
+# define ASM_TSAN_SYMBOL(symbol) symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) symbol
+#else
+# define ASM_HIDDEN(symbol)
+# define ASM_TYPE_FUNCTION(symbol)
+# define ASM_SIZE(symbol)
+# define ASM_TSAN_SYMBOL(symbol) _##symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol
+#endif
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h b/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
new file mode 100644
index 0000000..b26693e
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
@@ -0,0 +1,82 @@
+//===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_H
+#define SANITIZER_ATOMIC_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum memory_order {
+ memory_order_relaxed = 1 << 0,
+ memory_order_consume = 1 << 1,
+ memory_order_acquire = 1 << 2,
+ memory_order_release = 1 << 3,
+ memory_order_acq_rel = 1 << 4,
+ memory_order_seq_cst = 1 << 5
+};
+
+struct atomic_uint8_t {
+ typedef u8 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint16_t {
+ typedef u16 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint32_t {
+ typedef u32 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint64_t {
+ typedef u64 Type;
+ // On 32-bit platforms u64 is not necessary aligned on 8 bytes.
+ volatile ALIGNED(8) Type val_dont_use;
+};
+
+struct atomic_uintptr_t {
+ typedef uptr Type;
+ volatile Type val_dont_use;
+};
+
+} // namespace __sanitizer
+
+#if defined(__clang__) || defined(__GNUC__)
+# include "sanitizer_atomic_clang.h"
+#elif defined(_MSC_VER)
+# include "sanitizer_atomic_msvc.h"
+#else
+# error "Unsupported compiler"
+#endif
+
+namespace __sanitizer {
+
+// Clutter-reducing helpers.
+
+template<typename T>
+INLINE typename T::Type atomic_load_relaxed(const volatile T *a) {
+ return atomic_load(a, memory_order_relaxed);
+}
+
+template<typename T>
+INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) {
+ atomic_store(a, v, memory_order_relaxed);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ATOMIC_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
new file mode 100644
index 0000000..38363e8
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -0,0 +1,100 @@
+//===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_H
+#define SANITIZER_ATOMIC_CLANG_H
+
+#if defined(__i386__) || defined(__x86_64__)
+# include "sanitizer_atomic_clang_x86.h"
+#else
+# include "sanitizer_atomic_clang_other.h"
+#endif
+
+namespace __sanitizer {
+
+// We would like to just use compiler builtin atomic operations
+// for loads and stores, but they are mostly broken in clang:
+// - they lead to vastly inefficient code generation
+// (http://llvm.org/bugs/show_bug.cgi?id=17281)
+// - 64-bit atomic operations are not implemented on x86_32
+// (http://llvm.org/bugs/show_bug.cgi?id=15034)
+// - they are not implemented on ARM
+// error: undefined reference to '__atomic_load_4'
+
+// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
+// for mappings of the memory model to different processors.
+
+INLINE void atomic_signal_fence(memory_order) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ __sync_synchronize();
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_add(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_sub(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, -v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_exchange(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ DCHECK(!((uptr)a % sizeof(*a)));
+ if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
+ __sync_synchronize();
+ v = __sync_lock_test_and_set(&a->val_dont_use, v);
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ return v;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_strong(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ typedef typename T::Type Type;
+ Type cmpv = *cmp;
+ Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_weak(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ return atomic_compare_exchange_strong(a, cmp, xchg, mo);
+}
+
+} // namespace __sanitizer
+
+#undef ATOMIC_ORDER
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
new file mode 100644
index 0000000..099b9f7
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -0,0 +1,97 @@
+//===-- sanitizer_atomic_clang_other.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
+#define SANITIZER_ATOMIC_CLANG_OTHER_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __sync_synchronize();
+ } else { // seq_cst
+ // E.g. on POWER we need a hw fence even before the store.
+ __sync_synchronize();
+ v = a->val_dont_use;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ // Gross, but simple and reliable.
+ // Assume that it is not in read-only memory.
+ v = __sync_fetch_and_add(
+ const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ // Gross, but simple and reliable.
+ typename T::Type cmp = a->val_dont_use;
+ typename T::Type cur;
+ for (;;) {
+ cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
+ if (cmp == v)
+ break;
+ cmp = cur;
+ }
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
new file mode 100644
index 0000000..38feb29
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -0,0 +1,116 @@
+//===-- sanitizer_atomic_clang_x86.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_X86_H
+#define SANITIZER_ATOMIC_CLANG_X86_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+ for (int i = 0; i < cnt; i++)
+ __asm__ __volatile__("pause");
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ // On x86 loads are implicitly acquire.
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 plain MOV is enough for seq_cst store.
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;" // (ptr could be read-only)
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (v)
+ : "m" (a->val_dont_use)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;"
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (a->val_dont_use)
+ : "m" (v)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_X86_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
new file mode 100644
index 0000000..24d6f0f
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -0,0 +1,261 @@
+//===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_MSVC_H
+#define SANITIZER_ATOMIC_MSVC_H
+
+extern "C" void _ReadWriteBarrier();
+#pragma intrinsic(_ReadWriteBarrier)
+extern "C" void _mm_mfence();
+#pragma intrinsic(_mm_mfence)
+extern "C" void _mm_pause();
+#pragma intrinsic(_mm_pause)
+extern "C" char _InterlockedExchange8( // NOLINT
+ char volatile *Addend, char Value); // NOLINT
+#pragma intrinsic(_InterlockedExchange8)
+extern "C" short _InterlockedExchange16( // NOLINT
+ short volatile *Addend, short Value); // NOLINT
+#pragma intrinsic(_InterlockedExchange16)
+extern "C" long _InterlockedExchange( // NOLINT
+ long volatile *Addend, long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchange)
+extern "C" long _InterlockedExchangeAdd( // NOLINT
+ long volatile * Addend, long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd)
+extern "C" short _InterlockedCompareExchange16( // NOLINT
+ short volatile *Destination, // NOLINT
+ short Exchange, short Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange16)
+extern "C"
+long long _InterlockedCompareExchange64( // NOLINT
+ long long volatile *Destination, // NOLINT
+ long long Exchange, long long Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange64)
+extern "C" void *_InterlockedCompareExchangePointer(
+ void *volatile *Destination,
+ void *Exchange, void *Comparand);
+#pragma intrinsic(_InterlockedCompareExchangePointer)
+extern "C"
+long __cdecl _InterlockedCompareExchange( // NOLINT
+ long volatile *Destination, // NOLINT
+ long Exchange, long Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange)
+
+#ifdef _WIN64
+extern "C" long long _InterlockedExchangeAdd64( // NOLINT
+ long long volatile * Addend, long long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd64)
+#endif
+
+namespace __sanitizer {
+
+INLINE void atomic_signal_fence(memory_order) {
+ _ReadWriteBarrier();
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ _mm_mfence();
+}
+
+INLINE void proc_yield(int cnt) {
+ for (int i = 0; i < cnt; i++)
+ _mm_pause();
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+ // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ v = a->val_dont_use;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ a->val_dont_use = v;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ if (mo == memory_order_seq_cst)
+ atomic_thread_fence(memory_order_seq_cst);
+}
+
+INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+}
+
+INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+#endif
+}
+
+INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+}
+
+INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+#endif
+}
+
+INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
+ u8 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v);
+}
+
+INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
+ u16 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v);
+}
+
+INLINE u32 atomic_exchange(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v);
+}
+
+#ifndef _WIN64
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
+ u8 *cmp,
+ u8 xchgv,
+ memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ u8 cmpv = *cmp;
+ u8 prev;
+ __asm {
+ mov al, cmpv
+ mov ecx, a
+ mov dl, xchgv
+ lock cmpxchg [ecx], dl
+ mov prev, al
+ }
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+#endif
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
+ uptr *cmp,
+ uptr xchg,
+ memory_order mo) {
+ uptr cmpv = *cmp;
+ uptr prev = (uptr)_InterlockedCompareExchangePointer(
+ (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
+ u16 *cmp,
+ u16 xchg,
+ memory_order mo) {
+ u16 cmpv = *cmp;
+ u16 prev = (u16)_InterlockedCompareExchange16(
+ (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
+ u32 *cmp,
+ u32 xchg,
+ memory_order mo) {
+ u32 cmpv = *cmp;
+ u32 prev = (u32)_InterlockedCompareExchange(
+ (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
+ u64 *cmp,
+ u64 xchg,
+ memory_order mo) {
+ u64 cmpv = *cmp;
+ u64 prev = (u64)_InterlockedCompareExchange64(
+ (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_weak(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ return atomic_compare_exchange_strong(a, cmp, xchg, mo);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h b/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
new file mode 100644
index 0000000..d847273
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
@@ -0,0 +1,351 @@
+//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specializer BitVector implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BITVECTOR_H
+#define SANITIZER_BITVECTOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// Fixed size bit vector based on a single basic integer.
+template <class basic_int_t = uptr>
+class BasicBitVector {
+ public:
+ enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
+
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() { bits_ = 0; }
+ void setAll() { bits_ = ~(basic_int_t)0; }
+ bool empty() const { return bits_ == 0; }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ |= mask(idx);
+ return bits_ != old;
+ }
+
+ // Returns true if the bit has changed from 1 to 0.
+ bool clearBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ &= ~mask(idx);
+ return bits_ != old;
+ }
+
+ bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
+
+ uptr getAndClearFirstOne() {
+ CHECK(!empty());
+ uptr idx = LeastSignificantSetBitIndex(bits_);
+ clearBit(idx);
+ return idx;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ |= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= ~v.bits_;
+ return bits_ != old;
+ }
+
+ void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const BasicBitVector &v) const {
+ return (bits_ & v.bits_) != 0;
+ }
+
+ // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
+ bool hasNext() const { return !bv_.empty(); }
+ uptr next() { return bv_.getAndClearFirstOne(); }
+ void clear() { bv_.clear(); }
+ private:
+ BasicBitVector bv_;
+ };
+
+ private:
+ basic_int_t mask(uptr idx) const {
+ CHECK_LT(idx, size());
+ return (basic_int_t)1UL << idx;
+ }
+ basic_int_t bits_;
+};
+
+// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
+// The implementation is optimized for better performance on
+// sparse bit vectors, i.e. the those with few set bits.
+template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
+class TwoLevelBitVector {
+ // This is essentially a 2-level bit vector.
+ // Set bit in the first level BV indicates that there are set bits
+ // in the corresponding BV of the second level.
+ // This structure allows O(kLevel1Size) time for clear() and empty(),
+ // as well fast handling of sparse BVs.
+ public:
+ enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
+ // No CTOR.
+
+ uptr size() const { return kSize; }
+
+ void clear() {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ l1_[i].clear();
+ }
+
+ void setAll() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ l1_[i0].setAll();
+ for (uptr i1 = 0; i1 < BV::kSize; i1++)
+ l2_[i0][i1].setAll();
+ }
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ if (!l1_[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ if (!l1_[i0].getBit(i1)) {
+ l1_[i0].setBit(i1);
+ l2_[i0][i1].clear();
+ }
+ bool res = l2_[i0][i1].setBit(i2);
+ // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
+ // idx, i0, i1, i2, res);
+ return res;
+ }
+
+ bool clearBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ bool res = false;
+ if (l1_[i0].getBit(i1)) {
+ res = l2_[i0][i1].clearBit(i2);
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ return res;
+ }
+
+ bool getBit(uptr idx) const {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
+ return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
+ }
+
+ uptr getAndClearFirstOne() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].empty()) continue;
+ uptr i1 = l1_[i0].getAndClearFirstOne();
+ uptr i2 = l2_[i0][i1].getAndClearFirstOne();
+ if (!l2_[i0][i1].empty())
+ l1_[i0].setBit(i1);
+ uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
+ // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
+ return res;
+ }
+ CHECK(0);
+ return 0;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = v.l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l1_[i0].setBit(i1))
+ l2_[i0][i1].clear();
+ if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].setIntersection(v.l1_[i0]))
+ res = true;
+ if (!l1_[i0].empty()) {
+ BV t = l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ return res;
+ }
+
+ void copyFrom(const TwoLevelBitVector &v) {
+ clear();
+ setUnion(v);
+ }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const TwoLevelBitVector &v) const {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (!v.l1_[i0].getBit(i1)) continue;
+ if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
+ it1_.clear();
+ it2_.clear();
+ }
+
+ bool hasNext() const {
+ if (it1_.hasNext()) return true;
+ for (uptr i = i0_; i < kLevel1Size; i++)
+ if (!bv_.l1_[i].empty()) return true;
+ return false;
+ }
+
+ uptr next() {
+ // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ if (!it1_.hasNext() && !it2_.hasNext()) {
+ for (; i0_ < kLevel1Size; i0_++) {
+ if (bv_.l1_[i0_].empty()) continue;
+ it1_ = typename BV::Iterator(bv_.l1_[i0_]);
+ // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ break;
+ }
+ }
+ if (!it2_.hasNext()) {
+ CHECK(it1_.hasNext());
+ i1_ = it1_.next();
+ it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
+ // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ }
+ CHECK(it2_.hasNext());
+ uptr i2 = it2_.next();
+ uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
+ // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
+ // it1_.hasNext(), it2_.hasNext(), kSize, res);
+ if (!it1_.hasNext() && !it2_.hasNext())
+ i0_++;
+ return res;
+ }
+
+ private:
+ const TwoLevelBitVector &bv_;
+ uptr i0_, i1_;
+ typename BV::Iterator it1_, it2_;
+ };
+
+ private:
+ void check(uptr idx) const { CHECK_LE(idx, size()); }
+
+ uptr idx0(uptr idx) const {
+ uptr res = idx / (BV::kSize * BV::kSize);
+ CHECK_LE(res, kLevel1Size);
+ return res;
+ }
+
+ uptr idx1(uptr idx) const {
+ uptr res = (idx / BV::kSize) % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ uptr idx2(uptr idx) const {
+ uptr res = idx % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ BV l1_[kLevel1Size];
+ BV l2_[kLevel1Size][BV::kSize];
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BITVECTOR_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h
new file mode 100644
index 0000000..df72f1c
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h
@@ -0,0 +1,165 @@
+//===-- sanitizer_bvgraph.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// BVGraph -- a directed graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BVGRAPH_H
+#define SANITIZER_BVGRAPH_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bitvector.h"
+
+namespace __sanitizer {
+
+// Directed graph of fixed size implemented as an array of bit vectors.
+// Not thread-safe, all accesses should be protected by an external lock.
+template<class BV>
+class BVGraph {
+ public:
+ enum SizeEnum { kSize = BV::kSize };
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() {
+ for (uptr i = 0; i < size(); i++)
+ v[i].clear();
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < size(); i++)
+ if (!v[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if a new edge was added.
+ bool addEdge(uptr from, uptr to) {
+ check(from, to);
+ return v[from].setBit(to);
+ }
+
+ // Returns true if at least one new edge was added.
+ uptr addEdges(const BV &from, uptr to, uptr added_edges[],
+ uptr max_added_edges) {
+ uptr res = 0;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr node = t1.getAndClearFirstOne();
+ if (v[node].setBit(to))
+ if (res < max_added_edges)
+ added_edges[res++] = node;
+ }
+ return res;
+ }
+
+ // *EXPERIMENTAL*
+ // Returns true if an edge from=>to exist.
+ // This function does not use any global state except for 'this' itself,
+ // and thus can be called from different threads w/o locking.
+ // This would be racy.
+ // FIXME: investigate how much we can prove about this race being "benign".
+ bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); }
+
+ // Returns true if the edge from=>to was removed.
+ bool removeEdge(uptr from, uptr to) {
+ return v[from].clearBit(to);
+ }
+
+ // Returns true if at least one edge *=>to was removed.
+ bool removeEdgesTo(const BV &to) {
+ bool res = 0;
+ for (uptr from = 0; from < size(); from++) {
+ if (v[from].setDifference(to))
+ res = true;
+ }
+ return res;
+ }
+
+ // Returns true if at least one edge from=>* was removed.
+ bool removeEdgesFrom(const BV &from) {
+ bool res = false;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr idx = t1.getAndClearFirstOne();
+ if (!v[idx].empty()) {
+ v[idx].clear();
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ void removeEdgesFrom(uptr from) {
+ return v[from].clear();
+ }
+
+ bool hasEdge(uptr from, uptr to) const {
+ check(from, to);
+ return v[from].getBit(to);
+ }
+
+ // Returns true if there is a path from the node 'from'
+ // to any of the nodes in 'targets'.
+ bool isReachable(uptr from, const BV &targets) {
+ BV &to_visit = t1,
+ &visited = t2;
+ to_visit.copyFrom(v[from]);
+ visited.clear();
+ visited.setBit(from);
+ while (!to_visit.empty()) {
+ uptr idx = to_visit.getAndClearFirstOne();
+ if (visited.setBit(idx))
+ to_visit.setUnion(v[idx]);
+ }
+ return targets.intersectsWith(visited);
+ }
+
+ // Finds a path from 'from' to one of the nodes in 'target',
+ // stores up to 'path_size' items of the path into 'path',
+ // returns the path length, or 0 if there is no path of size 'path_size'.
+ uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) {
+ if (path_size == 0)
+ return 0;
+ path[0] = from;
+ if (targets.getBit(from))
+ return 1;
+ // The function is recursive, so we don't want to create BV on stack.
+ // Instead of a getAndClearFirstOne loop we use the slower iterator.
+ for (typename BV::Iterator it(v[from]); it.hasNext(); ) {
+ uptr idx = it.next();
+ if (uptr res = findPath(idx, targets, path + 1, path_size - 1))
+ return res + 1;
+ }
+ return 0;
+ }
+
+ // Same as findPath, but finds a shortest path.
+ uptr findShortestPath(uptr from, const BV &targets, uptr *path,
+ uptr path_size) {
+ for (uptr p = 1; p <= path_size; p++)
+ if (findPath(from, targets, path, p) == p)
+ return p;
+ return 0;
+ }
+
+ private:
+ void check(uptr idx1, uptr idx2) const {
+ CHECK_LT(idx1, size());
+ CHECK_LT(idx2, size());
+ }
+ BV v[kSize];
+ // Keep temporary vectors here since we can not create large objects on stack.
+ BV t1, t2;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BVGRAPH_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
new file mode 100644
index 0000000..9b41a3a
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
@@ -0,0 +1,508 @@
+//===-- sanitizer_common.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+const char *SanitizerToolName = "SanitizerTool";
+
+atomic_uint32_t current_verbosity;
+
+uptr GetPageSizeCached() {
+ static uptr PageSize;
+ if (!PageSize)
+ PageSize = GetPageSize();
+ return PageSize;
+}
+
+StaticSpinMutex report_file_mu;
+ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
+
+void RawWrite(const char *buffer) {
+ report_file.Write(buffer, internal_strlen(buffer));
+}
+
+void ReportFile::ReopenIfNecessary() {
+ mu->CheckLocked();
+ if (fd == kStdoutFd || fd == kStderrFd) return;
+
+ uptr pid = internal_getpid();
+ // If in tracer, use the parent's file.
+ if (pid == stoptheworld_tracer_pid)
+ pid = stoptheworld_tracer_ppid;
+ if (fd != kInvalidFd) {
+ // If the report file is already opened by the current process,
+ // do nothing. Otherwise the report file was opened by the parent
+ // process, close it now.
+ if (fd_pid == pid)
+ return;
+ else
+ CloseFile(fd);
+ }
+
+ const char *exe_name = GetProcessName();
+ if (common_flags()->log_exe_name && exe_name) {
+ internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
+ exe_name, pid);
+ } else {
+ internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
+ }
+ fd = OpenFile(full_path, WrOnly);
+ if (fd == kInvalidFd) {
+ const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
+ WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+ WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
+ Die();
+ }
+ fd_pid = pid;
+}
+
+void ReportFile::SetReportPath(const char *path) {
+ if (!path)
+ return;
+ uptr len = internal_strlen(path);
+ if (len > sizeof(path_prefix) - 100) {
+ Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
+ path[0], path[1], path[2], path[3],
+ path[4], path[5], path[6], path[7]);
+ Die();
+ }
+
+ SpinMutexLock l(mu);
+ if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
+ CloseFile(fd);
+ fd = kInvalidFd;
+ if (internal_strcmp(path, "stdout") == 0) {
+ fd = kStdoutFd;
+ } else if (internal_strcmp(path, "stderr") == 0) {
+ fd = kStderrFd;
+ } else {
+ internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
+ }
+}
+
+// PID of the tracer task in StopTheWorld. It shares the address space with the
+// main process, but has a different PID and thus requires special handling.
+uptr stoptheworld_tracer_pid = 0;
+// Cached pid of parent process - if the parent process dies, we want to keep
+// writing to the same log file.
+uptr stoptheworld_tracer_ppid = 0;
+
+static const int kMaxNumOfInternalDieCallbacks = 5;
+static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
+
+bool AddDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == nullptr) {
+ InternalDieCallbacks[i] = callback;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RemoveDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == callback) {
+ internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
+ sizeof(InternalDieCallbacks[0]) *
+ (kMaxNumOfInternalDieCallbacks - i - 1));
+ InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
+ return true;
+ }
+ }
+ return false;
+}
+
+static DieCallbackType UserDieCallback;
+void SetUserDieCallback(DieCallbackType callback) {
+ UserDieCallback = callback;
+}
+
+void NORETURN Die() {
+ if (UserDieCallback)
+ UserDieCallback();
+ for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
+ if (InternalDieCallbacks[i])
+ InternalDieCallbacks[i]();
+ }
+ if (common_flags()->abort_on_error)
+ Abort();
+ internal__exit(common_flags()->exitcode);
+}
+
+static CheckFailedCallbackType CheckFailedCallback;
+void SetCheckFailedCallback(CheckFailedCallbackType callback) {
+ CheckFailedCallback = callback;
+}
+
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ if (CheckFailedCallback) {
+ CheckFailedCallback(file, line, cond, v1, v2);
+ }
+ Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
+ v1, v2);
+ Die();
+}
+
+void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
+ const char *mmap_type, error_t err,
+ bool raw_report) {
+ static int recursion_count;
+ if (raw_report || recursion_count) {
+ // If raw report is requested or we went into recursion, just die.
+ // The Report() and CHECK calls below may call mmap recursively and fail.
+ RawWrite("ERROR: Failed to mmap\n");
+ Die();
+ }
+ recursion_count++;
+ Report("ERROR: %s failed to "
+ "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
+ SanitizerToolName, mmap_type, size, size, mem_type, err);
+#ifndef SANITIZER_GO
+ DumpProcessMap();
+#endif
+ UNREACHABLE("unable to mmap");
+}
+
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len, error_t *errno_p) {
+ uptr PageSize = GetPageSizeCached();
+ uptr kMinFileLen = PageSize;
+ *buff = nullptr;
+ *buff_size = 0;
+ *read_len = 0;
+ // The files we usually open are not seekable, so try different buffer sizes.
+ for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
+ fd_t fd = OpenFile(file_name, RdOnly, errno_p);
+ if (fd == kInvalidFd) return false;
+ UnmapOrDie(*buff, *buff_size);
+ *buff = (char*)MmapOrDie(size, __func__);
+ *buff_size = size;
+ *read_len = 0;
+ // Read up to one page at a time.
+ bool reached_eof = false;
+ while (*read_len + PageSize <= size) {
+ uptr just_read;
+ if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
+ UnmapOrDie(*buff, *buff_size);
+ return false;
+ }
+ if (just_read == 0) {
+ reached_eof = true;
+ break;
+ }
+ *read_len += just_read;
+ }
+ CloseFile(fd);
+ if (reached_eof) // We've read the whole file.
+ break;
+ }
+ return true;
+}
+
+typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
+
+template<class T>
+static inline bool CompareLess(const T &a, const T &b) {
+ return a < b;
+}
+
+void SortArray(uptr *array, uptr size) {
+ InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
+}
+
+// We want to map a chunk of address space aligned to 'alignment'.
+// We do it by maping a bit more and then unmaping redundant pieces.
+// We probably can do it with fewer syscalls in some OS-dependent way.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+// uptr PageSize = GetPageSizeCached();
+ CHECK(IsPowerOfTwo(size));
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = size + alignment;
+ uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
+ uptr map_end = map_res + map_size;
+ uptr res = map_res;
+ if (res & (alignment - 1)) // Not aligned.
+ res = (map_res + alignment) & ~(alignment - 1);
+ uptr end = res + size;
+ if (res != map_res)
+ UnmapOrDie((void*)map_res, res - map_res);
+ if (end != map_end)
+ UnmapOrDie((void*)end, map_end - end);
+ return (void*)res;
+}
+
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_path_prefix) {
+ if (!filepath) return nullptr;
+ if (!strip_path_prefix) return filepath;
+ const char *res = filepath;
+ if (const char *pos = internal_strstr(filepath, strip_path_prefix))
+ res = pos + internal_strlen(strip_path_prefix);
+ if (res[0] == '.' && res[1] == '/')
+ res += 2;
+ return res;
+}
+
+const char *StripModuleName(const char *module) {
+ if (!module)
+ return nullptr;
+ if (SANITIZER_WINDOWS) {
+ // On Windows, both slash and backslash are possible.
+ // Pick the one that goes last.
+ if (const char *bslash_pos = internal_strrchr(module, '\\'))
+ return StripModuleName(bslash_pos + 1);
+ }
+ if (const char *slash_pos = internal_strrchr(module, '/')) {
+ return slash_pos + 1;
+ }
+ return module;
+}
+
+void ReportErrorSummary(const char *error_message) {
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
+ __sanitizer_report_error_summary(buff.data());
+}
+
+#ifndef SANITIZER_GO
+void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("%s ", error_type);
+ RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
+ common_flags()->strip_path_prefix);
+ ReportErrorSummary(buff.data());
+}
+#endif
+
+// Removes the ANSI escape sequences from the input string (in-place).
+void RemoveANSIEscapeSequencesFromString(char *str) {
+ if (!str)
+ return;
+
+ // We are going to remove the escape sequences in place.
+ char *s = str;
+ char *z = str;
+ while (*s != '\0') {
+ CHECK_GE(s, z);
+ // Skip over ANSI escape sequences with pointer 's'.
+ if (*s == '\033' && *(s + 1) == '[') {
+ s = internal_strchrnul(s, 'm');
+ if (*s == '\0') {
+ break;
+ }
+ s++;
+ continue;
+ }
+ // 's' now points at a character we want to keep. Copy over the buffer
+ // content if the escape sequence has been perviously skipped andadvance
+ // both pointers.
+ if (s != z)
+ *z = *s;
+
+ // If we have not seen an escape sequence, just advance both pointers.
+ z++;
+ s++;
+ }
+
+ // Null terminate the string.
+ *z = '\0';
+}
+
+void LoadedModule::set(const char *module_name, uptr base_address) {
+ clear();
+ full_name_ = internal_strdup(module_name);
+ base_address_ = base_address;
+}
+
+void LoadedModule::clear() {
+ InternalFree(full_name_);
+ full_name_ = nullptr;
+ while (!ranges_.empty()) {
+ AddressRange *r = ranges_.front();
+ ranges_.pop_front();
+ InternalFree(r);
+ }
+}
+
+void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
+ void *mem = InternalAlloc(sizeof(AddressRange));
+ AddressRange *r = new(mem) AddressRange(beg, end, executable);
+ ranges_.push_back(r);
+}
+
+bool LoadedModule::containsAddress(uptr address) const {
+ for (Iterator iter = ranges(); iter.hasNext();) {
+ const AddressRange *r = iter.next();
+ if (r->beg <= address && address < r->end)
+ return true;
+ }
+ return false;
+}
+
+static atomic_uintptr_t g_total_mmaped;
+
+void IncreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ uptr total_mmaped =
+ atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
+ // Since for now mmap_limit_mb is not a user-facing flag, just kill
+ // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
+ RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
+}
+
+void DecreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
+}
+
+bool TemplateMatch(const char *templ, const char *str) {
+ if ((!str) || str[0] == 0)
+ return false;
+ bool start = false;
+ if (templ && templ[0] == '^') {
+ start = true;
+ templ++;
+ }
+ bool asterisk = false;
+ while (templ && templ[0]) {
+ if (templ[0] == '*') {
+ templ++;
+ start = false;
+ asterisk = true;
+ continue;
+ }
+ if (templ[0] == '$')
+ return str[0] == 0 || asterisk;
+ if (str[0] == 0)
+ return false;
+ char *tpos = (char*)internal_strchr(templ, '*');
+ char *tpos1 = (char*)internal_strchr(templ, '$');
+ if ((!tpos) || (tpos1 && tpos1 < tpos))
+ tpos = tpos1;
+ if (tpos)
+ tpos[0] = 0;
+ const char *str0 = str;
+ const char *spos = internal_strstr(str, templ);
+ str = spos + internal_strlen(templ);
+ templ = tpos;
+ if (tpos)
+ tpos[0] = tpos == tpos1 ? '$' : '*';
+ if (!spos)
+ return false;
+ if (start && spos != str0)
+ return false;
+ start = false;
+ asterisk = false;
+ }
+ return true;
+}
+
+static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
+
+char *FindPathToBinary(const char *name) {
+ const char *path = GetEnv("PATH");
+ if (!path)
+ return nullptr;
+ uptr name_len = internal_strlen(name);
+ InternalScopedBuffer<char> buffer(kMaxPathLength);
+ const char *beg = path;
+ while (true) {
+ const char *end = internal_strchrnul(beg, kPathSeparator);
+ uptr prefix_len = end - beg;
+ if (prefix_len + name_len + 2 <= kMaxPathLength) {
+ internal_memcpy(buffer.data(), beg, prefix_len);
+ buffer[prefix_len] = '/';
+ internal_memcpy(&buffer[prefix_len + 1], name, name_len);
+ buffer[prefix_len + 1 + name_len] = '\0';
+ if (FileExists(buffer.data()))
+ return internal_strdup(buffer.data());
+ }
+ if (*end == '\0') break;
+ beg = end + 1;
+ }
+ return nullptr;
+}
+
+static char binary_name_cache_str[kMaxPathLength];
+static char process_name_cache_str[kMaxPathLength];
+
+const char *GetProcessName() {
+ return process_name_cache_str;
+}
+
+static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
+ ReadLongProcessName(buf, buf_len);
+ char *s = const_cast<char *>(StripModuleName(buf));
+ uptr len = internal_strlen(s);
+ if (s != buf) {
+ internal_memmove(buf, s, len);
+ buf[len] = '\0';
+ }
+ return len;
+}
+
+void UpdateProcessName() {
+ ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
+}
+
+// Call once to make sure that binary_name_cache_str is initialized
+void CacheBinaryName() {
+ if (binary_name_cache_str[0] != '\0')
+ return;
+ ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
+ ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
+}
+
+uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
+ CacheBinaryName();
+ uptr name_len = internal_strlen(binary_name_cache_str);
+ name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
+ if (buf_len == 0)
+ return 0;
+ internal_memcpy(buf, binary_name_cache_str, name_len);
+ buf[name_len] = '\0';
+ return name_len;
+}
+
+} // namespace __sanitizer
+
+using namespace __sanitizer; // NOLINT
+
+extern "C" {
+void __sanitizer_set_report_path(const char *path) {
+ report_file.SetReportPath(path);
+}
+
+void __sanitizer_report_error_summary(const char *error_summary) {
+ Printf("%s\n", error_summary);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_set_death_callback(void (*callback)(void)) {
+ SetUserDieCallback(callback);
+}
+} // extern "C"
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
new file mode 100644
index 0000000..0585f6b
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -0,0 +1,749 @@
+//===-- sanitizer_common.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between run-time libraries of sanitizers.
+//
+// It declares common functions and classes that are used in both runtimes.
+// Implementation of some functions are provided in sanitizer_common, while
+// others must be defined by run-time library itself.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_COMMON_H
+#define SANITIZER_COMMON_H
+
+#include "sanitizer_flags.h"
+#include "sanitizer_interface_internal.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+
+#ifdef _MSC_VER
+extern "C" void _ReadWriteBarrier();
+#pragma intrinsic(_ReadWriteBarrier)
+#endif
+
+namespace __sanitizer {
+struct StackTrace;
+struct AddressInfo;
+
+// Constants.
+const uptr kWordSize = SANITIZER_WORDSIZE / 8;
+const uptr kWordSizeInBits = 8 * kWordSize;
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+ const uptr kCacheLineSize = 128;
+#else
+ const uptr kCacheLineSize = 64;
+#endif
+
+const uptr kMaxPathLength = 4096;
+
+// 16K loaded modules should be enough for everyone.
+static const uptr kMaxNumberOfModules = 1 << 14;
+
+const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
+
+static const uptr kErrorMessageBufferSize = 1 << 16;
+
+// Denotes fake PC values that come from JIT/JAVA/etc.
+// For such PC values __tsan_symbolize_external() will be called.
+const u64 kExternalPCBit = 1ULL << 60;
+
+extern const char *SanitizerToolName; // Can be changed by the tool.
+
+extern atomic_uint32_t current_verbosity;
+INLINE void SetVerbosity(int verbosity) {
+ atomic_store(¤t_verbosity, verbosity, memory_order_relaxed);
+}
+INLINE int Verbosity() {
+ return atomic_load(¤t_verbosity, memory_order_relaxed);
+}
+
+uptr GetPageSize();
+uptr GetPageSizeCached();
+uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
+// Threads
+uptr GetTid();
+uptr GetThreadSelf();
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom);
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size);
+
+// Memory management
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
+INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
+ return MmapOrDie(size, mem_type, /*raw_report*/ true);
+}
+void UnmapOrDie(void *addr, uptr size);
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
+ const char *name = nullptr);
+void *MmapNoReserveOrDie(uptr size, const char *mem_type);
+void *MmapFixedOrDie(uptr fixed_addr, uptr size);
+void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr);
+// Map aligned chunk of address space; size and alignment are powers of two.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
+// Disallow access to a memory range. Use MmapNoAccess to allocate an
+// unaccessible memory.
+bool MprotectNoAccess(uptr addr, uptr size);
+
+// Used to check if we can map shadow memory to a fixed location.
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
+void FlushUnneededShadowMemory(uptr addr, uptr size);
+void IncreaseTotalMmap(uptr size);
+void DecreaseTotalMmap(uptr size);
+uptr GetRSS();
+void NoHugePagesInRegion(uptr addr, uptr length);
+void DontDumpShadowMemory(uptr addr, uptr length);
+// Check if the built VMA size matches the runtime one.
+void CheckVMASize();
+
+// InternalScopedBuffer can be used instead of large stack arrays to
+// keep frame size low.
+// FIXME: use InternalAlloc instead of MmapOrDie once
+// InternalAlloc is made libc-free.
+template<typename T>
+class InternalScopedBuffer {
+ public:
+ explicit InternalScopedBuffer(uptr cnt) {
+ cnt_ = cnt;
+ ptr_ = (T*)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer");
+ }
+ ~InternalScopedBuffer() {
+ UnmapOrDie(ptr_, cnt_ * sizeof(T));
+ }
+ T &operator[](uptr i) { return ptr_[i]; }
+ T *data() { return ptr_; }
+ uptr size() { return cnt_ * sizeof(T); }
+
+ private:
+ T *ptr_;
+ uptr cnt_;
+ // Disallow evil constructors.
+ InternalScopedBuffer(const InternalScopedBuffer&);
+ void operator=(const InternalScopedBuffer&);
+};
+
+class InternalScopedString : public InternalScopedBuffer<char> {
+ public:
+ explicit InternalScopedString(uptr max_length)
+ : InternalScopedBuffer<char>(max_length), length_(0) {
+ (*this)[0] = '\0';
+ }
+ uptr length() { return length_; }
+ void clear() {
+ (*this)[0] = '\0';
+ length_ = 0;
+ }
+ void append(const char *format, ...);
+
+ private:
+ uptr length_;
+};
+
+// Simple low-level (mmap-based) allocator for internal use. Doesn't have
+// constructor, so all instances of LowLevelAllocator should be
+// linker initialized.
+class LowLevelAllocator {
+ public:
+ // Requires an external lock.
+ void *Allocate(uptr size);
+ private:
+ char *allocated_end_;
+ char *allocated_current_;
+};
+typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size);
+// Allows to register tool-specific callbacks for LowLevelAllocator.
+// Passing NULL removes the callback.
+void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
+
+// IO
+void RawWrite(const char *buffer);
+bool ColorizeReports();
+void RemoveANSIEscapeSequencesFromString(char *buffer);
+void Printf(const char *format, ...);
+void Report(const char *format, ...);
+void SetPrintfAndReportCallback(void (*callback)(const char *));
+#define VReport(level, ...) \
+ do { \
+ if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \
+ } while (0)
+#define VPrintf(level, ...) \
+ do { \
+ if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \
+ } while (0)
+
+// Can be used to prevent mixing error reports from different sanitizers.
+extern StaticSpinMutex CommonSanitizerReportMutex;
+
+struct ReportFile {
+ void Write(const char *buffer, uptr length);
+ bool SupportsColors();
+ void SetReportPath(const char *path);
+
+ // Don't use fields directly. They are only declared public to allow
+ // aggregate initialization.
+
+ // Protects fields below.
+ StaticSpinMutex *mu;
+ // Opened file descriptor. Defaults to stderr. It may be equal to
+ // kInvalidFd, in which case new file will be opened when necessary.
+ fd_t fd;
+ // Path prefix of report file, set via __sanitizer_set_report_path.
+ char path_prefix[kMaxPathLength];
+ // Full path to report, obtained as <path_prefix>.PID
+ char full_path[kMaxPathLength];
+ // PID of the process that opened fd. If a fork() occurs,
+ // the PID of child will be different from fd_pid.
+ uptr fd_pid;
+
+ private:
+ void ReopenIfNecessary();
+};
+extern ReportFile report_file;
+
+extern uptr stoptheworld_tracer_pid;
+extern uptr stoptheworld_tracer_ppid;
+
+enum FileAccessMode {
+ RdOnly,
+ WrOnly,
+ RdWr
+};
+
+// Returns kInvalidFd on error.
+fd_t OpenFile(const char *filename, FileAccessMode mode,
+ error_t *errno_p = nullptr);
+void CloseFile(fd_t);
+
+// Return true on success, false on error.
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size,
+ uptr *bytes_read = nullptr, error_t *error_p = nullptr);
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
+ uptr *bytes_written = nullptr, error_t *error_p = nullptr);
+
+bool RenameFile(const char *oldpath, const char *newpath,
+ error_t *error_p = nullptr);
+
+// Scoped file handle closer.
+struct FileCloser {
+ explicit FileCloser(fd_t fd) : fd(fd) {}
+ ~FileCloser() { CloseFile(fd); }
+ fd_t fd;
+};
+
+bool SupportsColoredOutput(fd_t fd);
+
+// Opens the file 'file_name" and reads up to 'max_len' bytes.
+// The resulting buffer is mmaped and stored in '*buff'.
+// The size of the mmaped region is stored in '*buff_size'.
+// The total number of read bytes is stored in '*read_len'.
+// Returns true if file was successfully opened and read.
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len = 1 << 26,
+ error_t *errno_p = nullptr);
+// Maps given file to virtual memory, and returns pointer to it
+// (or NULL if mapping fails). Stores the size of mmaped region
+// in '*buff_size'.
+void *MapFileToMemory(const char *file_name, uptr *buff_size);
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset);
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size);
+
+// Error report formatting.
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_file_prefix);
+// Strip the directories from the module name.
+const char *StripModuleName(const char *module);
+
+// OS
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
+uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
+uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
+const char *GetProcessName();
+void UpdateProcessName();
+void CacheBinaryName();
+void DisableCoreDumperIfNecessary();
+void DumpProcessMap();
+bool FileExists(const char *filename);
+const char *GetEnv(const char *name);
+bool SetEnv(const char *name, const char *value);
+const char *GetPwd();
+char *FindPathToBinary(const char *name);
+bool IsPathSeparator(const char c);
+bool IsAbsolutePath(const char *path);
+
+u32 GetUid();
+void ReExec();
+bool StackSizeIsUnlimited();
+void SetStackSizeLimitInBytes(uptr limit);
+bool AddressSpaceIsUnlimited();
+void SetAddressSpaceUnlimited();
+void AdjustStackSize(void *attr);
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void SetSandboxingCallback(void (*f)());
+
+void CoverageUpdateMapping();
+void CovBeforeFork();
+void CovAfterFork(int child_pid);
+
+void InitializeCoverage(bool enabled, const char *coverage_dir);
+void ReInitializeCoverage(bool enabled, const char *coverage_dir);
+
+void InitTlsSize();
+uptr GetTlsSize();
+
+// Other
+void SleepForSeconds(int seconds);
+void SleepForMillis(int millis);
+u64 NanoTime();
+int Atexit(void (*function)(void));
+void SortArray(uptr *array, uptr size);
+bool TemplateMatch(const char *templ, const char *str);
+
+// Exit
+void NORETURN Abort();
+void NORETURN Die();
+void NORETURN
+CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
+void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
+ const char *mmap_type, error_t err,
+ bool raw_report = false);
+
+// Set the name of the current thread to 'name', return true on succees.
+// The name may be truncated to a system-dependent limit.
+bool SanitizerSetThreadName(const char *name);
+// Get the name of the current thread (no more than max_len bytes),
+// return true on succees. name should have space for at least max_len+1 bytes.
+bool SanitizerGetThreadName(char *name, int max_len);
+
+// Specific tools may override behavior of "Die" and "CheckFailed" functions
+// to do tool-specific job.
+typedef void (*DieCallbackType)(void);
+
+// It's possible to add several callbacks that would be run when "Die" is
+// called. The callbacks will be run in the opposite order. The tools are
+// strongly recommended to setup all callbacks during initialization, when there
+// is only a single thread.
+bool AddDieCallback(DieCallbackType callback);
+bool RemoveDieCallback(DieCallbackType callback);
+
+void SetUserDieCallback(DieCallbackType callback);
+
+typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
+ u64, u64);
+void SetCheckFailedCallback(CheckFailedCallbackType callback);
+
+// Callback will be called if soft_rss_limit_mb is given and the limit is
+// exceeded (exceeded==true) or if rss went down below the limit
+// (exceeded==false).
+// The callback should be registered once at the tool init time.
+void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
+
+// Functions related to signal handling.
+typedef void (*SignalHandlerType)(int, void *, void *);
+bool IsDeadlySignal(int signum);
+void InstallDeadlySignalHandlers(SignalHandlerType handler);
+// Alternative signal stack (POSIX-only).
+void SetAlternateSignalStack();
+void UnsetAlternateSignalStack();
+
+// We don't want a summary too long.
+const int kMaxSummaryLength = 1024;
+// Construct a one-line string:
+// SUMMARY: SanitizerToolName: error_message
+// and pass it to __sanitizer_report_error_summary.
+void ReportErrorSummary(const char *error_message);
+// Same as above, but construct error_message as:
+// error_type file:line[:column][ function]
+void ReportErrorSummary(const char *error_type, const AddressInfo &info);
+// Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
+void ReportErrorSummary(const char *error_type, StackTrace *trace);
+
+// Math
+#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
+extern "C" {
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
+#if defined(_WIN64)
+unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT
+unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT
+#endif
+}
+#endif
+
+INLINE uptr MostSignificantSetBitIndex(uptr x) {
+ CHECK_NE(x, 0U);
+ unsigned long up; // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+# ifdef _WIN64
+ up = SANITIZER_WORDSIZE - 1 - __builtin_clzll(x);
+# else
+ up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
+# endif
+#elif defined(_WIN64)
+ _BitScanReverse64(&up, x);
+#else
+ _BitScanReverse(&up, x);
+#endif
+ return up;
+}
+
+INLINE uptr LeastSignificantSetBitIndex(uptr x) {
+ CHECK_NE(x, 0U);
+ unsigned long up; // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+# ifdef _WIN64
+ up = __builtin_ctzll(x);
+# else
+ up = __builtin_ctzl(x);
+# endif
+#elif defined(_WIN64)
+ _BitScanForward64(&up, x);
+#else
+ _BitScanForward(&up, x);
+#endif
+ return up;
+}
+
+INLINE bool IsPowerOfTwo(uptr x) {
+ return (x & (x - 1)) == 0;
+}
+
+INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+ CHECK(size);
+ if (IsPowerOfTwo(size)) return size;
+
+ uptr up = MostSignificantSetBitIndex(size);
+ CHECK(size < (1ULL << (up + 1)));
+ CHECK(size > (1ULL << up));
+ return 1ULL << (up + 1);
+}
+
+INLINE uptr RoundUpTo(uptr size, uptr boundary) {
+ RAW_CHECK(IsPowerOfTwo(boundary));
+ return (size + boundary - 1) & ~(boundary - 1);
+}
+
+INLINE uptr RoundDownTo(uptr x, uptr boundary) {
+ return x & ~(boundary - 1);
+}
+
+INLINE bool IsAligned(uptr a, uptr alignment) {
+ return (a & (alignment - 1)) == 0;
+}
+
+INLINE uptr Log2(uptr x) {
+ CHECK(IsPowerOfTwo(x));
+ return LeastSignificantSetBitIndex(x);
+}
+
+// Don't use std::min, std::max or std::swap, to minimize dependency
+// on libstdc++.
+template<class T> T Min(T a, T b) { return a < b ? a : b; }
+template<class T> T Max(T a, T b) { return a > b ? a : b; }
+template<class T> void Swap(T& a, T& b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+// Char handling
+INLINE bool IsSpace(int c) {
+ return (c == ' ') || (c == '\n') || (c == '\t') ||
+ (c == '\f') || (c == '\r') || (c == '\v');
+}
+INLINE bool IsDigit(int c) {
+ return (c >= '0') && (c <= '9');
+}
+INLINE int ToLower(int c) {
+ return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
+}
+
+// A low-level vector based on mmap. May incur a significant memory overhead for
+// small vectors.
+// WARNING: The current implementation supports only POD types.
+template<typename T>
+class InternalMmapVectorNoCtor {
+ public:
+ void Initialize(uptr initial_capacity) {
+ capacity_ = Max(initial_capacity, (uptr)1);
+ size_ = 0;
+ data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVectorNoCtor");
+ }
+ void Destroy() {
+ UnmapOrDie(data_, capacity_ * sizeof(T));
+ }
+ T &operator[](uptr i) {
+ CHECK_LT(i, size_);
+ return data_[i];
+ }
+ const T &operator[](uptr i) const {
+ CHECK_LT(i, size_);
+ return data_[i];
+ }
+ void push_back(const T &element) {
+ CHECK_LE(size_, capacity_);
+ if (size_ == capacity_) {
+ uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1);
+ Resize(new_capacity);
+ }
+ data_[size_++] = element;
+ }
+ T &back() {
+ CHECK_GT(size_, 0);
+ return data_[size_ - 1];
+ }
+ void pop_back() {
+ CHECK_GT(size_, 0);
+ size_--;
+ }
+ uptr size() const {
+ return size_;
+ }
+ const T *data() const {
+ return data_;
+ }
+ T *data() {
+ return data_;
+ }
+ uptr capacity() const {
+ return capacity_;
+ }
+
+ void clear() { size_ = 0; }
+ bool empty() const { return size() == 0; }
+
+ private:
+ void Resize(uptr new_capacity) {
+ CHECK_GT(new_capacity, 0);
+ CHECK_LE(size_, new_capacity);
+ T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T),
+ "InternalMmapVector");
+ internal_memcpy(new_data, data_, size_ * sizeof(T));
+ T *old_data = data_;
+ data_ = new_data;
+ UnmapOrDie(old_data, capacity_ * sizeof(T));
+ capacity_ = new_capacity;
+ }
+
+ T *data_;
+ uptr capacity_;
+ uptr size_;
+};
+
+template<typename T>
+class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
+ public:
+ explicit InternalMmapVector(uptr initial_capacity) {
+ InternalMmapVectorNoCtor<T>::Initialize(initial_capacity);
+ }
+ ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); }
+ // Disallow evil constructors.
+ InternalMmapVector(const InternalMmapVector&);
+ void operator=(const InternalMmapVector&);
+};
+
+// HeapSort for arrays and InternalMmapVector.
+template<class Container, class Compare>
+void InternalSort(Container *v, uptr size, Compare comp) {
+ if (size < 2)
+ return;
+ // Stage 1: insert elements to the heap.
+ for (uptr i = 1; i < size; i++) {
+ uptr j, p;
+ for (j = i; j > 0; j = p) {
+ p = (j - 1) / 2;
+ if (comp((*v)[p], (*v)[j]))
+ Swap((*v)[j], (*v)[p]);
+ else
+ break;
+ }
+ }
+ // Stage 2: swap largest element with the last one,
+ // and sink the new top.
+ for (uptr i = size - 1; i > 0; i--) {
+ Swap((*v)[0], (*v)[i]);
+ uptr j, max_ind;
+ for (j = 0; j < i; j = max_ind) {
+ uptr left = 2 * j + 1;
+ uptr right = 2 * j + 2;
+ max_ind = j;
+ if (left < i && comp((*v)[max_ind], (*v)[left]))
+ max_ind = left;
+ if (right < i && comp((*v)[max_ind], (*v)[right]))
+ max_ind = right;
+ if (max_ind != j)
+ Swap((*v)[j], (*v)[max_ind]);
+ else
+ break;
+ }
+ }
+}
+
+template<class Container, class Value, class Compare>
+uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
+ const Value &val, Compare comp) {
+ uptr not_found = last + 1;
+ while (last >= first) {
+ uptr mid = (first + last) / 2;
+ if (comp(v[mid], val))
+ first = mid + 1;
+ else if (comp(val, v[mid]))
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return not_found;
+}
+
+// Represents a binary loaded into virtual memory (e.g. this can be an
+// executable or a shared object).
+class LoadedModule {
+ public:
+ LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); }
+ void set(const char *module_name, uptr base_address);
+ void clear();
+ void addAddressRange(uptr beg, uptr end, bool executable);
+ bool containsAddress(uptr address) const;
+
+ const char *full_name() const { return full_name_; }
+ uptr base_address() const { return base_address_; }
+
+ struct AddressRange {
+ AddressRange *next;
+ uptr beg;
+ uptr end;
+ bool executable;
+
+ AddressRange(uptr beg, uptr end, bool executable)
+ : next(nullptr), beg(beg), end(end), executable(executable) {}
+ };
+
+ typedef IntrusiveList<AddressRange>::ConstIterator Iterator;
+ Iterator ranges() const { return Iterator(&ranges_); }
+
+ private:
+ char *full_name_; // Owned.
+ uptr base_address_;
+ IntrusiveList<AddressRange> ranges_;
+};
+
+// OS-dependent function that fills array with descriptions of at most
+// "max_modules" currently loaded modules. Returns the number of
+// initialized modules. If filter is nonzero, ignores modules for which
+// filter(full_name) is false.
+typedef bool (*string_predicate_t)(const char *);
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
+
+// Callback type for iterating over a set of memory ranges.
+typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
+
+enum AndroidApiLevel {
+ ANDROID_NOT_ANDROID = 0,
+ ANDROID_KITKAT = 19,
+ ANDROID_LOLLIPOP_MR1 = 22,
+ ANDROID_POST_LOLLIPOP = 23
+};
+
+void WriteToSyslog(const char *buffer);
+
+#if SANITIZER_MAC
+void LogFullErrorReport(const char *buffer);
+#else
+INLINE void LogFullErrorReport(const char *buffer) {}
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_MAC
+void WriteOneLineToSyslog(const char *s);
+#else
+INLINE void WriteOneLineToSyslog(const char *s) {}
+#endif
+
+#if SANITIZER_LINUX
+// Initialize Android logging. Any writes before this are silently lost.
+void AndroidLogInit();
+bool ShouldLogAfterPrintf();
+#else
+INLINE void AndroidLogInit() {}
+INLINE bool ShouldLogAfterPrintf() { return false; }
+#endif
+
+#if SANITIZER_ANDROID
+void SanitizerInitializeUnwinder();
+AndroidApiLevel AndroidGetApiLevel();
+#else
+INLINE void AndroidLogWrite(const char *buffer_unused) {}
+INLINE void SanitizerInitializeUnwinder() {}
+INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
+#endif
+
+INLINE uptr GetPthreadDestructorIterations() {
+#if SANITIZER_ANDROID
+ return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4;
+#elif SANITIZER_POSIX
+ return 4;
+#else
+// Unused on Windows.
+ return 0;
+#endif
+}
+
+void *internal_start_thread(void(*func)(void*), void *arg);
+void internal_join_thread(void *th);
+void MaybeStartBackgroudThread();
+
+// Make the compiler think that something is going on there.
+// Use this inside a loop that looks like memset/memcpy/etc to prevent the
+// compiler from recognising it and turning it into an actual call to
+// memset/memcpy/etc.
+static inline void SanitizerBreakOptimization(void *arg) {
+#if _MSC_VER && !defined(__clang__)
+ _ReadWriteBarrier();
+#else
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
+struct SignalContext {
+ void *context;
+ uptr addr;
+ uptr pc;
+ uptr sp;
+ uptr bp;
+
+ SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
+ context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
+ }
+
+ // Creates signal context in a platform-specific manner.
+ static SignalContext Create(void *siginfo, void *context);
+};
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+
+void DisableReexec();
+void MaybeReexec();
+
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ __sanitizer::LowLevelAllocator &alloc) {
+ return alloc.Allocate(size);
+}
+
+struct StackDepotStats {
+ uptr n_uniq_ids;
+ uptr allocated;
+};
+
+#endif // SANITIZER_COMMON_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
new file mode 100644
index 0000000..4639ddc
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -0,0 +1,5494 @@
+//===-- sanitizer_common_interceptors.inc -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common function interceptors for tools like AddressSanitizer,
+// ThreadSanitizer, MemorySanitizer, etc.
+//
+// This file should be included into the tool's interceptor file,
+// which has to define it's own macros:
+// COMMON_INTERCEPTOR_ENTER
+// COMMON_INTERCEPTOR_ENTER_NOIGNORE
+// COMMON_INTERCEPTOR_READ_RANGE
+// COMMON_INTERCEPTOR_WRITE_RANGE
+// COMMON_INTERCEPTOR_INITIALIZE_RANGE
+// COMMON_INTERCEPTOR_DIR_ACQUIRE
+// COMMON_INTERCEPTOR_FD_ACQUIRE
+// COMMON_INTERCEPTOR_FD_RELEASE
+// COMMON_INTERCEPTOR_FD_ACCESS
+// COMMON_INTERCEPTOR_SET_THREAD_NAME
+// COMMON_INTERCEPTOR_ON_DLOPEN
+// COMMON_INTERCEPTOR_ON_EXIT
+// COMMON_INTERCEPTOR_MUTEX_LOCK
+// COMMON_INTERCEPTOR_MUTEX_UNLOCK
+// COMMON_INTERCEPTOR_MUTEX_REPAIR
+// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
+// COMMON_INTERCEPTOR_HANDLE_RECVMSG
+// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_addrhashmap.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_platform_interceptors.h"
+#include "sanitizer_tls_get_addr.h"
+
+#include <stdarg.h>
+
+#if SANITIZER_INTERCEPTOR_HOOKS
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ do { \
+ if (f) \
+ f(__VA_ARGS__); \
+ } while (false);
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ extern "C" { \
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); \
+ } // extern "C"
+#else
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...)
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)
+
+#endif // SANITIZER_INTERCEPTOR_HOOKS
+
+#if SANITIZER_WINDOWS && !defined(va_copy)
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
+#if SANITIZER_FREEBSD
+#define pthread_setname_np pthread_set_name_np
+#define inet_aton __inet_aton
+#define inet_pton __inet_pton
+#define iconv __bsd_iconv
+#endif
+
+#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FD_ACCESS
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_OPEN
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_CLOSE
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \
+ COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__)
+#endif
+
+#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
+#endif
+
+#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \
+ COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
+#ifndef COMMON_INTERCEPTOR_ON_DLOPEN
+#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE
+#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0;
+#endif
+
+#ifndef COMMON_INTERCEPTOR_ACQUIRE
+#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_RELEASE
+#define COMMON_INTERCEPTOR_RELEASE(ctx, u) {}
+#endif
+
+struct FileMetadata {
+ // For open_memstream().
+ char **addr;
+ SIZE_T *size;
+};
+
+struct CommonInterceptorMetadata {
+ enum {
+ CIMT_INVALID = 0,
+ CIMT_FILE
+ } type;
+ union {
+ FileMetadata file;
+ };
+};
+
+typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap;
+
+static MetadataHashMap *interceptor_metadata_map;
+
+#if SI_NOT_WINDOWS
+UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr,
+ const FileMetadata &file) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr);
+ CHECK(h.created());
+ h->type = CommonInterceptorMetadata::CIMT_FILE;
+ h->file = file;
+}
+
+UNUSED static const FileMetadata *GetInterceptorMetadata(
+ __sanitizer_FILE *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr,
+ /* remove */ false,
+ /* create */ false);
+ if (h.exists()) {
+ CHECK(!h.created());
+ CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE);
+ return &h->file;
+ } else {
+ return 0;
+ }
+}
+
+UNUSED static void DeleteInterceptorMetadata(void *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true);
+ CHECK(h.exists());
+}
+#endif // SI_NOT_WINDOWS
+
+#if SANITIZER_INTERCEPT_TEXTDOMAIN
+INTERCEPTOR(char*, textdomain, const char *domainname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+ char *domain = REAL(textdomain)(domainname);
+ if (domain) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
+ }
+ return domain;
+}
+#define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain)
+#else
+#define INIT_TEXTDOMAIN
+#endif
+
+#if SANITIZER_INTERCEPT_STRCMP
+static inline int CharCmpX(unsigned char c1, unsigned char c2) {
+ return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc,
+ const char *s1, const char *s2)
+
+INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
+ s2);
+ unsigned char c1, c2;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
+ return CharCmpX(c1, c2);
+}
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc,
+ const char *s1, const char *s2, uptr n)
+
+INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strncmp(s1, s2, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
+ s2, size);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+ return CharCmpX(c1, c2);
+}
+
+#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp)
+#else
+#define INIT_STRCMP
+#define INIT_STRNCMP
+#endif
+
+#if SANITIZER_INTERCEPT_STRCASECMP
+static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
+ int c1_low = ToLower(c1);
+ int c2_low = ToLower(c2);
+ return c1_low - c2_low;
+}
+
+INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
+ return CharCaseCmp(c1, c2);
+}
+
+INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0; i < n; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
+ return CharCaseCmp(c1, c2);
+}
+
+#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp)
+#else
+#define INIT_STRCASECMP
+#define INIT_STRNCASECMP
+#endif
+
+#if SANITIZER_INTERCEPT_STRSTR || SANITIZER_INTERCEPT_STRCASESTR
+static inline void StrstrCheck(void *ctx, char *r, const char *s1,
+ const char *s2) {
+ uptr len1 = REAL(strlen)(s1);
+ uptr len2 = REAL(strlen)(s2);
+ COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1,
+ r ? r - s1 + len2 : len1 + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_STRSTR
+INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strstr(s1, s2);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strstr, s1, s2);
+ char *r = REAL(strstr)(s1, s2);
+ if (common_flags()->intercept_strstr)
+ StrstrCheck(ctx, r, s1, s2);
+ return r;
+}
+
+#define INIT_STRSTR COMMON_INTERCEPT_FUNCTION(strstr);
+#else
+#define INIT_STRSTR
+#endif
+
+#if SANITIZER_INTERCEPT_STRCASESTR
+INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2);
+ char *r = REAL(strcasestr)(s1, s2);
+ if (common_flags()->intercept_strstr)
+ StrstrCheck(ctx, r, s1, s2);
+ return r;
+}
+
+#define INIT_STRCASESTR COMMON_INTERCEPT_FUNCTION(strcasestr);
+#else
+#define INIT_STRCASESTR
+#endif
+
+#if SANITIZER_INTERCEPT_STRSPN
+INTERCEPTOR(SIZE_T, strspn, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strspn, s1, s2);
+ SIZE_T r = REAL(strspn)(s1, s2);
+ if (common_flags()->intercept_strspn) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1);
+ }
+ return r;
+}
+
+INTERCEPTOR(SIZE_T, strcspn, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcspn, s1, s2);
+ SIZE_T r = REAL(strcspn)(s1, s2);
+ if (common_flags()->intercept_strspn) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1);
+ }
+ return r;
+}
+
+#define INIT_STRSPN \
+ COMMON_INTERCEPT_FUNCTION(strspn); \
+ COMMON_INTERCEPT_FUNCTION(strcspn);
+#else
+#define INIT_STRSPN
+#endif
+
+#if SANITIZER_INTERCEPT_STRPBRK
+INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strpbrk, s1, s2);
+ char *r = REAL(strpbrk)(s1, s2);
+ if (common_flags()->intercept_strpbrk) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1,
+ r ? r - s1 + 1 : REAL(strlen)(s1) + 1);
+ }
+ return r;
+}
+
+#define INIT_STRPBRK COMMON_INTERCEPT_FUNCTION(strpbrk);
+#else
+#define INIT_STRPBRK
+#endif
+
+#if SANITIZER_INTERCEPT_MEMCMP
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc,
+ const void *s1, const void *s2, uptr n)
+
+INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memcmp(a1, a2, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1,
+ a2, size);
+ if (common_flags()->intercept_memcmp) {
+ if (common_flags()->strict_memcmp) {
+ // Check the entire regions even if the first bytes of the buffers are
+ // different.
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size);
+ // Fallthrough to REAL(memcmp) below.
+ } else {
+ unsigned char c1 = 0, c2 = 0;
+ const unsigned char *s1 = (const unsigned char*)a1;
+ const unsigned char *s2 = (const unsigned char*)a2;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if (c1 != c2) break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+ return CharCmpX(c1, c2);
+ }
+ }
+ return REAL(memcmp(a1, a2, size));
+}
+
+#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp)
+#else
+#define INIT_MEMCMP
+#endif
+
+#if SANITIZER_INTERCEPT_MEMCHR
+INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memchr(s, c, n);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
+ void *res = REAL(memchr)(s, c, n);
+ uptr len = res ? (char *)res - (const char *)s + 1 : n;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
+ return res;
+}
+
+#define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr)
+#else
+#define INIT_MEMCHR
+#endif
+
+#if SANITIZER_INTERCEPT_MEMRCHR
+INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n);
+ return REAL(memrchr)(s, c, n);
+}
+
+#define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr)
+#else
+#define INIT_MEMRCHR
+#endif
+
+#if SANITIZER_INTERCEPT_FREXP
+INTERCEPTOR(double, frexp, double x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp);
+ // Assuming frexp() always writes to |exp|.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ double res = REAL(frexp)(x, exp);
+ return res;
+}
+
+#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp);
+#else
+#define INIT_FREXP
+#endif // SANITIZER_INTERCEPT_FREXP
+
+#if SANITIZER_INTERCEPT_FREXPF_FREXPL
+INTERCEPTOR(float, frexpf, float x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ float res = REAL(frexpf)(x, exp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ return res;
+}
+
+INTERCEPTOR(long double, frexpl, long double x, int *exp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ long double res = REAL(frexpl)(x, exp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ return res;
+}
+
+#define INIT_FREXPF_FREXPL \
+ COMMON_INTERCEPT_FUNCTION(frexpf); \
+ COMMON_INTERCEPT_FUNCTION(frexpl)
+#else
+#define INIT_FREXPF_FREXPL
+#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
+
+#if SI_NOT_WINDOWS
+static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen);
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+#endif
+
+#if SANITIZER_INTERCEPT_READ
+INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SSIZE_T res = REAL(read)(fd, ptr, count);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_READ COMMON_INTERCEPT_FUNCTION(read)
+#else
+#define INIT_READ
+#endif
+
+#if SANITIZER_INTERCEPT_PREAD
+INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread)
+#else
+#define INIT_PREAD
+#endif
+
+#if SANITIZER_INTERCEPT_PREAD64
+INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64)
+#else
+#define INIT_PREAD64
+#endif
+
+#if SANITIZER_INTERCEPT_READV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv)
+#else
+#define INIT_READV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV
+INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv)
+#else
+#define INIT_PREADV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV64
+INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64)
+#else
+#define INIT_PREADV64
+#endif
+
+#if SANITIZER_INTERCEPT_WRITE
+INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(write)(fd, ptr, count);
+ // FIXME: this check should be _before_ the call to REAL(write), not after
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write)
+#else
+#define INIT_WRITE
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITE
+INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite)
+#else
+#define INIT_PWRITE
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITE64
+INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ return res;
+}
+#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64)
+#else
+#define INIT_PWRITE64
+#endif
+
+#if SANITIZER_INTERCEPT_WRITEV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev)
+#else
+#define INIT_WRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV
+INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev)
+#else
+#define INIT_PWRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV64
+INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64)
+#else
+#define INIT_PWRITEV64
+#endif
+
+#if SANITIZER_INTERCEPT_PRCTL
+INTERCEPTOR(int, prctl, int option, unsigned long arg2,
+ unsigned long arg3, // NOLINT
+ unsigned long arg4, unsigned long arg5) { // NOLINT
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
+ static const int PR_SET_NAME = 15;
+ int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
+ if (option == PR_SET_NAME) {
+ char buff[16];
+ internal_strncpy(buff, (char *)arg2, 15);
+ buff[15] = 0;
+ COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
+ }
+ return res;
+}
+#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl)
+#else
+#define INIT_PRCTL
+#endif // SANITIZER_INTERCEPT_PRCTL
+
+#if SANITIZER_INTERCEPT_TIME
+INTERCEPTOR(unsigned long, time, unsigned long *t) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, time, t);
+ unsigned long local_t;
+ unsigned long res = REAL(time)(&local_t);
+ if (t && res != (unsigned long)-1) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
+ *t = local_t;
+ }
+ return res;
+}
+#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time);
+#else
+#define INIT_TIME
+#endif // SANITIZER_INTERCEPT_TIME
+
+#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ if (tm->tm_zone) {
+ // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
+ // can point to shared memory and tsan would report a data race.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone,
+ REAL(strlen(tm->tm_zone)) + 1);
+ }
+}
+INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
+ __sanitizer_tm *res = REAL(localtime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
+ __sanitizer_tm *res = REAL(localtime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
+ __sanitizer_tm *res = REAL(gmtime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
+ __sanitizer_tm *res = REAL(gmtime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ unpoison_tm(ctx, res);
+ }
+ return res;
+}
+INTERCEPTOR(char *, ctime, unsigned long *timep) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(ctime)(timep);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(ctime_r)(timep, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(asctime)(tm);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(asctime_r)(tm, result);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+INTERCEPTOR(long, mktime, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst));
+ long res = REAL(mktime)(tm);
+ if (res != -1) unpoison_tm(ctx, tm);
+ return res;
+}
+#define INIT_LOCALTIME_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(localtime); \
+ COMMON_INTERCEPT_FUNCTION(localtime_r); \
+ COMMON_INTERCEPT_FUNCTION(gmtime); \
+ COMMON_INTERCEPT_FUNCTION(gmtime_r); \
+ COMMON_INTERCEPT_FUNCTION(ctime); \
+ COMMON_INTERCEPT_FUNCTION(ctime_r); \
+ COMMON_INTERCEPT_FUNCTION(asctime); \
+ COMMON_INTERCEPT_FUNCTION(asctime_r); \
+ COMMON_INTERCEPT_FUNCTION(mktime);
+#else
+#define INIT_LOCALTIME_AND_FRIENDS
+#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_STRPTIME
+INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm);
+ if (format)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(strptime)(s, format, tm);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
+ if (res && tm) {
+ // Do not call unpoison_tm here, because strptime does not, in fact,
+ // initialize the entire struct tm. For example, tm_zone pointer is left
+ // uninitialized.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ }
+ return res;
+}
+#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime);
+#else
+#define INIT_STRPTIME
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF
+#include "sanitizer_common_interceptors_format.inc"
+
+#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \
+ { \
+ void *ctx; \
+ va_list ap; \
+ va_start(ap, format); \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
+ int res = WRAP(vname)(__VA_ARGS__, ap); \
+ va_end(ap); \
+ return res; \
+ }
+
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF
+
+#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ if (res > 0) \
+ scanf_common(ctx, res, allowGnuMalloc, format, aq); \
+ va_end(aq); \
+ return res; \
+ }
+
+INTERCEPTOR(int, vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
+
+INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
+
+INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
+ va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
+#endif // SANITIZER_INTERCEPT_ISOC99_SCANF
+
+INTERCEPTOR(int, scanf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format)
+
+INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+
+INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+
+INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
+#endif
+
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF
+#define INIT_SCANF \
+ COMMON_INTERCEPT_FUNCTION(scanf); \
+ COMMON_INTERCEPT_FUNCTION(sscanf); \
+ COMMON_INTERCEPT_FUNCTION(fscanf); \
+ COMMON_INTERCEPT_FUNCTION(vscanf); \
+ COMMON_INTERCEPT_FUNCTION(vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(vfscanf);
+#else
+#define INIT_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+#define INIT_ISOC99_SCANF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#else
+#define INIT_ISOC99_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_PRINTF
+
+#define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap);
+
+#define VPRINTF_INTERCEPTOR_RETURN() \
+ va_end(aq);
+
+#define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \
+ if (common_flags()->check_printf) \
+ printf_common(ctx, format, aq); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://github.com/google/sanitizers/issues/321.
+#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://github.com/google/sanitizers/issues/321.
+#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, size, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1))); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// FIXME: under ASan the REAL() call below may write to freed memory and
+// corrupt its metadata. See
+// https://github.com/google/sanitizers/issues/321.
+#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(strp, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+INTERCEPTOR(int, vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap)
+
+INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format,
+ va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap)
+
+#if SANITIZER_INTERCEPT_PRINTF_L
+INTERCEPTOR(int, vsnprintf_l, char *str, SIZE_T size, void *loc,
+ const char *format, va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf_l, str, size, loc, format, ap)
+
+INTERCEPTOR(int, snprintf_l, char *str, SIZE_T size, void *loc,
+ const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf_l, vsnprintf_l, str, size, loc, format)
+#endif // SANITIZER_INTERCEPT_PRINTF_L
+
+INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
+VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream,
+ const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format,
+ va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format,
+ ap)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+INTERCEPTOR(int, printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format)
+
+INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format)
+
+INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT
+FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT
+
+INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format)
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
+
+INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format,
+ ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format)
+
+INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size,
+ const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
+ format)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+#endif // SANITIZER_INTERCEPT_PRINTF
+
+#if SANITIZER_INTERCEPT_PRINTF
+#define INIT_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(printf); \
+ COMMON_INTERCEPT_FUNCTION(sprintf); \
+ COMMON_INTERCEPT_FUNCTION(snprintf); \
+ COMMON_INTERCEPT_FUNCTION(asprintf); \
+ COMMON_INTERCEPT_FUNCTION(fprintf); \
+ COMMON_INTERCEPT_FUNCTION(vprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(vasprintf); \
+ COMMON_INTERCEPT_FUNCTION(vfprintf);
+#else
+#define INIT_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_PRINTF_L
+#define INIT_PRINTF_L \
+ COMMON_INTERCEPT_FUNCTION(snprintf_l); \
+ COMMON_INTERCEPT_FUNCTION(vsnprintf_l);
+#else
+#define INIT_PRINTF_L
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+#define INIT_ISOC99_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf);
+#else
+#define INIT_ISOC99_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_IOCTL
+#include "sanitizer_common_interceptors_ioctl.inc"
+INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) {
+ // We need a frame pointer, because we call into ioctl_common_[pre|post] which
+ // can trigger a report and we need to be able to unwind through this
+ // function. On Mac in debug mode we might not have a frame pointer, because
+ // ioctl_common_[pre|post] doesn't get inlined here.
+ ENABLE_FRAME_POINTER;
+
+ void *ctx;
+ va_list ap;
+ va_start(ap, request);
+ void *arg = va_arg(ap, void *);
+ va_end(ap);
+ COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg);
+
+ CHECK(ioctl_initialized);
+
+ // Note: TSan does not use common flags, and they are zero-initialized.
+ // This effectively disables ioctl handling in TSan.
+ if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg);
+
+ // Although request is unsigned long, the rest of the interceptor uses it
+ // as just "unsigned" to save space, because we know that all values fit in
+ // "unsigned" - they are compile-time constants.
+
+ const ioctl_desc *desc = ioctl_lookup(request);
+ ioctl_desc decoded_desc;
+ if (!desc) {
+ VPrintf(2, "Decoding unknown ioctl 0x%x\n", request);
+ if (!ioctl_decode(request, &decoded_desc))
+ Printf("WARNING: failed decoding unknown ioctl 0x%x\n", request);
+ else
+ desc = &decoded_desc;
+ }
+
+ if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
+ int res = REAL(ioctl)(d, request, arg);
+ // FIXME: some ioctls have different return values for success and failure.
+ if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg);
+ return res;
+}
+#define INIT_IOCTL \
+ ioctl_init(); \
+ COMMON_INTERCEPT_FUNCTION(ioctl);
+#else
+#define INIT_IOCTL
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
+ SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \
+ SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
+ if (pwd) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
+ if (pwd->pw_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_name,
+ REAL(strlen)(pwd->pw_name) + 1);
+ if (pwd->pw_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_passwd,
+ REAL(strlen)(pwd->pw_passwd) + 1);
+#if !SANITIZER_ANDROID
+ if (pwd->pw_gecos)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_gecos,
+ REAL(strlen)(pwd->pw_gecos) + 1);
+#endif
+#if SANITIZER_MAC
+ if (pwd->pw_class)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_class,
+ REAL(strlen)(pwd->pw_class) + 1);
+#endif
+ if (pwd->pw_dir)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_dir,
+ REAL(strlen)(pwd->pw_dir) + 1);
+ if (pwd->pw_shell)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_shell,
+ REAL(strlen)(pwd->pw_shell) + 1);
+ }
+}
+
+static void unpoison_group(void *ctx, __sanitizer_group *grp) {
+ if (grp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp));
+ if (grp->gr_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_name,
+ REAL(strlen)(grp->gr_name) + 1);
+ if (grp->gr_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_passwd,
+ REAL(strlen)(grp->gr_passwd) + 1);
+ char **p = grp->gr_mem;
+ for (; *p; ++p) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*p, REAL(strlen)(*p) + 1);
+ }
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_mem,
+ (p - grp->gr_mem + 1) * sizeof(*p));
+ }
+}
+#endif // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
+ // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT ||
+ // SANITIZER_INTERCEPT_GETPWENT_R ||
+ // SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ __sanitizer_passwd *res = REAL(getpwnam)(name);
+ if (res) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
+ __sanitizer_passwd *res = REAL(getpwuid)(uid);
+ if (res) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ __sanitizer_group *res = REAL(getgrnam)(name);
+ if (res) unpoison_group(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
+ __sanitizer_group *res = REAL(getgrgid)(gid);
+ if (res) unpoison_group(ctx, res);
+ return res;
+}
+#define INIT_GETPWNAM_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid);
+#else
+#define INIT_GETPWNAM_AND_FRIENDS
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
+ char *buf, SIZE_T buflen, __sanitizer_passwd **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_passwd(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_passwd(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
+ char *buf, SIZE_T buflen, __sanitizer_group **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_group(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
+ SIZE_T buflen, __sanitizer_group **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
+ if (!res) {
+ if (result && *result) unpoison_group(ctx, *result);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_GETPWNAM_R_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid_r);
+#else
+#define INIT_GETPWNAM_R_AND_FRIENDS
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT
+INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy);
+ __sanitizer_passwd *res = REAL(getpwent)(dummy);
+ if (res) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy);
+ __sanitizer_group *res = REAL(getgrent)(dummy);
+ if (res) unpoison_group(ctx, res);;
+ return res;
+}
+#define INIT_GETPWENT \
+ COMMON_INTERCEPT_FUNCTION(getpwent); \
+ COMMON_INTERCEPT_FUNCTION(getgrent);
+#else
+#define INIT_GETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_FGETPWENT
+INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp);
+ __sanitizer_passwd *res = REAL(fgetpwent)(fp);
+ if (res) unpoison_passwd(ctx, res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp);
+ __sanitizer_group *res = REAL(fgetgrent)(fp);
+ if (res) unpoison_group(ctx, res);
+ return res;
+}
+#define INIT_FGETPWENT \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent);
+#else
+#define INIT_FGETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT_R
+INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
+ __sanitizer_group **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_group **pwbufp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+#define INIT_GETPWENT_R \
+ COMMON_INTERCEPT_FUNCTION(getpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent_r);
+#else
+#define INIT_GETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_SETPWENT
+// The only thing these interceptors do is disable any nested interceptors.
+// These functions may open nss modules and call uninstrumented functions from
+// them, and we don't want things like strlen() to trigger.
+INTERCEPTOR(void, setpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy);
+ REAL(setpwent)(dummy);
+}
+INTERCEPTOR(void, endpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy);
+ REAL(endpwent)(dummy);
+}
+INTERCEPTOR(void, setgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy);
+ REAL(setgrent)(dummy);
+}
+INTERCEPTOR(void, endgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy);
+ REAL(endgrent)(dummy);
+}
+#define INIT_SETPWENT \
+ COMMON_INTERCEPT_FUNCTION(setpwent); \
+ COMMON_INTERCEPT_FUNCTION(endpwent); \
+ COMMON_INTERCEPT_FUNCTION(setgrent); \
+ COMMON_INTERCEPT_FUNCTION(endgrent);
+#else
+#define INIT_SETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_CLOCK_GETTIME
+INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(clock_getres)(clk_id, tp);
+ if (!res && tp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(clock_gettime)(clk_id, tp);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
+ return REAL(clock_settime)(clk_id, tp);
+}
+#define INIT_CLOCK_GETTIME \
+ COMMON_INTERCEPT_FUNCTION(clock_getres); \
+ COMMON_INTERCEPT_FUNCTION(clock_gettime); \
+ COMMON_INTERCEPT_FUNCTION(clock_settime);
+#else
+#define INIT_CLOCK_GETTIME
+#endif
+
+#if SANITIZER_INTERCEPT_GETITIMER
+INTERCEPTOR(int, getitimer, int which, void *curr_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getitimer)(which, curr_value);
+ if (!res && curr_value) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
+ if (new_value)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(setitimer)(which, new_value, old_value);
+ if (!res && old_value) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
+ }
+ return res;
+}
+#define INIT_GETITIMER \
+ COMMON_INTERCEPT_FUNCTION(getitimer); \
+ COMMON_INTERCEPT_FUNCTION(setitimer);
+#else
+#define INIT_GETITIMER
+#endif
+
+#if SANITIZER_INTERCEPT_GLOB
+static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob));
+ // +1 for NULL pointer at the end.
+ if (pglob->gl_pathv)
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
+ for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) {
+ char *p = pglob->gl_pathv[i];
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1);
+ }
+}
+
+static THREADLOCAL __sanitizer_glob_t *pglob_copy;
+
+static void wrapped_gl_closedir(void *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ pglob_copy->gl_closedir(dir);
+}
+
+static void *wrapped_gl_readdir(void *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ return pglob_copy->gl_readdir(dir);
+}
+
+static void *wrapped_gl_opendir(const char *s) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_opendir(s);
+}
+
+static int wrapped_gl_lstat(const char *s, void *st) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_lstat(s, st);
+}
+
+static int wrapped_gl_stat(const char *s, void *st) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+ return pglob_copy->gl_stat(s, st);
+}
+
+static const __sanitizer_glob_t kGlobCopy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+
+INTERCEPTOR(int, glob, const char *pattern, int flags,
+ int (*errfunc)(const char *epath, int eerrno),
+ __sanitizer_glob_t *pglob) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ pglob_copy = &glob_copy;
+ }
+ int res = REAL(glob)(pattern, flags, errfunc, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ }
+ pglob_copy = 0;
+ if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+ return res;
+}
+
+INTERCEPTOR(int, glob64, const char *pattern, int flags,
+ int (*errfunc)(const char *epath, int eerrno),
+ __sanitizer_glob_t *pglob) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ pglob_copy = &glob_copy;
+ }
+ int res = REAL(glob64)(pattern, flags, errfunc, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ Swap(pglob->gl_stat, glob_copy.gl_stat);
+ }
+ pglob_copy = 0;
+ if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+ return res;
+}
+#define INIT_GLOB \
+ COMMON_INTERCEPT_FUNCTION(glob); \
+ COMMON_INTERCEPT_FUNCTION(glob64);
+#else // SANITIZER_INTERCEPT_GLOB
+#define INIT_GLOB
+#endif // SANITIZER_INTERCEPT_GLOB
+
+#if SANITIZER_INTERCEPT_WAIT
+// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version
+// suffixes on Darwin. See the declaration of INTERCEPTOR_WITH_SUFFIX for
+// details.
+INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(wait)(status);
+ if (res != -1 && status)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ return res;
+}
+// On FreeBSD id_t is always 64-bit wide.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop,
+ int options) {
+#else
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
+ int options) {
+#endif
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(waitid)(idtype, id, infop, options);
+ if (res != -1 && infop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
+ return res;
+}
+INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(waitpid)(pid, status, options);
+ if (res != -1 && status)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ return res;
+}
+INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(wait3)(status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#if SANITIZER_ANDROID
+INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(__wait4)(pid, status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4);
+#else
+INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(wait4)(pid, status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4);
+#endif // SANITIZER_ANDROID
+#define INIT_WAIT \
+ COMMON_INTERCEPT_FUNCTION(wait); \
+ COMMON_INTERCEPT_FUNCTION(waitid); \
+ COMMON_INTERCEPT_FUNCTION(waitpid); \
+ COMMON_INTERCEPT_FUNCTION(wait3);
+#else
+#define INIT_WAIT
+#define INIT_WAIT4
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_ntop, af, src, dst, size);
+ uptr sz = __sanitizer_in_addr_sz(af);
+ if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
+ // FIXME: figure out read size based on the address family.
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(inet_ntop)(af, src, dst, size);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0);
+ // FIXME: figure out read size based on the address family.
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(inet_pton)(af, src, dst);
+ if (res == 1) {
+ uptr sz = __sanitizer_in_addr_sz(af);
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+ }
+ return res;
+}
+#define INIT_INET \
+ COMMON_INTERCEPT_FUNCTION(inet_ntop); \
+ COMMON_INTERCEPT_FUNCTION(inet_pton);
+#else
+#define INIT_INET
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst);
+ if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(inet_aton)(cp, dst);
+ if (res != 0) {
+ uptr sz = __sanitizer_in_addr_sz(af_inet);
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+ }
+ return res;
+}
+#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton);
+#else
+#define INIT_INET_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM
+INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(pthread_getschedparam)(thread, policy, param);
+ if (res == 0) {
+ if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
+ if (param) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, sizeof(*param));
+ }
+ return res;
+}
+#define INIT_PTHREAD_GETSCHEDPARAM \
+ COMMON_INTERCEPT_FUNCTION(pthread_getschedparam);
+#else
+#define INIT_PTHREAD_GETSCHEDPARAM
+#endif
+
+#if SANITIZER_INTERCEPT_GETADDRINFO
+INTERCEPTOR(int, getaddrinfo, char *node, char *service,
+ struct __sanitizer_addrinfo *hints,
+ struct __sanitizer_addrinfo **out) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out);
+ if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, REAL(strlen)(node) + 1);
+ if (service)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1);
+ if (hints)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getaddrinfo)(node, service, hints, out);
+ if (res == 0 && out) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
+ struct __sanitizer_addrinfo *p = *out;
+ while (p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (p->ai_addr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen);
+ if (p->ai_canonname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname,
+ REAL(strlen)(p->ai_canonname) + 1);
+ p = p->ai_next;
+ }
+ }
+ return res;
+}
+#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo);
+#else
+#define INIT_GETADDRINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETNAMEINFO
+INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
+ unsigned hostlen, char *serv, unsigned servlen, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen,
+ serv, servlen, flags);
+ // FIXME: consider adding READ_RANGE(sockaddr, salen)
+ // There is padding in in_addr that may make this too noisy
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res =
+ REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
+ if (res == 0) {
+ if (host && hostlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1);
+ if (serv && servlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1);
+ }
+ return res;
+}
+#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo);
+#else
+#define INIT_GETNAMEINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKNAME
+INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ int addrlen_in = *addrlen;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getsockname)(sock_fd, addr, addrlen);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
+ }
+ return res;
+}
+#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname);
+#else
+#define INIT_GETSOCKNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME || SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+static void write_hostent(void *ctx, struct __sanitizer_hostent *h) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h, sizeof(__sanitizer_hostent));
+ if (h->h_name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h->h_name, REAL(strlen)(h->h_name) + 1);
+ char **p = h->h_aliases;
+ while (*p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+ ++p;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, h->h_aliases, (p - h->h_aliases + 1) * sizeof(*h->h_aliases));
+ p = h->h_addr_list;
+ while (*p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, h->h_length);
+ ++p;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, h->h_addr_list, (p - h->h_addr_list + 1) * sizeof(*h->h_addr_list));
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname, char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname, name);
+ struct __sanitizer_hostent *res = REAL(gethostbyname)(name);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len,
+ int type) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr, addr, len, type);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+ struct __sanitizer_hostent *res = REAL(gethostbyaddr)(addr, len, type);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake);
+ struct __sanitizer_hostent *res = REAL(gethostent)(fake);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af);
+ struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af);
+ if (res) write_hostent(ctx, res);
+ return res;
+}
+#define INIT_GETHOSTBYNAME \
+ COMMON_INTERCEPT_FUNCTION(gethostent); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2);
+#else
+#define INIT_GETHOSTBYNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
+ char *buf, SIZE_T buflen, __sanitizer_hostent **result,
+ int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result,
+ h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r);
+#else
+#define INIT_GETHOSTBYNAME_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTENT_R
+INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
+ SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result,
+ h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTENT_R \
+ COMMON_INTERCEPT_FUNCTION(gethostent_r);
+#else
+#define INIT_GETHOSTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYADDR_R
+INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
+ struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+ __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf,
+ buflen, result, h_errnop);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
+ h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYADDR_R \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r);
+#else
+#define INIT_GETHOSTBYADDR_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R
+INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
+ struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+ __sanitizer_hostent **result, int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen,
+ result, h_errnop);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res =
+ REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYNAME2_R \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2_r);
+#else
+#define INIT_GETHOSTBYNAME2_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKOPT
+INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
+ int *optlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval,
+ optlen);
+ if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
+ if (res == 0)
+ if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
+ return res;
+}
+#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt);
+#else
+#define INIT_GETSOCKOPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT
+INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen);
+ unsigned addrlen0 = 0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ int fd2 = REAL(accept)(fd, addr, addrlen);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept);
+#else
+#define INIT_ACCEPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT4
+INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f);
+ unsigned addrlen0 = 0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int fd2 = REAL(accept4)(fd, addr, addrlen, f);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4);
+#else
+#define INIT_ACCEPT4
+#endif
+
+#if SANITIZER_INTERCEPT_MODF
+INTERCEPTOR(double, modf, double x, double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ double res = REAL(modf)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(float, modff, float x, float *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ float res = REAL(modff)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ long double res = REAL(modfl)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+#define INIT_MODF \
+ COMMON_INTERCEPT_FUNCTION(modf); \
+ COMMON_INTERCEPT_FUNCTION(modff); \
+ COMMON_INTERCEPT_FUNCTION(modfl);
+#else
+#define INIT_MODF
+#endif
+
+#if SANITIZER_INTERCEPT_RECVMSG
+static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
+ SSIZE_T maxlen) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg));
+ if (msg->msg_name && msg->msg_namelen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen);
+ if (msg->msg_iov && msg->msg_iovlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov,
+ sizeof(*msg->msg_iov) * msg->msg_iovlen);
+ write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
+ if (msg->msg_control && msg->msg_controllen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);
+}
+
+INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
+ int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
+ if (res >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ if (msg) {
+ write_msghdr(ctx, msg, res);
+ COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg);
+ }
+ }
+ return res;
+}
+#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg);
+#else
+#define INIT_RECVMSG
+#endif
+
+#if SANITIZER_INTERCEPT_GETPEERNAME
+INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen);
+ unsigned addr_sz;
+ if (addrlen) addr_sz = *addrlen;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getpeername)(sockfd, addr, addrlen);
+ if (!res && addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
+ return res;
+}
+#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername);
+#else
+#define INIT_GETPEERNAME
+#endif
+
+#if SANITIZER_INTERCEPT_SYSINFO
+INTERCEPTOR(int, sysinfo, void *info) {
+ void *ctx;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
+ int res = REAL(sysinfo)(info);
+ if (!res && info)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz);
+ return res;
+}
+#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo);
+#else
+#define INIT_SYSINFO
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR
+INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, opendir, path);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ __sanitizer_dirent *res = REAL(opendir)(path);
+ if (res)
+ COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path);
+ return res;
+}
+
+INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ __sanitizer_dirent *res = REAL(readdir)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
+ __sanitizer_dirent **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(readdir_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+
+#define INIT_READDIR \
+ COMMON_INTERCEPT_FUNCTION(opendir); \
+ COMMON_INTERCEPT_FUNCTION(readdir); \
+ COMMON_INTERCEPT_FUNCTION(readdir_r);
+#else
+#define INIT_READDIR
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR64
+INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ __sanitizer_dirent64 *res = REAL(readdir64)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
+ __sanitizer_dirent64 **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(readdir64_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+#define INIT_READDIR64 \
+ COMMON_INTERCEPT_FUNCTION(readdir64); \
+ COMMON_INTERCEPT_FUNCTION(readdir64_r);
+#else
+#define INIT_READDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_PTRACE
+INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
+ __sanitizer_iovec local_iovec;
+
+ if (data) {
+ if (request == ptrace_setregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
+ else if (request == ptrace_setfpregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_setfpxregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_setvfpregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
+ else if (request == ptrace_setsiginfo)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
+ // Some kernel might zero the iovec::iov_base in case of invalid
+ // write access. In this case copy the invalid address for further
+ // inspection.
+ else if (request == ptrace_setregset || request == ptrace_getregset) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec));
+ local_iovec = *iovec;
+ if (request == ptrace_setregset)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len);
+ }
+ }
+
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ uptr res = REAL(ptrace)(request, pid, addr, data);
+
+ if (!res && data) {
+ // Note that PEEK* requests assign different meaning to the return value.
+ // This function does not handle them (nor does it need to).
+ if (request == ptrace_getregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
+ else if (request == ptrace_getfpregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_getfpxregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_getvfpregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
+ else if (request == ptrace_getsiginfo)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
+ else if (request == ptrace_geteventmsg)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
+ else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base,
+ local_iovec.iov_len);
+ }
+ }
+ return res;
+}
+
+#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace);
+#else
+#define INIT_PTRACE
+#endif
+
+#if SANITIZER_INTERCEPT_SETLOCALE
+INTERCEPTOR(char *, setlocale, int category, char *locale) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale);
+ if (locale)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
+ char *res = REAL(setlocale)(category, locale);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale);
+#else
+#define INIT_SETLOCALE
+#endif
+
+#if SANITIZER_INTERCEPT_GETCWD
+INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(getcwd)(buf, size);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd);
+#else
+#define INIT_GETCWD
+#endif
+
+#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
+INTERCEPTOR(char *, get_current_dir_name, int fake) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(get_current_dir_name)(fake);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_GET_CURRENT_DIR_NAME \
+ COMMON_INTERCEPT_FUNCTION(get_current_dir_name);
+#else
+#define INIT_GET_CURRENT_DIR_NAME
+#endif
+
+UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
+ CHECK(endptr);
+ if (nptr == *endptr) {
+ // No digits were found at strtol call, we need to find out the last
+ // symbol accessed by strtoll on our own.
+ // We get this symbol by skipping leading blanks and optional +/- sign.
+ while (IsSpace(*nptr)) nptr++;
+ if (*nptr == '+' || *nptr == '-') nptr++;
+ *endptr = const_cast<char *>(nptr);
+ }
+ CHECK(*endptr >= nptr);
+}
+
+UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr,
+ char **endptr, char *real_endptr, int base) {
+ if (endptr) {
+ *endptr = real_endptr;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ }
+ // If base has unsupported value, strtol can exit with EINVAL
+ // without reading any characters. So do additional checks only
+ // if base is valid.
+ bool is_valid_base = (base == 0) || (2 <= base && base <= 36);
+ if (is_valid_base) {
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ }
+ COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ?
+ (real_endptr - nptr) + 1 : 0);
+}
+
+
+#if SANITIZER_INTERCEPT_STRTOIMAX
+INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *real_endptr;
+ INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ return res;
+}
+
+INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *real_endptr;
+ INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ return res;
+}
+
+#define INIT_STRTOIMAX \
+ COMMON_INTERCEPT_FUNCTION(strtoimax); \
+ COMMON_INTERCEPT_FUNCTION(strtoumax);
+#else
+#define INIT_STRTOIMAX
+#endif
+
+#if SANITIZER_INTERCEPT_MBSTOWCS
+INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(mbstowcs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps);
+ if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
+ if (res != (SIZE_T)(-1) && dest && src) {
+ // This function, and several others, may or may not write the terminating
+ // \0 character. They write it iff they clear *src.
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSTOWCS \
+ COMMON_INTERCEPT_FUNCTION(mbstowcs); \
+ COMMON_INTERCEPT_FUNCTION(mbsrtowcs);
+#else
+#define INIT_MBSTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_MBSNRTOWCS
+INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
+ if (res != (SIZE_T)(-1) && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs);
+#else
+#define INIT_MBSNRTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSTOMBS
+INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(wcstombs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps);
+ if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
+ if (res != (SIZE_T) - 1 && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSTOMBS \
+ COMMON_INTERCEPT_FUNCTION(wcstombs); \
+ COMMON_INTERCEPT_FUNCTION(wcsrtombs);
+#else
+#define INIT_WCSTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSNRTOMBS
+INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
+ if (res != ((SIZE_T)-1) && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs);
+#else
+#define INIT_WCSNRTOMBS
+#endif
+
+
+#if SANITIZER_INTERCEPT_WCRTOMB
+INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps);
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(wcrtomb)(dest, src, ps);
+ if (res != ((SIZE_T)-1) && dest) {
+ SIZE_T write_cnt = res;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCRTOMB COMMON_INTERCEPT_FUNCTION(wcrtomb);
+#else
+#define INIT_WCRTOMB
+#endif
+
+#if SANITIZER_INTERCEPT_TCGETATTR
+INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(tcgetattr)(fd, termios_p);
+ if (!res && termios_p)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
+ return res;
+}
+
+#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr);
+#else
+#define INIT_TCGETATTR
+#endif
+
+#if SANITIZER_INTERCEPT_REALPATH
+INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+
+ // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest
+ // version of a versioned symbol. For realpath(), this gives us something
+ // (called __old_realpath) that does not handle NULL in the second argument.
+ // Handle it as part of the interceptor.
+ char *allocated_path = nullptr;
+ if (!resolved_path)
+ allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
+
+ char *res = REAL(realpath)(path, resolved_path);
+ if (allocated_path && !res) WRAP(free)(allocated_path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath);
+#else
+#define INIT_REALPATH
+#endif
+
+#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME
+INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ char *res = REAL(canonicalize_file_name)(path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_CANONICALIZE_FILE_NAME \
+ COMMON_INTERCEPT_FUNCTION(canonicalize_file_name);
+#else
+#define INIT_CANONICALIZE_FILE_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_CONFSTR
+INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(confstr)(name, buf, len);
+ if (buf && res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
+ return res;
+}
+#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr);
+#else
+#define INIT_CONFSTR
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY
+INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
+ if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+ return res;
+}
+#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity);
+#else
+#define INIT_SCHED_GETAFFINITY
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETPARAM
+INTERCEPTOR(int, sched_getparam, int pid, void *param) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sched_getparam, pid, param);
+ int res = REAL(sched_getparam)(pid, param);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, struct_sched_param_sz);
+ return res;
+}
+#define INIT_SCHED_GETPARAM COMMON_INTERCEPT_FUNCTION(sched_getparam);
+#else
+#define INIT_SCHED_GETPARAM
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR
+INTERCEPTOR(char *, strerror, int errnum) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum);
+ char *res = REAL(strerror)(errnum);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
+#else
+#define INIT_STRERROR
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR_R
+INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(strerror_r)(errnum, buf, buflen);
+ // There are 2 versions of strerror_r:
+ // * POSIX version returns 0 on success, negative error code on failure,
+ // writes message to buf.
+ // * GNU version returns message pointer, which points to either buf or some
+ // static storage.
+ SIZE_T posix_res = (SIZE_T)res;
+ if (posix_res < 1024 || posix_res > (SIZE_T) - 1024) {
+ // POSIX version. Spec is not clear on whether buf is NULL-terminated.
+ // At least on OSX, buf contents are valid even when the call fails.
+ SIZE_T sz = internal_strnlen(buf, buflen);
+ if (sz < buflen) ++sz;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ } else {
+ // GNU version.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
+#else
+#define INIT_STRERROR_R
+#endif
+
+#if SANITIZER_INTERCEPT_XPG_STRERROR_R
+INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
+ // This version always returns a null-terminated string.
+ if (buf && buflen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ return res;
+}
+#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r);
+#else
+#define INIT_XPG_STRERROR_R
+#endif
+
+#if SANITIZER_INTERCEPT_SCANDIR
+typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *);
+typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **,
+ const struct __sanitizer_dirent **);
+
+static THREADLOCAL scandir_filter_f scandir_filter;
+static THREADLOCAL scandir_compar_f scandir_compar;
+
+static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+ return scandir_filter(dir);
+}
+
+static int wrapped_scandir_compar(const struct __sanitizer_dirent **a,
+ const struct __sanitizer_dirent **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
+ return scandir_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
+ scandir_filter_f filter, scandir_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
+ scandir_filter = filter;
+ scandir_compar = compar;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(scandir)(dirp, namelist,
+ filter ? wrapped_scandir_filter : nullptr,
+ compar ? wrapped_scandir_compar : nullptr);
+ scandir_filter = nullptr;
+ scandir_compar = nullptr;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir);
+#else
+#define INIT_SCANDIR
+#endif
+
+#if SANITIZER_INTERCEPT_SCANDIR64
+typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *);
+typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **,
+ const struct __sanitizer_dirent64 **);
+
+static THREADLOCAL scandir64_filter_f scandir64_filter;
+static THREADLOCAL scandir64_compar_f scandir64_compar;
+
+static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+ return scandir64_filter(dir);
+}
+
+static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a,
+ const struct __sanitizer_dirent64 **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
+ return scandir64_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
+ scandir64_filter_f filter, scandir64_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
+ scandir64_filter = filter;
+ scandir64_compar = compar;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res =
+ REAL(scandir64)(dirp, namelist,
+ filter ? wrapped_scandir64_filter : nullptr,
+ compar ? wrapped_scandir64_compar : nullptr);
+ scandir64_filter = nullptr;
+ scandir64_compar = nullptr;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64);
+#else
+#define INIT_SCANDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_GETGROUPS
+INTERCEPTOR(int, getgroups, int size, u32 *lst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(getgroups)(size, lst);
+ if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+ return res;
+}
+#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups);
+#else
+#define INIT_GETGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_POLL
+static void read_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events));
+ }
+}
+
+static void write_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents,
+ sizeof(fds[i].revents));
+}
+
+INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ int timeout) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll);
+#else
+#define INIT_POLL
+#endif
+
+#if SANITIZER_INTERCEPT_PPOLL
+INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ void *timeout_ts, __sanitizer_sigset_t *sigmask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ if (timeout_ts)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
+ // FIXME: read sigmask when all of sigemptyset, etc are intercepted.
+ int res =
+ COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll);
+#else
+#define INIT_PPOLL
+#endif
+
+#if SANITIZER_INTERCEPT_WORDEXP
+INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, flags);
+ if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(wordexp)(s, p, flags);
+ if (!res && p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (p->we_wordc)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv,
+ sizeof(*p->we_wordv) * p->we_wordc);
+ for (uptr i = 0; i < p->we_wordc; ++i) {
+ char *w = p->we_wordv[i];
+ if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, REAL(strlen)(w) + 1);
+ }
+ }
+ return res;
+}
+#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp);
+#else
+#define INIT_WORDEXP
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAIT
+INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigwait)(set, sig);
+ if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
+ return res;
+}
+#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait);
+#else
+#define INIT_SIGWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAITINFO
+INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigwaitinfo)(set, info);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo);
+#else
+#define INIT_SIGWAITINFO
+#endif
+
+#if SANITIZER_INTERCEPT_SIGTIMEDWAIT
+INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
+ void *timeout) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout);
+ if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigtimedwait)(set, info, timeout);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait);
+#else
+#define INIT_SIGTIMEDWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGSETOPS
+INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigemptyset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+
+INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigfillset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGSETOPS \
+ COMMON_INTERCEPT_FUNCTION(sigemptyset); \
+ COMMON_INTERCEPT_FUNCTION(sigfillset);
+#else
+#define INIT_SIGSETOPS
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPENDING
+INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigpending)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending);
+#else
+#define INIT_SIGPENDING
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPROCMASK
+INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(sigprocmask)(how, set, oldset);
+ if (!res && oldset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+ return res;
+}
+#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask);
+#else
+#define INIT_SIGPROCMASK
+#endif
+
+#if SANITIZER_INTERCEPT_BACKTRACE
+INTERCEPTOR(int, backtrace, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(backtrace)(buffer, size);
+ if (res && buffer)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
+ return res;
+}
+
+INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size);
+ if (buffer && size)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char **res = REAL(backtrace_symbols)(buffer, size);
+ if (res && size) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
+ for (int i = 0; i < size; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], REAL(strlen(res[i])) + 1);
+ }
+ return res;
+}
+#define INIT_BACKTRACE \
+ COMMON_INTERCEPT_FUNCTION(backtrace); \
+ COMMON_INTERCEPT_FUNCTION(backtrace_symbols);
+#else
+#define INIT_BACKTRACE
+#endif
+
+#if SANITIZER_INTERCEPT__EXIT
+INTERCEPTOR(void, _exit, int status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _exit, status);
+ int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx);
+ if (status == 0) status = status1;
+ REAL(_exit)(status);
+}
+#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit);
+#else
+#define INIT__EXIT
+#endif
+
+#if SANITIZER_INTERCEPT_PHTREAD_MUTEX
+INTERCEPTOR(int, pthread_mutex_lock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
+ int res = REAL(pthread_mutex_lock)(m);
+ if (res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
+#define INIT_PTHREAD_MUTEX_UNLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock)
+#else
+#define INIT_PTHREAD_MUTEX_LOCK
+#define INIT_PTHREAD_MUTEX_UNLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
+static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
+ if (mnt->mnt_fsname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname,
+ REAL(strlen)(mnt->mnt_fsname) + 1);
+ if (mnt->mnt_dir)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir,
+ REAL(strlen)(mnt->mnt_dir) + 1);
+ if (mnt->mnt_type)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type,
+ REAL(strlen)(mnt->mnt_type) + 1);
+ if (mnt->mnt_opts)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts,
+ REAL(strlen)(mnt->mnt_opts) + 1);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT
+INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp);
+ __sanitizer_mntent *res = REAL(getmntent)(fp);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent);
+#else
+#define INIT_GETMNTENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT_R
+INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp,
+ __sanitizer_mntent *mntbuf, char *buf, int buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen);
+ __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r);
+#else
+#define INIT_GETMNTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS
+INTERCEPTOR(int, statfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(statfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fstatfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+#define INIT_STATFS \
+ COMMON_INTERCEPT_FUNCTION(statfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs);
+#else
+#define INIT_STATFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS64
+INTERCEPTOR(int, statfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(statfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fstatfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+#define INIT_STATFS64 \
+ COMMON_INTERCEPT_FUNCTION(statfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs64);
+#else
+#define INIT_STATFS64
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS
+INTERCEPTOR(int, statvfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(statvfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fstatvfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+#define INIT_STATVFS \
+ COMMON_INTERCEPT_FUNCTION(statvfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs);
+#else
+#define INIT_STATVFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS64
+INTERCEPTOR(int, statvfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(statvfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fstatvfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+#define INIT_STATVFS64 \
+ COMMON_INTERCEPT_FUNCTION(statvfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs64);
+#else
+#define INIT_STATVFS64
+#endif
+
+#if SANITIZER_INTERCEPT_INITGROUPS
+INTERCEPTOR(int, initgroups, char *user, u32 group) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group);
+ if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1);
+ int res = REAL(initgroups)(user, group);
+ return res;
+}
+#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups);
+#else
+#define INIT_INITGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_NTOA_ATON
+INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ char *res = REAL(ether_ntoa)(addr);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ __sanitizer_ether_addr *res = REAL(ether_aton)(buf);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_NTOA_ATON \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton);
+#else
+#define INIT_ETHER_NTOA_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_HOST
+INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(ether_ntohost)(hostname, addr);
+ if (!res && hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ return res;
+}
+INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr);
+ if (hostname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(ether_hostton)(hostname, addr);
+ if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ return res;
+}
+INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
+ char *hostname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname);
+ if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(ether_line)(line, addr, hostname);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ }
+ return res;
+}
+#define INIT_ETHER_HOST \
+ COMMON_INTERCEPT_FUNCTION(ether_ntohost); \
+ COMMON_INTERCEPT_FUNCTION(ether_hostton); \
+ COMMON_INTERCEPT_FUNCTION(ether_line);
+#else
+#define INIT_ETHER_HOST
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_R
+INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(ether_ntoa_r)(addr, buf);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
+ __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_R \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton_r);
+#else
+#define INIT_ETHER_R
+#endif
+
+#if SANITIZER_INTERCEPT_SHMCTL
+INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(shmctl)(shmid, cmd, buf);
+ if (res >= 0) {
+ unsigned sz = 0;
+ if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat)
+ sz = sizeof(__sanitizer_shmid_ds);
+ else if (cmd == shmctl_ipc_info)
+ sz = struct_shminfo_sz;
+ else if (cmd == shmctl_shm_info)
+ sz = struct_shm_info_sz;
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ }
+ return res;
+}
+#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl);
+#else
+#define INIT_SHMCTL
+#endif
+
+#if SANITIZER_INTERCEPT_RANDOM_R
+INTERCEPTOR(int, random_r, void *buf, u32 *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(random_r)(buf, result);
+ if (!res && result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r);
+#else
+#define INIT_RANDOM_R
+#endif
+
+// FIXME: under ASan the REAL() call below may write to freed memory and corrupt
+// its metadata. See
+// https://github.com/google/sanitizers/issues/321.
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
+ SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET
+#define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \
+ INTERCEPTOR(int, fn, void *attr, void *r) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \
+ int res = REAL(fn)(attr, r); \
+ if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \
+ return res; \
+ }
+#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz)
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET
+INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T))
+INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz)
+INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T))
+INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(pthread_attr_getstack)(attr, addr, size);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size));
+ }
+ return res;
+}
+
+// We may need to call the real pthread_attr_getstack from the run-time
+// in sanitizer_common, but we don't want to include the interception headers
+// there. So, just define this function here.
+namespace __sanitizer {
+extern "C" {
+int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {
+ return REAL(pthread_attr_getstack)(attr, addr, size);
+}
+} // extern "C"
+} // namespace __sanitizer
+
+#define INIT_PTHREAD_ATTR_GET \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack);
+#else
+#define INIT_PTHREAD_ATTR_GET
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED
+INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int))
+
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched);
+#else
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP
+INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
+ void *cpuset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize,
+ cpuset);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
+ if (!res && cpusetsize && cpuset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
+ return res;
+}
+
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np);
+#else
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared);
+#else
+#define INIT_PTHREAD_CONDATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK
+INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETCLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock);
+#else
+#define INIT_PTHREAD_CONDATTR_GETCLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared);
+#else
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM
+INTERCEPTOR(char *, tmpnam, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s);
+ char *res = REAL(tmpnam)(s);
+ if (res) {
+ if (s)
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ else
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam);
+#else
+#define INIT_TMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM_R
+INTERCEPTOR(char *, tmpnam_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ char *res = REAL(tmpnam_r)(s);
+ if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r);
+#else
+#define INIT_TMPNAM_R
+#endif
+
+#if SANITIZER_INTERCEPT_TEMPNAM
+INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx);
+ if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1);
+ if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1);
+ char *res = REAL(tempnam)(dir, pfx);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
+#else
+#define INIT_TEMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP
+INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
+ COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
+ return REAL(pthread_setname_np)(thread, name);
+}
+#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np);
+#else
+#define INIT_PTHREAD_SETNAME_NP
+#endif
+
+#if SANITIZER_INTERCEPT_SINCOS
+INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ REAL(sincos)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ REAL(sincosf)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ REAL(sincosl)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+#define INIT_SINCOS \
+ COMMON_INTERCEPT_FUNCTION(sincos); \
+ COMMON_INTERCEPT_FUNCTION(sincosf); \
+ COMMON_INTERCEPT_FUNCTION(sincosl);
+#else
+#define INIT_SINCOS
+#endif
+
+#if SANITIZER_INTERCEPT_REMQUO
+INTERCEPTOR(double, remquo, double x, double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ double res = REAL(remquo)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(float, remquof, float x, float y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ float res = REAL(remquof)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ long double res = REAL(remquol)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+#define INIT_REMQUO \
+ COMMON_INTERCEPT_FUNCTION(remquo); \
+ COMMON_INTERCEPT_FUNCTION(remquof); \
+ COMMON_INTERCEPT_FUNCTION(remquol);
+#else
+#define INIT_REMQUO
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA
+extern int signgam;
+INTERCEPTOR(double, lgamma, double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x);
+ double res = REAL(lgamma)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(float, lgammaf, float x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x);
+ float res = REAL(lgammaf)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(long double, lgammal, long double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x);
+ long double res = REAL(lgammal)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+#define INIT_LGAMMA \
+ COMMON_INTERCEPT_FUNCTION(lgamma); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf); \
+ COMMON_INTERCEPT_FUNCTION(lgammal);
+#else
+#define INIT_LGAMMA
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA_R
+INTERCEPTOR(double, lgamma_r, double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ double res = REAL(lgamma_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ float res = REAL(lgammaf_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+#define INIT_LGAMMA_R \
+ COMMON_INTERCEPT_FUNCTION(lgamma_r); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf_r);
+#else
+#define INIT_LGAMMA_R
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMAL_R
+INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ long double res = REAL(lgammal_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION(lgammal_r);
+#else
+#define INIT_LGAMMAL_R
+#endif
+
+#if SANITIZER_INTERCEPT_DRAND48_R
+INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(drand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(lrand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_DRAND48_R \
+ COMMON_INTERCEPT_FUNCTION(drand48_r); \
+ COMMON_INTERCEPT_FUNCTION(lrand48_r);
+#else
+#define INIT_DRAND48_R
+#endif
+
+#if SANITIZER_INTERCEPT_RAND_R
+INTERCEPTOR(int, rand_r, unsigned *seedp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp));
+ return REAL(rand_r)(seedp);
+}
+#define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r);
+#else
+#define INIT_RAND_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETLINE
+INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SSIZE_T res = REAL(getline)(lineptr, n, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+
+// FIXME: under ASan the call below may write to freed memory and corrupt its
+// metadata. See
+// https://github.com/google/sanitizers/issues/321.
+#define GETDELIM_INTERCEPTOR_IMPL(vname) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, lineptr, n, delim, stream); \
+ SSIZE_T res = REAL(vname)(lineptr, n, delim, stream); \
+ if (res > 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); \
+ } \
+ return res; \
+ }
+
+INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream)
+GETDELIM_INTERCEPTOR_IMPL(__getdelim)
+
+// There's no __getdelim() on FreeBSD so we supply the getdelim() interceptor
+// with its own body.
+INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream)
+GETDELIM_INTERCEPTOR_IMPL(getdelim)
+
+#define INIT_GETLINE \
+ COMMON_INTERCEPT_FUNCTION(getline); \
+ COMMON_INTERCEPT_FUNCTION(__getdelim); \
+ COMMON_INTERCEPT_FUNCTION(getdelim);
+#else
+#define INIT_GETLINE
+#endif
+
+#if SANITIZER_INTERCEPT_ICONV
+INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
+ char **outbuf, SIZE_T *outbytesleft) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf,
+ outbytesleft);
+ if (inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft));
+ if (inbuf && inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
+ if (outbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
+ void *outbuf_orig = outbuf ? *outbuf : nullptr;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
+ if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
+ SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
+ }
+ return res;
+}
+#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv);
+#else
+#define INIT_ICONV
+#endif
+
+#if SANITIZER_INTERCEPT_TIMES
+INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ __sanitizer_clock_t res = REAL(times)(tms);
+ if (res != (__sanitizer_clock_t)-1 && tms)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
+ return res;
+}
+#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times);
+#else
+#define INIT_TIMES
+#endif
+
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
+// If you see any crashes around this functions, there are 2 known issues with
+// it: 1. __tls_get_addr can be called with mis-aligned stack due to:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
+// 2. It can be called recursively if sanitizer code uses __tls_get_addr
+// to access thread local variables (it should not happen normally,
+// because sanitizers use initial-exec tls model).
+INTERCEPTOR(void *, __tls_get_addr, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg);
+ void *res = REAL(__tls_get_addr)(arg);
+ uptr tls_begin, tls_end;
+ COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end);
+ DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end);
+ if (dtv) {
+ // New DTLS block has been allocated.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size);
+ }
+ return res;
+}
+#else
+#define INIT_TLS_GET_ADDR
+#endif
+
+#if SANITIZER_INTERCEPT_LISTXATTR
+INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size);