Index: third_party/tcmalloc/chromium/src/stacktrace_android-inl.h |
diff --git a/third_party/tcmalloc/chromium/src/stacktrace_libunwind-inl.h b/third_party/tcmalloc/chromium/src/stacktrace_android-inl.h |
similarity index 54% |
copy from third_party/tcmalloc/chromium/src/stacktrace_libunwind-inl.h |
copy to third_party/tcmalloc/chromium/src/stacktrace_android-inl.h |
index 82b0cfeb7aee7db0a2d7c96ce7c6769b23c32f3e..1f04bc9de27b31ea5b697f79de3743b86bae733f 100644 |
--- a/third_party/tcmalloc/chromium/src/stacktrace_libunwind-inl.h |
+++ b/third_party/tcmalloc/chromium/src/stacktrace_android-inl.h |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2005, Google Inc. |
+// Copyright (c) 2013, Google Inc. |
// All rights reserved. |
// |
// Redistribution and use in source and binary forms, with or without |
@@ -28,36 +28,76 @@ |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// --- |
-// Author: Arun Sharma |
+// Author: Marcus Bulach |
+// This is inspired by Doug Kwan's ARM's stacktrace code and Dai Mikurube's |
+// stack trace for chromium on android. |
// |
-// Produce stack trace using libunwind |
-#ifndef BASE_STACKTRACE_LIBINWIND_INL_H_ |
-#define BASE_STACKTRACE_LIBINWIND_INL_H_ |
+#ifndef BASE_STACKTRACE_ANDROID_INL_H_ |
+#define BASE_STACKTRACE_ANDROID_INL_H_ |
// Note: this file is included into stacktrace.cc more than once. |
// Anything that should only be defined once should be here: |
-// We only need local unwinder. |
-#define UNW_LOCAL_ONLY |
+#include <stdint.h> // for uintptr_t |
+// See http://crbug.com/236855, would be better to use Bionic's |
+// new get_backtrace(). |
+#include <unwind.h> |
-extern "C" { |
-#include <assert.h> |
-#include <string.h> // for memset() |
-#include <libunwind.h> |
-} |
-#include "gperftools/stacktrace.h" |
-#include "base/logging.h" |
+/* Depends on the system definition for _Unwind_Context */ |
+#ifdef HAVE_UNWIND_CONTEXT_STRUCT |
+typedef struct _Unwind_Context __unwind_context; |
+#else |
+typedef _Unwind_Context __unwind_context; |
+#endif |
+ |
+struct stack_crawl_state_t { |
+ uintptr_t* frames; |
+ size_t frame_count; |
+ int max_depth; |
+ int skip_count; |
+ bool have_skipped_self; |
+ |
+ stack_crawl_state_t(uintptr_t* frames, int max_depth, int skip_count) |
+ : frames(frames), |
+ frame_count(0), |
+ max_depth(max_depth), |
+ skip_count(skip_count), |
+ have_skipped_self(false) { |
+ } |
+}; |
+ |
+static _Unwind_Reason_Code tracer(__unwind_context* context, void* arg) { |
+ stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg); |
+ |
+#if defined(__clang__) |
+ // Vanilla Clang's unwind.h doesn't have _Unwind_GetIP for ARM. |
+ // See http://crbug.com/236855, too. |
+ uintptr_t ip = 0; |
+ _Unwind_VRS_Get(context, _UVRSC_CORE, 15, _UVRSD_UINT32, &ip); |
+ ip &= ~(uintptr_t)0x1; // remove thumb mode bit |
+#else |
+ uintptr_t ip = _Unwind_GetIP(context); |
+#endif |
+ |
+ // The first stack frame is this function itself. Skip it. |
+ if (ip != 0 && !state->have_skipped_self) { |
+ state->have_skipped_self = true; |
+ return _URC_NO_REASON; |
+ } |
+ |
+ if (state->skip_count) { |
+ --state->skip_count; |
+ return _URC_NO_REASON; |
+ } |
-// Sometimes, we can try to get a stack trace from within a stack |
-// trace, because libunwind can call mmap (maybe indirectly via an |
-// internal mmap based memory allocator), and that mmap gets trapped |
-// and causes a stack-trace request. If were to try to honor that |
-// recursive request, we'd end up with infinite recursion or deadlock. |
-// Luckily, it's safe to ignore those subsequent traces. In such |
-// cases, we return 0 to indicate the situation. |
-static __thread int recursive; |
+ state->frames[state->frame_count++] = ip; |
+ if (state->frame_count >= state->max_depth) |
+ return _URC_END_OF_STACK; |
+ else |
+ return _URC_NO_REASON; |
+} |
-#endif // BASE_STACKTRACE_LIBINWIND_INL_H_ |
+#endif // BASE_STACKTRACE_ANDROID_INL_H_ |
// Note: this part of the file is included several times. |
// Do not put globals below. |
@@ -74,55 +114,8 @@ static __thread int recursive; |
// int skip_count: how many stack pointers to skip before storing in result |
// void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) |
int GET_STACK_TRACE_OR_FRAMES { |
- void *ip; |
- int n = 0; |
- unw_cursor_t cursor; |
- unw_context_t uc; |
-#if IS_STACK_FRAMES |
- unw_word_t sp = 0, next_sp = 0; |
-#endif |
- |
- if (recursive) { |
- return 0; |
- } |
- ++recursive; |
- |
- unw_getcontext(&uc); |
- int ret = unw_init_local(&cursor, &uc); |
- assert(ret >= 0); |
- skip_count++; // Do not include current frame |
- |
- while (skip_count--) { |
- if (unw_step(&cursor) <= 0) { |
- goto out; |
- } |
-#if IS_STACK_FRAMES |
- if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp)) { |
- goto out; |
- } |
-#endif |
- } |
- |
- while (n < max_depth) { |
- if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) { |
- break; |
- } |
-#if IS_STACK_FRAMES |
- sizes[n] = 0; |
-#endif |
- result[n++] = ip; |
- if (unw_step(&cursor) <= 0) { |
- break; |
- } |
-#if IS_STACK_FRAMES |
- sp = next_sp; |
- if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp) , 0) { |
- break; |
- } |
- sizes[n - 1] = next_sp - sp; |
-#endif |
- } |
-out: |
- --recursive; |
- return n; |
+ stack_crawl_state_t state( |
+ reinterpret_cast<uintptr_t*>(result), max_depth, skip_count); |
+ _Unwind_Backtrace(tracer, &state); |
+ return state.frame_count; |
} |