xref: /openbsd-src/gnu/llvm/compiler-rt/lib/tsan/dd/dd_rtl.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- dd_rtl.cpp --------------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
93cab2bb3Spatrick #include "dd_rtl.h"
103cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
113cab2bb3Spatrick #include "sanitizer_common/sanitizer_placement_new.h"
123cab2bb3Spatrick #include "sanitizer_common/sanitizer_flags.h"
133cab2bb3Spatrick #include "sanitizer_common/sanitizer_flag_parser.h"
143cab2bb3Spatrick #include "sanitizer_common/sanitizer_stacktrace.h"
153cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
163cab2bb3Spatrick 
173cab2bb3Spatrick namespace __dsan {
183cab2bb3Spatrick 
193cab2bb3Spatrick static Context *ctx;
203cab2bb3Spatrick 
CurrentStackTrace(Thread * thr,uptr skip)213cab2bb3Spatrick static u32 CurrentStackTrace(Thread *thr, uptr skip) {
223cab2bb3Spatrick   BufferedStackTrace stack;
233cab2bb3Spatrick   thr->ignore_interceptors = true;
243cab2bb3Spatrick   stack.Unwind(1000, 0, 0, 0, 0, 0, false);
253cab2bb3Spatrick   thr->ignore_interceptors = false;
263cab2bb3Spatrick   if (stack.size <= skip)
273cab2bb3Spatrick     return 0;
283cab2bb3Spatrick   return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
293cab2bb3Spatrick }
303cab2bb3Spatrick 
PrintStackTrace(Thread * thr,u32 stk)313cab2bb3Spatrick static void PrintStackTrace(Thread *thr, u32 stk) {
323cab2bb3Spatrick   StackTrace stack = StackDepotGet(stk);
333cab2bb3Spatrick   thr->ignore_interceptors = true;
343cab2bb3Spatrick   stack.Print();
353cab2bb3Spatrick   thr->ignore_interceptors = false;
363cab2bb3Spatrick }
373cab2bb3Spatrick 
ReportDeadlock(Thread * thr,DDReport * rep)383cab2bb3Spatrick static void ReportDeadlock(Thread *thr, DDReport *rep) {
393cab2bb3Spatrick   if (rep == 0)
403cab2bb3Spatrick     return;
41*810390e3Srobert   Lock lock(&ctx->report_mutex);
423cab2bb3Spatrick   Printf("==============================\n");
433cab2bb3Spatrick   Printf("WARNING: lock-order-inversion (potential deadlock)\n");
443cab2bb3Spatrick   for (int i = 0; i < rep->n; i++) {
45*810390e3Srobert     Printf("Thread %lld locks mutex %llu while holding mutex %llu:\n",
463cab2bb3Spatrick            rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
473cab2bb3Spatrick     PrintStackTrace(thr, rep->loop[i].stk[1]);
483cab2bb3Spatrick     if (rep->loop[i].stk[0]) {
493cab2bb3Spatrick       Printf("Mutex %llu was acquired here:\n",
503cab2bb3Spatrick         rep->loop[i].mtx_ctx0);
513cab2bb3Spatrick       PrintStackTrace(thr, rep->loop[i].stk[0]);
523cab2bb3Spatrick     }
533cab2bb3Spatrick   }
543cab2bb3Spatrick   Printf("==============================\n");
553cab2bb3Spatrick }
563cab2bb3Spatrick 
Callback(Thread * thr)573cab2bb3Spatrick Callback::Callback(Thread *thr)
583cab2bb3Spatrick     : thr(thr) {
593cab2bb3Spatrick   lt = thr->dd_lt;
603cab2bb3Spatrick   pt = thr->dd_pt;
613cab2bb3Spatrick }
623cab2bb3Spatrick 
Unwind()633cab2bb3Spatrick u32 Callback::Unwind() {
643cab2bb3Spatrick   return CurrentStackTrace(thr, 3);
653cab2bb3Spatrick }
663cab2bb3Spatrick 
InitializeFlags()673cab2bb3Spatrick static void InitializeFlags() {
683cab2bb3Spatrick   Flags *f = flags();
693cab2bb3Spatrick 
703cab2bb3Spatrick   // Default values.
713cab2bb3Spatrick   f->second_deadlock_stack = false;
723cab2bb3Spatrick 
733cab2bb3Spatrick   SetCommonFlagsDefaults();
743cab2bb3Spatrick   {
753cab2bb3Spatrick     // Override some common flags defaults.
763cab2bb3Spatrick     CommonFlags cf;
773cab2bb3Spatrick     cf.CopyFrom(*common_flags());
783cab2bb3Spatrick     cf.allow_addr2line = true;
793cab2bb3Spatrick     OverrideCommonFlags(cf);
803cab2bb3Spatrick   }
813cab2bb3Spatrick 
823cab2bb3Spatrick   // Override from command line.
833cab2bb3Spatrick   FlagParser parser;
843cab2bb3Spatrick   RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
853cab2bb3Spatrick   RegisterCommonFlags(&parser);
863cab2bb3Spatrick   parser.ParseStringFromEnv("DSAN_OPTIONS");
873cab2bb3Spatrick   SetVerbosity(common_flags()->verbosity);
883cab2bb3Spatrick }
893cab2bb3Spatrick 
Initialize()903cab2bb3Spatrick void Initialize() {
913cab2bb3Spatrick   static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
923cab2bb3Spatrick   ctx = new(ctx_mem) Context();
933cab2bb3Spatrick 
943cab2bb3Spatrick   InitializeInterceptors();
953cab2bb3Spatrick   InitializeFlags();
963cab2bb3Spatrick   ctx->dd = DDetector::Create(flags());
973cab2bb3Spatrick }
983cab2bb3Spatrick 
ThreadInit(Thread * thr)993cab2bb3Spatrick void ThreadInit(Thread *thr) {
1003cab2bb3Spatrick   static atomic_uintptr_t id_gen;
1013cab2bb3Spatrick   uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
1023cab2bb3Spatrick   thr->dd_pt = ctx->dd->CreatePhysicalThread();
1033cab2bb3Spatrick   thr->dd_lt = ctx->dd->CreateLogicalThread(id);
1043cab2bb3Spatrick }
1053cab2bb3Spatrick 
ThreadDestroy(Thread * thr)1063cab2bb3Spatrick void ThreadDestroy(Thread *thr) {
1073cab2bb3Spatrick   ctx->dd->DestroyPhysicalThread(thr->dd_pt);
1083cab2bb3Spatrick   ctx->dd->DestroyLogicalThread(thr->dd_lt);
1093cab2bb3Spatrick }
1103cab2bb3Spatrick 
MutexBeforeLock(Thread * thr,uptr m,bool writelock)1113cab2bb3Spatrick void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
1123cab2bb3Spatrick   if (thr->ignore_interceptors)
1133cab2bb3Spatrick     return;
1143cab2bb3Spatrick   Callback cb(thr);
1153cab2bb3Spatrick   {
1163cab2bb3Spatrick     MutexHashMap::Handle h(&ctx->mutex_map, m);
1173cab2bb3Spatrick     if (h.created())
1183cab2bb3Spatrick       ctx->dd->MutexInit(&cb, &h->dd);
1193cab2bb3Spatrick     ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
1203cab2bb3Spatrick   }
1213cab2bb3Spatrick   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1223cab2bb3Spatrick }
1233cab2bb3Spatrick 
MutexAfterLock(Thread * thr,uptr m,bool writelock,bool trylock)1243cab2bb3Spatrick void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
1253cab2bb3Spatrick   if (thr->ignore_interceptors)
1263cab2bb3Spatrick     return;
1273cab2bb3Spatrick   Callback cb(thr);
1283cab2bb3Spatrick   {
1293cab2bb3Spatrick     MutexHashMap::Handle h(&ctx->mutex_map, m);
1303cab2bb3Spatrick     if (h.created())
1313cab2bb3Spatrick       ctx->dd->MutexInit(&cb, &h->dd);
1323cab2bb3Spatrick     ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
1333cab2bb3Spatrick   }
1343cab2bb3Spatrick   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1353cab2bb3Spatrick }
1363cab2bb3Spatrick 
MutexBeforeUnlock(Thread * thr,uptr m,bool writelock)1373cab2bb3Spatrick void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
1383cab2bb3Spatrick   if (thr->ignore_interceptors)
1393cab2bb3Spatrick     return;
1403cab2bb3Spatrick   Callback cb(thr);
1413cab2bb3Spatrick   {
1423cab2bb3Spatrick     MutexHashMap::Handle h(&ctx->mutex_map, m);
1433cab2bb3Spatrick     ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
1443cab2bb3Spatrick   }
1453cab2bb3Spatrick   ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1463cab2bb3Spatrick }
1473cab2bb3Spatrick 
MutexDestroy(Thread * thr,uptr m)1483cab2bb3Spatrick void MutexDestroy(Thread *thr, uptr m) {
1493cab2bb3Spatrick   if (thr->ignore_interceptors)
1503cab2bb3Spatrick     return;
1513cab2bb3Spatrick   Callback cb(thr);
1523cab2bb3Spatrick   MutexHashMap::Handle h(&ctx->mutex_map, m, true);
1533cab2bb3Spatrick   if (!h.exists())
1543cab2bb3Spatrick     return;
1553cab2bb3Spatrick   ctx->dd->MutexDestroy(&cb, &h->dd);
1563cab2bb3Spatrick }
1573cab2bb3Spatrick 
1583cab2bb3Spatrick }  // namespace __dsan
159