xref: /llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h (revision e31efd8f6fbc27000a4933f889e0deb922411006)
1 //===-- sanitizer_win_thunk_interception.h -------------------------  -----===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 // This header provide helper macros and functions to delegate calls to the
9 // shared runtime that lives in the sanitizer DLL.
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef SANITIZER_WIN_THUNK_INTERCEPTION_H
13 #define SANITIZER_WIN_THUNK_INTERCEPTION_H
14 #include <stdint.h>
15 
16 #include "sanitizer_internal_defs.h"
17 
18 extern "C" {
19 __declspec(dllimport) bool __cdecl __sanitizer_override_function(
20     const char *export_name, __sanitizer::uptr user_function,
21     __sanitizer::uptr *old_function = nullptr);
22 __declspec(dllimport) bool __cdecl __sanitizer_override_function_by_addr(
23     __sanitizer::uptr source_function, __sanitizer::uptr target_function,
24     __sanitizer::uptr *old_target_function = nullptr);
25 __declspec(dllimport) bool __cdecl __sanitizer_register_weak_function(
26     const char *export_name, __sanitizer::uptr user_function,
27     __sanitizer::uptr *old_function = nullptr);
28 }
29 
30 using sanitizer_thunk = int (*)();
31 
32 namespace __sanitizer {
33 int override_function(const char *export_name, uptr user_function);
34 int register_weak(const char *export_name, uptr user_function);
35 void initialize_thunks(const sanitizer_thunk *begin,
36                        const sanitizer_thunk *end);
37 }  // namespace __sanitizer
38 
39 // -------------------- Function interception macros ------------------------ //
40 // We can't define our own version of strlen etc. because that would lead to
41 // link-time or even type mismatch errors.  Instead, we can declare a function
42 // just to be able to get its address.  Me may miss the first few calls to the
43 // functions since it can be called before __dll_thunk_init, but that would lead
44 // to false negatives in the startup code before user's global initializers,
45 // which isn't a big deal.
46 // Use .INTR segment to register function pointers that are iterated over during
47 // startup that will replace local_function with sanitizer_export.
48 
49 #define INTERCEPT_LIBRARY_FUNCTION(local_function, sanitizer_export)   \
50   extern "C" void local_function();                                    \
51   static int intercept_##local_function() {                            \
52     return __sanitizer::override_function(                             \
53         sanitizer_export,                                              \
54         reinterpret_cast<__sanitizer::uptr>(local_function));          \
55   }                                                                    \
56   __pragma(section(".INTR$M", long, read)) __declspec(allocate(        \
57       ".INTR$M")) int (*__sanitizer_static_thunk_##local_function)() = \
58       intercept_##local_function;
59 
60 // ------------------ Weak symbol registration macros ---------------------- //
61 // Use .WEAK segment to register function pointers that are iterated over during
62 // startup that will replace sanitizer_export with local_function
63 #ifdef __clang__
64 #  define REGISTER_WEAK_OPTNONE __attribute__((optnone))
65 #  define REGISTER_WEAK_FUNCTION_ADDRESS(fn) __builtin_function_start(fn)
66 #else
67 #  define REGISTER_WEAK_OPTNONE
68 #  define REGISTER_WEAK_FUNCTION_ADDRESS(fn) &fn
69 #endif
70 
71 #define REGISTER_WEAK_FUNCTION(local_function)                          \
72   extern "C" void local_function();                                     \
73   extern "C" void WEAK_EXPORT_NAME(local_function)();                   \
74   WIN_WEAK_IMPORT_DEF(local_function)                                   \
75   REGISTER_WEAK_OPTNONE static int register_weak_##local_function() {   \
76     if ((uintptr_t)REGISTER_WEAK_FUNCTION_ADDRESS(local_function) !=    \
77         (uintptr_t)REGISTER_WEAK_FUNCTION_ADDRESS(                      \
78             WEAK_EXPORT_NAME(local_function))) {                        \
79       return __sanitizer::register_weak(                                \
80           SANITIZER_STRINGIFY(WEAK_EXPORT_NAME(local_function)),        \
81           reinterpret_cast<__sanitizer::uptr>(local_function));         \
82     }                                                                   \
83     return 0;                                                           \
84   }                                                                     \
85   __pragma(section(".WEAK$M", long, read)) __declspec(allocate(         \
86       ".WEAK$M")) int (*__sanitizer_register_weak_##local_function)() = \
87       register_weak_##local_function;
88 #endif  // SANITIZER_WIN_STATIC_RUNTIME_THUNK_H
89