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 17namespace __dsan { 18 19static Context *ctx; 20 21static 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 31static 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 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 68void 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 86void 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 96void 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 103void ThreadDestroy(Thread *thr) { 104 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 105 ctx->dd->DestroyLogicalThread(thr->dd_lt); 106} 107 108void 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 121void 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 134void 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 145void 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