brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · b3422af Raw
265 lines · cpp
1//===-- tsan_debugging.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer (TSan), a race detector.10//11// TSan debugging API implementation.12//===----------------------------------------------------------------------===//13#include "tsan_interface.h"14#include "tsan_report.h"15#include "tsan_rtl.h"16 17#include "sanitizer_common/sanitizer_stackdepot.h"18 19using namespace __tsan;20 21static const char *ReportTypeDescription(ReportType typ) {22  switch (typ) {23    case ReportTypeRace: return "data-race";24    case ReportTypeVptrRace: return "data-race-vptr";25    case ReportTypeUseAfterFree: return "heap-use-after-free";26    case ReportTypeVptrUseAfterFree: return "heap-use-after-free-vptr";27    case ReportTypeExternalRace: return "external-race";28    case ReportTypeThreadLeak: return "thread-leak";29    case ReportTypeMutexDestroyLocked: return "locked-mutex-destroy";30    case ReportTypeMutexDoubleLock: return "mutex-double-lock";31    case ReportTypeMutexInvalidAccess: return "mutex-invalid-access";32    case ReportTypeMutexBadUnlock: return "mutex-bad-unlock";33    case ReportTypeMutexBadReadLock: return "mutex-bad-read-lock";34    case ReportTypeMutexBadReadUnlock: return "mutex-bad-read-unlock";35    case ReportTypeSignalUnsafe: return "signal-unsafe-call";36    case ReportTypeErrnoInSignal: return "errno-in-signal-handler";37    case ReportTypeDeadlock: return "lock-order-inversion";38    case ReportTypeMutexHeldWrongContext:39      return "mutex-held-in-wrong-context";40      // No default case so compiler warns us if we miss one41  }42  UNREACHABLE("missing case");43}44 45static const char *ReportLocationTypeDescription(ReportLocationType typ) {46  switch (typ) {47    case ReportLocationGlobal: return "global";48    case ReportLocationHeap: return "heap";49    case ReportLocationStack: return "stack";50    case ReportLocationTLS: return "tls";51    case ReportLocationFD: return "fd";52    // No default case so compiler warns us if we miss one53  }54  UNREACHABLE("missing case");55}56 57static void CopyTrace(SymbolizedStack *first_frame, void **trace,58                      uptr trace_size) {59  uptr i = 0;60  for (SymbolizedStack *frame = first_frame; frame != nullptr;61       frame = frame->next) {62    trace[i++] = (void *)frame->info.address;63    if (i >= trace_size) break;64  }65}66 67// Meant to be called by the debugger.68SANITIZER_INTERFACE_ATTRIBUTE69void *__tsan_get_current_report() {70  return const_cast<ReportDesc*>(cur_thread()->current_report);71}72 73SANITIZER_INTERFACE_ATTRIBUTE74int __tsan_get_report_data(void *report, const char **description, int *count,75                           int *stack_count, int *mop_count, int *loc_count,76                           int *mutex_count, int *thread_count,77                           int *unique_tid_count, void **sleep_trace,78                           uptr trace_size) {79  const ReportDesc *rep = (ReportDesc *)report;80  *description = ReportTypeDescription(rep->typ);81  *count = rep->count;82  *stack_count = rep->stacks.Size();83  *mop_count = rep->mops.Size();84  *loc_count = rep->locs.Size();85  *mutex_count = rep->mutexes.Size();86  *thread_count = rep->threads.Size();87  *unique_tid_count = rep->unique_tids.Size();88  if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size);89  return 1;90}91 92SANITIZER_INTERFACE_ATTRIBUTE93int __tsan_get_report_tag(void *report, uptr *tag) {94  const ReportDesc *rep = (ReportDesc *)report;95  *tag = rep->tag;96  return 1;97}98 99SANITIZER_INTERFACE_ATTRIBUTE100int __tsan_get_report_stack(void *report, uptr idx, void **trace,101                            uptr trace_size) {102  const ReportDesc *rep = (ReportDesc *)report;103  CHECK_LT(idx, rep->stacks.Size());104  ReportStack *stack = rep->stacks[idx];105  if (stack) CopyTrace(stack->frames, trace, trace_size);106  return stack ? 1 : 0;107}108 109SANITIZER_INTERFACE_ATTRIBUTE110int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,111                          int *size, int *write, int *atomic, void **trace,112                          uptr trace_size) {113  const ReportDesc *rep = (ReportDesc *)report;114  CHECK_LT(idx, rep->mops.Size());115  ReportMop *mop = rep->mops[idx];116  *tid = mop->tid;117  *addr = (void *)mop->addr;118  *size = mop->size;119  *write = mop->write ? 1 : 0;120  *atomic = mop->atomic ? 1 : 0;121  if (mop->stack) CopyTrace(mop->stack->frames, trace, trace_size);122  return 1;123}124 125SANITIZER_INTERFACE_ATTRIBUTE126int __tsan_get_report_loc(void *report, uptr idx, const char **type,127                          void **addr, uptr *start, uptr *size, int *tid,128                          int *fd, int *suppressable, void **trace,129                          uptr trace_size) {130  const ReportDesc *rep = (ReportDesc *)report;131  CHECK_LT(idx, rep->locs.Size());132  ReportLocation *loc = rep->locs[idx];133  *type = ReportLocationTypeDescription(loc->type);134  *addr = (void *)loc->global.start;135  *start = loc->heap_chunk_start;136  *size = loc->heap_chunk_size;137  *tid = loc->tid;138  *fd = loc->fd;139  *suppressable = loc->suppressable;140  if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size);141  return 1;142}143 144SANITIZER_INTERFACE_ATTRIBUTE145int __tsan_get_report_loc_object_type(void *report, uptr idx,146                                      const char **object_type) {147  const ReportDesc *rep = (ReportDesc *)report;148  CHECK_LT(idx, rep->locs.Size());149  ReportLocation *loc = rep->locs[idx];150  *object_type = GetObjectTypeFromTag(loc->external_tag);151  return 1;152}153 154SANITIZER_INTERFACE_ATTRIBUTE155int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,156                            int *destroyed, void **trace, uptr trace_size) {157  const ReportDesc *rep = (ReportDesc *)report;158  CHECK_LT(idx, rep->mutexes.Size());159  ReportMutex *mutex = rep->mutexes[idx];160  *mutex_id = mutex->id;161  *addr = (void *)mutex->addr;162  *destroyed = false;163  if (mutex->stack) CopyTrace(mutex->stack->frames, trace, trace_size);164  return 1;165}166 167SANITIZER_INTERFACE_ATTRIBUTE168int __tsan_get_report_thread(void *report, uptr idx, int *tid, ThreadID *os_id,169                             int *running, const char **name, int *parent_tid,170                             void **trace, uptr trace_size) {171  const ReportDesc *rep = (ReportDesc *)report;172  CHECK_LT(idx, rep->threads.Size());173  ReportThread *thread = rep->threads[idx];174  *tid = thread->id;175  *os_id = thread->os_id;176  *running = thread->running;177  *name = thread->name;178  *parent_tid = thread->parent_tid;179  if (thread->stack) CopyTrace(thread->stack->frames, trace, trace_size);180  return 1;181}182 183SANITIZER_INTERFACE_ATTRIBUTE184int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {185  const ReportDesc *rep = (ReportDesc *)report;186  CHECK_LT(idx, rep->unique_tids.Size());187  *tid = rep->unique_tids[idx];188  return 1;189}190 191SANITIZER_INTERFACE_ATTRIBUTE192const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,193                                  uptr *region_address_ptr,194                                  uptr *region_size_ptr) {195  uptr region_address = 0;196  uptr region_size = 0;197  const char *region_kind = nullptr;198  if (name && name_size > 0) name[0] = 0;199 200  if (IsMetaMem(reinterpret_cast<u32 *>(addr))) {201    region_kind = "meta shadow";202  } else if (IsShadowMem(reinterpret_cast<RawShadow *>(addr))) {203    region_kind = "shadow";204  } else {205    bool is_stack = false;206    MBlock *b = 0;207    Allocator *a = allocator();208    if (a->PointerIsMine((void *)addr)) {209      void *block_begin = a->GetBlockBegin((void *)addr);210      if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);211    }212 213    if (b != 0) {214      region_address = (uptr)allocator()->GetBlockBegin((void *)addr);215      region_size = b->siz;216      region_kind = "heap";217    } else {218      // TODO(kuba.brecka): We should not lock. This is supposed to be called219      // from within the debugger when other threads are stopped.220      ctx->thread_registry.Lock();221      ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack);222      ctx->thread_registry.Unlock();223      if (tctx) {224        region_kind = is_stack ? "stack" : "tls";225      } else {226        region_kind = "global";227        DataInfo info;228        if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) {229          internal_strncpy(name, info.name, name_size);230          region_address = info.start;231          region_size = info.size;232        }233      }234    }235  }236 237  CHECK(region_kind);238  if (region_address_ptr) *region_address_ptr = region_address;239  if (region_size_ptr) *region_size_ptr = region_size;240  return region_kind;241}242 243SANITIZER_INTERFACE_ATTRIBUTE244int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,245                           ThreadID *os_id) {246  MBlock *b = 0;247  Allocator *a = allocator();248  if (a->PointerIsMine((void *)addr)) {249    void *block_begin = a->GetBlockBegin((void *)addr);250    if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);251  }252  if (b == 0) return 0;253 254  *thread_id = b->tid;255  // No locking.  This is supposed to be called from within the debugger when256  // other threads are stopped.257  ThreadContextBase *tctx = ctx->thread_registry.GetThreadLocked(b->tid);258  *os_id = tctx->os_id;259 260  StackTrace stack = StackDepotGet(b->stk);261  size = Min(size, (uptr)stack.size);262  for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1];263  return size;264}265