interception.h revision 6fb47af2d2d305adbfc3d41bea589d1527a364a9
1//===-- interception.h ------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Machinery for providing replacements/wrappers for system functions.
13//===----------------------------------------------------------------------===//
14
15#ifndef INTERCEPTION_H
16#define INTERCEPTION_H
17
18#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
19# error "Interception doesn't work on this operating system."
20#endif
21
22#include "sanitizer_common/sanitizer_internal_defs.h"
23
24// These typedefs should be used only in the interceptor definitions to replace
25// the standard system types (e.g. SSIZE_T instead of ssize_t)
26typedef __sanitizer::uptr    SIZE_T;
27typedef __sanitizer::sptr    SSIZE_T;
28typedef __sanitizer::sptr    PTRDIFF_T;
29typedef __sanitizer::s64     INTMAX_T;
30typedef __sanitizer::OFF_T   OFF_T;
31typedef __sanitizer::OFF64_T OFF64_T;
32
33// How to add an interceptor:
34// Suppose you need to wrap/replace system function (generally, from libc):
35//      int foo(const char *bar, double baz);
36// You'll need to:
37//      1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
38//         your source file.
39//      2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
40//         INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
41//         intercepted successfully.
42// You can access original function by calling REAL(foo)(bar, baz).
43// By default, REAL(foo) will be visible only inside your interceptor, and if
44// you want to use it in other parts of RTL, you'll need to:
45//      3a) add DECLARE_REAL(int, foo, const char*, double) to a
46//          header file.
47// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
48// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
49//      3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
50//          to a header file.
51
52// Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or
53//           DECLARE_REAL(...) are located inside namespaces.
54//        2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to
55//           effectively redirect calls from "foo" to "zoo". In this case
56//           you aren't required to implement
57//           INTERCEPTOR(int, foo, const char *bar, double baz) {...}
58//           but instead you'll have to add
59//           DECLARE_REAL(int, foo, const char *bar, double baz) in your
60//           source file (to define a pointer to overriden function).
61
62// How it works:
63// To replace system functions on Linux we just need to declare functions
64// with same names in our library and then obtain the real function pointers
65// using dlsym().
66// There is one complication. A user may also intercept some of the functions
67// we intercept. To resolve this we declare our interceptors with __interceptor_
68// prefix, and then make actual interceptors weak aliases to __interceptor_
69// functions.
70//
71// This is not so on Mac OS, where the two-level namespace makes
72// our replacement functions invisible to other libraries. This may be overcomed
73// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
74// libraries in Chromium were noticed when doing so.
75// Instead we create a dylib containing a __DATA,__interpose section that
76// associates library functions with their wrappers. When this dylib is
77// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
78// the calls to interposed functions done through stubs to the wrapper
79// functions.
80// As it's decided at compile time which functions are to be intercepted on Mac,
81// INTERCEPT_FUNCTION() is effectively a no-op on this system.
82
83#if defined(__APPLE__)
84
85// Just a pair of pointers.
86struct interpose_substitution {
87  const uptr replacement;
88  const uptr original;
89};
90
91// For a function foo() create a global pair of pointers { wrap_foo, foo } in
92// the __DATA,__interpose section.
93// As a result all the calls to foo() will be routed to wrap_foo() at runtime.
94#define INTERPOSER(func_name) __attribute__((used)) \
95const interpose_substitution substitution_##func_name[] \
96    __attribute__((section("__DATA, __interpose"))) = { \
97    { reinterpret_cast<const uptr>(WRAP(func_name)), \
98      reinterpret_cast<const uptr>(func_name) } \
99}
100
101// For a function foo() and a wrapper function bar() create a global pair
102// of pointers { bar, foo } in the __DATA,__interpose section.
103// As a result all the calls to foo() will be routed to bar() at runtime.
104#define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \
105const interpose_substitution substitution_##func_name[] \
106    __attribute__((section("__DATA, __interpose"))) = { \
107    { reinterpret_cast<const uptr>(wrapper_name), \
108      reinterpret_cast<const uptr>(func_name) } \
109}
110
111# define WRAP(x) wrap_##x
112# define WRAPPER_NAME(x) "wrap_"#x
113# define INTERCEPTOR_ATTRIBUTE
114# define DECLARE_WRAPPER(ret_type, func, ...)
115
116#elif defined(_WIN32)
117# if defined(_DLL)  // DLL CRT
118#  define WRAP(x) x
119#  define WRAPPER_NAME(x) #x
120#  define INTERCEPTOR_ATTRIBUTE
121# else  // Static CRT
122#  define WRAP(x) wrap_##x
123#  define WRAPPER_NAME(x) "wrap_"#x
124#  define INTERCEPTOR_ATTRIBUTE
125# endif
126# define DECLARE_WRAPPER(ret_type, func, ...)
127#else
128# define WRAP(x) __interceptor_ ## x
129# define WRAPPER_NAME(x) "__interceptor_" #x
130# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
131# define DECLARE_WRAPPER(ret_type, func, ...) \
132    extern "C" ret_type func(__VA_ARGS__) \
133    __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
134#endif
135
136#if !defined(__APPLE__)
137# define PTR_TO_REAL(x) real_##x
138# define REAL(x) __interception::PTR_TO_REAL(x)
139# define FUNC_TYPE(x) x##_f
140
141# define DECLARE_REAL(ret_type, func, ...) \
142    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
143    namespace __interception { \
144      extern FUNC_TYPE(func) PTR_TO_REAL(func); \
145    }
146#else  // __APPLE__
147# define REAL(x) x
148# define DECLARE_REAL(ret_type, func, ...) \
149    extern "C" ret_type func(__VA_ARGS__);
150#endif  // __APPLE__
151
152#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
153  DECLARE_REAL(ret_type, func, __VA_ARGS__) \
154  extern "C" ret_type WRAP(func)(__VA_ARGS__);
155
156// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
157// macros does its job. In exceptional cases you may need to call REAL(foo)
158// without defining INTERCEPTOR(..., foo, ...). For example, if you override
159// foo with an interceptor for other function.
160#if !defined(__APPLE__)
161# define DEFINE_REAL(ret_type, func, ...) \
162    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
163    namespace __interception { \
164      FUNC_TYPE(func) PTR_TO_REAL(func); \
165    }
166#else
167# define DEFINE_REAL(ret_type, func, ...)
168#endif
169
170#if !defined(__APPLE__)
171#define INTERCEPTOR(ret_type, func, ...) \
172  DEFINE_REAL(ret_type, func, __VA_ARGS__) \
173  DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
174  extern "C" \
175  INTERCEPTOR_ATTRIBUTE \
176  ret_type WRAP(func)(__VA_ARGS__)
177#else  // __APPLE__
178#define INTERCEPTOR(ret_type, func, ...) \
179  extern "C" ret_type func(__VA_ARGS__); \
180  extern "C" ret_type WRAP(func)(__VA_ARGS__); \
181  INTERPOSER(func); \
182  extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
183
184// Override |overridee| with |overrider|.
185#define OVERRIDE_FUNCTION(overridee, overrider) \
186  INTERPOSER_2(overridee, WRAP(overrider))
187#endif
188
189#if defined(_WIN32)
190# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
191    typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
192    namespace __interception { \
193      FUNC_TYPE(func) PTR_TO_REAL(func); \
194    } \
195    DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
196    extern "C" \
197    INTERCEPTOR_ATTRIBUTE \
198    ret_type __stdcall WRAP(func)(__VA_ARGS__)
199#endif
200
201// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
202// so we use casting via an integral type __interception::uptr,
203// assuming that system is POSIX-compliant. Using other hacks seem
204// challenging, as we don't even pass function type to
205// INTERCEPT_FUNCTION macro, only its name.
206namespace __interception {
207#if defined(_WIN64)
208typedef unsigned long long uptr;  // NOLINT
209#else
210typedef unsigned long uptr;  // NOLINT
211#endif  // _WIN64
212}  // namespace __interception
213
214#define INCLUDED_FROM_INTERCEPTION_LIB
215
216#if defined(__linux__)
217# include "interception_linux.h"
218# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
219#elif defined(__APPLE__)
220# include "interception_mac.h"
221# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
222#else  // defined(_WIN32)
223# include "interception_win.h"
224# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
225#endif
226
227#undef INCLUDED_FROM_INTERCEPTION_LIB
228
229#endif  // INTERCEPTION_H
230