1*7c3d14c8STreehugger Robot //===-- dd_rtl.cc ---------------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot
10*7c3d14c8STreehugger Robot #include "dd_rtl.h"
11*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
12*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
13*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_flags.h"
14*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_flag_parser.h"
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stacktrace.h"
16*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stackdepot.h"
17*7c3d14c8STreehugger Robot
18*7c3d14c8STreehugger Robot namespace __dsan {
19*7c3d14c8STreehugger Robot
20*7c3d14c8STreehugger Robot static Context *ctx;
21*7c3d14c8STreehugger Robot
CurrentStackTrace(Thread * thr,uptr skip)22*7c3d14c8STreehugger Robot static u32 CurrentStackTrace(Thread *thr, uptr skip) {
23*7c3d14c8STreehugger Robot BufferedStackTrace stack;
24*7c3d14c8STreehugger Robot thr->ignore_interceptors = true;
25*7c3d14c8STreehugger Robot stack.Unwind(1000, 0, 0, 0, 0, 0, false);
26*7c3d14c8STreehugger Robot thr->ignore_interceptors = false;
27*7c3d14c8STreehugger Robot if (stack.size <= skip)
28*7c3d14c8STreehugger Robot return 0;
29*7c3d14c8STreehugger Robot return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
30*7c3d14c8STreehugger Robot }
31*7c3d14c8STreehugger Robot
PrintStackTrace(Thread * thr,u32 stk)32*7c3d14c8STreehugger Robot static void PrintStackTrace(Thread *thr, u32 stk) {
33*7c3d14c8STreehugger Robot StackTrace stack = StackDepotGet(stk);
34*7c3d14c8STreehugger Robot thr->ignore_interceptors = true;
35*7c3d14c8STreehugger Robot stack.Print();
36*7c3d14c8STreehugger Robot thr->ignore_interceptors = false;
37*7c3d14c8STreehugger Robot }
38*7c3d14c8STreehugger Robot
ReportDeadlock(Thread * thr,DDReport * rep)39*7c3d14c8STreehugger Robot static void ReportDeadlock(Thread *thr, DDReport *rep) {
40*7c3d14c8STreehugger Robot if (rep == 0)
41*7c3d14c8STreehugger Robot return;
42*7c3d14c8STreehugger Robot BlockingMutexLock lock(&ctx->report_mutex);
43*7c3d14c8STreehugger Robot Printf("==============================\n");
44*7c3d14c8STreehugger Robot Printf("WARNING: lock-order-inversion (potential deadlock)\n");
45*7c3d14c8STreehugger Robot for (int i = 0; i < rep->n; i++) {
46*7c3d14c8STreehugger Robot Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
47*7c3d14c8STreehugger Robot rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
48*7c3d14c8STreehugger Robot PrintStackTrace(thr, rep->loop[i].stk[1]);
49*7c3d14c8STreehugger Robot if (rep->loop[i].stk[0]) {
50*7c3d14c8STreehugger Robot Printf("Mutex %llu was acquired here:\n",
51*7c3d14c8STreehugger Robot rep->loop[i].mtx_ctx0);
52*7c3d14c8STreehugger Robot PrintStackTrace(thr, rep->loop[i].stk[0]);
53*7c3d14c8STreehugger Robot }
54*7c3d14c8STreehugger Robot }
55*7c3d14c8STreehugger Robot Printf("==============================\n");
56*7c3d14c8STreehugger Robot }
57*7c3d14c8STreehugger Robot
Callback(Thread * thr)58*7c3d14c8STreehugger Robot Callback::Callback(Thread *thr)
59*7c3d14c8STreehugger Robot : thr(thr) {
60*7c3d14c8STreehugger Robot lt = thr->dd_lt;
61*7c3d14c8STreehugger Robot pt = thr->dd_pt;
62*7c3d14c8STreehugger Robot }
63*7c3d14c8STreehugger Robot
Unwind()64*7c3d14c8STreehugger Robot u32 Callback::Unwind() {
65*7c3d14c8STreehugger Robot return CurrentStackTrace(thr, 3);
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot
InitializeFlags()68*7c3d14c8STreehugger Robot static void InitializeFlags() {
69*7c3d14c8STreehugger Robot Flags *f = flags();
70*7c3d14c8STreehugger Robot
71*7c3d14c8STreehugger Robot // Default values.
72*7c3d14c8STreehugger Robot f->second_deadlock_stack = false;
73*7c3d14c8STreehugger Robot
74*7c3d14c8STreehugger Robot SetCommonFlagsDefaults();
75*7c3d14c8STreehugger Robot {
76*7c3d14c8STreehugger Robot // Override some common flags defaults.
77*7c3d14c8STreehugger Robot CommonFlags cf;
78*7c3d14c8STreehugger Robot cf.CopyFrom(*common_flags());
79*7c3d14c8STreehugger Robot cf.allow_addr2line = true;
80*7c3d14c8STreehugger Robot OverrideCommonFlags(cf);
81*7c3d14c8STreehugger Robot }
82*7c3d14c8STreehugger Robot
83*7c3d14c8STreehugger Robot // Override from command line.
84*7c3d14c8STreehugger Robot FlagParser parser;
85*7c3d14c8STreehugger Robot RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
86*7c3d14c8STreehugger Robot RegisterCommonFlags(&parser);
87*7c3d14c8STreehugger Robot parser.ParseString(GetEnv("DSAN_OPTIONS"));
88*7c3d14c8STreehugger Robot SetVerbosity(common_flags()->verbosity);
89*7c3d14c8STreehugger Robot }
90*7c3d14c8STreehugger Robot
Initialize()91*7c3d14c8STreehugger Robot void Initialize() {
92*7c3d14c8STreehugger Robot static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
93*7c3d14c8STreehugger Robot ctx = new(ctx_mem) Context();
94*7c3d14c8STreehugger Robot
95*7c3d14c8STreehugger Robot InitializeInterceptors();
96*7c3d14c8STreehugger Robot InitializeFlags();
97*7c3d14c8STreehugger Robot ctx->dd = DDetector::Create(flags());
98*7c3d14c8STreehugger Robot }
99*7c3d14c8STreehugger Robot
ThreadInit(Thread * thr)100*7c3d14c8STreehugger Robot void ThreadInit(Thread *thr) {
101*7c3d14c8STreehugger Robot static atomic_uintptr_t id_gen;
102*7c3d14c8STreehugger Robot uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
103*7c3d14c8STreehugger Robot thr->dd_pt = ctx->dd->CreatePhysicalThread();
104*7c3d14c8STreehugger Robot thr->dd_lt = ctx->dd->CreateLogicalThread(id);
105*7c3d14c8STreehugger Robot }
106*7c3d14c8STreehugger Robot
ThreadDestroy(Thread * thr)107*7c3d14c8STreehugger Robot void ThreadDestroy(Thread *thr) {
108*7c3d14c8STreehugger Robot ctx->dd->DestroyPhysicalThread(thr->dd_pt);
109*7c3d14c8STreehugger Robot ctx->dd->DestroyLogicalThread(thr->dd_lt);
110*7c3d14c8STreehugger Robot }
111*7c3d14c8STreehugger Robot
MutexBeforeLock(Thread * thr,uptr m,bool writelock)112*7c3d14c8STreehugger Robot void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
113*7c3d14c8STreehugger Robot if (thr->ignore_interceptors)
114*7c3d14c8STreehugger Robot return;
115*7c3d14c8STreehugger Robot Callback cb(thr);
116*7c3d14c8STreehugger Robot {
117*7c3d14c8STreehugger Robot MutexHashMap::Handle h(&ctx->mutex_map, m);
118*7c3d14c8STreehugger Robot if (h.created())
119*7c3d14c8STreehugger Robot ctx->dd->MutexInit(&cb, &h->dd);
120*7c3d14c8STreehugger Robot ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
121*7c3d14c8STreehugger Robot }
122*7c3d14c8STreehugger Robot ReportDeadlock(thr, ctx->dd->GetReport(&cb));
123*7c3d14c8STreehugger Robot }
124*7c3d14c8STreehugger Robot
MutexAfterLock(Thread * thr,uptr m,bool writelock,bool trylock)125*7c3d14c8STreehugger Robot void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
126*7c3d14c8STreehugger Robot if (thr->ignore_interceptors)
127*7c3d14c8STreehugger Robot return;
128*7c3d14c8STreehugger Robot Callback cb(thr);
129*7c3d14c8STreehugger Robot {
130*7c3d14c8STreehugger Robot MutexHashMap::Handle h(&ctx->mutex_map, m);
131*7c3d14c8STreehugger Robot if (h.created())
132*7c3d14c8STreehugger Robot ctx->dd->MutexInit(&cb, &h->dd);
133*7c3d14c8STreehugger Robot ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
134*7c3d14c8STreehugger Robot }
135*7c3d14c8STreehugger Robot ReportDeadlock(thr, ctx->dd->GetReport(&cb));
136*7c3d14c8STreehugger Robot }
137*7c3d14c8STreehugger Robot
MutexBeforeUnlock(Thread * thr,uptr m,bool writelock)138*7c3d14c8STreehugger Robot void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
139*7c3d14c8STreehugger Robot if (thr->ignore_interceptors)
140*7c3d14c8STreehugger Robot return;
141*7c3d14c8STreehugger Robot Callback cb(thr);
142*7c3d14c8STreehugger Robot {
143*7c3d14c8STreehugger Robot MutexHashMap::Handle h(&ctx->mutex_map, m);
144*7c3d14c8STreehugger Robot ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
145*7c3d14c8STreehugger Robot }
146*7c3d14c8STreehugger Robot ReportDeadlock(thr, ctx->dd->GetReport(&cb));
147*7c3d14c8STreehugger Robot }
148*7c3d14c8STreehugger Robot
MutexDestroy(Thread * thr,uptr m)149*7c3d14c8STreehugger Robot void MutexDestroy(Thread *thr, uptr m) {
150*7c3d14c8STreehugger Robot if (thr->ignore_interceptors)
151*7c3d14c8STreehugger Robot return;
152*7c3d14c8STreehugger Robot Callback cb(thr);
153*7c3d14c8STreehugger Robot MutexHashMap::Handle h(&ctx->mutex_map, m, true);
154*7c3d14c8STreehugger Robot if (!h.exists())
155*7c3d14c8STreehugger Robot return;
156*7c3d14c8STreehugger Robot ctx->dd->MutexDestroy(&cb, &h->dd);
157*7c3d14c8STreehugger Robot }
158*7c3d14c8STreehugger Robot
159*7c3d14c8STreehugger Robot } // namespace __dsan
160