summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2012-12-13 09:34:23 +0000
committerKostya Serebryany <kcc@google.com>2012-12-13 09:34:23 +0000
commita30c8f9eac981dcf137e84226810b760e35c7be1 (patch)
treea0b04b76b22b48d7518b1dbdd6dbf728530f01b6
parentd62237995d0fc50697e375ea50f015e996162884 (diff)
[asan] add two asan flags: fast_unwind_on_fatal and fast_unwind_on_malloc to allow using the slow CFI-based unwinder
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@170117 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_allocator.cc2
-rw-r--r--lib/asan/asan_flags.h6
-rw-r--r--lib/asan/asan_interceptors.cc6
-rw-r--r--lib/asan/asan_linux.cc48
-rw-r--r--lib/asan/asan_mac.cc16
-rw-r--r--lib/asan/asan_malloc_linux.cc20
-rw-r--r--lib/asan/asan_malloc_mac.cc28
-rw-r--r--lib/asan/asan_malloc_win.cc10
-rw-r--r--lib/asan/asan_new_delete.cc4
-rw-r--r--lib/asan/asan_report.cc4
-rw-r--r--lib/asan/asan_rtl.cc4
-rw-r--r--lib/asan/asan_stack.h32
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc43
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h1
14 files changed, 128 insertions, 96 deletions
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 484f9e126..b6ae3c84b 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -819,7 +819,7 @@ uptr __asan_get_allocated_size(const void *p) {
uptr allocated_size = malloc_info.AllocationSize((uptr)p);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_FATAL_HERE;
ReportAsanGetAllocatedSizeNotOwned((uptr)p, &stack);
}
return allocated_size;
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 989784df0..ded2b24c8 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -45,7 +45,7 @@ struct Flags {
int report_globals;
// If set, attempts to catch initialization order issues.
bool check_initialization_order;
- // Max number of stack frames kept for each allocation.
+ // Max number of stack frames kept for each allocation/deallocation.
int malloc_context_size;
// If set, uses custom wrappers and replacements for libc string functions
// to find more errors.
@@ -95,6 +95,10 @@ struct Flags {
bool print_full_thread_history;
// ASan will write logs to "log_path.pid" instead of stderr.
const char *log_path;
+ // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
+ bool fast_unwind_on_fatal;
+ // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
+ bool fast_unwind_on_malloc;
};
Flags *flags();
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 595f0ed3f..d3969ed59 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -71,7 +71,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
const char *offset1 = (const char*)_offset1; \
const char *offset2 = (const char*)_offset2; \
if (RangesOverlap(offset1, length1, offset2, length2)) { \
- GET_STACK_TRACE_HERE(kStackTraceMax); \
+ GET_STACK_TRACE_FATAL_HERE; \
ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
offset2, length2, &stack); \
} \
@@ -112,7 +112,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
#if ASAN_INTERCEPT_PTHREAD_CREATE
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_THREAD;
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
asanThreadRegistry().RegisterThread(t);
@@ -647,7 +647,7 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
DWORD (__stdcall *start_routine)(void*), void* arg,
DWORD flags, void* tid) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_THREAD;
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
asanThreadRegistry().RegisterThread(t);
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 068f7b100..02a3d144c 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -122,53 +122,21 @@ 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
-
-uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
-#ifdef __arm__
- uptr 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 & ~(uptr)1;
-#else
- return _Unwind_GetIP(ctx);
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
+#if defined(__arm__) || \
+ defined(__powerpc__) || defined(__powerpc64__) || \
+ defined(__sparc__)
+ fast = false;
#endif
-}
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
- void *param) {
- StackTrace *b = (StackTrace*)param;
- CHECK(b->size < b->max_size);
- uptr pc = Unwind_GetIP(ctx);
- b->trace[b->size++] = pc;
- if (b->size == b->max_size) return UNWIND_STOP;
- return UNWIND_CONTINUE;
-}
-
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
+ if (!fast)
+ return stack->SlowUnwindStack(pc, max_s, 3);
stack->size = 0;
stack->trace[0] = pc;
- if ((max_s) > 1) {
+ if (max_s > 1) {
stack->max_size = max_s;
-#if defined(__arm__) || \
- defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__sparc__)
- _Unwind_Backtrace(Unwind_Trace, stack);
- // Pop off the two ASAN functions from the backtrace.
- stack->PopStackFrames(2);
-#else
if (!asan_inited) return;
if (AsanThread *t = asanThreadRegistry().GetCurrent())
stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
-#endif
}
}
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 7abe9a429..11e6a13a8 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -160,7 +160,7 @@ void AsanLock::Unlock() {
OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
}
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
stack->size = 0;
stack->trace[0] = pc;
if ((max_s) > 1) {
@@ -308,7 +308,7 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
// alloc_asan_context().
extern "C"
void asan_dispatch_call_block_and_release(void *block) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_THREAD;
asan_block_context_t *context = (asan_block_context_t*)block;
if (flags()->verbosity >= 2) {
Report("asan_dispatch_call_block_and_release(): "
@@ -343,7 +343,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
dispatch_function_t func) { \
- GET_STACK_TRACE_HERE(kStackTraceMax); \
+ GET_STACK_TRACE_THREAD; \
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
if (flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
@@ -361,7 +361,7 @@ INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
dispatch_queue_t dq, void *ctxt,
dispatch_function_t func) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (flags()->verbosity >= 2) {
Report("dispatch_after_f: %p\n", asan_ctxt);
@@ -374,7 +374,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
dispatch_queue_t dq, void *ctxt,
dispatch_function_t func) {
- GET_STACK_TRACE_HERE(kStackTraceMax);
+ GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
if (flags()->verbosity >= 2) {
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
@@ -409,7 +409,7 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
void (^asan_block)(void); \
int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \
asan_block = ^(void) { \
- GET_STACK_TRACE_HERE(kStackTraceMax); \
+ GET_STACK_TRACE_THREAD; \
asan_register_worker_thread(parent_tid, &stack); \
work(); \
}
@@ -459,7 +459,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);
+ GET_STACK_TRACE_THREAD;
asan_free(arg, &stack);
return result;
}
@@ -467,7 +467,7 @@ void *wrap_workitem_func(void *arg) {
INTERCEPTOR(int, 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);
+ GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt =
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack);
asan_ctxt->block = workitem_arg;
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 5eb23ddbc..1bf90518f 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -59,17 +59,17 @@ void ReplaceSystemMalloc() {
using namespace __asan; // NOLINT
INTERCEPTOR(void, free, void *ptr) {
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
asan_free(ptr, &stack);
}
INTERCEPTOR(void, cfree, void *ptr) {
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
asan_free(ptr, &stack);
}
INTERCEPTOR(void*, malloc, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -85,17 +85,17 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack);
}
@@ -103,7 +103,7 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
ALIAS("memalign");
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc_usable_size(ptr, &stack);
}
@@ -126,18 +126,18 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {
}
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
// Printf("posix_memalign: %zx %zu\n", alignment, size);
return asan_posix_memalign(memptr, alignment, size, &stack);
}
INTERCEPTOR(void*, valloc, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_valloc(size, &stack);
}
INTERCEPTOR(void*, pvalloc, uptr size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_pvalloc(size, &stack);
}
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index b32c18ef2..15d166d28 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -92,7 +92,7 @@ INTERCEPTOR(void, free, void *ptr) {
#endif
} else {
if (!asan_mz_size(ptr)) ptr = get_saved_cfallocator_ref(ptr);
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
asan_free(ptr, &stack);
}
}
@@ -130,7 +130,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -139,7 +139,7 @@ void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -155,7 +155,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
@@ -164,7 +164,7 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_valloc(system_malloc_zone, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_memalign(GetPageSizeCached(), size, &stack);
}
@@ -175,7 +175,7 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) {
void ALWAYS_INLINE free_common(void *context, void *ptr) {
if (!ptr) return;
if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
asan_free(ptr, &stack);
} else {
// If the pointer does not belong to any of the zones, use one of the
@@ -190,7 +190,7 @@ void ALWAYS_INLINE free_common(void *context, void *ptr) {
// If the memory chunk pointer was moved to store additional
// CFAllocatorRef, fix it back.
ptr = get_saved_cfallocator_ref(ptr);
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
if (!flags()->mac_ignore_invalid_free) {
asan_free(ptr, &stack);
} else {
@@ -213,17 +213,17 @@ void cf_free(void *ptr, void *info) {
void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
if (!ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
} else {
if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
} else {
// We can't recover from reallocating an unknown address, because
// this would require reading at most |size| bytes from
// potentially unaccessible memory.
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
GET_ZONE_FOR_PTR(ptr);
ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
}
@@ -232,17 +232,17 @@ void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
if (!ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
} else {
if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
} else {
// We can't recover from reallocating an unknown address, because
// this would require reading at most |size| bytes from
// potentially unaccessible memory.
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ ET_STACK_TRACE_FREE(ptr);
GET_ZONE_FOR_PTR(ptr);
ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
}
@@ -261,7 +261,7 @@ void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
CHECK(system_malloc_zone);
return malloc_zone_memalign(system_malloc_zone, align, size);
}
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_memalign(align, size, &stack);
}
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index 3ec76d89c..0ddc3ca44 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -31,7 +31,7 @@ using namespace __asan; // NOLINT
extern "C" {
void free(void *ptr) {
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+ GET_STACK_TRACE_FREE;
return asan_free(ptr, &stack);
}
@@ -44,7 +44,7 @@ void cfree(void *ptr) {
}
void *malloc(size_t size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
@@ -53,7 +53,7 @@ void* _malloc_dbg(size_t size, int , const char*, int) {
}
void *calloc(size_t nmemb, size_t size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
@@ -66,7 +66,7 @@ void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
}
void *realloc(void *ptr, size_t size) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
@@ -85,7 +85,7 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
}
size_t _msize(void *ptr) {
- GET_STACK_TRACE_HERE_FOR_MALLOC;
+ GET_STACK_TRACE_MALLOC;
return asan_malloc_usable_size(ptr, &stack);
}
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index 756810dc3..e21aa4522 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -36,7 +36,7 @@ struct nothrow_t {};
} // namespace std
#define OPERATOR_NEW_BODY \
- GET_STACK_TRACE_HERE_FOR_MALLOC;\
+ GET_STACK_TRACE_MALLOC;\
return asan_memalign(0, size, &stack);
INTERCEPTOR_ATTRIBUTE
@@ -49,7 +49,7 @@ INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
#define OPERATOR_DELETE_BODY \
- GET_STACK_TRACE_HERE_FOR_FREE(ptr);\
+ GET_STACK_TRACE_FREE;\
asan_free(ptr, &stack);
INTERCEPTOR_ATTRIBUTE
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 558e4f202..5ad911565 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -358,7 +358,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
asanThreadRegistry().GetCurrentTidOrInvalid());
Printf("AddressSanitizer can not provide additional info.\n");
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
+ GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
}
@@ -506,7 +506,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
access_size, (void*)addr, curr_tid,
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
+ GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
DescribeAddress(addr, access_size);
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 37c9583a7..e186d9515 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -104,6 +104,8 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
ParseFlag(str, &f->log_path, "log_path");
+ ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
+ ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
}
void InitializeFlags(Flags *f, const char *env) {
@@ -137,6 +139,8 @@ void InitializeFlags(Flags *f, const char *env) {
f->allow_reexec = true;
f->print_full_thread_history = true;
f->log_path = 0;
+ f->fast_unwind_on_fatal = true;
+ f->fast_unwind_on_malloc = true;
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 99f2cac14..46c9f3408 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -15,10 +15,11 @@
#define ASAN_STACK_H
#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "asan_flags.h"
namespace __asan {
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp);
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast);
void PrintStack(StackTrace *stack);
} // namespace __asan
@@ -27,27 +28,38 @@ void PrintStack(StackTrace *stack);
// 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, pc, bp) \
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
StackTrace stack; \
- GetStackTrace(&stack, max_s, pc, bp)
+ GetStackTrace(&stack, max_s, pc, bp, fast)
// 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) \
+#define GET_STACK_TRACE(max_size, fast) \
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
+ StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
-#define GET_STACK_TRACE_HERE_FOR_MALLOC \
- GET_STACK_TRACE_HERE(flags()->malloc_context_size)
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
+ flags()->fast_unwind_on_fatal)
-#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \
- GET_STACK_TRACE_HERE(flags()->malloc_context_size)
+#define GET_STACK_TRACE_FATAL_HERE \
+ GET_STACK_TRACE(kStackTraceMax, flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_THREAD \
+ GET_STACK_TRACE(kStackTraceMax, true)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(flags()->malloc_context_size, \
+ flags()->fast_unwind_on_malloc)
+
+#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
#define PRINT_CURRENT_STACK() \
{ \
- GET_STACK_TRACE_HERE(kStackTraceMax); \
+ GET_STACK_TRACE(kStackTraceMax, \
+ flags()->fast_unwind_on_fatal); \
PrintStack(&stack); \
}
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 5be76e9e6..6a0f2615e 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -19,6 +19,7 @@
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
#include <fcntl.h>
#include <pthread.h>
@@ -30,6 +31,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <unwind.h>
#include <errno.h>
#include <sys/prctl.h>
@@ -378,6 +380,47 @@ bool SanitizerGetThreadName(char *name, int max_len) {
return true;
}
+//------------------------- SlowUnwindStack -----------------------------------
+#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
+
+uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
+#ifdef __arm__
+ uptr 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 & ~(uptr)1;
+#else
+ return _Unwind_GetIP(ctx);
+#endif
+}
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+ StackTrace *b = (StackTrace*)param;
+ CHECK(b->size < b->max_size);
+ uptr pc = Unwind_GetIP(ctx);
+ b->trace[b->size++] = pc;
+ if (b->size == b->max_size) return UNWIND_STOP;
+ return UNWIND_CONTINUE;
+}
+
+void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth, uptr frames_to_pop) {
+ this->size = 0;
+ this->trace[0] = pc;
+ this->max_size = max_depth;
+ if (max_depth > 1) {
+ _Unwind_Backtrace(Unwind_Trace, this);
+ this->PopStackFrames(frames_to_pop);
+ }
+}
+
} // namespace __sanitizer
#endif // __linux__
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index fe2dcf064..64979ec5a 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -44,6 +44,7 @@ struct StackTrace {
}
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom);
+ void SlowUnwindStack(uptr pc, uptr max_depth, uptr frames_to_pop);
void PopStackFrames(uptr count);