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