diff options
author | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
commit | 11023dc647fd8f41418da90d59db138400d0f334 (patch) | |
tree | 50f0ab80515576749ef638dd0766b70a65904bfa /lib/interception/interception.h | |
parent | 58aabf08b77d221489f10e274812ec60917c21a8 (diff) |
Diffstat (limited to 'lib/interception/interception.h')
-rw-r--r-- | lib/interception/interception.h | 126 |
1 files changed, 83 insertions, 43 deletions
diff --git a/lib/interception/interception.h b/lib/interception/interception.h index 030bda7cba0c7..d50af35415d6e 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -19,35 +19,24 @@ # error "Interception doesn't work on this operating system." #endif -#include "sanitizer/common_interface_defs.h" +#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::u64 OFF_T; -typedef __sanitizer::u64 OFF64_T; - -// How to use this library: -// 1) Include this header to define your own interceptors -// (see details below). -// 2) Build all *.cc files and link against them. -// On Mac you will also need to: -// 3) Provide your own implementation for the following functions: -// mach_error_t __interception::allocate_island(void **ptr, -// size_t size, -// void *hint); -// mach_error_t __interception::deallocate_island(void *ptr); -// See "interception_mac.h" for more details. +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. @@ -61,15 +50,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 @@ -79,29 +73,53 @@ 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 -// libraries in Chromium were noticed when doing so. Instead we use -// 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 +// 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) # if defined(_DLL) // DLL CRT # define WRAP(x) x @@ -122,7 +140,7 @@ typedef __sanitizer::u64 OFF64_T; __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); #endif -#if !MAC_INTERPOSE_FUNCTIONS +#if !defined(__APPLE__) # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) # define FUNC_TYPE(x) x##_f @@ -132,11 +150,11 @@ typedef __sanitizer::u64 OFF64_T; namespace __interception { \ extern FUNC_TYPE(func) PTR_TO_REAL(func); \ } -#else // MAC_INTERPOSE_FUNCTIONS +#else // __APPLE__ # define REAL(x) x # define DECLARE_REAL(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__); -#endif // MAC_INTERPOSE_FUNCTIONS +#endif // __APPLE__ #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ DECLARE_REAL(ret_type, func, __VA_ARGS__) \ @@ -146,7 +164,7 @@ typedef __sanitizer::u64 OFF64_T; // 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 !MAC_INTERPOSE_FUNCTIONS +#if !defined(__APPLE__) # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -156,6 +174,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__) \ @@ -163,6 +182,29 @@ 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__); \ @@ -195,8 +237,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" |