10b57cec5SDimitry Andric //===-- sanitizer_win_dll_thunk.h -----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // This header provide helper macros to delegate calls to the shared runtime
90b57cec5SDimitry Andric // that lives in the main executable. It should be included to dll_thunks that
100b57cec5SDimitry Andric // will be linked to the dlls, when the sanitizer is a static library included
110b57cec5SDimitry Andric // in the main executable.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric #ifndef SANITIZER_WIN_DLL_THUNK_H
140b57cec5SDimitry Andric #define SANITIZER_WIN_DLL_THUNK_H
150b57cec5SDimitry Andric #include "sanitizer_internal_defs.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace __sanitizer {
180b57cec5SDimitry Andric uptr dllThunkGetRealAddrOrDie(const char *name);
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric int dllThunkIntercept(const char* main_function, uptr dll_function);
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric int dllThunkInterceptWhenPossible(const char* main_function,
230b57cec5SDimitry Andric     const char* default_function, uptr dll_function);
240b57cec5SDimitry Andric }
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric extern "C" int __dll_thunk_init();
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // ----------------- Function interception helper macros -------------------- //
290b57cec5SDimitry Andric // Override dll_function with main_function from main executable.
300b57cec5SDimitry Andric #define INTERCEPT_OR_DIE(main_function, dll_function)                          \
310b57cec5SDimitry Andric   static int intercept_##dll_function() {                                      \
320b57cec5SDimitry Andric     return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr)   \
330b57cec5SDimitry Andric         dll_function);                                                         \
340b57cec5SDimitry Andric   }                                                                            \
350b57cec5SDimitry Andric   __pragma(section(".DLLTH$M", long, read))                                    \
360b57cec5SDimitry Andric   __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() =       \
370b57cec5SDimitry Andric     intercept_##dll_function;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric // Try to override dll_function with main_function from main executable.
400b57cec5SDimitry Andric // If main_function is not present, override dll_function with default_function.
410b57cec5SDimitry Andric #define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \
420b57cec5SDimitry Andric   static int intercept_##dll_function() {                                      \
430b57cec5SDimitry Andric     return __sanitizer::dllThunkInterceptWhenPossible(main_function,           \
440b57cec5SDimitry Andric         default_function, (__sanitizer::uptr)dll_function);                    \
450b57cec5SDimitry Andric   }                                                                            \
460b57cec5SDimitry Andric   __pragma(section(".DLLTH$M", long, read))                                    \
470b57cec5SDimitry Andric   __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() =       \
480b57cec5SDimitry Andric     intercept_##dll_function;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric // -------------------- Function interception macros ------------------------ //
510b57cec5SDimitry Andric // Special case of hooks -- ASan own interface functions.  Those are only called
520b57cec5SDimitry Andric // after __asan_init, thus an empty implementation is sufficient.
530b57cec5SDimitry Andric #define INTERCEPT_SANITIZER_FUNCTION(name)                                     \
540b57cec5SDimitry Andric   extern "C" __declspec(noinline) void name() {                                \
550b57cec5SDimitry Andric     volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__;                  \
560b57cec5SDimitry Andric     static const char function_name[] = #name;                                 \
570b57cec5SDimitry Andric     for (const char* ptr = &function_name[0]; *ptr; ++ptr)                     \
580b57cec5SDimitry Andric       prevent_icf ^= *ptr;                                                     \
590b57cec5SDimitry Andric     (void)prevent_icf;                                                         \
600b57cec5SDimitry Andric     __debugbreak();                                                            \
610b57cec5SDimitry Andric   }                                                                            \
620b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name)
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric // Special case of hooks -- Weak functions, could be redefined in the main
650b57cec5SDimitry Andric // executable, but that is not necessary, so we shouldn't die if we can not find
660b57cec5SDimitry Andric // a reference. Instead, when the function is not present in the main executable
670b57cec5SDimitry Andric // we consider the default impl provided by asan library.
680b57cec5SDimitry Andric #define INTERCEPT_SANITIZER_WEAK_FUNCTION(name)                                \
690b57cec5SDimitry Andric   extern "C" __declspec(noinline) void name() {                                \
700b57cec5SDimitry Andric     volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__;                  \
710b57cec5SDimitry Andric     static const char function_name[] = #name;                                 \
720b57cec5SDimitry Andric     for (const char* ptr = &function_name[0]; *ptr; ++ptr)                     \
730b57cec5SDimitry Andric       prevent_icf ^= *ptr;                                                     \
740b57cec5SDimitry Andric     (void)prevent_icf;                                                         \
750b57cec5SDimitry Andric     __debugbreak();                                                            \
760b57cec5SDimitry Andric   }                                                                            \
770b57cec5SDimitry Andric   INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name)
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric // We can't define our own version of strlen etc. because that would lead to
800b57cec5SDimitry Andric // link-time or even type mismatch errors.  Instead, we can declare a function
810b57cec5SDimitry Andric // just to be able to get its address.  Me may miss the first few calls to the
820b57cec5SDimitry Andric // functions since it can be called before __dll_thunk_init, but that would lead
830b57cec5SDimitry Andric // to false negatives in the startup code before user's global initializers,
840b57cec5SDimitry Andric // which isn't a big deal.
850b57cec5SDimitry Andric #define INTERCEPT_LIBRARY_FUNCTION(name)                                       \
860b57cec5SDimitry Andric   extern "C" void name();                                                      \
8706c3fb27SDimitry Andric   INTERCEPT_OR_DIE(STRINGIFY(WRAP(name)), name)
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric // Use these macros for functions that could be called before __dll_thunk_init()
900b57cec5SDimitry Andric // is executed and don't lead to errors if defined (free, malloc, etc).
910b57cec5SDimitry Andric #define INTERCEPT_WRAP_V_V(name)                                               \
920b57cec5SDimitry Andric   extern "C" void name() {                                                     \
930b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
940b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
950b57cec5SDimitry Andric     fn();                                                                      \
960b57cec5SDimitry Andric   }                                                                            \
970b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric #define INTERCEPT_WRAP_V_W(name)                                               \
1000b57cec5SDimitry Andric   extern "C" void name(void *arg) {                                            \
1010b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1020b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1030b57cec5SDimitry Andric     fn(arg);                                                                   \
1040b57cec5SDimitry Andric   }                                                                            \
1050b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric #define INTERCEPT_WRAP_V_WW(name)                                              \
1080b57cec5SDimitry Andric   extern "C" void name(void *arg1, void *arg2) {                               \
1090b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1100b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1110b57cec5SDimitry Andric     fn(arg1, arg2);                                                            \
1120b57cec5SDimitry Andric   }                                                                            \
1130b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric #define INTERCEPT_WRAP_V_WWW(name)                                             \
1160b57cec5SDimitry Andric   extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
1170b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1180b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1190b57cec5SDimitry Andric     fn(arg1, arg2, arg3);                                                      \
1200b57cec5SDimitry Andric   }                                                                            \
1210b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_V(name)                                               \
1240b57cec5SDimitry Andric   extern "C" void *name() {                                                    \
1250b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1260b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1270b57cec5SDimitry Andric     return fn();                                                               \
1280b57cec5SDimitry Andric   }                                                                            \
1290b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_W(name)                                               \
1320b57cec5SDimitry Andric   extern "C" void *name(void *arg) {                                           \
1330b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1340b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1350b57cec5SDimitry Andric     return fn(arg);                                                            \
1360b57cec5SDimitry Andric   }                                                                            \
1370b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_WW(name)                                              \
1400b57cec5SDimitry Andric   extern "C" void *name(void *arg1, void *arg2) {                              \
1410b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1420b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1430b57cec5SDimitry Andric     return fn(arg1, arg2);                                                     \
1440b57cec5SDimitry Andric   }                                                                            \
1450b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_WWW(name)                                             \
1480b57cec5SDimitry Andric   extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
1490b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1500b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1510b57cec5SDimitry Andric     return fn(arg1, arg2, arg3);                                               \
1520b57cec5SDimitry Andric   }                                                                            \
1530b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_WWWW(name)                                            \
1560b57cec5SDimitry Andric   extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
1570b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1580b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1590b57cec5SDimitry Andric     return fn(arg1, arg2, arg3, arg4);                                         \
1600b57cec5SDimitry Andric   }                                                                            \
1610b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_WWWWW(name)                                           \
1640b57cec5SDimitry Andric   extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
1650b57cec5SDimitry Andric                         void *arg5) {                                          \
1660b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1670b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1680b57cec5SDimitry Andric     return fn(arg1, arg2, arg3, arg4, arg5);                                   \
1690b57cec5SDimitry Andric   }                                                                            \
1700b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric #define INTERCEPT_WRAP_W_WWWWWW(name)                                          \
1730b57cec5SDimitry Andric   extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
1740b57cec5SDimitry Andric                         void *arg5, void *arg6) {                              \
1750b57cec5SDimitry Andric     typedef decltype(name) *fntype;                                            \
1760b57cec5SDimitry Andric     static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
1770b57cec5SDimitry Andric     return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
1780b57cec5SDimitry Andric   }                                                                            \
1790b57cec5SDimitry Andric   INTERCEPT_OR_DIE(#name, name);
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric #endif // SANITIZER_WIN_DLL_THUNK_H
182