tsan_symbolize.cpp revision 353944
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 22namespace __tsan { 23 24void EnterSymbolizer() { 25 ThreadState *thr = cur_thread(); 26 CHECK(!thr->in_symbolizer); 27 thr->in_symbolizer = true; 28 thr->ignore_interceptors++; 29} 30 31void 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. 41SANITIZER_WEAK_DEFAULT_IMPL 42bool __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. 50SANITIZER_WEAK_DEFAULT_IMPL 51void __tsan_symbolize_external_ex(uptr pc, 52 void (*add_frame)(void *, const char *, 53 const char *, int, int), 54 void *ctx) {} 55 56struct SymbolizedStackBuilder { 57 SymbolizedStack *head; 58 SymbolizedStack *tail; 59 uptr addr; 60}; 61 62static 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 82SymbolizedStack *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 109ReportLocation *SymbolizeData(uptr addr) { 110 DataInfo info; 111 if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) 112 return 0; 113 ReportLocation *ent = ReportLocation::New(ReportLocationGlobal); 114 internal_memcpy(&ent->global, &info, sizeof(info)); 115 return ent; 116} 117 118void SymbolizeFlush() { 119 Symbolizer::GetOrInit()->Flush(); 120} 121 122} // namespace __tsan 123