[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