From fbaaed6b581a3d08b16f0a247e32e98398d014ea Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Thu, 6 Nov 2014 18:43:45 +0000 Subject: [PATCH] [Sanitizer] Introduce "stack_trace_format" runtime flag. This flag can be used to specify the format of stack frames - user can now provide a string with placeholders, which should be printed for each stack frame with placeholders replaced with actual data. For example "%p" will be replaced by PC, "%s" will be replaced by the source file name etc. "DEFAULT" value enforces default stack trace format currently used in all the sanitizers except TSan. This change also implements __sanitizer_print_stack_trace interface function in TSan. llvm-svn: 221469 --- compiler-rt/lib/sanitizer_common/sanitizer_flags.cc | 5 +++++ compiler-rt/lib/sanitizer_common/sanitizer_flags.h | 1 + .../sanitizer_common/sanitizer_stacktrace_libcdep.cc | 4 ++-- compiler-rt/lib/tsan/rtl/tsan_flags.cc | 1 + compiler-rt/lib/tsan/rtl/tsan_report.cc | 4 ++-- compiler-rt/lib/tsan/rtl/tsan_rtl.h | 2 +- compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc | 15 ++++++++++++--- .../sanitizer_common/TestCases/print-stack-trace.cc | 20 ++++++++++---------- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc index 55644e0..40b6ec0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc @@ -68,6 +68,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->print_suppressions = true; f->disable_coredump = (SANITIZER_WORDSIZE == 64); f->symbolize_inline_frames = true; + f->stack_trace_format = "DEFAULT"; } void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { @@ -161,6 +162,10 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { "default and for sanitizers that don't reserve lots of virtual memory."); ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames", "Print inlined frames in stacktraces. Defaults to true."); + ParseFlag(str, &f->stack_trace_format, "stack_trace_format", + "Format string used to render stack frames. " + "See sanitizer_stacktrace_printer.h for the format description. " + "Use DEFAULT to get default format."); // Do a sanity check for certain flags. if (f->malloc_context_size < 1) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h index 6d1d9b60..4791397 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h @@ -62,6 +62,7 @@ struct CommonFlags { bool print_suppressions; bool disable_coredump; bool symbolize_inline_frames; + const char *stack_trace_format; }; inline CommonFlags *common_flags() { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc index 2c37ebc..13fb01f9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -43,8 +43,8 @@ void StackTrace::Print() const { for (uptr j = 0; j < addr_frames_num; j++) { AddressInfo &info = addr_frames[j]; frame_desc.clear(); - RenderFrame(&frame_desc, "DEFAULT", frame_num++, info, - common_flags()->strip_path_prefix); + RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, + info, common_flags()->strip_path_prefix); Printf("%s\n", frame_desc.data()); info.Clear(); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc index 92b312c..5dc331f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc @@ -99,6 +99,7 @@ void InitializeFlags(Flags *f, const char *env) { cf->allow_addr2line = true; cf->detect_deadlocks = true; cf->print_suppressions = false; + cf->stack_trace_format = " #%n %f %S %M"; // Let a frontend override. ParseFlags(f, __tsan_default_options()); diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc index 1503a04..f4a1ddb 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc @@ -118,9 +118,9 @@ void PrintStack(const ReportStack *ent) { Printf(" [failed to restore the stack]\n\n"); return; } - for (int i = 0; ent; ent = ent->next, i++) { + for (int i = 0; ent && ent->info.address; ent = ent->next, i++) { InternalScopedString res(2 * GetPageSizeCached()); - RenderFrame(&res, " #%n %f %S %M", i, ent->info, + RenderFrame(&res, common_flags()->stack_trace_format, i, ent->info, common_flags()->strip_path_prefix, "__interceptor_"); Printf("%s\n", res.data()); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index 3ace2f5..3d483bc 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -586,7 +586,7 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent); u32 CurrentStackId(ThreadState *thr, uptr pc); ReportStack *SymbolizeStackId(u32 stack_id); void PrintCurrentStack(ThreadState *thr, uptr pc); -void PrintCurrentStackSlow(); // uses libunwind +void PrintCurrentStackSlow(uptr pc); // uses libunwind void Initialize(ThreadState *thr); int Finalize(ThreadState *thr); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc index 00be371..c7a00c9 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc @@ -41,7 +41,7 @@ void TsanCheckFailed(const char *file, int line, const char *cond, Printf("FATAL: ThreadSanitizer CHECK failed: " "%s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); - PrintCurrentStackSlow(); + PrintCurrentStackSlow(StackTrace::GetCurrentPc()); Die(); } @@ -668,12 +668,12 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) { PrintStack(SymbolizeStack(trace)); } -void PrintCurrentStackSlow() { +void PrintCurrentStackSlow(uptr pc) { #ifndef TSAN_GO BufferedStackTrace *ptrace = new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) BufferedStackTrace(); - ptrace->Unwind(kStackTraceMax, StackTrace::GetCurrentPc(), 0, 0, 0, 0, false); + ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false); for (uptr i = 0; i < ptrace->size / 2; i++) { uptr tmp = ptrace->trace_buffer[i]; ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; @@ -684,3 +684,12 @@ void PrintCurrentStackSlow() { } } // namespace __tsan + +using namespace __tsan; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_stack_trace() { + PrintCurrentStackSlow(StackTrace::GetCurrentPc()); +} +} // extern "C" diff --git a/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace.cc b/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace.cc index a842ca6..1251f67 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace.cc +++ b/compiler-rt/test/sanitizer_common/TestCases/print-stack-trace.cc @@ -1,10 +1,7 @@ -// RUN: %clangxx -O0 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx -O3 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %tool_options=symbolize_inline_frames=false %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE - -// Not yet implemented for TSan. -// https://code.google.com/p/address-sanitizer/issues/detail?id=243 -// XFAIL: tsan +// RUN: %clangxx -O0 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -O3 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s +// RUN: %tool_options='stack_trace_format="frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM +// RUN: %tool_options=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE #include @@ -17,8 +14,11 @@ int main() { return 0; } // CHECK: {{ #0 0x.* in __sanitizer_print_stack_trace}} -// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:12}} -// CHECK: {{ #2 0x.* in main.*print-stack-trace.cc:16}} +// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:9}} +// CHECK: {{ #2 0x.* in main.*print-stack-trace.cc:13}} + +// CUSTOM: frame:1 lineno:9 +// CUSTOM: frame:2 lineno:13 // NOINLINE: #0 0x{{.*}} in __sanitizer_print_stack_trace -// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:12 +// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:9 -- 2.7.4