]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
Merge OpenSSL 1.0.1l.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / tsan / dd / dd_rtl.cc
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_stacktrace.h"
15 #include "sanitizer_common/sanitizer_stackdepot.h"
16
17 namespace __dsan {
18
19 static Context *ctx;
20
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)
27     return 0;
28   return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
29 }
30
31 static void PrintStackTrace(Thread *thr, u32 stk) {
32   StackTrace stack = StackDepotGet(stk);
33   thr->ignore_interceptors = true;
34   stack.Print();
35   thr->ignore_interceptors = false;
36 }
37
38 static void ReportDeadlock(Thread *thr, DDReport *rep) {
39   if (rep == 0)
40     return;
41   BlockingMutexLock 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 %d 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]);
52     }
53   }
54   Printf("==============================\n");
55 }
56
57 Callback::Callback(Thread *thr)
58     : thr(thr) {
59   lt = thr->dd_lt;
60   pt = thr->dd_pt;
61 }
62
63 u32 Callback::Unwind() {
64   return CurrentStackTrace(thr, 3);
65 }
66
67 void InitializeFlags(Flags *f, const char *env) {
68   internal_memset(f, 0, sizeof(*f));
69
70   // Default values.
71   f->second_deadlock_stack = false;
72
73   CommonFlags *cf = common_flags();
74   SetCommonFlagsDefaults(cf);
75   // Override some common flags defaults.
76   cf->allow_addr2line = true;
77
78   // Override from command line.
79   ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
80   ParseCommonFlagsFromString(cf, env);
81 }
82
83 void Initialize() {
84   static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
85   ctx = new(ctx_mem) Context();
86
87   InitializeInterceptors();
88   InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
89   ctx->dd = DDetector::Create(flags());
90 }
91
92 void ThreadInit(Thread *thr) {
93   static atomic_uintptr_t id_gen;
94   uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
95   thr->dd_pt = ctx->dd->CreatePhysicalThread();
96   thr->dd_lt = ctx->dd->CreateLogicalThread(id);
97 }
98
99 void ThreadDestroy(Thread *thr) {
100   ctx->dd->DestroyPhysicalThread(thr->dd_pt);
101   ctx->dd->DestroyLogicalThread(thr->dd_lt);
102 }
103
104 void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
105   if (thr->ignore_interceptors)
106     return;
107   Callback cb(thr);
108   {
109     MutexHashMap::Handle h(&ctx->mutex_map, m);
110     if (h.created())
111       ctx->dd->MutexInit(&cb, &h->dd);
112     ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
113   }
114   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
115 }
116
117 void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
118   if (thr->ignore_interceptors)
119     return;
120   Callback cb(thr);
121   {
122     MutexHashMap::Handle h(&ctx->mutex_map, m);
123     if (h.created())
124       ctx->dd->MutexInit(&cb, &h->dd);
125     ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
126   }
127   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
128 }
129
130 void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
131   if (thr->ignore_interceptors)
132     return;
133   Callback cb(thr);
134   {
135     MutexHashMap::Handle h(&ctx->mutex_map, m);
136     ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
137   }
138   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
139 }
140
141 void MutexDestroy(Thread *thr, uptr m) {
142   if (thr->ignore_interceptors)
143     return;
144   Callback cb(thr);
145   MutexHashMap::Handle h(&ctx->mutex_map, m, true);
146   if (!h.exists())
147     return;
148   ctx->dd->MutexDestroy(&cb, &h->dd);
149 }
150
151 }  // namespace __dsan