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