]>
Commit | Line | Data |
---|---|---|
5d3805fc JJ |
1 | //===-- sanitizer_win_dll_thunk.h -----------------------------------------===// |
2 | // | |
b667dd70 ML |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. | |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
5d3805fc JJ |
6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // This header provide helper macros to delegate calls to the shared runtime | |
9 | // that lives in the main executable. It should be included to dll_thunks that | |
10 | // will be linked to the dlls, when the sanitizer is a static library included | |
11 | // in the main executable. | |
12 | //===----------------------------------------------------------------------===// | |
13 | #ifndef SANITIZER_WIN_DLL_THUNK_H | |
14 | #define SANITIZER_WIN_DLL_THUNK_H | |
15 | #include "sanitizer_internal_defs.h" | |
16 | ||
17 | namespace __sanitizer { | |
18 | uptr dllThunkGetRealAddrOrDie(const char *name); | |
19 | ||
20 | int dllThunkIntercept(const char* main_function, uptr dll_function); | |
21 | ||
22 | int dllThunkInterceptWhenPossible(const char* main_function, | |
23 | const char* default_function, uptr dll_function); | |
24 | } | |
25 | ||
26 | extern "C" int __dll_thunk_init(); | |
27 | ||
28 | // ----------------- Function interception helper macros -------------------- // | |
29 | // Override dll_function with main_function from main executable. | |
30 | #define INTERCEPT_OR_DIE(main_function, dll_function) \ | |
31 | static int intercept_##dll_function() { \ | |
32 | return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr) \ | |
33 | dll_function); \ | |
34 | } \ | |
35 | __pragma(section(".DLLTH$M", long, read)) \ | |
36 | __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ | |
37 | intercept_##dll_function; | |
38 | ||
39 | // Try to override dll_function with main_function from main executable. | |
40 | // If main_function is not present, override dll_function with default_function. | |
41 | #define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \ | |
42 | static int intercept_##dll_function() { \ | |
43 | return __sanitizer::dllThunkInterceptWhenPossible(main_function, \ | |
44 | default_function, (__sanitizer::uptr)dll_function); \ | |
45 | } \ | |
46 | __pragma(section(".DLLTH$M", long, read)) \ | |
47 | __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ | |
48 | intercept_##dll_function; | |
49 | ||
50 | // -------------------- Function interception macros ------------------------ // | |
51 | // Special case of hooks -- ASan own interface functions. Those are only called | |
52 | // after __asan_init, thus an empty implementation is sufficient. | |
53 | #define INTERCEPT_SANITIZER_FUNCTION(name) \ | |
54 | extern "C" __declspec(noinline) void name() { \ | |
55 | volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ | |
56 | static const char function_name[] = #name; \ | |
57 | for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ | |
58 | prevent_icf ^= *ptr; \ | |
59 | (void)prevent_icf; \ | |
60 | __debugbreak(); \ | |
61 | } \ | |
62 | INTERCEPT_OR_DIE(#name, name) | |
63 | ||
64 | // Special case of hooks -- Weak functions, could be redefined in the main | |
65 | // executable, but that is not necessary, so we shouldn't die if we can not find | |
66 | // a reference. Instead, when the function is not present in the main executable | |
67 | // we consider the default impl provided by asan library. | |
68 | #define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \ | |
69 | extern "C" __declspec(noinline) void name() { \ | |
70 | volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ | |
71 | static const char function_name[] = #name; \ | |
72 | for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ | |
73 | prevent_icf ^= *ptr; \ | |
74 | (void)prevent_icf; \ | |
75 | __debugbreak(); \ | |
76 | } \ | |
77 | INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name) | |
78 | ||
79 | // We can't define our own version of strlen etc. because that would lead to | |
80 | // link-time or even type mismatch errors. Instead, we can declare a function | |
81 | // just to be able to get its address. Me may miss the first few calls to the | |
82 | // functions since it can be called before __dll_thunk_init, but that would lead | |
83 | // to false negatives in the startup code before user's global initializers, | |
84 | // which isn't a big deal. | |
85 | #define INTERCEPT_LIBRARY_FUNCTION(name) \ | |
86 | extern "C" void name(); \ | |
87 | INTERCEPT_OR_DIE(WRAPPER_NAME(name), name) | |
88 | ||
89 | // Use these macros for functions that could be called before __dll_thunk_init() | |
90 | // is executed and don't lead to errors if defined (free, malloc, etc). | |
91 | #define INTERCEPT_WRAP_V_V(name) \ | |
92 | extern "C" void name() { \ | |
93 | typedef decltype(name) *fntype; \ | |
94 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
95 | fn(); \ | |
96 | } \ | |
97 | INTERCEPT_OR_DIE(#name, name); | |
98 | ||
99 | #define INTERCEPT_WRAP_V_W(name) \ | |
100 | extern "C" void name(void *arg) { \ | |
101 | typedef decltype(name) *fntype; \ | |
102 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
103 | fn(arg); \ | |
104 | } \ | |
105 | INTERCEPT_OR_DIE(#name, name); | |
106 | ||
107 | #define INTERCEPT_WRAP_V_WW(name) \ | |
108 | extern "C" void name(void *arg1, void *arg2) { \ | |
109 | typedef decltype(name) *fntype; \ | |
110 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
111 | fn(arg1, arg2); \ | |
112 | } \ | |
113 | INTERCEPT_OR_DIE(#name, name); | |
114 | ||
115 | #define INTERCEPT_WRAP_V_WWW(name) \ | |
116 | extern "C" void name(void *arg1, void *arg2, void *arg3) { \ | |
117 | typedef decltype(name) *fntype; \ | |
118 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
119 | fn(arg1, arg2, arg3); \ | |
120 | } \ | |
121 | INTERCEPT_OR_DIE(#name, name); | |
122 | ||
123 | #define INTERCEPT_WRAP_W_V(name) \ | |
124 | extern "C" void *name() { \ | |
125 | typedef decltype(name) *fntype; \ | |
126 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
127 | return fn(); \ | |
128 | } \ | |
129 | INTERCEPT_OR_DIE(#name, name); | |
130 | ||
131 | #define INTERCEPT_WRAP_W_W(name) \ | |
132 | extern "C" void *name(void *arg) { \ | |
133 | typedef decltype(name) *fntype; \ | |
134 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
135 | return fn(arg); \ | |
136 | } \ | |
137 | INTERCEPT_OR_DIE(#name, name); | |
138 | ||
139 | #define INTERCEPT_WRAP_W_WW(name) \ | |
140 | extern "C" void *name(void *arg1, void *arg2) { \ | |
141 | typedef decltype(name) *fntype; \ | |
142 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
143 | return fn(arg1, arg2); \ | |
144 | } \ | |
145 | INTERCEPT_OR_DIE(#name, name); | |
146 | ||
147 | #define INTERCEPT_WRAP_W_WWW(name) \ | |
148 | extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ | |
149 | typedef decltype(name) *fntype; \ | |
150 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
151 | return fn(arg1, arg2, arg3); \ | |
152 | } \ | |
153 | INTERCEPT_OR_DIE(#name, name); | |
154 | ||
155 | #define INTERCEPT_WRAP_W_WWWW(name) \ | |
156 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ | |
157 | typedef decltype(name) *fntype; \ | |
158 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
159 | return fn(arg1, arg2, arg3, arg4); \ | |
160 | } \ | |
161 | INTERCEPT_OR_DIE(#name, name); | |
162 | ||
163 | #define INTERCEPT_WRAP_W_WWWWW(name) \ | |
164 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ | |
165 | void *arg5) { \ | |
166 | typedef decltype(name) *fntype; \ | |
167 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
168 | return fn(arg1, arg2, arg3, arg4, arg5); \ | |
169 | } \ | |
170 | INTERCEPT_OR_DIE(#name, name); | |
171 | ||
172 | #define INTERCEPT_WRAP_W_WWWWWW(name) \ | |
173 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ | |
174 | void *arg5, void *arg6) { \ | |
175 | typedef decltype(name) *fntype; \ | |
176 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | |
177 | return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ | |
178 | } \ | |
179 | INTERCEPT_OR_DIE(#name, name); | |
180 | ||
181 | #endif // SANITIZER_WIN_DLL_THUNK_H |