xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/dd/dd_rtl.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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