summaryrefslogtreecommitdiff
path: root/libsanitizer/interception
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2013-11-04 21:33:31 +0000
committerKostya Serebryany <kcc@gcc.gnu.org>2013-11-04 21:33:31 +0000
commitef1b3fda32c08e9bd6977b96e1e619aae3e3726a (patch)
tree7cfc103c9b6b4ce7ca19d39f91509a1b68819a63 /libsanitizer/interception
parentfd5564d3c71195714c28ba150de7e9b90bf9c83d (diff)
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.h99
-rw-r--r--libsanitizer/interception/interception_linux.cc8
-rw-r--r--libsanitizer/interception/interception_linux.h7
3 files changed, 91 insertions, 23 deletions
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index c4c5026c7ed..71740c5c403 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 4929a7fce49..0a8df474ab4 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 7940ef257c8..fbbfecbe037 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__