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(ssb->addr); 67 ssb->tail = ssb->tail->next; 68 } else { 69 ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr); 70 } 71 AddressInfo *info = &ssb->tail->info; 72 if (function_name) { 73 info->function = internal_strdup(function_name); 74 } 75 if (file) { 76 info->file = internal_strdup(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 = {nullptr, nullptr, addr}; 86 __tsan_symbolize_external_ex(addr, AddFrame, &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(addr, func_buf, sizeof(func_buf), file_buf, 98 sizeof(file_buf), &line, &col)) { 99 frame->info.function = internal_strdup(func_buf); 100 frame->info.file = internal_strdup(file_buf); 101 frame->info.line = line; 102 frame->info.column = col; 103 } 104 return frame; 105 } 106 return Symbolizer::GetOrInit()->SymbolizePC(addr); 107 } 108 109 ReportLocation *SymbolizeData(uptr addr) { 110 DataInfo info; 111 if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) 112 return 0; 113 auto *ent = New<ReportLocation>(); 114 ent->type = ReportLocationGlobal; 115 internal_memcpy(&ent->global, &info, sizeof(info)); 116 return ent; 117 } 118 119 void SymbolizeFlush() { 120 Symbolizer::GetOrInit()->Flush(); 121 } 122 123 } // namespace __tsan 124