brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · 0ac6d32 Raw
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