1 //===-- tsan_debugging.cc -------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 // TSan debugging API implementation.
11 //===----------------------------------------------------------------------===//
12 #include "tsan_interface.h"
13 #include "tsan_report.h"
16 using namespace __tsan
;
18 static const char *ReportTypeDescription(ReportType typ
) {
19 if (typ
== ReportTypeRace
) return "data-race";
20 if (typ
== ReportTypeVptrRace
) return "data-race-vptr";
21 if (typ
== ReportTypeUseAfterFree
) return "heap-use-after-free";
22 if (typ
== ReportTypeVptrUseAfterFree
) return "heap-use-after-free-vptr";
23 if (typ
== ReportTypeThreadLeak
) return "thread-leak";
24 if (typ
== ReportTypeMutexDestroyLocked
) return "locked-mutex-destroy";
25 if (typ
== ReportTypeMutexDoubleLock
) return "mutex-double-lock";
26 if (typ
== ReportTypeMutexInvalidAccess
) return "mutex-invalid-access";
27 if (typ
== ReportTypeMutexBadUnlock
) return "mutex-bad-unlock";
28 if (typ
== ReportTypeMutexBadReadLock
) return "mutex-bad-read-lock";
29 if (typ
== ReportTypeMutexBadReadUnlock
) return "mutex-bad-read-unlock";
30 if (typ
== ReportTypeSignalUnsafe
) return "signal-unsafe-call";
31 if (typ
== ReportTypeErrnoInSignal
) return "errno-in-signal-handler";
32 if (typ
== ReportTypeDeadlock
) return "lock-order-inversion";
36 static const char *ReportLocationTypeDescription(ReportLocationType typ
) {
37 if (typ
== ReportLocationGlobal
) return "global";
38 if (typ
== ReportLocationHeap
) return "heap";
39 if (typ
== ReportLocationStack
) return "stack";
40 if (typ
== ReportLocationTLS
) return "tls";
41 if (typ
== ReportLocationFD
) return "fd";
45 static void CopyTrace(SymbolizedStack
*first_frame
, void **trace
,
48 for (SymbolizedStack
*frame
= first_frame
; frame
!= nullptr;
49 frame
= frame
->next
) {
50 trace
[i
++] = (void *)frame
->info
.address
;
51 if (i
>= trace_size
) break;
55 // Meant to be called by the debugger.
56 SANITIZER_INTERFACE_ATTRIBUTE
57 void *__tsan_get_current_report() {
58 return const_cast<ReportDesc
*>(cur_thread()->current_report
);
61 SANITIZER_INTERFACE_ATTRIBUTE
62 int __tsan_get_report_data(void *report
, const char **description
, int *count
,
63 int *stack_count
, int *mop_count
, int *loc_count
,
64 int *mutex_count
, int *thread_count
,
65 int *unique_tid_count
, void **sleep_trace
,
67 const ReportDesc
*rep
= (ReportDesc
*)report
;
68 *description
= ReportTypeDescription(rep
->typ
);
70 *stack_count
= rep
->stacks
.Size();
71 *mop_count
= rep
->mops
.Size();
72 *loc_count
= rep
->locs
.Size();
73 *mutex_count
= rep
->mutexes
.Size();
74 *thread_count
= rep
->threads
.Size();
75 *unique_tid_count
= rep
->unique_tids
.Size();
76 if (rep
->sleep
) CopyTrace(rep
->sleep
->frames
, sleep_trace
, trace_size
);
80 SANITIZER_INTERFACE_ATTRIBUTE
81 int __tsan_get_report_stack(void *report
, uptr idx
, void **trace
,
83 const ReportDesc
*rep
= (ReportDesc
*)report
;
84 CHECK_LT(idx
, rep
->stacks
.Size());
85 ReportStack
*stack
= rep
->stacks
[idx
];
86 if (stack
) CopyTrace(stack
->frames
, trace
, trace_size
);
90 SANITIZER_INTERFACE_ATTRIBUTE
91 int __tsan_get_report_mop(void *report
, uptr idx
, int *tid
, void **addr
,
92 int *size
, int *write
, int *atomic
, void **trace
,
94 const ReportDesc
*rep
= (ReportDesc
*)report
;
95 CHECK_LT(idx
, rep
->mops
.Size());
96 ReportMop
*mop
= rep
->mops
[idx
];
98 *addr
= (void *)mop
->addr
;
100 *write
= mop
->write
? 1 : 0;
101 *atomic
= mop
->atomic
? 1 : 0;
102 if (mop
->stack
) CopyTrace(mop
->stack
->frames
, trace
, trace_size
);
106 SANITIZER_INTERFACE_ATTRIBUTE
107 int __tsan_get_report_loc(void *report
, uptr idx
, const char **type
,
108 void **addr
, uptr
*start
, uptr
*size
, int *tid
,
109 int *fd
, int *suppressable
, void **trace
,
111 const ReportDesc
*rep
= (ReportDesc
*)report
;
112 CHECK_LT(idx
, rep
->locs
.Size());
113 ReportLocation
*loc
= rep
->locs
[idx
];
114 *type
= ReportLocationTypeDescription(loc
->type
);
115 *addr
= (void *)loc
->global
.start
;
116 *start
= loc
->heap_chunk_start
;
117 *size
= loc
->heap_chunk_size
;
120 *suppressable
= loc
->suppressable
;
121 if (loc
->stack
) CopyTrace(loc
->stack
->frames
, trace
, trace_size
);
125 SANITIZER_INTERFACE_ATTRIBUTE
126 int __tsan_get_report_mutex(void *report
, uptr idx
, uptr
*mutex_id
, void **addr
,
127 int *destroyed
, void **trace
, uptr trace_size
) {
128 const ReportDesc
*rep
= (ReportDesc
*)report
;
129 CHECK_LT(idx
, rep
->mutexes
.Size());
130 ReportMutex
*mutex
= rep
->mutexes
[idx
];
131 *mutex_id
= mutex
->id
;
132 *addr
= (void *)mutex
->addr
;
133 *destroyed
= mutex
->destroyed
;
134 if (mutex
->stack
) CopyTrace(mutex
->stack
->frames
, trace
, trace_size
);
138 SANITIZER_INTERFACE_ATTRIBUTE
139 int __tsan_get_report_thread(void *report
, uptr idx
, int *tid
, uptr
*os_id
,
140 int *running
, const char **name
, int *parent_tid
,
141 void **trace
, uptr trace_size
) {
142 const ReportDesc
*rep
= (ReportDesc
*)report
;
143 CHECK_LT(idx
, rep
->threads
.Size());
144 ReportThread
*thread
= rep
->threads
[idx
];
146 *os_id
= thread
->os_id
;
147 *running
= thread
->running
;
148 *name
= thread
->name
;
149 *parent_tid
= thread
->parent_tid
;
150 if (thread
->stack
) CopyTrace(thread
->stack
->frames
, trace
, trace_size
);
154 SANITIZER_INTERFACE_ATTRIBUTE
155 int __tsan_get_report_unique_tid(void *report
, uptr idx
, int *tid
) {
156 const ReportDesc
*rep
= (ReportDesc
*)report
;
157 CHECK_LT(idx
, rep
->unique_tids
.Size());
158 *tid
= rep
->unique_tids
[idx
];