| 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 | |