xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- tsan_symbolize.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 //===----------------------------------------------------------------------===//
12*68d75effSDimitry Andric 
13*68d75effSDimitry Andric #include "tsan_symbolize.h"
14*68d75effSDimitry Andric 
15*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
16*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
17*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
18*68d75effSDimitry Andric #include "tsan_flags.h"
19*68d75effSDimitry Andric #include "tsan_report.h"
20*68d75effSDimitry Andric #include "tsan_rtl.h"
21*68d75effSDimitry Andric 
22*68d75effSDimitry Andric namespace __tsan {
23*68d75effSDimitry Andric 
24*68d75effSDimitry Andric void EnterSymbolizer() {
25*68d75effSDimitry Andric   ThreadState *thr = cur_thread();
26*68d75effSDimitry Andric   CHECK(!thr->in_symbolizer);
27*68d75effSDimitry Andric   thr->in_symbolizer = true;
28*68d75effSDimitry Andric   thr->ignore_interceptors++;
29*68d75effSDimitry Andric }
30*68d75effSDimitry Andric 
31*68d75effSDimitry Andric void ExitSymbolizer() {
32*68d75effSDimitry Andric   ThreadState *thr = cur_thread();
33*68d75effSDimitry Andric   CHECK(thr->in_symbolizer);
34*68d75effSDimitry Andric   thr->in_symbolizer = false;
35*68d75effSDimitry Andric   thr->ignore_interceptors--;
36*68d75effSDimitry Andric }
37*68d75effSDimitry Andric 
38*68d75effSDimitry Andric // Legacy API.
39*68d75effSDimitry Andric // May be overriden by JIT/JAVA/etc,
40*68d75effSDimitry Andric // whatever produces PCs marked with kExternalPCBit.
41*68d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL
42*68d75effSDimitry Andric bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,
43*68d75effSDimitry Andric                                char *file_buf, uptr file_siz, int *line,
44*68d75effSDimitry Andric                                int *col) {
45*68d75effSDimitry Andric   return false;
46*68d75effSDimitry Andric }
47*68d75effSDimitry Andric 
48*68d75effSDimitry Andric // New API: call __tsan_symbolize_external_ex only when it exists.
49*68d75effSDimitry Andric // Once old clients are gone, provide dummy implementation.
50*68d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL
51*68d75effSDimitry Andric void __tsan_symbolize_external_ex(uptr pc,
52*68d75effSDimitry Andric                                   void (*add_frame)(void *, const char *,
53*68d75effSDimitry Andric                                                     const char *, int, int),
54*68d75effSDimitry Andric                                   void *ctx) {}
55*68d75effSDimitry Andric 
56*68d75effSDimitry Andric struct SymbolizedStackBuilder {
57*68d75effSDimitry Andric   SymbolizedStack *head;
58*68d75effSDimitry Andric   SymbolizedStack *tail;
59*68d75effSDimitry Andric   uptr addr;
60*68d75effSDimitry Andric };
61*68d75effSDimitry Andric 
62*68d75effSDimitry Andric static void AddFrame(void *ctx, const char *function_name, const char *file,
63*68d75effSDimitry Andric                      int line, int column) {
64*68d75effSDimitry Andric   SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx;
65*68d75effSDimitry Andric   if (ssb->tail) {
66*68d75effSDimitry Andric     ssb->tail->next = SymbolizedStack::New(ssb->addr);
67*68d75effSDimitry Andric     ssb->tail = ssb->tail->next;
68*68d75effSDimitry Andric   } else {
69*68d75effSDimitry Andric     ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr);
70*68d75effSDimitry Andric   }
71*68d75effSDimitry Andric   AddressInfo *info = &ssb->tail->info;
72*68d75effSDimitry Andric   if (function_name) {
73*68d75effSDimitry Andric     info->function = internal_strdup(function_name);
74*68d75effSDimitry Andric   }
75*68d75effSDimitry Andric   if (file) {
76*68d75effSDimitry Andric     info->file = internal_strdup(file);
77*68d75effSDimitry Andric   }
78*68d75effSDimitry Andric   info->line = line;
79*68d75effSDimitry Andric   info->column = column;
80*68d75effSDimitry Andric }
81*68d75effSDimitry Andric 
82*68d75effSDimitry Andric SymbolizedStack *SymbolizeCode(uptr addr) {
83*68d75effSDimitry Andric   // Check if PC comes from non-native land.
84*68d75effSDimitry Andric   if (addr & kExternalPCBit) {
85*68d75effSDimitry Andric     SymbolizedStackBuilder ssb = {nullptr, nullptr, addr};
86*68d75effSDimitry Andric     __tsan_symbolize_external_ex(addr, AddFrame, &ssb);
87*68d75effSDimitry Andric     if (ssb.head)
88*68d75effSDimitry Andric       return ssb.head;
89*68d75effSDimitry Andric     // Legacy code: remove along with the declaration above
90*68d75effSDimitry Andric     // once all clients using this API are gone.
91*68d75effSDimitry Andric     // Declare static to not consume too much stack space.
92*68d75effSDimitry Andric     // We symbolize reports in a single thread, so this is fine.
93*68d75effSDimitry Andric     static char func_buf[1024];
94*68d75effSDimitry Andric     static char file_buf[1024];
95*68d75effSDimitry Andric     int line, col;
96*68d75effSDimitry Andric     SymbolizedStack *frame = SymbolizedStack::New(addr);
97*68d75effSDimitry Andric     if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
98*68d75effSDimitry Andric                                   sizeof(file_buf), &line, &col)) {
99*68d75effSDimitry Andric       frame->info.function = internal_strdup(func_buf);
100*68d75effSDimitry Andric       frame->info.file = internal_strdup(file_buf);
101*68d75effSDimitry Andric       frame->info.line = line;
102*68d75effSDimitry Andric       frame->info.column = col;
103*68d75effSDimitry Andric     }
104*68d75effSDimitry Andric     return frame;
105*68d75effSDimitry Andric   }
106*68d75effSDimitry Andric   return Symbolizer::GetOrInit()->SymbolizePC(addr);
107*68d75effSDimitry Andric }
108*68d75effSDimitry Andric 
109*68d75effSDimitry Andric ReportLocation *SymbolizeData(uptr addr) {
110*68d75effSDimitry Andric   DataInfo info;
111*68d75effSDimitry Andric   if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
112*68d75effSDimitry Andric     return 0;
113*68d75effSDimitry Andric   ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
114*68d75effSDimitry Andric   internal_memcpy(&ent->global, &info, sizeof(info));
115*68d75effSDimitry Andric   return ent;
116*68d75effSDimitry Andric }
117*68d75effSDimitry Andric 
118*68d75effSDimitry Andric void SymbolizeFlush() {
119*68d75effSDimitry Andric   Symbolizer::GetOrInit()->Flush();
120*68d75effSDimitry Andric }
121*68d75effSDimitry Andric 
122*68d75effSDimitry Andric }  // namespace __tsan
123