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