xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/dd/dd_rtl.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- dd_rtl.cpp --------------------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric 
9*68d75effSDimitry Andric #include "dd_rtl.h"
10*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
11*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
12*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
13*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flag_parser.h"
14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
15*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
16*68d75effSDimitry Andric 
17*68d75effSDimitry Andric namespace __dsan {
18*68d75effSDimitry Andric 
19*68d75effSDimitry Andric static Context *ctx;
20*68d75effSDimitry Andric 
21*68d75effSDimitry Andric static u32 CurrentStackTrace(Thread *thr, uptr skip) {
22*68d75effSDimitry Andric   BufferedStackTrace stack;
23*68d75effSDimitry Andric   thr->ignore_interceptors = true;
24*68d75effSDimitry Andric   stack.Unwind(1000, 0, 0, 0, 0, 0, false);
25*68d75effSDimitry Andric   thr->ignore_interceptors = false;
26*68d75effSDimitry Andric   if (stack.size <= skip)
27*68d75effSDimitry Andric     return 0;
28*68d75effSDimitry Andric   return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
29*68d75effSDimitry Andric }
30*68d75effSDimitry Andric 
31*68d75effSDimitry Andric static void PrintStackTrace(Thread *thr, u32 stk) {
32*68d75effSDimitry Andric   StackTrace stack = StackDepotGet(stk);
33*68d75effSDimitry Andric   thr->ignore_interceptors = true;
34*68d75effSDimitry Andric   stack.Print();
35*68d75effSDimitry Andric   thr->ignore_interceptors = false;
36*68d75effSDimitry Andric }
37*68d75effSDimitry Andric 
38*68d75effSDimitry Andric static void ReportDeadlock(Thread *thr, DDReport *rep) {
39*68d75effSDimitry Andric   if (rep == 0)
40*68d75effSDimitry Andric     return;
41*68d75effSDimitry Andric   BlockingMutexLock lock(&ctx->report_mutex);
42*68d75effSDimitry Andric   Printf("==============================\n");
43*68d75effSDimitry Andric   Printf("WARNING: lock-order-inversion (potential deadlock)\n");
44*68d75effSDimitry Andric   for (int i = 0; i < rep->n; i++) {
45*68d75effSDimitry Andric     Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
46*68d75effSDimitry Andric       rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
47*68d75effSDimitry Andric     PrintStackTrace(thr, rep->loop[i].stk[1]);
48*68d75effSDimitry Andric     if (rep->loop[i].stk[0]) {
49*68d75effSDimitry Andric       Printf("Mutex %llu was acquired here:\n",
50*68d75effSDimitry Andric         rep->loop[i].mtx_ctx0);
51*68d75effSDimitry Andric       PrintStackTrace(thr, rep->loop[i].stk[0]);
52*68d75effSDimitry Andric     }
53*68d75effSDimitry Andric   }
54*68d75effSDimitry Andric   Printf("==============================\n");
55*68d75effSDimitry Andric }
56*68d75effSDimitry Andric 
57*68d75effSDimitry Andric Callback::Callback(Thread *thr)
58*68d75effSDimitry Andric     : thr(thr) {
59*68d75effSDimitry Andric   lt = thr->dd_lt;
60*68d75effSDimitry Andric   pt = thr->dd_pt;
61*68d75effSDimitry Andric }
62*68d75effSDimitry Andric 
63*68d75effSDimitry Andric u32 Callback::Unwind() {
64*68d75effSDimitry Andric   return CurrentStackTrace(thr, 3);
65*68d75effSDimitry Andric }
66*68d75effSDimitry Andric 
67*68d75effSDimitry Andric static void InitializeFlags() {
68*68d75effSDimitry Andric   Flags *f = flags();
69*68d75effSDimitry Andric 
70*68d75effSDimitry Andric   // Default values.
71*68d75effSDimitry Andric   f->second_deadlock_stack = false;
72*68d75effSDimitry Andric 
73*68d75effSDimitry Andric   SetCommonFlagsDefaults();
74*68d75effSDimitry Andric   {
75*68d75effSDimitry Andric     // Override some common flags defaults.
76*68d75effSDimitry Andric     CommonFlags cf;
77*68d75effSDimitry Andric     cf.CopyFrom(*common_flags());
78*68d75effSDimitry Andric     cf.allow_addr2line = true;
79*68d75effSDimitry Andric     OverrideCommonFlags(cf);
80*68d75effSDimitry Andric   }
81*68d75effSDimitry Andric 
82*68d75effSDimitry Andric   // Override from command line.
83*68d75effSDimitry Andric   FlagParser parser;
84*68d75effSDimitry Andric   RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
85*68d75effSDimitry Andric   RegisterCommonFlags(&parser);
86*68d75effSDimitry Andric   parser.ParseStringFromEnv("DSAN_OPTIONS");
87*68d75effSDimitry Andric   SetVerbosity(common_flags()->verbosity);
88*68d75effSDimitry Andric }
89*68d75effSDimitry Andric 
90*68d75effSDimitry Andric void Initialize() {
91*68d75effSDimitry Andric   static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
92*68d75effSDimitry Andric   ctx = new(ctx_mem) Context();
93*68d75effSDimitry Andric 
94*68d75effSDimitry Andric   InitializeInterceptors();
95*68d75effSDimitry Andric   InitializeFlags();
96*68d75effSDimitry Andric   ctx->dd = DDetector::Create(flags());
97*68d75effSDimitry Andric }
98*68d75effSDimitry Andric 
99*68d75effSDimitry Andric void ThreadInit(Thread *thr) {
100*68d75effSDimitry Andric   static atomic_uintptr_t id_gen;
101*68d75effSDimitry Andric   uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
102*68d75effSDimitry Andric   thr->dd_pt = ctx->dd->CreatePhysicalThread();
103*68d75effSDimitry Andric   thr->dd_lt = ctx->dd->CreateLogicalThread(id);
104*68d75effSDimitry Andric }
105*68d75effSDimitry Andric 
106*68d75effSDimitry Andric void ThreadDestroy(Thread *thr) {
107*68d75effSDimitry Andric   ctx->dd->DestroyPhysicalThread(thr->dd_pt);
108*68d75effSDimitry Andric   ctx->dd->DestroyLogicalThread(thr->dd_lt);
109*68d75effSDimitry Andric }
110*68d75effSDimitry Andric 
111*68d75effSDimitry Andric void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
112*68d75effSDimitry Andric   if (thr->ignore_interceptors)
113*68d75effSDimitry Andric     return;
114*68d75effSDimitry Andric   Callback cb(thr);
115*68d75effSDimitry Andric   {
116*68d75effSDimitry Andric     MutexHashMap::Handle h(&ctx->mutex_map, m);
117*68d75effSDimitry Andric     if (h.created())
118*68d75effSDimitry Andric       ctx->dd->MutexInit(&cb, &h->dd);
119*68d75effSDimitry Andric     ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
120*68d75effSDimitry Andric   }
121*68d75effSDimitry Andric   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
122*68d75effSDimitry Andric }
123*68d75effSDimitry Andric 
124*68d75effSDimitry Andric void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
125*68d75effSDimitry Andric   if (thr->ignore_interceptors)
126*68d75effSDimitry Andric     return;
127*68d75effSDimitry Andric   Callback cb(thr);
128*68d75effSDimitry Andric   {
129*68d75effSDimitry Andric     MutexHashMap::Handle h(&ctx->mutex_map, m);
130*68d75effSDimitry Andric     if (h.created())
131*68d75effSDimitry Andric       ctx->dd->MutexInit(&cb, &h->dd);
132*68d75effSDimitry Andric     ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
133*68d75effSDimitry Andric   }
134*68d75effSDimitry Andric   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
135*68d75effSDimitry Andric }
136*68d75effSDimitry Andric 
137*68d75effSDimitry Andric void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
138*68d75effSDimitry Andric   if (thr->ignore_interceptors)
139*68d75effSDimitry Andric     return;
140*68d75effSDimitry Andric   Callback cb(thr);
141*68d75effSDimitry Andric   {
142*68d75effSDimitry Andric     MutexHashMap::Handle h(&ctx->mutex_map, m);
143*68d75effSDimitry Andric     ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
144*68d75effSDimitry Andric   }
145*68d75effSDimitry Andric   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
146*68d75effSDimitry Andric }
147*68d75effSDimitry Andric 
148*68d75effSDimitry Andric void MutexDestroy(Thread *thr, uptr m) {
149*68d75effSDimitry Andric   if (thr->ignore_interceptors)
150*68d75effSDimitry Andric     return;
151*68d75effSDimitry Andric   Callback cb(thr);
152*68d75effSDimitry Andric   MutexHashMap::Handle h(&ctx->mutex_map, m, true);
153*68d75effSDimitry Andric   if (!h.exists())
154*68d75effSDimitry Andric     return;
155*68d75effSDimitry Andric   ctx->dd->MutexDestroy(&cb, &h->dd);
156*68d75effSDimitry Andric }
157*68d75effSDimitry Andric 
158*68d75effSDimitry Andric }  // namespace __dsan
159