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