Path: blob/main/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_debugging.cpp
35269 views
//===-- tsan_debugging.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of ThreadSanitizer (TSan), a race detector.9//10// TSan debugging API implementation.11//===----------------------------------------------------------------------===//12#include "tsan_interface.h"13#include "tsan_report.h"14#include "tsan_rtl.h"1516#include "sanitizer_common/sanitizer_stackdepot.h"1718using namespace __tsan;1920static const char *ReportTypeDescription(ReportType typ) {21switch (typ) {22case ReportTypeRace: return "data-race";23case ReportTypeVptrRace: return "data-race-vptr";24case ReportTypeUseAfterFree: return "heap-use-after-free";25case ReportTypeVptrUseAfterFree: return "heap-use-after-free-vptr";26case ReportTypeExternalRace: return "external-race";27case ReportTypeThreadLeak: return "thread-leak";28case ReportTypeMutexDestroyLocked: return "locked-mutex-destroy";29case ReportTypeMutexDoubleLock: return "mutex-double-lock";30case ReportTypeMutexInvalidAccess: return "mutex-invalid-access";31case ReportTypeMutexBadUnlock: return "mutex-bad-unlock";32case ReportTypeMutexBadReadLock: return "mutex-bad-read-lock";33case ReportTypeMutexBadReadUnlock: return "mutex-bad-read-unlock";34case ReportTypeSignalUnsafe: return "signal-unsafe-call";35case ReportTypeErrnoInSignal: return "errno-in-signal-handler";36case ReportTypeDeadlock: return "lock-order-inversion";37case ReportTypeMutexHeldWrongContext:38return "mutex-held-in-wrong-context";39// No default case so compiler warns us if we miss one40}41UNREACHABLE("missing case");42}4344static const char *ReportLocationTypeDescription(ReportLocationType typ) {45switch (typ) {46case ReportLocationGlobal: return "global";47case ReportLocationHeap: return "heap";48case ReportLocationStack: return "stack";49case ReportLocationTLS: return "tls";50case ReportLocationFD: return "fd";51// No default case so compiler warns us if we miss one52}53UNREACHABLE("missing case");54}5556static void CopyTrace(SymbolizedStack *first_frame, void **trace,57uptr trace_size) {58uptr i = 0;59for (SymbolizedStack *frame = first_frame; frame != nullptr;60frame = frame->next) {61trace[i++] = (void *)frame->info.address;62if (i >= trace_size) break;63}64}6566// Meant to be called by the debugger.67SANITIZER_INTERFACE_ATTRIBUTE68void *__tsan_get_current_report() {69return const_cast<ReportDesc*>(cur_thread()->current_report);70}7172SANITIZER_INTERFACE_ATTRIBUTE73int __tsan_get_report_data(void *report, const char **description, int *count,74int *stack_count, int *mop_count, int *loc_count,75int *mutex_count, int *thread_count,76int *unique_tid_count, void **sleep_trace,77uptr trace_size) {78const ReportDesc *rep = (ReportDesc *)report;79*description = ReportTypeDescription(rep->typ);80*count = rep->count;81*stack_count = rep->stacks.Size();82*mop_count = rep->mops.Size();83*loc_count = rep->locs.Size();84*mutex_count = rep->mutexes.Size();85*thread_count = rep->threads.Size();86*unique_tid_count = rep->unique_tids.Size();87if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size);88return 1;89}9091SANITIZER_INTERFACE_ATTRIBUTE92int __tsan_get_report_tag(void *report, uptr *tag) {93const ReportDesc *rep = (ReportDesc *)report;94*tag = rep->tag;95return 1;96}9798SANITIZER_INTERFACE_ATTRIBUTE99int __tsan_get_report_stack(void *report, uptr idx, void **trace,100uptr trace_size) {101const ReportDesc *rep = (ReportDesc *)report;102CHECK_LT(idx, rep->stacks.Size());103ReportStack *stack = rep->stacks[idx];104if (stack) CopyTrace(stack->frames, trace, trace_size);105return stack ? 1 : 0;106}107108SANITIZER_INTERFACE_ATTRIBUTE109int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,110int *size, int *write, int *atomic, void **trace,111uptr trace_size) {112const ReportDesc *rep = (ReportDesc *)report;113CHECK_LT(idx, rep->mops.Size());114ReportMop *mop = rep->mops[idx];115*tid = mop->tid;116*addr = (void *)mop->addr;117*size = mop->size;118*write = mop->write ? 1 : 0;119*atomic = mop->atomic ? 1 : 0;120if (mop->stack) CopyTrace(mop->stack->frames, trace, trace_size);121return 1;122}123124SANITIZER_INTERFACE_ATTRIBUTE125int __tsan_get_report_loc(void *report, uptr idx, const char **type,126void **addr, uptr *start, uptr *size, int *tid,127int *fd, int *suppressable, void **trace,128uptr trace_size) {129const ReportDesc *rep = (ReportDesc *)report;130CHECK_LT(idx, rep->locs.Size());131ReportLocation *loc = rep->locs[idx];132*type = ReportLocationTypeDescription(loc->type);133*addr = (void *)loc->global.start;134*start = loc->heap_chunk_start;135*size = loc->heap_chunk_size;136*tid = loc->tid;137*fd = loc->fd;138*suppressable = loc->suppressable;139if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size);140return 1;141}142143SANITIZER_INTERFACE_ATTRIBUTE144int __tsan_get_report_loc_object_type(void *report, uptr idx,145const char **object_type) {146const ReportDesc *rep = (ReportDesc *)report;147CHECK_LT(idx, rep->locs.Size());148ReportLocation *loc = rep->locs[idx];149*object_type = GetObjectTypeFromTag(loc->external_tag);150return 1;151}152153SANITIZER_INTERFACE_ATTRIBUTE154int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,155int *destroyed, void **trace, uptr trace_size) {156const ReportDesc *rep = (ReportDesc *)report;157CHECK_LT(idx, rep->mutexes.Size());158ReportMutex *mutex = rep->mutexes[idx];159*mutex_id = mutex->id;160*addr = (void *)mutex->addr;161*destroyed = false;162if (mutex->stack) CopyTrace(mutex->stack->frames, trace, trace_size);163return 1;164}165166SANITIZER_INTERFACE_ATTRIBUTE167int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id,168int *running, const char **name, int *parent_tid,169void **trace, uptr trace_size) {170const ReportDesc *rep = (ReportDesc *)report;171CHECK_LT(idx, rep->threads.Size());172ReportThread *thread = rep->threads[idx];173*tid = thread->id;174*os_id = thread->os_id;175*running = thread->running;176*name = thread->name;177*parent_tid = thread->parent_tid;178if (thread->stack) CopyTrace(thread->stack->frames, trace, trace_size);179return 1;180}181182SANITIZER_INTERFACE_ATTRIBUTE183int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {184const ReportDesc *rep = (ReportDesc *)report;185CHECK_LT(idx, rep->unique_tids.Size());186*tid = rep->unique_tids[idx];187return 1;188}189190SANITIZER_INTERFACE_ATTRIBUTE191const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,192uptr *region_address_ptr,193uptr *region_size_ptr) {194uptr region_address = 0;195uptr region_size = 0;196const char *region_kind = nullptr;197if (name && name_size > 0) name[0] = 0;198199if (IsMetaMem(reinterpret_cast<u32 *>(addr))) {200region_kind = "meta shadow";201} else if (IsShadowMem(reinterpret_cast<RawShadow *>(addr))) {202region_kind = "shadow";203} else {204bool is_stack = false;205MBlock *b = 0;206Allocator *a = allocator();207if (a->PointerIsMine((void *)addr)) {208void *block_begin = a->GetBlockBegin((void *)addr);209if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);210}211212if (b != 0) {213region_address = (uptr)allocator()->GetBlockBegin((void *)addr);214region_size = b->siz;215region_kind = "heap";216} else {217// TODO(kuba.brecka): We should not lock. This is supposed to be called218// from within the debugger when other threads are stopped.219ctx->thread_registry.Lock();220ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack);221ctx->thread_registry.Unlock();222if (tctx) {223region_kind = is_stack ? "stack" : "tls";224} else {225region_kind = "global";226DataInfo info;227if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) {228internal_strncpy(name, info.name, name_size);229region_address = info.start;230region_size = info.size;231}232}233}234}235236CHECK(region_kind);237if (region_address_ptr) *region_address_ptr = region_address;238if (region_size_ptr) *region_size_ptr = region_size;239return region_kind;240}241242SANITIZER_INTERFACE_ATTRIBUTE243int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,244tid_t *os_id) {245MBlock *b = 0;246Allocator *a = allocator();247if (a->PointerIsMine((void *)addr)) {248void *block_begin = a->GetBlockBegin((void *)addr);249if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);250}251if (b == 0) return 0;252253*thread_id = b->tid;254// No locking. This is supposed to be called from within the debugger when255// other threads are stopped.256ThreadContextBase *tctx = ctx->thread_registry.GetThreadLocked(b->tid);257*os_id = tctx->os_id;258259StackTrace stack = StackDepotGet(b->stk);260size = Min(size, (uptr)stack.size);261for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1];262return size;263}264265266