Index: lib/sanitizer_common/sanitizer_symbolizer.h =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer.h +++ lib/sanitizer_common/sanitizer_symbolizer.h @@ -144,6 +144,20 @@ }; }; +struct ReportStack { + ReportStack *next; + AddressInfo info; + bool suppressable; + static ReportStack *New(uptr addr); + + private: + ReportStack(); +}; + +ReportStack *SymbolizeCode(uptr addr); + +ReportStack *SymbolizeStack(StackTrace trace, bool strip_main = true); + } // namespace __sanitizer #endif // SANITIZER_SYMBOLIZER_H Index: lib/sanitizer_common/sanitizer_symbolizer.cc =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer.cc +++ lib/sanitizer_common/sanitizer_symbolizer.cc @@ -14,6 +14,7 @@ #include "sanitizer_platform.h" #include "sanitizer_internal_defs.h" #include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" namespace __sanitizer { @@ -49,4 +50,105 @@ sym_->end_hook_(); } +ReportStack::ReportStack() : next(nullptr), info(), suppressable(false) {} + +ReportStack *ReportStack::New(uptr addr) { + void *mem = InternalAlloc(sizeof(ReportStack)); + ReportStack *res = new(mem) ReportStack(); + res->info.address = addr; + return res; +} + +ReportStack *SymbolizeCode(uptr addr) { + static const uptr kMaxAddrFrames = 16; + InternalScopedBuffer addr_frames(kMaxAddrFrames); + for (uptr i = 0; i < kMaxAddrFrames; i++) + new(&addr_frames[i]) AddressInfo(); + uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC( + addr, addr_frames.data(), kMaxAddrFrames); + if (addr_frames_num == 0) + return ReportStack::New(addr); + ReportStack *top = 0; + ReportStack *bottom = 0; + for (uptr i = 0; i < addr_frames_num; i++) { + ReportStack *cur_entry = ReportStack::New(addr); + cur_entry->info = addr_frames[i]; + if (i == 0) + top = cur_entry; + else + bottom->next = cur_entry; + bottom = cur_entry; + } + return top; +} + +static void StackStripMain(ReportStack *stack) { + ReportStack *last_frame = 0; + ReportStack *last_frame2 = 0; + for (ReportStack *ent = stack; ent; ent = ent->next) { + last_frame2 = last_frame; + last_frame = ent; + } + + if (last_frame2 == 0) + return; + const char *last = last_frame->info.function; +#ifndef SANITIZER_GO + const char *last2 = last_frame2->info.function; + // Strip frame above 'main' + if (last2 && 0 == internal_strcmp(last2, "main")) { + last_frame2->next = 0; + // Strip our internal thread start routine. + } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { + last_frame2->next = 0; + // Strip global ctors init. + } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { + last_frame2->next = 0; + // If both are 0, then we probably just failed to symbolize. + } else if (last || last2) { + // Ensure that we recovered stack completely. Trimmed stack + // can actually happen if we do not instrument some code, + // so it's only a debug print. However we must try hard to not miss it + // due to our fault. + Printf("Bottom stack frame of stack %zx is missed\n", stack->info.address); + } +#else + // The last frame always point into runtime (gosched0, goexit0, runtime.main). + last_frame2->next = 0; + (void)last; +#endif +} + +ReportStack *SymbolizeStack(StackTrace trace, bool strip_main) { + if (trace.size == 0) + return 0; + ReportStack *stack = 0; + for (uptr si = 0; si < trace.size; si++) { + const uptr pc = trace.trace[si]; +#ifndef SANITIZER_GO + // We obtain the return address, that is, address of the next instruction, + // so offset it by 1 byte. + const uptr pc1 = StackTrace::GetPreviousInstructionPc(pc); +#else + // FIXME(dvyukov): Go sometimes uses address of a function as top pc. + uptr pc1 = pc; + if (si != trace.size - 1) + pc1 -= 1; +#endif + ReportStack *ent = SymbolizeCode(pc1); + CHECK_NE(ent, 0); + ReportStack *last = ent; + while (last->next) { + last->info.address = pc; // restore original pc for report + last = last->next; + } + last->info.address = pc; // restore original pc for report + last->next = stack; + stack = ent; + } + if (strip_main) + StackStripMain(stack); + return stack; +} + } // namespace __sanitizer Index: lib/tsan/rtl/tsan_report.h =================================================================== --- lib/tsan/rtl/tsan_report.h +++ lib/tsan/rtl/tsan_report.h @@ -35,16 +35,6 @@ ReportTypeDeadlock }; -struct ReportStack { - ReportStack *next; - AddressInfo info; - bool suppressable; - static ReportStack *New(uptr addr); - - private: - ReportStack(); -}; - struct ReportMopMutex { u64 id; bool write; Index: lib/tsan/rtl/tsan_report.cc =================================================================== --- lib/tsan/rtl/tsan_report.cc +++ lib/tsan/rtl/tsan_report.cc @@ -19,15 +19,6 @@ namespace __tsan { -ReportStack::ReportStack() : next(nullptr), info(), suppressable(false) {} - -ReportStack *ReportStack::New(uptr addr) { - void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack)); - ReportStack *res = new(mem) ReportStack(); - res->info.address = addr; - return res; -} - ReportLocation::ReportLocation(ReportLocationType type) : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0), fd(0), suppressable(false), stack(nullptr) {} Index: lib/tsan/rtl/tsan_rtl_report.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_report.cc +++ lib/tsan/rtl/tsan_rtl_report.cc @@ -30,8 +30,6 @@ using namespace __sanitizer; // NOLINT -static ReportStack *SymbolizeStack(StackTrace trace); - void TsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { // There is high probability that interceptors will check-fail as well, @@ -56,43 +54,6 @@ } #endif -static void StackStripMain(ReportStack *stack) { - ReportStack *last_frame = 0; - ReportStack *last_frame2 = 0; - for (ReportStack *ent = stack; ent; ent = ent->next) { - last_frame2 = last_frame; - last_frame = ent; - } - - if (last_frame2 == 0) - return; - const char *last = last_frame->info.function; -#ifndef TSAN_GO - const char *last2 = last_frame2->info.function; - // Strip frame above 'main' - if (last2 && 0 == internal_strcmp(last2, "main")) { - last_frame2->next = 0; - // Strip our internal thread start routine. - } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { - last_frame2->next = 0; - // Strip global ctors init. - } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { - last_frame2->next = 0; - // If both are 0, then we probably just failed to symbolize. - } else if (last || last2) { - // Ensure that we recovered stack completely. Trimmed stack - // can actually happen if we do not instrument some code, - // so it's only a debug print. However we must try hard to not miss it - // due to our fault. - DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc); - } -#else - // The last frame always point into runtime (gosched0, goexit0, runtime.main). - last_frame2->next = 0; - (void)last; -#endif -} - ReportStack *SymbolizeStackId(u32 stack_id) { if (stack_id == 0) return 0; @@ -102,37 +63,6 @@ return SymbolizeStack(stack); } -static ReportStack *SymbolizeStack(StackTrace trace) { - if (trace.size == 0) - return 0; - ReportStack *stack = 0; - for (uptr si = 0; si < trace.size; si++) { - const uptr pc = trace.trace[si]; -#ifndef TSAN_GO - // We obtain the return address, that is, address of the next instruction, - // so offset it by 1 byte. - const uptr pc1 = StackTrace::GetPreviousInstructionPc(pc); -#else - // FIXME(dvyukov): Go sometimes uses address of a function as top pc. - uptr pc1 = pc; - if (si != trace.size - 1) - pc1 -= 1; -#endif - ReportStack *ent = SymbolizeCode(pc1); - CHECK_NE(ent, 0); - ReportStack *last = ent; - while (last->next) { - last->info.address = pc; // restore original pc for report - last = last->next; - } - last->info.address = pc; // restore original pc for report - last->next = stack; - stack = ent; - } - StackStripMain(stack); - return stack; -} - ScopedReport::ScopedReport(ReportType typ) { ctx->thread_registry->CheckLocked(); void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); Index: lib/tsan/rtl/tsan_symbolize.cc =================================================================== --- lib/tsan/rtl/tsan_symbolize.cc +++ lib/tsan/rtl/tsan_symbolize.cc @@ -73,26 +73,7 @@ ent->info.column = col; return ent; } - static const uptr kMaxAddrFrames = 16; - InternalScopedBuffer addr_frames(kMaxAddrFrames); - for (uptr i = 0; i < kMaxAddrFrames; i++) - new(&addr_frames[i]) AddressInfo(); - uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC( - addr, addr_frames.data(), kMaxAddrFrames); - if (addr_frames_num == 0) - return ReportStack::New(addr); - ReportStack *top = 0; - ReportStack *bottom = 0; - for (uptr i = 0; i < addr_frames_num; i++) { - ReportStack *cur_entry = ReportStack::New(addr); - cur_entry->info = addr_frames[i]; - if (i == 0) - top = cur_entry; - else - bottom->next = cur_entry; - bottom = cur_entry; - } - return top; + return __sanitizer::SymbolizeCode(addr); } ReportLocation *SymbolizeData(uptr addr) {