xref: /freebsd/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric #ifndef TSAN_INTERCEPTORS_H
20b57cec5SDimitry Andric #define TSAN_INTERCEPTORS_H
30b57cec5SDimitry Andric 
40b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
50b57cec5SDimitry Andric #include "tsan_rtl.h"
60b57cec5SDimitry Andric 
70b57cec5SDimitry Andric namespace __tsan {
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric class ScopedInterceptor {
100b57cec5SDimitry Andric  public:
110b57cec5SDimitry Andric   ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
120b57cec5SDimitry Andric   ~ScopedInterceptor();
DisableIgnores()13349cc55cSDimitry Andric   void DisableIgnores() {
14349cc55cSDimitry Andric     if (UNLIKELY(ignoring_))
15349cc55cSDimitry Andric       DisableIgnoresImpl();
16349cc55cSDimitry Andric   }
EnableIgnores()17349cc55cSDimitry Andric   void EnableIgnores() {
18349cc55cSDimitry Andric     if (UNLIKELY(ignoring_))
19349cc55cSDimitry Andric       EnableIgnoresImpl();
20349cc55cSDimitry Andric   }
21349cc55cSDimitry Andric 
220b57cec5SDimitry Andric  private:
230b57cec5SDimitry Andric   ThreadState *const thr_;
24bdd1243dSDimitry Andric   bool in_ignored_lib_ = false;
25bdd1243dSDimitry Andric   bool in_blocking_func_ = false;
26bdd1243dSDimitry Andric   bool ignoring_ = false;
27349cc55cSDimitry Andric 
28349cc55cSDimitry Andric   void DisableIgnoresImpl();
29349cc55cSDimitry Andric   void EnableIgnoresImpl();
300b57cec5SDimitry Andric };
310b57cec5SDimitry Andric 
32*06c3fb27SDimitry Andric struct TsanInterceptorContext {
33*06c3fb27SDimitry Andric   ThreadState *thr;
34*06c3fb27SDimitry Andric   const uptr pc;
35*06c3fb27SDimitry Andric };
36*06c3fb27SDimitry Andric 
370b57cec5SDimitry Andric LibIgnore *libignore();
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric #if !SANITIZER_GO
in_symbolizer()40e8d8bef9SDimitry Andric inline bool in_symbolizer() {
41349cc55cSDimitry Andric   return UNLIKELY(cur_thread_init()->in_symbolizer);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric #endif
440b57cec5SDimitry Andric 
MustIgnoreInterceptor(ThreadState * thr)450eae32dcSDimitry Andric inline bool MustIgnoreInterceptor(ThreadState *thr) {
460eae32dcSDimitry Andric   return !thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib;
470eae32dcSDimitry Andric }
480eae32dcSDimitry Andric 
490b57cec5SDimitry Andric }  // namespace __tsan
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric #define SCOPED_INTERCEPTOR_RAW(func, ...)            \
52349cc55cSDimitry Andric   ThreadState *thr = cur_thread_init();              \
53349cc55cSDimitry Andric   ScopedInterceptor si(thr, #func, GET_CALLER_PC()); \
54349cc55cSDimitry Andric   UNUSED const uptr pc = GET_CURRENT_PC();
550b57cec5SDimitry Andric 
56349cc55cSDimitry Andric #ifdef __powerpc64__
57349cc55cSDimitry Andric // Debugging of crashes on powerpc after commit:
58349cc55cSDimitry Andric // c80604f7a3 ("tsan: remove real func check from interceptors")
59349cc55cSDimitry Andric // Somehow replacing if with DCHECK leads to strange failures in:
60349cc55cSDimitry Andric // SanitizerCommon-tsan-powerpc64le-Linux :: Linux/ptrace.cpp
61349cc55cSDimitry Andric // https://lab.llvm.org/buildbot/#/builders/105
62349cc55cSDimitry Andric // https://lab.llvm.org/buildbot/#/builders/121
63349cc55cSDimitry Andric // https://lab.llvm.org/buildbot/#/builders/57
64349cc55cSDimitry Andric #  define CHECK_REAL_FUNC(func)                                          \
650b57cec5SDimitry Andric     if (REAL(func) == 0) {                                               \
660b57cec5SDimitry Andric       Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
670b57cec5SDimitry Andric       Die();                                                             \
68349cc55cSDimitry Andric     }
69349cc55cSDimitry Andric #else
70349cc55cSDimitry Andric #  define CHECK_REAL_FUNC(func) DCHECK(REAL(func))
71349cc55cSDimitry Andric #endif
72349cc55cSDimitry Andric 
73349cc55cSDimitry Andric #define SCOPED_TSAN_INTERCEPTOR(func, ...)   \
74349cc55cSDimitry Andric   SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
75349cc55cSDimitry Andric   CHECK_REAL_FUNC(func);                     \
760eae32dcSDimitry Andric   if (MustIgnoreInterceptor(thr))            \
77349cc55cSDimitry Andric     return REAL(func)(__VA_ARGS__);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric #define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \
800b57cec5SDimitry Andric     si.DisableIgnores();
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric #define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \
830b57cec5SDimitry Andric     si.EnableIgnores();
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
860b57cec5SDimitry Andric 
871c21bfb1SDimitry Andric #if SANITIZER_FREEBSD
881c21bfb1SDimitry Andric #  define TSAN_INTERCEPTOR_FREEBSD_ALIAS(ret, func, ...) \
891c21bfb1SDimitry Andric     TSAN_INTERCEPTOR(ret, _pthread_##func, __VA_ARGS__)  \
90*06c3fb27SDimitry Andric     ALIAS(WRAP(pthread_##func));
911c21bfb1SDimitry Andric #else
921c21bfb1SDimitry Andric #  define TSAN_INTERCEPTOR_FREEBSD_ALIAS(ret, func, ...)
931c21bfb1SDimitry Andric #endif
941c21bfb1SDimitry Andric 
950b57cec5SDimitry Andric #if SANITIZER_NETBSD
960b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) \
970b57cec5SDimitry Andric   TSAN_INTERCEPTOR(ret, __libc_##func, __VA_ARGS__) \
98*06c3fb27SDimitry Andric   ALIAS(WRAP(pthread_##func));
990b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) \
1000b57cec5SDimitry Andric   TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \
101*06c3fb27SDimitry Andric   ALIAS(WRAP(pthread_##func));
1020b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...) \
1030b57cec5SDimitry Andric   TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \
104*06c3fb27SDimitry Andric   ALIAS(WRAP(pthread_##func2));
1050b57cec5SDimitry Andric #else
1060b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...)
1070b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...)
1080b57cec5SDimitry Andric # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...)
1090b57cec5SDimitry Andric #endif
1100b57cec5SDimitry Andric 
111*06c3fb27SDimitry Andric #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
112*06c3fb27SDimitry Andric 
113*06c3fb27SDimitry Andric #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
114*06c3fb27SDimitry Andric   (!cur_thread_init()->is_inited)
115*06c3fb27SDimitry Andric 
116*06c3fb27SDimitry Andric #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                    \
117*06c3fb27SDimitry Andric   MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr,                 \
118*06c3fb27SDimitry Andric                     ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \
119*06c3fb27SDimitry Andric                     true)
120*06c3fb27SDimitry Andric 
121*06c3fb27SDimitry Andric #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)                       \
122*06c3fb27SDimitry Andric   MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr,                  \
123*06c3fb27SDimitry Andric                     ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \
124*06c3fb27SDimitry Andric                     false)
125*06c3fb27SDimitry Andric 
126*06c3fb27SDimitry Andric #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
127*06c3fb27SDimitry Andric   SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__);    \
128*06c3fb27SDimitry Andric   TsanInterceptorContext _ctx = {thr, pc};       \
129*06c3fb27SDimitry Andric   ctx = (void *)&_ctx;                           \
130*06c3fb27SDimitry Andric   (void)ctx;
131*06c3fb27SDimitry Andric 
1320b57cec5SDimitry Andric #endif  // TSAN_INTERCEPTORS_H
133