[compiler-rt] r263126 - [tsan] Add TSan debugger APIs

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 10 10:07:14 PST 2016


While it isn't blamed for it, I think this is failing on all the bots:

http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-debian-fast/builds/36295
http://lab.llvm.org:8011/builders/clang-ppc64be-linux/builds/2170

On Thu, Mar 10, 2016 at 6:05 PM Kuba Brecka via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: kuba.brecka
> Date: Thu Mar 10 11:00:29 2016
> New Revision: 263126
>
> URL: http://llvm.org/viewvc/llvm-project?rev=263126&view=rev
> Log:
> [tsan] Add TSan debugger APIs
>
> Currently, TSan only reports everything in a formatted textual form. The
> idea behind this patch is to provide a consistent API that can be used to
> query information contained in a TSan-produced report. User can use these
> APIs either in a debugger (via a script or directly), or they can use it
> directly from the process (e.g. in the __tsan_on_report callback). ASan
> already has a similar API, see http://reviews.llvm.org/D4466.
>
> Differential Revision: http://reviews.llvm.org/D16191
>
>
> Added:
>     compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc
>     compiler-rt/trunk/test/tsan/debugging.cc
> Modified:
>     compiler-rt/trunk/lib/tsan/CMakeLists.txt
>     compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
>     compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
>     compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
>
> Modified: compiler-rt/trunk/lib/tsan/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/CMakeLists.txt?rev=263126&r1=263125&r2=263126&view=diff
>
> ==============================================================================
> --- compiler-rt/trunk/lib/tsan/CMakeLists.txt (original)
> +++ compiler-rt/trunk/lib/tsan/CMakeLists.txt Thu Mar 10 11:00:29 2016
> @@ -24,6 +24,7 @@ append_list_if(COMPILER_RT_HAS_WGLOBAL_C
>
>  set(TSAN_SOURCES
>    rtl/tsan_clock.cc
> +  rtl/tsan_debugging.cc
>    rtl/tsan_flags.cc
>    rtl/tsan_fd.cc
>    rtl/tsan_ignoreset.cc
>
> Added: compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc?rev=263126&view=auto
>
> ==============================================================================
> --- compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc (added)
> +++ compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc Thu Mar 10 11:00:29
> 2016
> @@ -0,0 +1,162 @@
> +//===-- tsan_debugging.cc
> -------------------------------------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This file is a part of ThreadSanitizer (TSan), a race detector.
> +//
> +// TSan debugging API implementation.
>
> +//===----------------------------------------------------------------------===//
> +#include "tsan_interface.h"
> +#include "tsan_report.h"
> +#include "tsan_rtl.h"
> +
> +using namespace __tsan;
> +
> +static const char *ReportTypeDescription(ReportType typ) {
> +  if (typ == ReportTypeRace) return "data-race";
> +  if (typ == ReportTypeVptrRace) return "data-race-vptr";
> +  if (typ == ReportTypeUseAfterFree) return "heap-use-after-free";
> +  if (typ == ReportTypeVptrUseAfterFree) return
> "heap-use-after-free-vptr";
> +  if (typ == ReportTypeThreadLeak) return "thread-leak";
> +  if (typ == ReportTypeMutexDestroyLocked) return "locked-mutex-destroy";
> +  if (typ == ReportTypeMutexDoubleLock) return "mutex-double-lock";
> +  if (typ == ReportTypeMutexBadUnlock) return "mutex-bad-unlock";
> +  if (typ == ReportTypeMutexBadReadLock) return "mutex-bad-read-lock";
> +  if (typ == ReportTypeMutexBadReadUnlock) return "mutex-bad-read-unlock";
> +  if (typ == ReportTypeSignalUnsafe) return "signal-unsafe-call";
> +  if (typ == ReportTypeErrnoInSignal) return "errno-in-signal-handler";
> +  if (typ == ReportTypeDeadlock) return "lock-order-inversion";
> +  return "";
> +}
> +
> +static const char *ReportLocationTypeDescription(ReportLocationType typ) {
> +  if (typ == ReportLocationGlobal) return "global";
> +  if (typ == ReportLocationHeap) return "heap";
> +  if (typ == ReportLocationStack) return "stack";
> +  if (typ == ReportLocationTLS) return "tls";
> +  if (typ == ReportLocationFD) return "fd";
> +  return "";
> +}
> +
> +static void CopyTrace(SymbolizedStack *first_frame, void **trace,
> +                      uptr trace_size) {
> +  uptr i = 0;
> +  for (SymbolizedStack *frame = first_frame; frame != nullptr;
> +       frame = frame->next) {
> +    trace[i++] = (void *)frame->info.address;
> +    if (i >= trace_size) break;
> +  }
> +}
> +
> +// Meant to be called by the debugger.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +void *__tsan_get_current_report() {
> +  const ReportDesc *rep = cur_thread()->current_report;
> +  return (void *)rep;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_data(void *report, const char **description, int
> *count,
> +                           int *stack_count, int *mop_count, int
> *loc_count,
> +                           int *mutex_count, int *thread_count,
> +                           int *unique_tid_count, void **sleep_trace,
> +                           uptr trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  *description = ReportTypeDescription(rep->typ);
> +  *count = rep->count;
> +  *stack_count = rep->stacks.Size();
> +  *mop_count = rep->mops.Size();
> +  *loc_count = rep->locs.Size();
> +  *mutex_count = rep->mutexes.Size();
> +  *thread_count = rep->threads.Size();
> +  *unique_tid_count = rep->unique_tids.Size();
> +  if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_stack(void *report, uptr idx, void **trace,
> +                            uptr trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->stacks.Size());
> +  ReportStack *stack = rep->stacks[idx];
> +  CopyTrace(stack->frames, trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,
> +                          int *size, int *write, int *atomic, void
> **trace,
> +                          uptr trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->mops.Size());
> +  ReportMop *mop = rep->mops[idx];
> +  *tid = mop->tid;
> +  *addr = (void *)mop->addr;
> +  *size = mop->size;
> +  *write = mop->write ? 1 : 0;
> +  *atomic = mop->atomic ? 1 : 0;
> +  CopyTrace(mop->stack->frames, trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_loc(void *report, uptr idx, const char **type,
> +                          void **addr, uptr *start, uptr *size, int *tid,
> +                          int *fd, int *suppressable, void **trace,
> +                          uptr trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->locs.Size());
> +  ReportLocation *loc = rep->locs[idx];
> +  *type = ReportLocationTypeDescription(loc->type);
> +  *addr = (void *)loc->global.start;
> +  *start = loc->heap_chunk_start;
> +  *size = loc->heap_chunk_size;
> +  *tid = loc->tid;
> +  *fd = loc->fd;
> +  *suppressable = loc->suppressable;
> +  if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void
> **addr,
> +                            int *destroyed, void **trace, uptr
> trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->mutexes.Size());
> +  ReportMutex *mutex = rep->mutexes[idx];
> +  *mutex_id = mutex->id;
> +  *addr = (void *)mutex->addr;
> +  *destroyed = mutex->destroyed;
> +  CopyTrace(mutex->stack->frames, trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *pid,
> +                             int *running, const char **name, int
> *parent_tid,
> +                             void **trace, uptr trace_size) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->threads.Size());
> +  ReportThread *thread = rep->threads[idx];
> +  *tid = thread->id;
> +  *pid = thread->pid;
> +  *running = thread->running;
> +  *name = thread->name;
> +  *parent_tid = thread->parent_tid;
> +  CopyTrace(thread->stack->frames, trace, trace_size);
> +  return 1;
> +}
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {
> +  const ReportDesc *rep = (ReportDesc *)report;
> +  CHECK_LT(idx, rep->unique_tids.Size());
> +  *tid = rep->unique_tids[idx];
> +  return 1;
> +}
>
> Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h?rev=263126&r1=263125&r2=263126&view=diff
>
> ==============================================================================
> --- compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h (original)
> +++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h Thu Mar 10 11:00:29
> 2016
> @@ -75,6 +75,61 @@ void __tsan_read_range(void *addr, unsig
>  SANITIZER_INTERFACE_ATTRIBUTE
>  void __tsan_write_range(void *addr, unsigned long size);  // NOLINT
>
> +// User may provide function that would be called right when TSan detects
> +// an error. The argument 'report' is an opaque pointer that can be used
> to
> +// gather additional information using other TSan report API functions.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +void __tsan_on_report(void *report);
> +
> +// If TSan is currently reporting a detected issue on the current thread,
> +// returns an opaque pointer to the current report. Otherwise returns
> NULL.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +void *__tsan_get_current_report();
> +
> +// Returns a report's description (issue type), number of duplicate issues
> +// found, counts of array data (stack traces, memory operations,
> locations,
> +// mutexes, threads, unique thread IDs) and a stack trace of a sleep()
> call (if
> +// one was involved in the issue).
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_data(void *report, const char **description, int
> *count,
> +                           int *stack_count, int *mop_count, int
> *loc_count,
> +                           int *mutex_count, int *thread_count,
> +                           int *unique_tid_count, void **sleep_trace,
> +                           uptr trace_size);
> +
> +// Returns information about stack traces included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_stack(void *report, uptr idx, void **trace,
> +                            uptr trace_size);
> +
> +// Returns information about memory operations included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,
> +                          int *size, int *write, int *atomic, void
> **trace,
> +                          uptr trace_size);
> +
> +// Returns information about locations included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_loc(void *report, uptr idx, const char **type,
> +                          void **addr, uptr *start, uptr *size, int *tid,
> +                          int *fd, int *suppressable, void **trace,
> +                          uptr trace_size);
> +
> +// Returns information about mutexes included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void
> **addr,
> +                            int *destroyed, void **trace, uptr
> trace_size);
> +
> +// Returns information about threads included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *pid,
> +                             int *running, const char **name, int
> *parent_tid,
> +                             void **trace, uptr trace_size);
> +
> +// Returns information about unique thread IDs included in the report.
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid);
> +
>  #ifdef __cplusplus
>  }  // extern "C"
>  #endif
>
> Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=263126&r1=263125&r2=263126&view=diff
>
> ==============================================================================
> --- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
> +++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Thu Mar 10 11:00:29 2016
> @@ -404,6 +404,8 @@ struct ThreadState {
>    // If set, malloc must not be called.
>    int nomalloc;
>
> +  const ReportDesc *current_report;
> +
>    explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
>                         unsigned reuse_count,
>                         uptr stk_addr, uptr stk_size,
>
> Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=263126&r1=263125&r2=263126&view=diff
>
> ==============================================================================
> --- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
> +++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Thu Mar 10 11:00:29
> 2016
> @@ -56,6 +56,11 @@ bool OnReport(const ReportDesc *rep, boo
>  }
>  #endif
>
> +SANITIZER_WEAK_DEFAULT_IMPL
> +void __tsan_on_report(const ReportDesc *rep) {
> +  (void)rep;
> +}
> +
>  static void StackStripMain(SymbolizedStack *frames) {
>    SymbolizedStack *last_frame = nullptr;
>    SymbolizedStack *last_frame2 = nullptr;
> @@ -492,6 +497,8 @@ bool OutputReport(ThreadState *thr, cons
>      return false;
>    atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
>    const ReportDesc *rep = srep.GetReport();
> +  CHECK_EQ(thr->current_report, nullptr);
> +  thr->current_report = rep;
>    Suppression *supp = 0;
>    uptr pc_or_addr = 0;
>    for (uptr i = 0; pc_or_addr == 0 && i < rep->mops.Size(); i++)
> @@ -512,13 +519,17 @@ bool OutputReport(ThreadState *thr, cons
>      thr->is_freeing = false;
>      bool suppressed = OnReport(rep, pc_or_addr != 0);
>      thr->is_freeing = old_is_freeing;
> -    if (suppressed)
> +    if (suppressed) {
> +      thr->current_report = nullptr;
>        return false;
> +    }
>    }
>    PrintReport(rep);
> +  __tsan_on_report(rep);
>    ctx->nreported++;
>    if (flags()->halt_on_error)
>      Die();
> +  thr->current_report = nullptr;
>    return true;
>  }
>
>
> Added: compiler-rt/trunk/test/tsan/debugging.cc
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/debugging.cc?rev=263126&view=auto
>
> ==============================================================================
> --- compiler-rt/trunk/test/tsan/debugging.cc (added)
> +++ compiler-rt/trunk/test/tsan/debugging.cc Thu Mar 10 11:00:29 2016
> @@ -0,0 +1,88 @@
> +// RUN: %clangxx_tsan -O1 %s -o %t
> +// RUN: %deflake %run %t 2>&1 | FileCheck %s
> +
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "test.h"
> +
> +extern "C" {
> +void __tsan_on_report(void *report);
> +void *__tsan_get_current_report();
> +int __tsan_get_report_data(void *report, const char **description, int
> *count,
> +                           int *stack_count, int *mop_count, int
> *loc_count,
> +                           int *mutex_count, int *thread_count,
> +                           int *unique_tid_count, void **sleep_trace,
> +                           unsigned long trace_size);
> +int __tsan_get_report_mop(void *report, unsigned long idx, int *tid,
> +                          void **addr, int *size, int *write, int *atomic,
> +                          void **trace, unsigned long trace_size);
> +}
> +
> +long my_global;
> +
> +void *Thread(void *a) {
> +  barrier_wait(&barrier);
> +  my_global = 42;
> +  return NULL;
> +}
> +
> +int main() {
> +  barrier_init(&barrier, 2);
> +  fprintf(stderr, "&my_global = %p\n", &my_global);
> +  // CHECK: &my_global = [[GLOBAL:0x[0-9a-f]+]]
> +  pthread_t t;
> +  pthread_create(&t, 0, Thread, 0);
> +  my_global = 41;
> +  barrier_wait(&barrier);
> +  pthread_join(t, 0);
> +  fprintf(stderr, "Done.\n");
> +}
> +
> +void __tsan_on_report(void *report) {
> +  fprintf(stderr, "__tsan_on_report(%p)\n", report);
> +  fprintf(stderr, "__tsan_get_current_report() = %p\n",
> +          __tsan_get_current_report());
> +  // CHECK: __tsan_on_report([[REPORT:0x[0-9a-f]+]])
> +  // CHECK: __tsan_get_current_report() = [[REPORT]]
> +
> +  const char *description;
> +  int count;
> +  int stack_count, mop_count, loc_count, mutex_count, thread_count,
> +      unique_tid_count;
> +  void *sleep_trace[16] = {0};
> +  __tsan_get_report_data(report, &description, &count, &stack_count,
> &mop_count,
> +                         &loc_count, &mutex_count, &thread_count,
> +                         &unique_tid_count, sleep_trace, 16);
> +  fprintf(stderr, "report type = '%s', count = %d\n", description, count);
> +  // CHECK: report type = 'data-race', count = 0
> +
> +  fprintf(stderr, "mop_count = %d\n", mop_count);
> +  // CHECK: mop_count = 2
> +
> +  int tid;
> +  void *addr;
> +  int size, write, atomic;
> +  void *trace[16] = {0};
> +
> +  __tsan_get_report_mop(report, 0, &tid, &addr, &size, &write, &atomic,
> trace,
> +                        16);
> +  fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic =
> %d\n",
> +          tid, addr, size, write, atomic);
> +  // CHECK: tid = 1, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
> +  fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
> +  // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = 0x0
> +
> +  __tsan_get_report_mop(report, 1, &tid, &addr, &size, &write, &atomic,
> trace,
> +                        16);
> +  fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic =
> %d\n",
> +          tid, addr, size, write, atomic);
> +  // CHECK: tid = 0, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
> +  fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
> +  // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = 0x0
> +}
> +
> +// CHECK: Done.
> +// CHECK: ThreadSanitizer: reported 1 warnings
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160310/b7f14dcd/attachment.html>


More information about the llvm-commits mailing list