1 //===-- dd_rtl.cpp --------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "dd_rtl.h" 10 #include "sanitizer_common/sanitizer_common.h" 11 #include "sanitizer_common/sanitizer_placement_new.h" 12 #include "sanitizer_common/sanitizer_flags.h" 13 #include "sanitizer_common/sanitizer_flag_parser.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 static void InitializeFlags() { 68 Flags *f = flags(); 69 70 // Default values. 71 f->second_deadlock_stack = false; 72 73 SetCommonFlagsDefaults(); 74 { 75 // Override some common flags defaults. 76 CommonFlags cf; 77 cf.CopyFrom(*common_flags()); 78 cf.allow_addr2line = true; 79 OverrideCommonFlags(cf); 80 } 81 82 // Override from command line. 83 FlagParser parser; 84 RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack); 85 RegisterCommonFlags(&parser); 86 parser.ParseStringFromEnv("DSAN_OPTIONS"); 87 SetVerbosity(common_flags()->verbosity); 88 } 89 90 void Initialize() { 91 static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1]; 92 ctx = new(ctx_mem) Context(); 93 94 InitializeInterceptors(); 95 InitializeFlags(); 96 ctx->dd = DDetector::Create(flags()); 97 } 98 99 void ThreadInit(Thread *thr) { 100 static atomic_uintptr_t id_gen; 101 uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed); 102 thr->dd_pt = ctx->dd->CreatePhysicalThread(); 103 thr->dd_lt = ctx->dd->CreateLogicalThread(id); 104 } 105 106 void ThreadDestroy(Thread *thr) { 107 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 108 ctx->dd->DestroyLogicalThread(thr->dd_lt); 109 } 110 111 void MutexBeforeLock(Thread *thr, uptr m, bool writelock) { 112 if (thr->ignore_interceptors) 113 return; 114 Callback cb(thr); 115 { 116 MutexHashMap::Handle h(&ctx->mutex_map, m); 117 if (h.created()) 118 ctx->dd->MutexInit(&cb, &h->dd); 119 ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock); 120 } 121 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 122 } 123 124 void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) { 125 if (thr->ignore_interceptors) 126 return; 127 Callback cb(thr); 128 { 129 MutexHashMap::Handle h(&ctx->mutex_map, m); 130 if (h.created()) 131 ctx->dd->MutexInit(&cb, &h->dd); 132 ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock); 133 } 134 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 135 } 136 137 void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) { 138 if (thr->ignore_interceptors) 139 return; 140 Callback cb(thr); 141 { 142 MutexHashMap::Handle h(&ctx->mutex_map, m); 143 ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock); 144 } 145 ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 146 } 147 148 void MutexDestroy(Thread *thr, uptr m) { 149 if (thr->ignore_interceptors) 150 return; 151 Callback cb(thr); 152 MutexHashMap::Handle h(&ctx->mutex_map, m, true); 153 if (!h.exists()) 154 return; 155 ctx->dd->MutexDestroy(&cb, &h->dd); 156 } 157 158 } // namespace __dsan 159