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 StackTrace trace; 23 thr->ignore_interceptors = true; 24 trace.Unwind(1000, 0, 0, 0, 0, 0, false); 25 thr->ignore_interceptors = false; 26 if (trace.size <= skip) 27 return 0; 28 return StackDepotPut(trace.trace + skip, trace.size - skip); 29 } 30 31 static void PrintStackTrace(Thread *thr, u32 stk) { 32 uptr size = 0; 33 const uptr *trace = StackDepotGet(stk, &size); 34 thr->ignore_interceptors = true; 35 StackTrace::PrintStack(trace, size); 36 thr->ignore_interceptors = false; 37 } 38 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 58 Callback::Callback(Thread *thr) 59 : thr(thr) { 60 lt = thr->dd_lt; 61 pt = thr->dd_pt; 62 } 63 64 u32 Callback::Unwind() { 65 return CurrentStackTrace(thr, 3); 66 } 67 68 void InitializeFlags(Flags *f, const char *env) { 69 internal_memset(f, 0, sizeof(*f)); 70 71 // Default values. 72 f->second_deadlock_stack = false; 73 74 SetCommonFlagsDefaults(f); 75 // Override some common flags defaults. 76 f->allow_addr2line = true; 77 78 // Override from command line. 79 ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", ""); 80 ParseCommonFlagsFromString(f, env); 81 82 // Copy back to common flags. 83 *common_flags() = *f; 84 } 85 86 void Initialize() { 87 static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1]; 88 ctx = new(ctx_mem) Context(); 89 90 InitializeInterceptors(); 91 InitializeFlags(flags(), GetEnv("DSAN_OPTIONS")); 92 common_flags()->symbolize = true; 93 ctx->dd = DDetector::Create(flags()); 94 } 95 96 void ThreadInit(Thread *thr) { 97 static atomic_uintptr_t id_gen; 98 uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed); 99 thr->dd_pt = ctx->dd->CreatePhysicalThread(); 100 thr->dd_lt = ctx->dd->CreateLogicalThread(id); 101 } 102 103 void ThreadDestroy(Thread *thr) { 104 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 105 ctx->dd->DestroyLogicalThread(thr->dd_lt); 106 } 107 108 void MutexBeforeLock(Thread *thr, uptr m, bool writelock) { 109 if (thr->ignore_interceptors) 110 return; 111 Callback cb(thr); 112 { 113 MutexHashMap::Handle h(&ctx->mutex_map, m); 114 if (h.created()) 115 ctx->dd->MutexInit(&cb, &h->dd); 116 ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock); 117 } 118 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 119 } 120 121 void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) { 122 if (thr->ignore_interceptors) 123 return; 124 Callback cb(thr); 125 { 126 MutexHashMap::Handle h(&ctx->mutex_map, m); 127 if (h.created()) 128 ctx->dd->MutexInit(&cb, &h->dd); 129 ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock); 130 } 131 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 132 } 133 134 void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) { 135 if (thr->ignore_interceptors) 136 return; 137 Callback cb(thr); 138 { 139 MutexHashMap::Handle h(&ctx->mutex_map, m); 140 ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock); 141 } 142 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 143 } 144 145 void MutexDestroy(Thread *thr, uptr m) { 146 if (thr->ignore_interceptors) 147 return; 148 Callback cb(thr); 149 MutexHashMap::Handle h(&ctx->mutex_map, m, true); 150 if (!h.exists()) 151 return; 152 ctx->dd->MutexDestroy(&cb, &h->dd); 153 } 154 155 } // namespace __dsan 156