diff options
author | Alexander Potapenko <glider@google.com> | 2012-08-17 09:00:08 +0000 |
---|---|---|
committer | Alexander Potapenko <glider@google.com> | 2012-08-17 09:00:08 +0000 |
commit | c62210e3ff1ca610d16f73751f338aa40d8ff4a3 (patch) | |
tree | f1263381a99f86d8b227909fea063ec847d69ba1 | |
parent | c4540bc6a3661c304f3abadfa2d1974e829fa609 (diff) | |
download | bcm5719-llvm-c62210e3ff1ca610d16f73751f338aa40d8ff4a3.tar.gz bcm5719-llvm-c62210e3ff1ca610d16f73751f338aa40d8ff4a3.zip |
Commit the source and CMake changes that will allow to build ASan runtime
as a shared library on Mac OS. This will provide an alternative to
mach_override.
llvm-svn: 162091
-rw-r--r-- | compiler-rt/lib/asan/CMakeLists.txt | 29 | ||||
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 36 | ||||
-rw-r--r-- | compiler-rt/lib/asan/asan_malloc_mac.cc | 6 | ||||
-rw-r--r-- | compiler-rt/lib/asan/dynamic/asan_interceptors_dynamic.cc | 93 | ||||
-rw-r--r-- | compiler-rt/lib/interception/interception.h | 48 |
5 files changed, 196 insertions, 16 deletions
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 9d81ca5b54f..7f552b07245 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -22,6 +22,11 @@ set(ASAN_SOURCES asan_win.cc ) +set(ASAN_DYLIB_SOURCES + ${ASAN_SOURCES} + dynamic/asan_interceptors_dynamic.cc + ) + include_directories(..) set(ASAN_CFLAGS @@ -33,6 +38,12 @@ set(ASAN_CFLAGS -fomit-frame-pointer -O3 ) + +set(ASAN_DYLIB_DEFINITIONS + ${ASAN_COMMON_DEFINITIONS} + MAC_INTERPOSE_FUNCTIONS=1 + ) + if (SUPPORTS_NO_VARIADIC_MACROS_FLAG) list(APPEND ASAN_CFLAGS -Wno-variadic-macros) endif () @@ -89,6 +100,24 @@ set_property(TARGET ${ASAN_RUNTIME_LIBRARIES} APPEND PROPERTY COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS}) add_clang_runtime_static_library(${ASAN_RUNTIME_LIBRARIES}) +set(ASAN_DYNAMIC_RUNTIME_LIBRARIES) +if(APPLE) + # Build universal binary on APPLE. + add_library(clang_rt.asan_osx_dynamic SHARED + ${ASAN_DYLIB_SOURCES} + $<TARGET_OBJECTS:RTInterception.osx> + $<TARGET_OBJECTS:RTSanitizerCommon.osx> + ) + set_target_compile_flags(clang_rt.asan_osx_dynamic ${ASAN_CFLAGS}) + filter_available_targets(ASAN_TARGETS x86_64 i386) + set_target_properties(clang_rt.asan_osx_dynamic PROPERTIES + COMPILE_DEFINITIONS ${ASAN_DYLIB_DEFINITIONS} + OSX_ARCHITECTURES "${ASAN_TARGETS}" + LINK_FLAGS "-framework Foundation") + list(APPEND ASAN_DYNAMIC_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic) +endif() + + if(LLVM_INCLUDE_TESTS) add_subdirectory(tests) endif() diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 48986d7a5ae..4064e689dc1 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -206,6 +206,9 @@ static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { } INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(memcmp)(a1, a2, size); +#endif ENSURE_ASAN_INITED(); unsigned char c1 = 0, c2 = 0; const unsigned char *s1 = (const unsigned char*)a1; @@ -265,6 +268,9 @@ INTERCEPTOR(void*, memset, void *block, int c, uptr size) { } INTERCEPTOR(char*, strchr, const char *str, int c) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strchr)(str, c); +#endif ENSURE_ASAN_INITED(); char *result = REAL(strchr)(str, c); if (flags()->replace_str) { @@ -322,6 +328,9 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { } INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strcmp)(s1, s2); +#endif if (asan_init_is_running) { return REAL(strcmp)(s1, s2); } @@ -339,6 +348,9 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { } INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strcpy)(to, from); +#endif // strcpy is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. if (asan_init_is_running) { @@ -356,6 +368,9 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT #if ASAN_INTERCEPT_STRDUP INTERCEPTOR(char*, strdup, const char *s) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strdup)(s); +#endif ENSURE_ASAN_INITED(); if (flags()->replace_str) { uptr length = REAL(strlen)(s); @@ -366,6 +381,9 @@ INTERCEPTOR(char*, strdup, const char *s) { #endif INTERCEPTOR(uptr, strlen, const char *s) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strlen)(s); +#endif // strlen is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. if (asan_init_is_running) { @@ -410,6 +428,9 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, uptr n) { #endif // ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(strncmp)(s1, s2, size); +#endif // strncmp is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. if (asan_init_is_running) { @@ -486,6 +507,9 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT } INTERCEPTOR(int, atoi, const char *nptr) { +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(atoi)(nptr); +#endif ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(atoi)(nptr); @@ -502,6 +526,9 @@ INTERCEPTOR(int, atoi, const char *nptr) { } INTERCEPTOR(long, atol, const char *nptr) { // NOLINT +#if MAC_INTERPOSE_FUNCTIONS + if (!asan_inited) return REAL(atol)(nptr); +#endif ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(atol)(nptr); @@ -580,6 +607,9 @@ void InitializeAsanInterceptors() { static bool was_called_once; CHECK(was_called_once == false); was_called_once = true; +#if MAC_INTERPOSE_FUNCTIONS + return; +#endif // Intercept mem* functions. ASAN_INTERCEPT_FUNC(memcmp); ASAN_INTERCEPT_FUNC(memmove); @@ -587,7 +617,11 @@ void InitializeAsanInterceptors() { if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { ASAN_INTERCEPT_FUNC(memcpy); } else { - REAL(memcpy) = REAL(memmove); +#if !MAC_INTERPOSE_FUNCTIONS + // If we're using dynamic interceptors on Mac, these two are just plain + // functions. + *(uptr*)&REAL(memcpy) = (uptr)REAL(memmove); +#endif } // Intercept str* functions. diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cc b/compiler-rt/lib/asan/asan_malloc_mac.cc index 1b8ce7a93d7..76a47196c86 100644 --- a/compiler-rt/lib/asan/asan_malloc_mac.cc +++ b/compiler-rt/lib/asan/asan_malloc_mac.cc @@ -95,10 +95,14 @@ namespace __asan { // See http://code.google.com/p/address-sanitizer/issues/detail?id=87 // and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c INTERCEPTOR(void, __CFInitialize) { + // If the runtime is built as dynamic library, __CFInitialize wrapper may be + // called before __asan_init. +#if !MAC_INTERPOSE_FUNCTIONS CHECK(flags()->replace_cfallocator); CHECK(asan_inited); +#endif REAL(__CFInitialize)(); - if (!cf_asan) ReplaceCFAllocator(); + if (!cf_asan && asan_inited) ReplaceCFAllocator(); } namespace { diff --git a/compiler-rt/lib/asan/dynamic/asan_interceptors_dynamic.cc b/compiler-rt/lib/asan/dynamic/asan_interceptors_dynamic.cc new file mode 100644 index 00000000000..af2e206d38f --- /dev/null +++ b/compiler-rt/lib/asan/dynamic/asan_interceptors_dynamic.cc @@ -0,0 +1,93 @@ +//===-- asan_interceptors_dynamic.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. +// +// __DATA,__interpose section of the dynamic runtime library for Mac OS. +//===----------------------------------------------------------------------===// + +#if defined(__APPLE__) + +#include "asan_interceptors.h" +#include "asan_intercepted_functions.h" + +namespace __asan { + +#define INTERPOSE_FUNCTION(function) \ + { reinterpret_cast<const uptr>(WRAP(function)), \ + reinterpret_cast<const uptr>(function) } + +#define INTERPOSE_FUNCTION_2(function, wrapper) \ + { reinterpret_cast<const uptr>(wrapper), \ + reinterpret_cast<const uptr>(function) } + +struct interpose_substitution { + const uptr replacement; + const uptr original; +}; + +__attribute__((used)) +const interpose_substitution substitutions[] + __attribute__((section("__DATA, __interpose"))) = { + INTERPOSE_FUNCTION(strlen), + INTERPOSE_FUNCTION(memcmp), + INTERPOSE_FUNCTION(memcpy), + INTERPOSE_FUNCTION(memmove), + INTERPOSE_FUNCTION(memset), + INTERPOSE_FUNCTION(strchr), + INTERPOSE_FUNCTION(strcat), + INTERPOSE_FUNCTION(strncat), + INTERPOSE_FUNCTION(strcpy), + INTERPOSE_FUNCTION(strncpy), + INTERPOSE_FUNCTION(pthread_create), + INTERPOSE_FUNCTION(longjmp), + INTERPOSE_FUNCTION(_longjmp), + INTERPOSE_FUNCTION(siglongjmp), +#if ASAN_INTERCEPT_STRDUP + INTERPOSE_FUNCTION(strdup), +#endif +#if ASAN_INTERCEPT_STRNLEN + INTERPOSE_FUNCTION(strnlen), +#endif +#if ASAN_INTERCEPT_INDEX + INTERPOSE_FUNCTION_2(index, WRAP(strchr)), +#endif + INTERPOSE_FUNCTION(strcmp), + INTERPOSE_FUNCTION(strncmp), +#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP + INTERPOSE_FUNCTION(strcasecmp), + INTERPOSE_FUNCTION(strncasecmp), +#endif + INTERPOSE_FUNCTION(atoi), + INTERPOSE_FUNCTION(atol), + INTERPOSE_FUNCTION(strtol), +#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL + INTERPOSE_FUNCTION(atoll), + INTERPOSE_FUNCTION(strtoll), +#endif +#if ASAN_INTERCEPT_MLOCKX + INTERPOSE_FUNCTION(mlock), + INTERPOSE_FUNCTION(munlock), + INTERPOSE_FUNCTION(mlockall), + INTERPOSE_FUNCTION(munlockall), +#endif + INTERPOSE_FUNCTION(dispatch_async_f), + INTERPOSE_FUNCTION(dispatch_sync_f), + INTERPOSE_FUNCTION(dispatch_after_f), + INTERPOSE_FUNCTION(dispatch_barrier_async_f), + INTERPOSE_FUNCTION(dispatch_group_async_f), + + INTERPOSE_FUNCTION(__CFInitialize), + INTERPOSE_FUNCTION(CFStringCreateCopy), + INTERPOSE_FUNCTION(free), +}; + +} // namespace __asan + +#endif // __APPLE__ diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h index d0505237074..b52a1067480 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -75,6 +75,16 @@ // mach_override, a handy framework for patching functions at runtime. // To avoid possible name clashes, our replacement functions have // the "wrap_" prefix on Mac. +// An alternative to function patching is to 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. Such a library is built with +// -DMAC_INTERPOSE_FUNCTIONS=1. + +#if !defined(MAC_INTERPOSE_FUNCTIONS) || !defined(__APPLE__) +# define MAC_INTERPOSE_FUNCTIONS 0 +#endif #if defined(__APPLE__) # define WRAP(x) wrap_##x @@ -101,15 +111,21 @@ __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); #endif -#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); \ - } +#if !MAC_INTERPOSE_FUNCTIONS +# 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 // MAC_INTERPOSE_FUNCTIONS +# define REAL(x) x +# define DECLARE_REAL(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__); +#endif // MAC_INTERPOSE_FUNCTIONS #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ DECLARE_REAL(ret_type, func, ##__VA_ARGS__) \ @@ -118,11 +134,15 @@ // FIXME(timurrrr): We might need to add DECLARE_REAL_EX etc to support // different calling conventions later. -#define DEFINE_REAL_EX(ret_type, convention, func, ...) \ - typedef ret_type (convention *FUNC_TYPE(func))(__VA_ARGS__); \ - namespace __interception { \ - FUNC_TYPE(func) PTR_TO_REAL(func); \ - } +#if !MAC_INTERPOSE_FUNCTIONS +# define DEFINE_REAL_EX(ret_type, convention, func, ...) \ + typedef ret_type (convention *FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __interception { \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ + } +#else +# define DEFINE_REAL_EX(ret_type, convention, func, ...) +#endif // 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) |