diff options
author | Kostya Serebryany <kcc@google.com> | 2013-11-04 21:33:31 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@gcc.gnu.org> | 2013-11-04 21:33:31 +0000 |
commit | ef1b3fda32c08e9bd6977b96e1e619aae3e3726a (patch) | |
tree | 7cfc103c9b6b4ce7ca19d39f91509a1b68819a63 /libsanitizer/interception | |
parent | fd5564d3c71195714c28ba150de7e9b90bf9c83d (diff) | |
download | gcc-ef1b3fda32c08e9bd6977b96e1e619aae3e3726a.zip gcc-ef1b3fda32c08e9bd6977b96e1e619aae3e3726a.tar.gz gcc-ef1b3fda32c08e9bd6977b96e1e619aae3e3726a.tar.bz2 |
libsanitizer merge from upstream r191666
This may break gcc-asan on Mac, will follow up separately.
From-SVN: r204368
Diffstat (limited to 'libsanitizer/interception')
-rw-r--r-- | libsanitizer/interception/interception.h | 99 | ||||
-rw-r--r-- | libsanitizer/interception/interception_linux.cc | 8 | ||||
-rw-r--r-- | libsanitizer/interception/interception_linux.h | 7 |
3 files changed, 91 insertions, 23 deletions
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h index c4c5026..71740c5 100644 --- a/libsanitizer/interception/interception.h +++ b/libsanitizer/interception/interception.h @@ -21,27 +21,20 @@ // 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; -// WARNING: OFF_T may be different from OS type off_t, depending on the value of -// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls -// like pread and mmap, as opposed to pread64 and mmap64. -// Mac and Linux/x86-64 are special. -#if defined(__APPLE__) || (defined(__linux__) && defined(__x86_64__)) -typedef __sanitizer::u64 OFF_T; -#else -typedef __sanitizer::uptr OFF_T; -#endif -typedef __sanitizer::u64 OFF64_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. +// 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. @@ -55,15 +48,20 @@ typedef __sanitizer::u64 OFF64_T; // 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double) // to a header file. -// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or +// 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 +// 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 -// DEFINE_REAL(int, foo, const char *bar, double baz) in your +// 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 @@ -73,6 +71,7 @@ typedef __sanitizer::u64 OFF64_T; // 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 @@ -82,12 +81,43 @@ typedef __sanitizer::u64 OFF64_T; // 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) # if defined(_DLL) // DLL CRT # define WRAP(x) x @@ -98,7 +128,10 @@ typedef __sanitizer::u64 OFF64_T; # define WRAPPER_NAME(x) "wrap_"#x # define INTERCEPTOR_ATTRIBUTE # endif -# define DECLARE_WRAPPER(ret_type, func, ...) +# 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__); #else # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x @@ -142,6 +175,7 @@ typedef __sanitizer::u64 OFF64_T; # 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__) \ @@ -149,13 +183,36 @@ typedef __sanitizer::u64 OFF64_T; 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); \ } \ - DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ + DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \ extern "C" \ INTERCEPTOR_ATTRIBUTE \ ret_type __stdcall WRAP(func)(__VA_ARGS__) @@ -181,8 +238,6 @@ typedef unsigned long uptr; // NOLINT # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func) #elif defined(__APPLE__) # include "interception_mac.h" -# define OVERRIDE_FUNCTION(old_func, new_func) \ - OVERRIDE_FUNCTION_MAC(old_func, new_func) # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) #else // defined(_WIN32) # include "interception_win.h" diff --git a/libsanitizer/interception/interception_linux.cc b/libsanitizer/interception/interception_linux.cc index 4929a7f..0a8df47 100644 --- a/libsanitizer/interception/interception_linux.cc +++ b/libsanitizer/interception/interception_linux.cc @@ -13,7 +13,6 @@ #ifdef __linux__ #include "interception.h" -#include <stddef.h> // for NULL #include <dlfcn.h> // for dlsym namespace __interception { @@ -22,6 +21,13 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, *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 diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h index 7940ef2..fbbfecb 100644 --- a/libsanitizer/interception/interception_linux.h +++ b/libsanitizer/interception/interception_linux.h @@ -23,6 +23,7 @@ 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(func) \ @@ -31,5 +32,11 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, (::__interception::uptr)&(func), \ (::__interception::uptr)&WRAP(func)) +#if !defined(__ANDROID__) // android does not have dlvsym +#define INTERCEPT_FUNCTION_VER(func, symver) \ + ::__interception::real_##func = (func##_f)(unsigned long) \ + ::__interception::GetFuncAddrVer(#func, #symver) +#endif // !defined(__ANDROID__) + #endif // INTERCEPTION_LINUX_H #endif // __linux__ |