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