forked from OSchip/llvm-project
[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
This commit is contained in:
parent
e6352e4797
commit
fbaaed6b58
|
|
@ -68,6 +68,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) {
|
||||||
f->print_suppressions = true;
|
f->print_suppressions = true;
|
||||||
f->disable_coredump = (SANITIZER_WORDSIZE == 64);
|
f->disable_coredump = (SANITIZER_WORDSIZE == 64);
|
||||||
f->symbolize_inline_frames = true;
|
f->symbolize_inline_frames = true;
|
||||||
|
f->stack_trace_format = "DEFAULT";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
|
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.");
|
"default and for sanitizers that don't reserve lots of virtual memory.");
|
||||||
ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
|
ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
|
||||||
"Print inlined frames in stacktraces. Defaults to true.");
|
"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.
|
// Do a sanity check for certain flags.
|
||||||
if (f->malloc_context_size < 1)
|
if (f->malloc_context_size < 1)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ struct CommonFlags {
|
||||||
bool print_suppressions;
|
bool print_suppressions;
|
||||||
bool disable_coredump;
|
bool disable_coredump;
|
||||||
bool symbolize_inline_frames;
|
bool symbolize_inline_frames;
|
||||||
|
const char *stack_trace_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline CommonFlags *common_flags() {
|
inline CommonFlags *common_flags() {
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ void StackTrace::Print() const {
|
||||||
for (uptr j = 0; j < addr_frames_num; j++) {
|
for (uptr j = 0; j < addr_frames_num; j++) {
|
||||||
AddressInfo &info = addr_frames[j];
|
AddressInfo &info = addr_frames[j];
|
||||||
frame_desc.clear();
|
frame_desc.clear();
|
||||||
RenderFrame(&frame_desc, "DEFAULT", frame_num++, info,
|
RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
|
||||||
common_flags()->strip_path_prefix);
|
info, common_flags()->strip_path_prefix);
|
||||||
Printf("%s\n", frame_desc.data());
|
Printf("%s\n", frame_desc.data());
|
||||||
info.Clear();
|
info.Clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||||
cf->allow_addr2line = true;
|
cf->allow_addr2line = true;
|
||||||
cf->detect_deadlocks = true;
|
cf->detect_deadlocks = true;
|
||||||
cf->print_suppressions = false;
|
cf->print_suppressions = false;
|
||||||
|
cf->stack_trace_format = " #%n %f %S %M";
|
||||||
|
|
||||||
// Let a frontend override.
|
// Let a frontend override.
|
||||||
ParseFlags(f, __tsan_default_options());
|
ParseFlags(f, __tsan_default_options());
|
||||||
|
|
|
||||||
|
|
@ -118,9 +118,9 @@ void PrintStack(const ReportStack *ent) {
|
||||||
Printf(" [failed to restore the stack]\n\n");
|
Printf(" [failed to restore the stack]\n\n");
|
||||||
return;
|
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());
|
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_");
|
common_flags()->strip_path_prefix, "__interceptor_");
|
||||||
Printf("%s\n", res.data());
|
Printf("%s\n", res.data());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -586,7 +586,7 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent);
|
||||||
u32 CurrentStackId(ThreadState *thr, uptr pc);
|
u32 CurrentStackId(ThreadState *thr, uptr pc);
|
||||||
ReportStack *SymbolizeStackId(u32 stack_id);
|
ReportStack *SymbolizeStackId(u32 stack_id);
|
||||||
void PrintCurrentStack(ThreadState *thr, uptr pc);
|
void PrintCurrentStack(ThreadState *thr, uptr pc);
|
||||||
void PrintCurrentStackSlow(); // uses libunwind
|
void PrintCurrentStackSlow(uptr pc); // uses libunwind
|
||||||
|
|
||||||
void Initialize(ThreadState *thr);
|
void Initialize(ThreadState *thr);
|
||||||
int Finalize(ThreadState *thr);
|
int Finalize(ThreadState *thr);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ void TsanCheckFailed(const char *file, int line, const char *cond,
|
||||||
Printf("FATAL: ThreadSanitizer CHECK failed: "
|
Printf("FATAL: ThreadSanitizer CHECK failed: "
|
||||||
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||||
file, line, cond, (uptr)v1, (uptr)v2);
|
file, line, cond, (uptr)v1, (uptr)v2);
|
||||||
PrintCurrentStackSlow();
|
PrintCurrentStackSlow(StackTrace::GetCurrentPc());
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -668,12 +668,12 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
|
||||||
PrintStack(SymbolizeStack(trace));
|
PrintStack(SymbolizeStack(trace));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintCurrentStackSlow() {
|
void PrintCurrentStackSlow(uptr pc) {
|
||||||
#ifndef TSAN_GO
|
#ifndef TSAN_GO
|
||||||
BufferedStackTrace *ptrace =
|
BufferedStackTrace *ptrace =
|
||||||
new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
|
new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
|
||||||
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++) {
|
for (uptr i = 0; i < ptrace->size / 2; i++) {
|
||||||
uptr tmp = ptrace->trace_buffer[i];
|
uptr tmp = ptrace->trace_buffer[i];
|
||||||
ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
|
ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
|
||||||
|
|
@ -684,3 +684,12 @@ void PrintCurrentStackSlow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace __tsan
|
} // namespace __tsan
|
||||||
|
|
||||||
|
using namespace __tsan;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
void __sanitizer_print_stack_trace() {
|
||||||
|
PrintCurrentStackSlow(StackTrace::GetCurrentPc());
|
||||||
|
}
|
||||||
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
// RUN: %clangxx -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
|
// RUN: %clangxx -O0 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s
|
||||||
// RUN: %clangxx -O3 %s -o %t && %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=symbolize_inline_frames=false %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE
|
// 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
|
||||||
// Not yet implemented for TSan.
|
|
||||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=243
|
|
||||||
// XFAIL: tsan
|
|
||||||
|
|
||||||
#include <sanitizer/common_interface_defs.h>
|
#include <sanitizer/common_interface_defs.h>
|
||||||
|
|
||||||
|
|
@ -17,8 +14,11 @@ int main() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// CHECK: {{ #0 0x.* in __sanitizer_print_stack_trace}}
|
// CHECK: {{ #0 0x.* in __sanitizer_print_stack_trace}}
|
||||||
// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:12}}
|
// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:9}}
|
||||||
// CHECK: {{ #2 0x.* in main.*print-stack-trace.cc:16}}
|
// 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: #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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue