forked from OSchip/llvm-project
[sanitizer] Use system unwinder in signal handlers on Android.
Because of the way Bionic sets up signal stack frames, libc unwinder is unable to step through it, resulting in broken SEGV stack traces. Luckily, libcorkscrew.so on Android implements an unwinder that can start with a signal context, thus sidestepping the issue. llvm-svn: 201151
This commit is contained in:
parent
ca183eed55
commit
769d46f373
|
@ -38,7 +38,7 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
|
|||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||
uptr pc, sp, bp;
|
||||
GetPcSpBp(context, &pc, &sp, &bp);
|
||||
ReportSIGSEGV(pc, sp, bp, addr);
|
||||
ReportSIGSEGV(pc, sp, bp, context, addr);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
|
|
@ -570,7 +570,7 @@ class ScopedInErrorReport {
|
|||
}
|
||||
};
|
||||
|
||||
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
|
||||
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
|
||||
ScopedInErrorReport in_report;
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
|
@ -579,7 +579,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
|
|||
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
|
||||
GetCurrentTidOrInvalid());
|
||||
Printf("%s", d.EndWarning());
|
||||
GET_STACK_TRACE_FATAL(pc, bp);
|
||||
GET_STACK_TRACE_SIGNAL(pc, bp, context);
|
||||
stack.Print();
|
||||
Printf("AddressSanitizer can not provide additional info.\n");
|
||||
ReportErrorSummary("SEGV", &stack);
|
||||
|
|
|
@ -32,7 +32,8 @@ void DescribeAddress(uptr addr, uptr access_size);
|
|||
void DescribeThread(AsanThreadContext *context);
|
||||
|
||||
// Different kinds of error reports.
|
||||
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
|
||||
void NORETURN
|
||||
ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
|
||||
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
|
||||
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
|
||||
void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
|
||||
|
|
|
@ -532,6 +532,7 @@ static void AsanInitInternal() {
|
|||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart(internal_getpid());
|
||||
force_interface_symbols(); // no-op.
|
||||
SanitizerInitializeUnwinder();
|
||||
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
__lsan::InitCommonLsan();
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
// The pc will be in the position 0 of the resulting stack trace.
|
||||
// The bp may refer to the current frame or to the caller's frame.
|
||||
#if SANITIZER_WINDOWS
|
||||
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
|
||||
StackTrace stack; \
|
||||
stack.Unwind(max_s, pc, bp, 0, 0, fast)
|
||||
#define GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_s, pc, bp, context, fast) \
|
||||
StackTrace stack; \
|
||||
stack.Unwind(max_s, pc, bp, context, 0, 0, fast)
|
||||
#else
|
||||
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
|
||||
#define GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_s, pc, bp, context, fast) \
|
||||
StackTrace stack; \
|
||||
{ \
|
||||
AsanThread *t; \
|
||||
|
@ -37,10 +37,10 @@
|
|||
uptr stack_top = t->stack_top(); \
|
||||
uptr stack_bottom = t->stack_bottom(); \
|
||||
ScopedUnwinding unwind_scope(t); \
|
||||
stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
|
||||
stack.Unwind(max_s, pc, bp, context, stack_top, stack_bottom, fast); \
|
||||
} else if (t == 0 && !fast) { \
|
||||
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */ \
|
||||
stack.Unwind(max_s, pc, bp, 0, 0, false); \
|
||||
stack.Unwind(max_s, pc, bp, context, 0, 0, false); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
@ -50,13 +50,17 @@
|
|||
// as early as possible (in functions exposed to the user), as we generally
|
||||
// don't want stack trace to contain functions from ASan internals.
|
||||
|
||||
#define GET_STACK_TRACE(max_size, fast) \
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
|
||||
StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
|
||||
#define GET_STACK_TRACE(max_size, fast) \
|
||||
GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_size, StackTrace::GetCurrentPc(), \
|
||||
GET_CURRENT_FRAME(), 0, fast)
|
||||
|
||||
#define GET_STACK_TRACE_FATAL(pc, bp) \
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
#define GET_STACK_TRACE_FATAL(pc, bp) \
|
||||
GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(kStackTraceMax, pc, bp, 0, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_SIGNAL(pc, bp, context) \
|
||||
GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(kStackTraceMax, pc, bp, context, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_FATAL_HERE \
|
||||
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
|
||||
|
|
|
@ -154,11 +154,11 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
|
|||
if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
|
||||
// Block reports from our interceptors during _Unwind_Backtrace.
|
||||
SymbolizerScope sym_scope;
|
||||
return stack->Unwind(max_s, pc, bp, 0, 0, request_fast_unwind);
|
||||
return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
|
||||
}
|
||||
uptr stack_bottom = msan_stack_bounds.stack_addr;
|
||||
uptr stack_top = stack_bottom + msan_stack_bounds.stack_size;
|
||||
stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
|
||||
stack->Unwind(max_s, pc, bp, 0, stack_top, stack_bottom, request_fast_unwind);
|
||||
}
|
||||
|
||||
void PrintWarning(uptr pc, uptr bp) {
|
||||
|
|
|
@ -509,9 +509,11 @@ F IndirectExternCall(F f) {
|
|||
#if SANITIZER_ANDROID
|
||||
void AndroidLogWrite(const char *buffer);
|
||||
void GetExtraActivationFlags(char *buf, uptr size);
|
||||
void SanitizerInitializeUnwinder();
|
||||
#else
|
||||
INLINE void AndroidLogWrite(const char *buffer_unused) {}
|
||||
INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
|
||||
INLINE void SanitizerInitializeUnwinder() {}
|
||||
#endif
|
||||
} // namespace __sanitizer
|
||||
|
||||
|
|
|
@ -142,6 +142,51 @@ bool SanitizerGetThreadName(char *name, int max_len) {
|
|||
|
||||
#ifndef SANITIZER_GO
|
||||
//------------------------- SlowUnwindStack -----------------------------------
|
||||
|
||||
typedef struct {
|
||||
uptr absolute_pc;
|
||||
uptr stack_top;
|
||||
uptr stack_size;
|
||||
} backtrace_frame_t;
|
||||
|
||||
extern "C" {
|
||||
typedef void *(*acquire_my_map_info_list_func)();
|
||||
typedef void (*release_my_map_info_list_func)(void *map);
|
||||
typedef sptr (*unwind_backtrace_signal_arch_func)(
|
||||
void *siginfo, void *sigcontext, void *map_info_list,
|
||||
backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
|
||||
acquire_my_map_info_list_func acquire_my_map_info_list;
|
||||
release_my_map_info_list_func release_my_map_info_list;
|
||||
unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
|
||||
} // extern "C"
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
void SanitizerInitializeUnwinder() {
|
||||
void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
|
||||
if (!p) {
|
||||
VReport(1,
|
||||
"Failed to open libcorkscrew.so. You may see broken stack traces "
|
||||
"in SEGV reports.");
|
||||
return;
|
||||
}
|
||||
acquire_my_map_info_list =
|
||||
(acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
|
||||
release_my_map_info_list =
|
||||
(release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
|
||||
unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
|
||||
p, "unwind_backtrace_signal_arch");
|
||||
if (!acquire_my_map_info_list || !release_my_map_info_list ||
|
||||
!unwind_backtrace_signal_arch) {
|
||||
VReport(1,
|
||||
"Failed to find one of the required symbols in libcorkscrew.so. "
|
||||
"You may see broken stack traces in SEGV reports.");
|
||||
acquire_my_map_info_list = NULL;
|
||||
unwind_backtrace_signal_arch = NULL;
|
||||
release_my_map_info_list = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#define UNWIND_STOP _URC_END_OF_STACK
|
||||
#define UNWIND_CONTINUE _URC_NO_REASON
|
||||
|
@ -192,6 +237,31 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
|
|||
trace[0] = pc;
|
||||
}
|
||||
|
||||
void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
|
||||
uptr max_depth) {
|
||||
if (!unwind_backtrace_signal_arch) {
|
||||
SlowUnwindStack(pc, max_depth);
|
||||
return;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
if (max_depth == 0) return;
|
||||
|
||||
void *map = acquire_my_map_info_list();
|
||||
CHECK(map);
|
||||
backtrace_frame_t frames[kStackTraceMax];
|
||||
// siginfo argument appears to be unused.
|
||||
sptr res =
|
||||
unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map, frames,
|
||||
/* ignore_depth */ 0, max_depth);
|
||||
release_my_map_info_list(map);
|
||||
if (res < 0) return;
|
||||
CHECK((uptr)res <= kStackTraceMax);
|
||||
|
||||
for (sptr i = 0; i < res; ++i)
|
||||
trace[size++] = frames[i].absolute_pc;
|
||||
}
|
||||
|
||||
#endif // !SANITIZER_GO
|
||||
|
||||
static uptr g_tls_size;
|
||||
|
|
|
@ -58,7 +58,7 @@ struct StackTrace {
|
|||
return request_fast_unwind;
|
||||
}
|
||||
|
||||
void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
|
||||
void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
|
||||
uptr stack_bottom, bool request_fast_unwind);
|
||||
|
||||
static uptr GetCurrentPc();
|
||||
|
@ -68,6 +68,8 @@ struct StackTrace {
|
|||
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
|
||||
uptr max_depth);
|
||||
void SlowUnwindStack(uptr pc, uptr max_depth);
|
||||
void SlowUnwindStackWithContext(uptr pc, void *context,
|
||||
uptr max_depth);
|
||||
void PopStackFrames(uptr count);
|
||||
uptr LocatePcInTrace(uptr pc);
|
||||
};
|
||||
|
|
|
@ -63,12 +63,17 @@ void StackTrace::PrintStack(const uptr *addr, uptr size) {
|
|||
Printf("\n");
|
||||
}
|
||||
|
||||
void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
|
||||
uptr stack_bottom, bool request_fast_unwind) {
|
||||
if (!WillUseFastUnwind(request_fast_unwind))
|
||||
SlowUnwindStack(pc, max_depth);
|
||||
else
|
||||
void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
|
||||
uptr stack_top, uptr stack_bottom,
|
||||
bool request_fast_unwind) {
|
||||
if (!WillUseFastUnwind(request_fast_unwind)) {
|
||||
if (context)
|
||||
SlowUnwindStackWithContext(pc, context, max_depth);
|
||||
else
|
||||
SlowUnwindStack(pc, max_depth);
|
||||
} else {
|
||||
FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
|
||||
}
|
||||
|
||||
top_frame_bp = size ? bp : 0;
|
||||
}
|
||||
|
|
|
@ -713,8 +713,8 @@ void PrintCurrentStackSlow() {
|
|||
#ifndef TSAN_GO
|
||||
__sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
|
||||
sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
|
||||
ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(),
|
||||
0, 0, 0, false);
|
||||
ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(), 0, 0,
|
||||
0, 0, false);
|
||||
for (uptr i = 0; i < ptrace->size / 2; i++) {
|
||||
uptr tmp = ptrace->trace[i];
|
||||
ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
|
||||
|
|
Loading…
Reference in New Issue