1 //===-- dd_rtl.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "sanitizer_common/sanitizer_common.h"
11 #include "sanitizer_common/sanitizer_placement_new.h"
12 #include "sanitizer_common/sanitizer_flags.h"
13 #include "sanitizer_common/sanitizer_flag_parser.h"
14 #include "sanitizer_common/sanitizer_stacktrace.h"
15 #include "sanitizer_common/sanitizer_stackdepot.h"
21 static u32
CurrentStackTrace(Thread
*thr
, uptr skip
) {
22 BufferedStackTrace stack
;
23 thr
->ignore_interceptors
= true;
24 stack
.Unwind(1000, 0, 0, 0, 0, 0, false);
25 thr
->ignore_interceptors
= false;
26 if (stack
.size
<= skip
)
28 return StackDepotPut(StackTrace(stack
.trace
+ skip
, stack
.size
- skip
));
31 static void PrintStackTrace(Thread
*thr
, u32 stk
) {
32 StackTrace stack
= StackDepotGet(stk
);
33 thr
->ignore_interceptors
= true;
35 thr
->ignore_interceptors
= false;
38 static void ReportDeadlock(Thread
*thr
, DDReport
*rep
) {
41 Lock
lock(&ctx
->report_mutex
);
42 Printf("==============================\n");
43 Printf("WARNING: lock-order-inversion (potential deadlock)\n");
44 for (int i
= 0; i
< rep
->n
; i
++) {
45 Printf("Thread %lld locks mutex %llu while holding mutex %llu:\n",
46 rep
->loop
[i
].thr_ctx
, rep
->loop
[i
].mtx_ctx1
, rep
->loop
[i
].mtx_ctx0
);
47 PrintStackTrace(thr
, rep
->loop
[i
].stk
[1]);
48 if (rep
->loop
[i
].stk
[0]) {
49 Printf("Mutex %llu was acquired here:\n",
50 rep
->loop
[i
].mtx_ctx0
);
51 PrintStackTrace(thr
, rep
->loop
[i
].stk
[0]);
54 Printf("==============================\n");
57 Callback::Callback(Thread
*thr
)
63 u32
Callback::Unwind() {
64 return CurrentStackTrace(thr
, 3);
67 static void InitializeFlags() {
71 f
->second_deadlock_stack
= false;
73 SetCommonFlagsDefaults();
75 // Override some common flags defaults.
77 cf
.CopyFrom(*common_flags());
78 cf
.allow_addr2line
= true;
79 OverrideCommonFlags(cf
);
82 // Override from command line.
84 RegisterFlag(&parser
, "second_deadlock_stack", "", &f
->second_deadlock_stack
);
85 RegisterCommonFlags(&parser
);
86 parser
.ParseStringFromEnv("DSAN_OPTIONS");
87 SetVerbosity(common_flags()->verbosity
);
91 static u64 ctx_mem
[sizeof(Context
) / sizeof(u64
) + 1];
92 ctx
= new(ctx_mem
) Context();
94 InitializeInterceptors();
96 ctx
->dd
= DDetector::Create(flags());
99 void ThreadInit(Thread
*thr
) {
100 static atomic_uintptr_t id_gen
;
101 uptr id
= atomic_fetch_add(&id_gen
, 1, memory_order_relaxed
);
102 thr
->dd_pt
= ctx
->dd
->CreatePhysicalThread();
103 thr
->dd_lt
= ctx
->dd
->CreateLogicalThread(id
);
106 void ThreadDestroy(Thread
*thr
) {
107 ctx
->dd
->DestroyPhysicalThread(thr
->dd_pt
);
108 ctx
->dd
->DestroyLogicalThread(thr
->dd_lt
);
111 void MutexBeforeLock(Thread
*thr
, uptr m
, bool writelock
) {
112 if (thr
->ignore_interceptors
)
116 MutexHashMap::Handle
h(&ctx
->mutex_map
, m
);
118 ctx
->dd
->MutexInit(&cb
, &h
->dd
);
119 ctx
->dd
->MutexBeforeLock(&cb
, &h
->dd
, writelock
);
121 ReportDeadlock(thr
, ctx
->dd
->GetReport(&cb
));
124 void MutexAfterLock(Thread
*thr
, uptr m
, bool writelock
, bool trylock
) {
125 if (thr
->ignore_interceptors
)
129 MutexHashMap::Handle
h(&ctx
->mutex_map
, m
);
131 ctx
->dd
->MutexInit(&cb
, &h
->dd
);
132 ctx
->dd
->MutexAfterLock(&cb
, &h
->dd
, writelock
, trylock
);
134 ReportDeadlock(thr
, ctx
->dd
->GetReport(&cb
));
137 void MutexBeforeUnlock(Thread
*thr
, uptr m
, bool writelock
) {
138 if (thr
->ignore_interceptors
)
142 MutexHashMap::Handle
h(&ctx
->mutex_map
, m
);
143 ctx
->dd
->MutexBeforeUnlock(&cb
, &h
->dd
, writelock
);
145 ReportDeadlock(thr
, ctx
->dd
->GetReport(&cb
));
148 void MutexDestroy(Thread
*thr
, uptr m
) {
149 if (thr
->ignore_interceptors
)
152 MutexHashMap::Handle
h(&ctx
->mutex_map
, m
, true);
155 ctx
->dd
->MutexDestroy(&cb
, &h
->dd
);
158 } // namespace __dsan