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
18namespace __dsan {
19
20static Context *ctx;
21
22static 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
32static 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
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
68static 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
91void 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
100void 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
107void ThreadDestroy(Thread *thr) {
108  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
109  ctx->dd->DestroyLogicalThread(thr->dd_lt);
110}
111
112void 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
125void 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
138void 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
149void 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