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