xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_debugging.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
168d75effSDimitry Andric //===-- tsan_debugging.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 // This file is a part of ThreadSanitizer (TSan), a race detector.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // TSan debugging API implementation.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric #include "tsan_interface.h"
1468d75effSDimitry Andric #include "tsan_report.h"
1568d75effSDimitry Andric #include "tsan_rtl.h"
1668d75effSDimitry Andric 
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
1868d75effSDimitry Andric 
1968d75effSDimitry Andric using namespace __tsan;
2068d75effSDimitry Andric 
2168d75effSDimitry Andric static const char *ReportTypeDescription(ReportType typ) {
2268d75effSDimitry Andric   switch (typ) {
2368d75effSDimitry Andric     case ReportTypeRace: return "data-race";
2468d75effSDimitry Andric     case ReportTypeVptrRace: return "data-race-vptr";
2568d75effSDimitry Andric     case ReportTypeUseAfterFree: return "heap-use-after-free";
2668d75effSDimitry Andric     case ReportTypeVptrUseAfterFree: return "heap-use-after-free-vptr";
2768d75effSDimitry Andric     case ReportTypeExternalRace: return "external-race";
2868d75effSDimitry Andric     case ReportTypeThreadLeak: return "thread-leak";
2968d75effSDimitry Andric     case ReportTypeMutexDestroyLocked: return "locked-mutex-destroy";
3068d75effSDimitry Andric     case ReportTypeMutexDoubleLock: return "mutex-double-lock";
3168d75effSDimitry Andric     case ReportTypeMutexInvalidAccess: return "mutex-invalid-access";
3268d75effSDimitry Andric     case ReportTypeMutexBadUnlock: return "mutex-bad-unlock";
3368d75effSDimitry Andric     case ReportTypeMutexBadReadLock: return "mutex-bad-read-lock";
3468d75effSDimitry Andric     case ReportTypeMutexBadReadUnlock: return "mutex-bad-read-unlock";
3568d75effSDimitry Andric     case ReportTypeSignalUnsafe: return "signal-unsafe-call";
3668d75effSDimitry Andric     case ReportTypeErrnoInSignal: return "errno-in-signal-handler";
3768d75effSDimitry Andric     case ReportTypeDeadlock: return "lock-order-inversion";
3868d75effSDimitry Andric     // No default case so compiler warns us if we miss one
3968d75effSDimitry Andric   }
4068d75effSDimitry Andric   UNREACHABLE("missing case");
4168d75effSDimitry Andric }
4268d75effSDimitry Andric 
4368d75effSDimitry Andric static const char *ReportLocationTypeDescription(ReportLocationType typ) {
4468d75effSDimitry Andric   switch (typ) {
4568d75effSDimitry Andric     case ReportLocationGlobal: return "global";
4668d75effSDimitry Andric     case ReportLocationHeap: return "heap";
4768d75effSDimitry Andric     case ReportLocationStack: return "stack";
4868d75effSDimitry Andric     case ReportLocationTLS: return "tls";
4968d75effSDimitry Andric     case ReportLocationFD: return "fd";
5068d75effSDimitry Andric     // No default case so compiler warns us if we miss one
5168d75effSDimitry Andric   }
5268d75effSDimitry Andric   UNREACHABLE("missing case");
5368d75effSDimitry Andric }
5468d75effSDimitry Andric 
5568d75effSDimitry Andric static void CopyTrace(SymbolizedStack *first_frame, void **trace,
5668d75effSDimitry Andric                       uptr trace_size) {
5768d75effSDimitry Andric   uptr i = 0;
5868d75effSDimitry Andric   for (SymbolizedStack *frame = first_frame; frame != nullptr;
5968d75effSDimitry Andric        frame = frame->next) {
6068d75effSDimitry Andric     trace[i++] = (void *)frame->info.address;
6168d75effSDimitry Andric     if (i >= trace_size) break;
6268d75effSDimitry Andric   }
6368d75effSDimitry Andric }
6468d75effSDimitry Andric 
6568d75effSDimitry Andric // Meant to be called by the debugger.
6668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
6768d75effSDimitry Andric void *__tsan_get_current_report() {
6868d75effSDimitry Andric   return const_cast<ReportDesc*>(cur_thread()->current_report);
6968d75effSDimitry Andric }
7068d75effSDimitry Andric 
7168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
7268d75effSDimitry Andric int __tsan_get_report_data(void *report, const char **description, int *count,
7368d75effSDimitry Andric                            int *stack_count, int *mop_count, int *loc_count,
7468d75effSDimitry Andric                            int *mutex_count, int *thread_count,
7568d75effSDimitry Andric                            int *unique_tid_count, void **sleep_trace,
7668d75effSDimitry Andric                            uptr trace_size) {
7768d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
7868d75effSDimitry Andric   *description = ReportTypeDescription(rep->typ);
7968d75effSDimitry Andric   *count = rep->count;
8068d75effSDimitry Andric   *stack_count = rep->stacks.Size();
8168d75effSDimitry Andric   *mop_count = rep->mops.Size();
8268d75effSDimitry Andric   *loc_count = rep->locs.Size();
8368d75effSDimitry Andric   *mutex_count = rep->mutexes.Size();
8468d75effSDimitry Andric   *thread_count = rep->threads.Size();
8568d75effSDimitry Andric   *unique_tid_count = rep->unique_tids.Size();
8668d75effSDimitry Andric   if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size);
8768d75effSDimitry Andric   return 1;
8868d75effSDimitry Andric }
8968d75effSDimitry Andric 
9068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
9168d75effSDimitry Andric int __tsan_get_report_tag(void *report, uptr *tag) {
9268d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
9368d75effSDimitry Andric   *tag = rep->tag;
9468d75effSDimitry Andric   return 1;
9568d75effSDimitry Andric }
9668d75effSDimitry Andric 
9768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
9868d75effSDimitry Andric int __tsan_get_report_stack(void *report, uptr idx, void **trace,
9968d75effSDimitry Andric                             uptr trace_size) {
10068d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
10168d75effSDimitry Andric   CHECK_LT(idx, rep->stacks.Size());
10268d75effSDimitry Andric   ReportStack *stack = rep->stacks[idx];
10368d75effSDimitry Andric   if (stack) CopyTrace(stack->frames, trace, trace_size);
10468d75effSDimitry Andric   return stack ? 1 : 0;
10568d75effSDimitry Andric }
10668d75effSDimitry Andric 
10768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
10868d75effSDimitry Andric int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,
10968d75effSDimitry Andric                           int *size, int *write, int *atomic, void **trace,
11068d75effSDimitry Andric                           uptr trace_size) {
11168d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
11268d75effSDimitry Andric   CHECK_LT(idx, rep->mops.Size());
11368d75effSDimitry Andric   ReportMop *mop = rep->mops[idx];
11468d75effSDimitry Andric   *tid = mop->tid;
11568d75effSDimitry Andric   *addr = (void *)mop->addr;
11668d75effSDimitry Andric   *size = mop->size;
11768d75effSDimitry Andric   *write = mop->write ? 1 : 0;
11868d75effSDimitry Andric   *atomic = mop->atomic ? 1 : 0;
11968d75effSDimitry Andric   if (mop->stack) CopyTrace(mop->stack->frames, trace, trace_size);
12068d75effSDimitry Andric   return 1;
12168d75effSDimitry Andric }
12268d75effSDimitry Andric 
12368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
12468d75effSDimitry Andric int __tsan_get_report_loc(void *report, uptr idx, const char **type,
12568d75effSDimitry Andric                           void **addr, uptr *start, uptr *size, int *tid,
12668d75effSDimitry Andric                           int *fd, int *suppressable, void **trace,
12768d75effSDimitry Andric                           uptr trace_size) {
12868d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
12968d75effSDimitry Andric   CHECK_LT(idx, rep->locs.Size());
13068d75effSDimitry Andric   ReportLocation *loc = rep->locs[idx];
13168d75effSDimitry Andric   *type = ReportLocationTypeDescription(loc->type);
13268d75effSDimitry Andric   *addr = (void *)loc->global.start;
13368d75effSDimitry Andric   *start = loc->heap_chunk_start;
13468d75effSDimitry Andric   *size = loc->heap_chunk_size;
13568d75effSDimitry Andric   *tid = loc->tid;
13668d75effSDimitry Andric   *fd = loc->fd;
13768d75effSDimitry Andric   *suppressable = loc->suppressable;
13868d75effSDimitry Andric   if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size);
13968d75effSDimitry Andric   return 1;
14068d75effSDimitry Andric }
14168d75effSDimitry Andric 
14268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
14368d75effSDimitry Andric int __tsan_get_report_loc_object_type(void *report, uptr idx,
14468d75effSDimitry Andric                                       const char **object_type) {
14568d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
14668d75effSDimitry Andric   CHECK_LT(idx, rep->locs.Size());
14768d75effSDimitry Andric   ReportLocation *loc = rep->locs[idx];
14868d75effSDimitry Andric   *object_type = GetObjectTypeFromTag(loc->external_tag);
14968d75effSDimitry Andric   return 1;
15068d75effSDimitry Andric }
15168d75effSDimitry Andric 
15268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
15368d75effSDimitry Andric int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
15468d75effSDimitry Andric                             int *destroyed, void **trace, uptr trace_size) {
15568d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
15668d75effSDimitry Andric   CHECK_LT(idx, rep->mutexes.Size());
15768d75effSDimitry Andric   ReportMutex *mutex = rep->mutexes[idx];
15868d75effSDimitry Andric   *mutex_id = mutex->id;
15968d75effSDimitry Andric   *addr = (void *)mutex->addr;
16068d75effSDimitry Andric   *destroyed = mutex->destroyed;
16168d75effSDimitry Andric   if (mutex->stack) CopyTrace(mutex->stack->frames, trace, trace_size);
16268d75effSDimitry Andric   return 1;
16368d75effSDimitry Andric }
16468d75effSDimitry Andric 
16568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
16668d75effSDimitry Andric int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id,
16768d75effSDimitry Andric                              int *running, const char **name, int *parent_tid,
16868d75effSDimitry Andric                              void **trace, uptr trace_size) {
16968d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
17068d75effSDimitry Andric   CHECK_LT(idx, rep->threads.Size());
17168d75effSDimitry Andric   ReportThread *thread = rep->threads[idx];
17268d75effSDimitry Andric   *tid = thread->id;
17368d75effSDimitry Andric   *os_id = thread->os_id;
17468d75effSDimitry Andric   *running = thread->running;
17568d75effSDimitry Andric   *name = thread->name;
17668d75effSDimitry Andric   *parent_tid = thread->parent_tid;
17768d75effSDimitry Andric   if (thread->stack) CopyTrace(thread->stack->frames, trace, trace_size);
17868d75effSDimitry Andric   return 1;
17968d75effSDimitry Andric }
18068d75effSDimitry Andric 
18168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
18268d75effSDimitry Andric int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {
18368d75effSDimitry Andric   const ReportDesc *rep = (ReportDesc *)report;
18468d75effSDimitry Andric   CHECK_LT(idx, rep->unique_tids.Size());
18568d75effSDimitry Andric   *tid = rep->unique_tids[idx];
18668d75effSDimitry Andric   return 1;
18768d75effSDimitry Andric }
18868d75effSDimitry Andric 
18968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
19068d75effSDimitry Andric const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,
19168d75effSDimitry Andric                                   uptr *region_address_ptr,
19268d75effSDimitry Andric                                   uptr *region_size_ptr) {
19368d75effSDimitry Andric   uptr region_address = 0;
19468d75effSDimitry Andric   uptr region_size = 0;
19568d75effSDimitry Andric   const char *region_kind = nullptr;
19668d75effSDimitry Andric   if (name && name_size > 0) name[0] = 0;
19768d75effSDimitry Andric 
198*349cc55cSDimitry Andric   if (IsMetaMem(reinterpret_cast<u32 *>(addr))) {
19968d75effSDimitry Andric     region_kind = "meta shadow";
200*349cc55cSDimitry Andric   } else if (IsShadowMem(reinterpret_cast<RawShadow *>(addr))) {
20168d75effSDimitry Andric     region_kind = "shadow";
20268d75effSDimitry Andric   } else {
20368d75effSDimitry Andric     bool is_stack = false;
20468d75effSDimitry Andric     MBlock *b = 0;
20568d75effSDimitry Andric     Allocator *a = allocator();
20668d75effSDimitry Andric     if (a->PointerIsMine((void *)addr)) {
20768d75effSDimitry Andric       void *block_begin = a->GetBlockBegin((void *)addr);
20868d75effSDimitry Andric       if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
20968d75effSDimitry Andric     }
21068d75effSDimitry Andric 
21168d75effSDimitry Andric     if (b != 0) {
21268d75effSDimitry Andric       region_address = (uptr)allocator()->GetBlockBegin((void *)addr);
21368d75effSDimitry Andric       region_size = b->siz;
21468d75effSDimitry Andric       region_kind = "heap";
21568d75effSDimitry Andric     } else {
21668d75effSDimitry Andric       // TODO(kuba.brecka): We should not lock. This is supposed to be called
21768d75effSDimitry Andric       // from within the debugger when other threads are stopped.
218*349cc55cSDimitry Andric       ctx->thread_registry.Lock();
21968d75effSDimitry Andric       ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack);
220*349cc55cSDimitry Andric       ctx->thread_registry.Unlock();
22168d75effSDimitry Andric       if (tctx) {
22268d75effSDimitry Andric         region_kind = is_stack ? "stack" : "tls";
22368d75effSDimitry Andric       } else {
22468d75effSDimitry Andric         region_kind = "global";
22568d75effSDimitry Andric         DataInfo info;
22668d75effSDimitry Andric         if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) {
22768d75effSDimitry Andric           internal_strncpy(name, info.name, name_size);
22868d75effSDimitry Andric           region_address = info.start;
22968d75effSDimitry Andric           region_size = info.size;
23068d75effSDimitry Andric         }
23168d75effSDimitry Andric       }
23268d75effSDimitry Andric     }
23368d75effSDimitry Andric   }
23468d75effSDimitry Andric 
23568d75effSDimitry Andric   CHECK(region_kind);
23668d75effSDimitry Andric   if (region_address_ptr) *region_address_ptr = region_address;
23768d75effSDimitry Andric   if (region_size_ptr) *region_size_ptr = region_size;
23868d75effSDimitry Andric   return region_kind;
23968d75effSDimitry Andric }
24068d75effSDimitry Andric 
24168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
24268d75effSDimitry Andric int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,
24368d75effSDimitry Andric                            tid_t *os_id) {
24468d75effSDimitry Andric   MBlock *b = 0;
24568d75effSDimitry Andric   Allocator *a = allocator();
24668d75effSDimitry Andric   if (a->PointerIsMine((void *)addr)) {
24768d75effSDimitry Andric     void *block_begin = a->GetBlockBegin((void *)addr);
24868d75effSDimitry Andric     if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
24968d75effSDimitry Andric   }
25068d75effSDimitry Andric   if (b == 0) return 0;
25168d75effSDimitry Andric 
25268d75effSDimitry Andric   *thread_id = b->tid;
25368d75effSDimitry Andric   // No locking.  This is supposed to be called from within the debugger when
25468d75effSDimitry Andric   // other threads are stopped.
255*349cc55cSDimitry Andric   ThreadContextBase *tctx = ctx->thread_registry.GetThreadLocked(b->tid);
25668d75effSDimitry Andric   *os_id = tctx->os_id;
25768d75effSDimitry Andric 
25868d75effSDimitry Andric   StackTrace stack = StackDepotGet(b->stk);
25968d75effSDimitry Andric   size = Min(size, (uptr)stack.size);
26068d75effSDimitry Andric   for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1];
26168d75effSDimitry Andric   return size;
26268d75effSDimitry Andric }
263