interception.h revision 65e5090c3ca13ebf1061a7043449d1b3561daa6a
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;
30// WARNING: OFF_T may be different from OS type off_t, depending on the value of
31// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
32// like pread and mmap, as opposed to pread64 and mmap64.
33typedef __sanitizer::uptr OFF_T;
34typedef __sanitizer::u64  OFF64_T;
35
36// How to add an interceptor:
37// Suppose you need to wrap/replace system function (generally, from libc):
38//      int foo(const char *bar, double baz);
39// You'll need to:
40//      1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
41//         your source file.
42//      2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
43//         INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
44//         intercepted successfully.
45// You can access original function by calling REAL(foo)(bar, baz).
46// By default, REAL(foo) will be visible only inside your interceptor, and if
47// you want to use it in other parts of RTL, you'll need to:
48//      3a) add DECLARE_REAL(int, foo, const char*, double) to a
49//          header file.
50// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
51// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
52//      3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
53//          to a header file.
54
55// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or
56//           DECLARE_REAL(...) are located inside namespaces.
57//        2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo);" to
58//           effectively redirect calls from "foo" to "zoo". In this case
59//           you aren't required to implement
60//           INTERCEPTOR(int, foo, const char *bar, double baz) {...}
61//           but instead you'll have to add
62//           DEFINE_REAL(int, foo, const char *bar, double baz) in your
63//           source file (to define a pointer to overriden function).
64
65// How it works:
66// To replace system functions on Linux we just need to declare functions
67// with same names in our library and then obtain the real function pointers
68// using dlsym().
69// There is one complication. A user may also intercept some of the functions
70// we intercept. To resolve this we declare our interceptors with __interceptor_
71// prefix, and then make actual interceptors weak aliases to __interceptor_
72// functions.
73// This is not so on Mac OS, where the two-level namespace makes
74// our replacement functions invisible to other libraries. This may be overcomed
75// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
76// libraries in Chromium were noticed when doing so.
77// Instead we create a dylib containing a __DATA,__interpose section that
78// associates library functions with their wrappers. When this dylib is
79// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
80// the calls to interposed functions done through stubs to the wrapper
81// functions.
82
83#if defined(__APPLE__)
84# define WRAP(x) wrap_##x
85# define WRAPPER_NAME(x) "wrap_"#x
86# define INTERCEPTOR_ATTRIBUTE
87# define DECLARE_WRAPPER(ret_type, func, ...)
88#elif defined(_WIN32)
89# if defined(_DLL)  // DLL CRT
90#  define WRAP(x) x
91#  define WRAPPER_NAME(x) #x
92#  define INTERCEPTOR_ATTRIBUTE
93# else  // Static CRT
94#  define WRAP(x) wrap_##x
95#  define WRAPPER_NAME(x) "wrap_"#x
96#  define INTERCEPTOR_ATTRIBUTE
97# endif
98# define DECLARE_WRAPPER(ret_type, func, ...)
99#else
100# define WRAP(x) __interceptor_ ## x
101# define WRAPPER_NAME(x) "__interceptor_" #x
102# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
103# define DECLARE_WRAPPER(ret_type, func, ...) \
104    extern "C" ret_type func(__VA_ARGS__) \
105    __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
106#endif
107
108#if !defined(__APPLE__)
109# define PTR_TO_REAL(x) real_##x
110# define REAL(x) __interception::PTR_TO_REAL(x)
111# define FUNC_TYPE(x) x##_f
112
113# define DECLARE_REAL(ret_type, func, ...) \
114    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
115    namespace __interception { \
116      extern FUNC_TYPE(func) PTR_TO_REAL(func); \
117    }
118#else  // __APPLE__
119# define REAL(x) x
120# define DECLARE_REAL(ret_type, func, ...) \
121    extern "C" ret_type func(__VA_ARGS__);
122#endif  // __APPLE__
123
124#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
125  DECLARE_REAL(ret_type, func, __VA_ARGS__) \
126  extern "C" ret_type WRAP(func)(__VA_ARGS__);
127
128// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
129// macros does its job. In exceptional cases you may need to call REAL(foo)
130// without defining INTERCEPTOR(..., foo, ...). For example, if you override
131// foo with an interceptor for other function.
132#if !defined(__APPLE__)
133# define DEFINE_REAL(ret_type, func, ...) \
134    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
135    namespace __interception { \
136      FUNC_TYPE(func) PTR_TO_REAL(func); \
137    }
138#else
139# define DEFINE_REAL(ret_type, func, ...)
140#endif
141
142#define INTERCEPTOR(ret_type, func, ...) \
143  DEFINE_REAL(ret_type, func, __VA_ARGS__) \
144  DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
145  extern "C" \
146  INTERCEPTOR_ATTRIBUTE \
147  ret_type WRAP(func)(__VA_ARGS__)
148
149#if defined(_WIN32)
150# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
151    typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
152    namespace __interception { \
153      FUNC_TYPE(func) PTR_TO_REAL(func); \
154    } \
155    DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
156    extern "C" \
157    INTERCEPTOR_ATTRIBUTE \
158    ret_type __stdcall WRAP(func)(__VA_ARGS__)
159#endif
160
161// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
162// so we use casting via an integral type __interception::uptr,
163// assuming that system is POSIX-compliant. Using other hacks seem
164// challenging, as we don't even pass function type to
165// INTERCEPT_FUNCTION macro, only its name.
166namespace __interception {
167#if defined(_WIN64)
168typedef unsigned long long uptr;  // NOLINT
169#else
170typedef unsigned long uptr;  // NOLINT
171#endif  // _WIN64
172}  // namespace __interception
173
174#define INCLUDED_FROM_INTERCEPTION_LIB
175
176#if defined(__linux__)
177# include "interception_linux.h"
178# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
179#elif defined(__APPLE__)
180# include "interception_mac.h"
181# define OVERRIDE_FUNCTION(old_func, new_func) \
182    OVERRIDE_FUNCTION_MAC(old_func, new_func)
183# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
184#else  // defined(_WIN32)
185# include "interception_win.h"
186# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
187#endif
188
189#undef INCLUDED_FROM_INTERCEPTION_LIB
190
191#endif  // INTERCEPTION_H
192