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