blob: de9a58fa47d0c7d018dcc23b2b6cb28e2343e0fe [file] [log] [blame]
Dmitry Vyukov512a18e2014-02-28 14:52:20 +00001//===-- 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"
Dmitry Vyukov54a03032014-03-04 11:39:56 +000012#include "sanitizer_common/sanitizer_placement_new.h"
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000013#include "sanitizer_common/sanitizer_flags.h"
14#include "sanitizer_common/sanitizer_stacktrace.h"
15#include "sanitizer_common/sanitizer_stackdepot.h"
16
17namespace __dsan {
18
Dmitry Vyukov54a03032014-03-04 11:39:56 +000019static Context *ctx;
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000020
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000021static u32 CurrentStackTrace(Thread *thr, uptr skip) {
Alexey Samsonov6e7af812014-10-26 05:43:17 +000022 BufferedStackTrace trace;
Dmitry Vyukov54a03032014-03-04 11:39:56 +000023 thr->ignore_interceptors = true;
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000024 trace.Unwind(1000, 0, 0, 0, 0, 0, false);
Dmitry Vyukov54a03032014-03-04 11:39:56 +000025 thr->ignore_interceptors = false;
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000026 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) {
Alexey Samsonov6e7af812014-10-26 05:43:17 +000032 StackTrace stack = StackDepotGet(stk);
Dmitry Vyukov54a03032014-03-04 11:39:56 +000033 thr->ignore_interceptors = true;
Alexey Samsonov6e7af812014-10-26 05:43:17 +000034 stack.Print();
Dmitry Vyukov54a03032014-03-04 11:39:56 +000035 thr->ignore_interceptors = false;
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000036}
37
38static void ReportDeadlock(Thread *thr, DDReport *rep) {
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000039 if (rep == 0)
40 return;
Dmitry Vyukov51f5b5f2014-04-11 17:54:27 +000041 BlockingMutexLock lock(&ctx->report_mutex);
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000042 Printf("==============================\n");
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000043 Printf("WARNING: lock-order-inversion (potential deadlock)\n");
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000044 for (int i = 0; i < rep->n; i++) {
Dmitry Vyukov69bd9ca2014-03-06 12:02:17 +000045 Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000046 rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
Kostya Serebryanye7846202014-03-17 15:16:25 +000047 PrintStackTrace(thr, rep->loop[i].stk[1]);
Dmitry Vyukov3cd028c2014-03-18 13:13:47 +000048 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 }
Dmitry Vyukov512a18e2014-02-28 14:52:20 +000053 }
54 Printf("==============================\n");
55}
56
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000057Callback::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
Dmitry Vyukov3cd028c2014-03-18 13:13:47 +000067void InitializeFlags(Flags *f, const char *env) {
68 internal_memset(f, 0, sizeof(*f));
69
70 // Default values.
71 f->second_deadlock_stack = false;
72
73 SetCommonFlagsDefaults(f);
74 // Override some common flags defaults.
75 f->allow_addr2line = true;
76
77 // Override from command line.
Alexander Potapenko12964362014-03-20 12:52:52 +000078 ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
Dmitry Vyukov3cd028c2014-03-18 13:13:47 +000079 ParseCommonFlagsFromString(f, env);
80
81 // Copy back to common flags.
82 *common_flags() = *f;
83}
84
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000085void Initialize() {
86 static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
87 ctx = new(ctx_mem) Context();
88
89 InitializeInterceptors();
Dmitry Vyukov3cd028c2014-03-18 13:13:47 +000090 InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000091 common_flags()->symbolize = true;
Dmitry Vyukov3cd028c2014-03-18 13:13:47 +000092 ctx->dd = DDetector::Create(flags());
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +000093}
94
95void ThreadInit(Thread *thr) {
96 static atomic_uintptr_t id_gen;
97 uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
98 thr->dd_pt = ctx->dd->CreatePhysicalThread();
99 thr->dd_lt = ctx->dd->CreateLogicalThread(id);
100}
101
102void ThreadDestroy(Thread *thr) {
103 ctx->dd->DestroyPhysicalThread(thr->dd_pt);
104 ctx->dd->DestroyLogicalThread(thr->dd_lt);
105}
106
107void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000108 if (thr->ignore_interceptors)
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000109 return;
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000110 Callback cb(thr);
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000111 {
112 MutexHashMap::Handle h(&ctx->mutex_map, m);
113 if (h.created())
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000114 ctx->dd->MutexInit(&cb, &h->dd);
115 ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000116 }
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000117 ReportDeadlock(thr, ctx->dd->GetReport(&cb));
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000118}
119
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000120void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000121 if (thr->ignore_interceptors)
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000122 return;
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000123 Callback cb(thr);
124 {
125 MutexHashMap::Handle h(&ctx->mutex_map, m);
126 if (h.created())
127 ctx->dd->MutexInit(&cb, &h->dd);
128 ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
129 }
130 ReportDeadlock(thr, ctx->dd->GetReport(&cb));
131}
132
133void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
134 if (thr->ignore_interceptors)
135 return;
136 Callback cb(thr);
137 {
138 MutexHashMap::Handle h(&ctx->mutex_map, m);
139 ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
140 }
141 ReportDeadlock(thr, ctx->dd->GetReport(&cb));
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000142}
143
144void MutexDestroy(Thread *thr, uptr m) {
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000145 if (thr->ignore_interceptors)
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000146 return;
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000147 Callback cb(thr);
Dmitry Vyukov54a03032014-03-04 11:39:56 +0000148 MutexHashMap::Handle h(&ctx->mutex_map, m, true);
149 if (!h.exists())
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000150 return;
Dmitry Vyukov9b410fb2014-03-05 13:41:21 +0000151 ctx->dd->MutexDestroy(&cb, &h->dd);
Dmitry Vyukov512a18e2014-02-28 14:52:20 +0000152}
153
154} // namespace __dsan