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 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 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 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 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 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 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 107 void ThreadDestroy(Thread *thr) { 108 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 109 ctx->dd->DestroyLogicalThread(thr->dd_lt); 110 } 111 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 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 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 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