168d75effSDimitry Andric //===-- dd_rtl.cpp --------------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric
968d75effSDimitry Andric #include "dd_rtl.h"
1068d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1168d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
1268d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
1368d75effSDimitry Andric #include "sanitizer_common/sanitizer_flag_parser.h"
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
1668d75effSDimitry Andric
1768d75effSDimitry Andric namespace __dsan {
1868d75effSDimitry Andric
1968d75effSDimitry Andric static Context *ctx;
2068d75effSDimitry Andric
CurrentStackTrace(Thread * thr,uptr skip)2168d75effSDimitry Andric static u32 CurrentStackTrace(Thread *thr, uptr skip) {
2268d75effSDimitry Andric BufferedStackTrace stack;
2368d75effSDimitry Andric thr->ignore_interceptors = true;
2468d75effSDimitry Andric stack.Unwind(1000, 0, 0, 0, 0, 0, false);
2568d75effSDimitry Andric thr->ignore_interceptors = false;
2668d75effSDimitry Andric if (stack.size <= skip)
2768d75effSDimitry Andric return 0;
2868d75effSDimitry Andric return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
2968d75effSDimitry Andric }
3068d75effSDimitry Andric
PrintStackTrace(Thread * thr,u32 stk)3168d75effSDimitry Andric static void PrintStackTrace(Thread *thr, u32 stk) {
3268d75effSDimitry Andric StackTrace stack = StackDepotGet(stk);
3368d75effSDimitry Andric thr->ignore_interceptors = true;
3468d75effSDimitry Andric stack.Print();
3568d75effSDimitry Andric thr->ignore_interceptors = false;
3668d75effSDimitry Andric }
3768d75effSDimitry Andric
ReportDeadlock(Thread * thr,DDReport * rep)3868d75effSDimitry Andric static void ReportDeadlock(Thread *thr, DDReport *rep) {
3968d75effSDimitry Andric if (rep == 0)
4068d75effSDimitry Andric return;
41*349cc55cSDimitry Andric Lock lock(&ctx->report_mutex);
4268d75effSDimitry Andric Printf("==============================\n");
4368d75effSDimitry Andric Printf("WARNING: lock-order-inversion (potential deadlock)\n");
4468d75effSDimitry Andric for (int i = 0; i < rep->n; i++) {
45*349cc55cSDimitry Andric Printf("Thread %lld locks mutex %llu while holding mutex %llu:\n",
4668d75effSDimitry Andric rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
4768d75effSDimitry Andric PrintStackTrace(thr, rep->loop[i].stk[1]);
4868d75effSDimitry Andric if (rep->loop[i].stk[0]) {
4968d75effSDimitry Andric Printf("Mutex %llu was acquired here:\n",
5068d75effSDimitry Andric rep->loop[i].mtx_ctx0);
5168d75effSDimitry Andric PrintStackTrace(thr, rep->loop[i].stk[0]);
5268d75effSDimitry Andric }
5368d75effSDimitry Andric }
5468d75effSDimitry Andric Printf("==============================\n");
5568d75effSDimitry Andric }
5668d75effSDimitry Andric
Callback(Thread * thr)5768d75effSDimitry Andric Callback::Callback(Thread *thr)
5868d75effSDimitry Andric : thr(thr) {
5968d75effSDimitry Andric lt = thr->dd_lt;
6068d75effSDimitry Andric pt = thr->dd_pt;
6168d75effSDimitry Andric }
6268d75effSDimitry Andric
Unwind()6368d75effSDimitry Andric u32 Callback::Unwind() {
6468d75effSDimitry Andric return CurrentStackTrace(thr, 3);
6568d75effSDimitry Andric }
6668d75effSDimitry Andric
InitializeFlags()6768d75effSDimitry Andric static void InitializeFlags() {
6868d75effSDimitry Andric Flags *f = flags();
6968d75effSDimitry Andric
7068d75effSDimitry Andric // Default values.
7168d75effSDimitry Andric f->second_deadlock_stack = false;
7268d75effSDimitry Andric
7368d75effSDimitry Andric SetCommonFlagsDefaults();
7468d75effSDimitry Andric {
7568d75effSDimitry Andric // Override some common flags defaults.
7668d75effSDimitry Andric CommonFlags cf;
7768d75effSDimitry Andric cf.CopyFrom(*common_flags());
7868d75effSDimitry Andric cf.allow_addr2line = true;
7968d75effSDimitry Andric OverrideCommonFlags(cf);
8068d75effSDimitry Andric }
8168d75effSDimitry Andric
8268d75effSDimitry Andric // Override from command line.
8368d75effSDimitry Andric FlagParser parser;
8468d75effSDimitry Andric RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
8568d75effSDimitry Andric RegisterCommonFlags(&parser);
8668d75effSDimitry Andric parser.ParseStringFromEnv("DSAN_OPTIONS");
8768d75effSDimitry Andric SetVerbosity(common_flags()->verbosity);
8868d75effSDimitry Andric }
8968d75effSDimitry Andric
Initialize()9068d75effSDimitry Andric void Initialize() {
9168d75effSDimitry Andric static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
9268d75effSDimitry Andric ctx = new(ctx_mem) Context();
9368d75effSDimitry Andric
9468d75effSDimitry Andric InitializeInterceptors();
9568d75effSDimitry Andric InitializeFlags();
9668d75effSDimitry Andric ctx->dd = DDetector::Create(flags());
9768d75effSDimitry Andric }
9868d75effSDimitry Andric
ThreadInit(Thread * thr)9968d75effSDimitry Andric void ThreadInit(Thread *thr) {
10068d75effSDimitry Andric static atomic_uintptr_t id_gen;
10168d75effSDimitry Andric uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
10268d75effSDimitry Andric thr->dd_pt = ctx->dd->CreatePhysicalThread();
10368d75effSDimitry Andric thr->dd_lt = ctx->dd->CreateLogicalThread(id);
10468d75effSDimitry Andric }
10568d75effSDimitry Andric
ThreadDestroy(Thread * thr)10668d75effSDimitry Andric void ThreadDestroy(Thread *thr) {
10768d75effSDimitry Andric ctx->dd->DestroyPhysicalThread(thr->dd_pt);
10868d75effSDimitry Andric ctx->dd->DestroyLogicalThread(thr->dd_lt);
10968d75effSDimitry Andric }
11068d75effSDimitry Andric
MutexBeforeLock(Thread * thr,uptr m,bool writelock)11168d75effSDimitry Andric void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
11268d75effSDimitry Andric if (thr->ignore_interceptors)
11368d75effSDimitry Andric return;
11468d75effSDimitry Andric Callback cb(thr);
11568d75effSDimitry Andric {
11668d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m);
11768d75effSDimitry Andric if (h.created())
11868d75effSDimitry Andric ctx->dd->MutexInit(&cb, &h->dd);
11968d75effSDimitry Andric ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
12068d75effSDimitry Andric }
12168d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb));
12268d75effSDimitry Andric }
12368d75effSDimitry Andric
MutexAfterLock(Thread * thr,uptr m,bool writelock,bool trylock)12468d75effSDimitry Andric void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
12568d75effSDimitry Andric if (thr->ignore_interceptors)
12668d75effSDimitry Andric return;
12768d75effSDimitry Andric Callback cb(thr);
12868d75effSDimitry Andric {
12968d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m);
13068d75effSDimitry Andric if (h.created())
13168d75effSDimitry Andric ctx->dd->MutexInit(&cb, &h->dd);
13268d75effSDimitry Andric ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
13368d75effSDimitry Andric }
13468d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb));
13568d75effSDimitry Andric }
13668d75effSDimitry Andric
MutexBeforeUnlock(Thread * thr,uptr m,bool writelock)13768d75effSDimitry Andric void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
13868d75effSDimitry Andric if (thr->ignore_interceptors)
13968d75effSDimitry Andric return;
14068d75effSDimitry Andric Callback cb(thr);
14168d75effSDimitry Andric {
14268d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m);
14368d75effSDimitry Andric ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
14468d75effSDimitry Andric }
14568d75effSDimitry Andric ReportDeadlock(thr, ctx->dd->GetReport(&cb));
14668d75effSDimitry Andric }
14768d75effSDimitry Andric
MutexDestroy(Thread * thr,uptr m)14868d75effSDimitry Andric void MutexDestroy(Thread *thr, uptr m) {
14968d75effSDimitry Andric if (thr->ignore_interceptors)
15068d75effSDimitry Andric return;
15168d75effSDimitry Andric Callback cb(thr);
15268d75effSDimitry Andric MutexHashMap::Handle h(&ctx->mutex_map, m, true);
15368d75effSDimitry Andric if (!h.exists())
15468d75effSDimitry Andric return;
15568d75effSDimitry Andric ctx->dd->MutexDestroy(&cb, &h->dd);
15668d75effSDimitry Andric }
15768d75effSDimitry Andric
15868d75effSDimitry Andric } // namespace __dsan
159