1*68d75effSDimitry Andric //===-- dd_rtl.cpp --------------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric 9*68d75effSDimitry Andric #include "dd_rtl.h" 10*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 11*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 12*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h" 13*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flag_parser.h" 14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h" 15*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 16*68d75effSDimitry Andric 17*68d75effSDimitry Andric namespace __dsan { 18*68d75effSDimitry Andric 19*68d75effSDimitry Andric static Context *ctx; 20*68d75effSDimitry Andric 21*68d75effSDimitry Andric static u32 CurrentStackTrace(Thread *thr, uptr skip) { 22*68d75effSDimitry Andric BufferedStackTrace stack; 23*68d75effSDimitry Andric thr->ignore_interceptors = true; 24*68d75effSDimitry Andric stack.Unwind(1000, 0, 0, 0, 0, 0, false); 25*68d75effSDimitry Andric thr->ignore_interceptors = false; 26*68d75effSDimitry Andric if (stack.size <= skip) 27*68d75effSDimitry Andric return 0; 28*68d75effSDimitry Andric return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip)); 29*68d75effSDimitry Andric } 30*68d75effSDimitry Andric 31*68d75effSDimitry Andric static void PrintStackTrace(Thread *thr, u32 stk) { 32*68d75effSDimitry Andric StackTrace stack = StackDepotGet(stk); 33*68d75effSDimitry Andric thr->ignore_interceptors = true; 34*68d75effSDimitry Andric stack.Print(); 35*68d75effSDimitry Andric thr->ignore_interceptors = false; 36*68d75effSDimitry Andric } 37*68d75effSDimitry Andric 38*68d75effSDimitry Andric static void ReportDeadlock(Thread *thr, DDReport *rep) { 39*68d75effSDimitry Andric if (rep == 0) 40*68d75effSDimitry Andric return; 41*68d75effSDimitry Andric BlockingMutexLock lock(&ctx->report_mutex); 42*68d75effSDimitry Andric Printf("==============================\n"); 43*68d75effSDimitry Andric Printf("WARNING: lock-order-inversion (potential deadlock)\n"); 44*68d75effSDimitry Andric for (int i = 0; i < rep->n; i++) { 45*68d75effSDimitry Andric Printf("Thread %d locks mutex %llu while holding mutex %llu:\n", 46*68d75effSDimitry Andric rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0); 47*68d75effSDimitry Andric PrintStackTrace(thr, rep->loop[i].stk[1]); 48*68d75effSDimitry Andric if (rep->loop[i].stk[0]) { 49*68d75effSDimitry Andric Printf("Mutex %llu was acquired here:\n", 50*68d75effSDimitry Andric rep->loop[i].mtx_ctx0); 51*68d75effSDimitry Andric PrintStackTrace(thr, rep->loop[i].stk[0]); 52*68d75effSDimitry Andric } 53*68d75effSDimitry Andric } 54*68d75effSDimitry Andric Printf("==============================\n"); 55*68d75effSDimitry Andric } 56*68d75effSDimitry Andric 57*68d75effSDimitry Andric Callback::Callback(Thread *thr) 58*68d75effSDimitry Andric : thr(thr) { 59*68d75effSDimitry Andric lt = thr->dd_lt; 60*68d75effSDimitry Andric pt = thr->dd_pt; 61*68d75effSDimitry Andric } 62*68d75effSDimitry Andric 63*68d75effSDimitry Andric u32 Callback::Unwind() { 64*68d75effSDimitry Andric return CurrentStackTrace(thr, 3); 65*68d75effSDimitry Andric } 66*68d75effSDimitry Andric 67*68d75effSDimitry Andric static void InitializeFlags() { 68*68d75effSDimitry Andric Flags *f = flags(); 69*68d75effSDimitry Andric 70*68d75effSDimitry Andric // Default values. 71*68d75effSDimitry Andric f->second_deadlock_stack = false; 72*68d75effSDimitry Andric 73*68d75effSDimitry Andric SetCommonFlagsDefaults(); 74*68d75effSDimitry Andric { 75*68d75effSDimitry Andric // Override some common flags defaults. 76*68d75effSDimitry Andric CommonFlags cf; 77*68d75effSDimitry Andric cf.CopyFrom(*common_flags()); 78*68d75effSDimitry Andric cf.allow_addr2line = true; 79*68d75effSDimitry Andric OverrideCommonFlags(cf); 80*68d75effSDimitry Andric } 81*68d75effSDimitry Andric 82*68d75effSDimitry Andric // Override from command line. 83*68d75effSDimitry Andric FlagParser parser; 84*68d75effSDimitry Andric RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack); 85*68d75effSDimitry Andric RegisterCommonFlags(&parser); 86*68d75effSDimitry Andric parser.ParseStringFromEnv("DSAN_OPTIONS"); 87*68d75effSDimitry Andric SetVerbosity(common_flags()->verbosity); 88*68d75effSDimitry Andric } 89*68d75effSDimitry Andric 90*68d75effSDimitry Andric void Initialize() { 91*68d75effSDimitry Andric static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1]; 92*68d75effSDimitry Andric ctx = new(ctx_mem) Context(); 93*68d75effSDimitry Andric 94*68d75effSDimitry Andric InitializeInterceptors(); 95*68d75effSDimitry Andric InitializeFlags(); 96*68d75effSDimitry Andric ctx->dd = DDetector::Create(flags()); 97*68d75effSDimitry Andric } 98*68d75effSDimitry Andric 99*68d75effSDimitry Andric void ThreadInit(Thread *thr) { 100*68d75effSDimitry Andric static atomic_uintptr_t id_gen; 101*68d75effSDimitry Andric uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed); 102*68d75effSDimitry Andric thr->dd_pt = ctx->dd->CreatePhysicalThread(); 103*68d75effSDimitry Andric thr->dd_lt = ctx->dd->CreateLogicalThread(id); 104*68d75effSDimitry Andric } 105*68d75effSDimitry Andric 106*68d75effSDimitry Andric void ThreadDestroy(Thread *thr) { 107*68d75effSDimitry Andric ctx->dd->DestroyPhysicalThread(thr->dd_pt); 108*68d75effSDimitry Andric ctx->dd->DestroyLogicalThread(thr->dd_lt); 109*68d75effSDimitry Andric } 110*68d75effSDimitry Andric 111*68d75effSDimitry Andric void MutexBeforeLock(Thread *thr, uptr m, bool writelock) { 112*68d75effSDimitry Andric if (thr->ignore_interceptors) 113*68d75effSDimitry Andric return; 114*68d75effSDimitry Andric Callback cb(thr); 115*68d75effSDimitry Andric { 116*68d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m); 117*68d75effSDimitry Andric if (h.created()) 118*68d75effSDimitry Andric ctx->dd->MutexInit(&cb, &h->dd); 119*68d75effSDimitry Andric ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock); 120*68d75effSDimitry Andric } 121*68d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 122*68d75effSDimitry Andric } 123*68d75effSDimitry Andric 124*68d75effSDimitry Andric void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) { 125*68d75effSDimitry Andric if (thr->ignore_interceptors) 126*68d75effSDimitry Andric return; 127*68d75effSDimitry Andric Callback cb(thr); 128*68d75effSDimitry Andric { 129*68d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m); 130*68d75effSDimitry Andric if (h.created()) 131*68d75effSDimitry Andric ctx->dd->MutexInit(&cb, &h->dd); 132*68d75effSDimitry Andric ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock); 133*68d75effSDimitry Andric } 134*68d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 135*68d75effSDimitry Andric } 136*68d75effSDimitry Andric 137*68d75effSDimitry Andric void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) { 138*68d75effSDimitry Andric if (thr->ignore_interceptors) 139*68d75effSDimitry Andric return; 140*68d75effSDimitry Andric Callback cb(thr); 141*68d75effSDimitry Andric { 142*68d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m); 143*68d75effSDimitry Andric ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock); 144*68d75effSDimitry Andric } 145*68d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb)); 146*68d75effSDimitry Andric } 147*68d75effSDimitry Andric 148*68d75effSDimitry Andric void MutexDestroy(Thread *thr, uptr m) { 149*68d75effSDimitry Andric if (thr->ignore_interceptors) 150*68d75effSDimitry Andric return; 151*68d75effSDimitry Andric Callback cb(thr); 152*68d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m, true); 153*68d75effSDimitry Andric if (!h.exists()) 154*68d75effSDimitry Andric return; 155*68d75effSDimitry Andric ctx->dd->MutexDestroy(&cb, &h->dd); 156*68d75effSDimitry Andric } 157*68d75effSDimitry Andric 158*68d75effSDimitry Andric } // namespace __dsan 159