forked from OSchip/llvm-project
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:
parent
a875b7ccc7
commit
84c44a8b8b
|
@ -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);
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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(); \
|
||||
} \
|
||||
|
||||
|
|
Loading…
Reference in New Issue