159 lines · cpp
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-exception6//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 17namespace __dsan {18 19static Context *ctx;20 21static u32 CurrentStackTrace(Thread *thr, uptr skip) {22 UNINITIALIZED 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 31static 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 38static void ReportDeadlock(Thread *thr, DDReport *rep) {39 if (rep == 0)40 return;41 Lock 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 %lld 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 57Callback::Callback(Thread *thr)58 : thr(thr) {59 lt = thr->dd_lt;60 pt = thr->dd_pt;61}62 63u32 Callback::Unwind() {64 return CurrentStackTrace(thr, 3);65}66 67static 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 90void 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 99void 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 106void ThreadDestroy(Thread *thr) {107 ctx->dd->DestroyPhysicalThread(thr->dd_pt);108 ctx->dd->DestroyLogicalThread(thr->dd_lt);109}110 111void 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 124void 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 137void 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 148void 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 __dsan159