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 18namespace __dsan { 19 20static Context *ctx; 21 22static 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 32static 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 39static 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 58Callback::Callback(Thread *thr) 59 : thr(thr) { 60 lt = thr->dd_lt; 61 pt = thr->dd_pt; 62} 63 64u32 Callback::Unwind() { 65 return CurrentStackTrace(thr, 3); 66} 67 68static 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 91void 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 100void 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 107void ThreadDestroy(Thread *thr) { 108 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 109 ctx->dd->DestroyLogicalThread(thr->dd_lt); 110} 111 112void 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 125void 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 138void 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 149void 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