EHABI-based stack trace on ARM.

The change removes the unused FLAG_fast_unwind, and forces EHABI-based unwind
on ARM, and fast (FP-based) unwind everywhere else.

llvm-svn: 148468
This commit is contained in:
Evgeniy Stepanov 2012-01-19 11:34:18 +00:00
parent a875b7ccc7
commit 84c44a8b8b
7 changed files with 79 additions and 48 deletions

View File

@ -278,7 +278,7 @@ __attribute__((visibility("default")))
#endif
int WRAP(pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
int current_tid = asanThreadRegistry().GetCurrentTidOrMinusOne();
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
asanThreadRegistry().RegisterThread(t);

View File

@ -29,6 +29,7 @@
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unwind.h>
#ifndef ANDROID
// FIXME: where to get ucontext on Android?
@ -338,6 +339,50 @@ void AsanLock::Unlock() {
pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
}
#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif
uintptr_t Unwind_GetIP(struct _Unwind_Context *ctx) {
#ifdef __arm__
uintptr_t val;
_Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
15 /* r15 = PC */, _UVRSD_UINT32, &val);
CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
// Clear the Thumb bit.
return val & ~(uintptr_t)1;
#else
return _Unwind_GetIP(ctx);
#endif
}
_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
void *param) {
AsanStackTrace *b = (AsanStackTrace*)param;
CHECK(b->size < b->max_size);
uintptr_t pc = Unwind_GetIP(ctx);
b->trace[b->size++] = pc;
if (b->size == b->max_size) return UNWIND_STOP;
return UNWIND_CONTINUE;
}
void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
size = 0;
trace[0] = pc;
if ((max_s) > 1) {
max_size = max_s;
#ifdef __arm__
_Unwind_Backtrace(Unwind_Trace, this);
#else
FastUnwindStack(pc, bp);
#endif
}
}
} // namespace __asan
#endif // __linux__

View File

@ -263,6 +263,15 @@ void AsanLock::Unlock() {
OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
}
void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
size = 0;
trace[0] = pc;
if ((max_s) > 1) {
max_size = max_s;
FastUnwindStack(pc, bp);
}
}
// The range of pages to be used by __asan_mach_override_ptr for escape
// islands.
// TODO(glider): instead of mapping a fixed range we must find a range of
@ -335,7 +344,7 @@ mach_error_t __asan_deallocate_island(void *ptr) {
extern "C"
void asan_dispatch_call_block_and_release(void *block) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *context = (asan_block_context_t*)block;
if (FLAG_v >= 2) {
Report("asan_dispatch_call_block_and_release(): "
@ -376,7 +385,7 @@ extern "C"
int WRAP(dispatch_async_f)(dispatch_queue_t dq,
void *ctxt,
dispatch_function_t func) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (FLAG_v >= 2) {
Report("dispatch_async_f(): context: %p, pthread_self: %p\n",
@ -391,7 +400,7 @@ extern "C"
int WRAP(dispatch_sync_f)(dispatch_queue_t dq,
void *ctxt,
dispatch_function_t func) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (FLAG_v >= 2) {
Report("dispatch_sync_f(): context: %p, pthread_self: %p\n",
@ -407,7 +416,7 @@ int WRAP(dispatch_after_f)(dispatch_time_t when,
dispatch_queue_t dq,
void *ctxt,
dispatch_function_t func) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (FLAG_v >= 2) {
Report("dispatch_after_f: %p\n", asan_ctxt);
@ -420,7 +429,7 @@ int WRAP(dispatch_after_f)(dispatch_time_t when,
extern "C"
void WRAP(dispatch_barrier_async_f)(dispatch_queue_t dq,
void *ctxt, dispatch_function_t func) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (FLAG_v >= 2) {
Report("dispatch_barrier_async_f(): context: %p, pthread_self: %p\n",
@ -435,7 +444,7 @@ extern "C"
void WRAP(dispatch_group_async_f)(dispatch_group_t group,
dispatch_queue_t dq,
void *ctxt, dispatch_function_t func) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (FLAG_v >= 2) {
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
@ -460,7 +469,7 @@ void *wrap_workitem_func(void *arg) {
asan_block_context_t *ctxt = (asan_block_context_t*)arg;
worker_t fn = (worker_t)(ctxt->func);
void *result = fn(ctxt->block);
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_free(arg, &stack);
return result;
}
@ -469,7 +478,7 @@ extern "C"
int WRAP(pthread_workqueue_additem_np)(pthread_workqueue_t workq,
void *(*workitem_func)(void *), void * workitem_arg,
pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) {
GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
GET_STACK_TRACE_HERE(kStackTraceMax);
asan_block_context_t *asan_ctxt =
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack);
asan_ctxt->block = workitem_arg;

View File

@ -52,7 +52,7 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
addr, pc, sp, bp,
asanThreadRegistry().GetCurrentTidOrMinusOne());
Printf("AddressSanitizer can not provide additional info. ABORTING\n");
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, false, pc, bp);
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
stack.PrintStack();
ShowStatsAndAbort();
}

View File

@ -28,7 +28,6 @@ namespace __asan {
// -------------------------- Flags ------------------------- {{{1
static const size_t kMallocContextSize = 30;
static int FLAG_atexit;
bool FLAG_fast_unwind = true;
size_t FLAG_redzone; // power of two, >= 32
size_t FLAG_quarantine_size;
@ -341,9 +340,7 @@ void __asan_report_error(uintptr_t pc, uintptr_t bp, uintptr_t sp,
PrintBytes("PC: ", (uintptr_t*)pc);
}
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax,
false, // FLAG_fast_unwind,
pc, bp);
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
stack.PrintStack();
CHECK(AddrIsInMem(addr));
@ -400,7 +397,6 @@ void __asan_init() {
FLAG_demangle = IntFlagValue(options, "demangle=", 1);
FLAG_debug = IntFlagValue(options, "debug=", 0);
FLAG_replace_cfallocator = IntFlagValue(options, "replace_cfallocator=", 1);
FLAG_fast_unwind = IntFlagValue(options, "fast_unwind=", 1);
FLAG_replace_str = IntFlagValue(options, "replace_str=", 1);
FLAG_replace_intrin = IntFlagValue(options, "replace_intrin=", 1);
FLAG_use_fake_stack = IntFlagValue(options, "use_fake_stack=", 1);
@ -437,7 +433,6 @@ void __asan_init() {
MEM_TO_SHADOW(kHighShadowEnd));
Printf("red_zone=%ld\n", FLAG_redzone);
Printf("malloc_context_size=%ld\n", (int)FLAG_malloc_context_size);
Printf("fast_unwind=%d\n", (int)FLAG_fast_unwind);
Printf("SHADOW_SCALE: %lx\n", SHADOW_SCALE);
Printf("SHADOW_GRANULARITY: %lx\n", SHADOW_GRANULARITY);

View File

@ -54,14 +54,6 @@ void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) {
}
#endif // ASAN_USE_EXTERNAL_SYMBOLIZER
#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_OK
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif
uintptr_t AsanStackTrace::GetCurrentPc() {
return GET_CALLER_PC();
}

View File

@ -43,16 +43,16 @@ struct AsanStackTrace {
}
}
void GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp);
void FastUnwindStack(uintptr_t pc, uintptr_t bp);
// static _Unwind_Reason_Code Unwind_Trace(
// struct _Unwind_Context *ctx, void *param);
static uintptr_t GetCurrentPc();
static size_t CompressStack(AsanStackTrace *stack,
uint32_t *compressed, size_t size);
static void UncompressStack(AsanStackTrace *stack,
uint32_t *compressed, size_t size);
size_t full_frame_count;
};
} // namespace __asan
@ -61,37 +61,27 @@ struct AsanStackTrace {
// 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.
// fast_unwind is currently unused.
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, fast_unwind, pc, bp) \
AsanStackTrace stack; \
{ \
uintptr_t saved_pc = pc; \
uintptr_t saved_bp = bp; \
stack.size = 0; \
stack.full_frame_count = 0; \
stack.trace[0] = saved_pc; \
if ((max_s) > 1) { \
stack.max_size = max_s; \
stack.FastUnwindStack(saved_pc, saved_bp); \
} \
} \
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp) \
AsanStackTrace stack; \
stack.GetStackTrace(max_s, pc, bp); \
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
// 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_HERE(max_size, fast_unwind) \
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, fast_unwind, \
AsanStackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) \
#define GET_STACK_TRACE_HERE(max_size) \
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
AsanStackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) \
#define GET_STACK_TRACE_HERE_FOR_MALLOC \
GET_STACK_TRACE_HERE(FLAG_malloc_context_size, FLAG_fast_unwind)
#define GET_STACK_TRACE_HERE_FOR_MALLOC \
GET_STACK_TRACE_HERE(FLAG_malloc_context_size)
#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \
GET_STACK_TRACE_HERE(FLAG_malloc_context_size, FLAG_fast_unwind)
#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \
GET_STACK_TRACE_HERE(FLAG_malloc_context_size)
#define PRINT_CURRENT_STACK() \
{ \
GET_STACK_TRACE_HERE(kStackTraceMax, false); \
GET_STACK_TRACE_HERE(kStackTraceMax); \
stack.PrintStack(); \
} \