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