tsan_symbolize.cc revision 66d91e3356a0c4d7aff3beaaaff3e87bbaec805c
1//===-- tsan_symbolize.cc -------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of ThreadSanitizer (TSan), a race detector. 11// 12//===----------------------------------------------------------------------===// 13 14#include "tsan_symbolize.h" 15 16#include "sanitizer_common/sanitizer_common.h" 17#include "sanitizer_common/sanitizer_placement_new.h" 18#include "sanitizer_common/sanitizer_symbolizer.h" 19#include "tsan_flags.h" 20#include "tsan_report.h" 21#include "tsan_rtl.h" 22 23namespace __tsan { 24 25void EnterSymbolizer() { 26 ThreadState *thr = cur_thread(); 27 CHECK(!thr->in_symbolizer); 28 thr->in_symbolizer = true; 29} 30 31void ExitSymbolizer() { 32 ThreadState *thr = cur_thread(); 33 CHECK(thr->in_symbolizer); 34 thr->in_symbolizer = false; 35} 36 37ReportStack *NewReportStackEntry(uptr addr) { 38 ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack, 39 sizeof(ReportStack)); 40 internal_memset(ent, 0, sizeof(*ent)); 41 ent->pc = addr; 42 return ent; 43} 44 45// Strip module path to make output shorter. 46static char *StripModuleName(const char *module) { 47 if (module == 0) 48 return 0; 49 const char *short_module_name = internal_strrchr(module, '/'); 50 if (short_module_name) 51 short_module_name += 1; 52 else 53 short_module_name = module; 54 return internal_strdup(short_module_name); 55} 56 57static ReportStack *NewReportStackEntry(const AddressInfo &info) { 58 ReportStack *ent = NewReportStackEntry(info.address); 59 ent->module = StripModuleName(info.module); 60 ent->offset = info.module_offset; 61 if (info.function) 62 ent->func = internal_strdup(info.function); 63 if (info.file) 64 ent->file = internal_strdup(info.file); 65 ent->line = info.line; 66 ent->col = info.column; 67 return ent; 68} 69 70 71 ReportStack *next; 72 char *module; 73 uptr offset; 74 uptr pc; 75 char *func; 76 char *file; 77 int line; 78 int col; 79 80 81// Denotes fake PC values that come from JIT/JAVA/etc. 82// For such PC values __tsan_symbolize_external() will be called. 83const uptr kExternalPCBit = 1ULL << 60; 84 85// May be overriden by JIT/JAVA/etc, 86// whatever produces PCs marked with kExternalPCBit. 87extern "C" bool __tsan_symbolize_external(uptr pc, 88 char *func_buf, uptr func_siz, 89 char *file_buf, uptr file_siz, 90 int *line, int *col) 91 SANITIZER_WEAK_ATTRIBUTE; 92 93bool __tsan_symbolize_external(uptr pc, 94 char *func_buf, uptr func_siz, 95 char *file_buf, uptr file_siz, 96 int *line, int *col) { 97 return false; 98} 99 100ReportStack *SymbolizeCode(uptr addr) { 101 // Check if PC comes from non-native land. 102 if (addr & kExternalPCBit) { 103 // Declare static to not consume too much stack space. 104 // We symbolize reports in a single thread, so this is fine. 105 static char func_buf[1024]; 106 static char file_buf[1024]; 107 int line, col; 108 if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), 109 file_buf, sizeof(file_buf), &line, &col)) 110 return NewReportStackEntry(addr); 111 ReportStack *ent = NewReportStackEntry(addr); 112 ent->module = 0; 113 ent->offset = 0; 114 ent->func = internal_strdup(func_buf); 115 ent->file = internal_strdup(file_buf); 116 ent->line = line; 117 ent->col = col; 118 return ent; 119 } 120 if (!Symbolizer::Get()->IsAvailable()) 121 return SymbolizeCodeAddr2Line(addr); 122 static const uptr kMaxAddrFrames = 16; 123 InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames); 124 for (uptr i = 0; i < kMaxAddrFrames; i++) 125 new(&addr_frames[i]) AddressInfo(); 126 uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode( 127 addr, addr_frames.data(), kMaxAddrFrames); 128 if (addr_frames_num == 0) 129 return NewReportStackEntry(addr); 130 ReportStack *top = 0; 131 ReportStack *bottom = 0; 132 for (uptr i = 0; i < addr_frames_num; i++) { 133 ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]); 134 CHECK(cur_entry); 135 addr_frames[i].Clear(); 136 if (i == 0) 137 top = cur_entry; 138 else 139 bottom->next = cur_entry; 140 bottom = cur_entry; 141 } 142 return top; 143} 144 145ReportLocation *SymbolizeData(uptr addr) { 146 if (!Symbolizer::Get()->IsAvailable()) 147 return 0; 148 DataInfo info; 149 if (!Symbolizer::Get()->SymbolizeData(addr, &info)) 150 return 0; 151 ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack, 152 sizeof(ReportLocation)); 153 internal_memset(ent, 0, sizeof(*ent)); 154 ent->type = ReportLocationGlobal; 155 ent->module = StripModuleName(info.module); 156 ent->offset = info.module_offset; 157 if (info.name) 158 ent->name = internal_strdup(info.name); 159 ent->addr = info.start; 160 ent->size = info.size; 161 return ent; 162} 163 164void SymbolizeFlush() { 165 if (!Symbolizer::Get()->IsAvailable()) 166 return; 167 Symbolizer::Get()->Flush(); 168} 169 170} // namespace __tsan 171