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_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  StackTrace trace;
23  thr->ignore_interceptors = true;
24  trace.Unwind(1000, 0, 0, 0, 0, 0, false);
25  thr->ignore_interceptors = false;
26  if (trace.size <= skip)
27    return 0;
28  return StackDepotPut(trace.trace + skip, trace.size - skip);
29}
30
31static void PrintStackTrace(Thread *thr, u32 stk) {
32  uptr size = 0;
33  const uptr *trace = StackDepotGet(stk, &size);
34  thr->ignore_interceptors = true;
35  StackTrace::PrintStack(trace, size);
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
68void InitializeFlags(Flags *f, const char *env) {
69  internal_memset(f, 0, sizeof(*f));
70
71  // Default values.
72  f->second_deadlock_stack = false;
73
74  SetCommonFlagsDefaults(f);
75  // Override some common flags defaults.
76  f->allow_addr2line = true;
77
78  // Override from command line.
79  ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
80  ParseCommonFlagsFromString(f, env);
81
82  // Copy back to common flags.
83  *common_flags() = *f;
84}
85
86void Initialize() {
87  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
88  ctx = new(ctx_mem) Context();
89
90  InitializeInterceptors();
91  InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
92  common_flags()->symbolize = true;
93  ctx->dd = DDetector::Create(flags());
94}
95
96void ThreadInit(Thread *thr) {
97  static atomic_uintptr_t id_gen;
98  uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
99  thr->dd_pt = ctx->dd->CreatePhysicalThread();
100  thr->dd_lt = ctx->dd->CreateLogicalThread(id);
101}
102
103void ThreadDestroy(Thread *thr) {
104  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
105  ctx->dd->DestroyLogicalThread(thr->dd_lt);
106}
107
108void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
109  if (thr->ignore_interceptors)
110    return;
111  Callback cb(thr);
112  {
113    MutexHashMap::Handle h(&ctx->mutex_map, m);
114    if (h.created())
115      ctx->dd->MutexInit(&cb, &h->dd);
116    ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
117  }
118  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
119}
120
121void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
122  if (thr->ignore_interceptors)
123    return;
124  Callback cb(thr);
125  {
126    MutexHashMap::Handle h(&ctx->mutex_map, m);
127    if (h.created())
128      ctx->dd->MutexInit(&cb, &h->dd);
129    ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
130  }
131  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
132}
133
134void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
135  if (thr->ignore_interceptors)
136    return;
137  Callback cb(thr);
138  {
139    MutexHashMap::Handle h(&ctx->mutex_map, m);
140    ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
141  }
142  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
143}
144
145void MutexDestroy(Thread *thr, uptr m) {
146  if (thr->ignore_interceptors)
147    return;
148  Callback cb(thr);
149  MutexHashMap::Handle h(&ctx->mutex_map, m, true);
150  if (!h.exists())
151    return;
152  ctx->dd->MutexDestroy(&cb, &h->dd);
153}
154
155}  // namespace __dsan
156