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