diff options
author | Aliaksey Kandratsenka <alk@tut.by> | 2014-02-08 15:30:36 -0800 |
---|---|---|
committer | Aliaksey Kandratsenka <alk@tut.by> | 2014-02-16 19:22:06 -0800 |
commit | 90ba15d1f2f6704af96f62ce1e8c5f214697bab1 (patch) | |
tree | 52c0481abd9ad93aa9ee7dd603335cc2b7dd966d | |
parent | 33f6781d64af88ea23698a084188d8c2ab94ecb1 (diff) | |
download | gperftools-90ba15d1f2f6704af96f62ce1e8c5f214697bab1.tar.gz |
issue-604: implement runtime-selectable stacktrace capturing
We're now building all supported stacktrace capturing methods. And
there's now a way to select at runtime which method is used.
-rwxr-xr-x | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/stacktrace.cc | 245 | ||||
-rw-r--r-- | src/stacktrace_arm-inl.h | 4 | ||||
-rwxr-xr-x | src/stacktrace_config.h | 97 | ||||
-rw-r--r-- | src/stacktrace_generic-inl.h | 4 | ||||
-rw-r--r-- | src/stacktrace_impl_setup-inl.h | 94 | ||||
-rwxr-xr-x | src/stacktrace_instrument-inl.h | 4 | ||||
-rw-r--r-- | src/stacktrace_libunwind-inl.h | 6 | ||||
-rw-r--r-- | src/stacktrace_powerpc-inl.h | 24 | ||||
-rw-r--r-- | src/stacktrace_win32-inl.h | 29 | ||||
-rw-r--r-- | src/stacktrace_x86-inl.h | 4 |
12 files changed, 346 insertions, 169 deletions
diff --git a/Makefile.am b/Makefile.am index 7467326..11ec97a 100755 --- a/Makefile.am +++ b/Makefile.am @@ -345,7 +345,7 @@ atomicops_unittest_LDADD = $(LIBSPINLOCK) if WITH_STACK_TRACE ### The header files we use. We divide into categories based on directory -S_STACKTRACE_INCLUDES = src/stacktrace_config.h \ +S_STACKTRACE_INCLUDES = src/stacktrace_impl_setup-inl.h \ src/stacktrace_generic-inl.h \ src/stacktrace_libunwind-inl.h \ src/stacktrace_arm-inl.h \ diff --git a/configure.ac b/configure.ac index d128d13..8023cb3 100644 --- a/configure.ac +++ b/configure.ac @@ -388,6 +388,8 @@ case "$host" in ;; esac +AC_CHECK_DECLS([backtrace], [], [], [#include <execinfo.h>]) + # For windows, this has a non-trivial value (__declspec(export)), but any # system that uses configure wants this to be the empty string. diff --git a/src/stacktrace.cc b/src/stacktrace.cc index 10f24a7..df9630a 100644 --- a/src/stacktrace.cc +++ b/src/stacktrace.cc @@ -1,11 +1,11 @@ // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- // Copyright (c) 2005, Google Inc. // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: -// +// // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above @@ -15,7 +15,7 @@ // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -54,49 +54,145 @@ // Some code may do that. #include <config.h> -#include <gperftools/stacktrace.h> -#include "stacktrace_config.h" - -#if defined(STACKTRACE_INL_HEADER) - -#define IS_STACK_FRAMES 0 -#define IS_WITH_CONTEXT 0 -#define GET_STACK_TRACE_OR_FRAMES \ - GetStackTrace(void **result, int max_depth, int skip_count) -#include STACKTRACE_INL_HEADER -#undef IS_STACK_FRAMES -#undef IS_WITH_CONTEXT -#undef GET_STACK_TRACE_OR_FRAMES - -#define IS_STACK_FRAMES 1 -#define IS_WITH_CONTEXT 0 -#define GET_STACK_TRACE_OR_FRAMES \ - GetStackFrames(void **result, int *sizes, int max_depth, int skip_count) -#include STACKTRACE_INL_HEADER -#undef IS_STACK_FRAMES -#undef IS_WITH_CONTEXT -#undef GET_STACK_TRACE_OR_FRAMES - -#define IS_STACK_FRAMES 0 -#define IS_WITH_CONTEXT 1 -#define GET_STACK_TRACE_OR_FRAMES \ - GetStackTraceWithContext(void **result, int max_depth, \ - int skip_count, const void *ucp) -#include STACKTRACE_INL_HEADER -#undef IS_STACK_FRAMES -#undef IS_WITH_CONTEXT -#undef GET_STACK_TRACE_OR_FRAMES - -#define IS_STACK_FRAMES 1 -#define IS_WITH_CONTEXT 1 -#define GET_STACK_TRACE_OR_FRAMES \ - GetStackFramesWithContext(void **result, int *sizes, int max_depth, \ - int skip_count, const void *ucp) -#include STACKTRACE_INL_HEADER -#undef IS_STACK_FRAMES -#undef IS_WITH_CONTEXT -#undef GET_STACK_TRACE_OR_FRAMES +#include <stdlib.h> // for getenv +#include <string.h> // for strcmp +#include <stdio.h> // for fprintf +#include "gperftools/stacktrace.h" +#include "base/commandlineflags.h" +#include "base/googleinit.h" + + +// we're using plain struct and not class to avoid any possible issues +// during initialization. Struct of pointers is easy to init at +// link-time. +struct GetStackImplementation { + int (*GetStackFramesPtr)(void** result, int* sizes, int max_depth, + int skip_count); + + int (*GetStackFramesWithContextPtr)(void** result, int* sizes, int max_depth, + int skip_count, const void *uc); + + int (*GetStackTracePtr)(void** result, int max_depth, + int skip_count); + + int (*GetStackTraceWithContextPtr)(void** result, int max_depth, + int skip_count, const void *uc); + + const char *name; +}; + +#if HAVE_DECL_BACKTRACE +#define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h" +#define GST_SUFFIX generic +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_generic +#endif + +#if HAVE_LIBUNWIND_H +#define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h" +#define GST_SUFFIX libunwind +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_libunwind +#endif // HAVE_LIBUNWIND_H + +#if defined(__i386__) || defined(__x86_64__) +#define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h" +#define GST_SUFFIX x86 +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_x86 +#endif // i386 || x86_64 + +#if defined(__ppc__) || defined(__PPC__) +#define STACKTRACE_INL_HEADER "stacktrace_powerpc-inl.h" +#define GST_SUFFIX ppc +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_ppc +#endif + +#if defined(__arm__) +#define STACKTRACE_INL_HEADER "stacktrace_arm-inl.h" +#define GST_SUFFIX arm +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_arm +#endif + +#ifdef TCMALLOC_ENABLE_INSTRUMENT_STACKTRACE +#define STACKTRACE_INL_HEADER "stacktrace_instrument-inl.h" +#define GST_SUFFIX instrument +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_instrument +#endif + +// The Windows case -- probably cygwin and mingw will use one of the +// x86-includes above, but if not, we can fall back to windows intrinsics. +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) +#define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h" +#define GST_SUFFIX win32 +#include "stacktrace_impl_setup-inl.h" +#undef GST_SUFFIX +#undef STACKTRACE_INL_HEADER +#define HAVE_GST_win32 +#endif + +static GetStackImplementation *all_impls[] = { +#ifdef HAVE_GST_generic + &impl__generic, +#endif +#ifdef HAVE_GST_libunwind + &impl__libunwind, +#endif +#ifdef HAVE_GST_x86 + &impl__x86, +#endif +#ifdef HAVE_GST_arm + &impl__arm, +#endif +#ifdef HAVE_GST_ppc + &impl__ppc, +#endif +#ifdef HAVE_GST_instrument + &impl__instrument, +#endif +#ifdef HAVE_GST_win32 + &impl__win32, +#endif + NULL +}; + +// ppc and i386 implementations prefer arch-specific asm implementations. +// arm's asm implementation is broken +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__PPC__) +#if !defined(NO_FRAME_POINTER) +#define TCMALLOC_DONT_PREFER_LIBUNWIND +#endif +#endif +#if defined(HAVE_GST_instrument) +static GetStackImplementation *get_stack_impl = &impl__instrument; +#elif defined(HAVE_GST_win32) +static GetStackImplementation *get_stack_impl = &impl__win32; +#elif defined(HAVE_GST_x86) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND) +static GetStackImplementation *get_stack_impl = &impl__x86; +#elif defined(HAVE_GST_ppc) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND) +static GetStackImplementation *get_stack_impl = &impl__ppc; +#elif defined(HAVE_GST_libunwind) +static GetStackImplementation *get_stack_impl = &impl__libunwind; +#elif defined(HAVE_GST_arm) +static GetStackImplementation *get_stack_impl = &impl__arm; +#elif defined(HAVE_GST_generic) +static GetStackImplementation *get_stack_impl = &impl__generic; #elif 0 // This is for the benefit of code analysis tools that may have // trouble with the computed #include above. @@ -106,6 +202,63 @@ # include "stacktrace_powerpc-inl.h" # include "stacktrace_win32-inl.h" # include "stacktrace_arm-inl.h" +# include "stacktrace_instrument-inl.h" #else -# error Cannot calculate stack trace: will need to write for your environment +#error Cannot calculate stack trace: will need to write for your environment #endif + +static int ATTRIBUTE_NOINLINE frame_forcer(int rv) { + return rv; +} + +PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth, + int skip_count) { + return frame_forcer(get_stack_impl->GetStackFramesPtr(result, sizes, max_depth, skip_count)); +} + +PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth, + int skip_count, const void *uc) { + return frame_forcer(get_stack_impl->GetStackFramesWithContextPtr( + result, sizes, max_depth, + skip_count, uc)); +} + +PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth, + int skip_count) { + return frame_forcer(get_stack_impl->GetStackTracePtr(result, max_depth, skip_count)); +} + +PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth, + int skip_count, const void *uc) { + return frame_forcer(get_stack_impl->GetStackTraceWithContextPtr( + result, max_depth, skip_count, uc)); +} + +static void init_default_stack_impl_inner(void) { + char *val = getenv("TCMALLOC_STACKTRACE_METHOD"); + if (!val || !*val) { + return; + } + for (GetStackImplementation **p = all_impls; *p; p++) { + GetStackImplementation *c = *p; + if (strcmp(c->name, val) == 0) { + get_stack_impl = c; + return; + } + } + fprintf(stderr, "Unknown or unsupported stacktrace method requested: %s. Ignoring it\n", val); +} + +static void init_default_stack_impl(void) { + init_default_stack_impl_inner(); + if (EnvToBool("TCMALLOC_STACKTRACE_METHOD_VERBOSE", false)) { + fprintf(stderr, "Chosen stacktrace method is %s\nSupported methods:\n", get_stack_impl->name); + for (GetStackImplementation **p = all_impls; *p; p++) { + GetStackImplementation *c = *p; + fprintf(stderr, "* %s\n", c->name); + } + fputs("\n", stderr); + } +} + +REGISTER_MODULE_INITIALIZER(stacktrace_init_default_stack_impl, init_default_stack_impl()); diff --git a/src/stacktrace_arm-inl.h b/src/stacktrace_arm-inl.h index 194a84e..1586b8f 100644 --- a/src/stacktrace_arm-inl.h +++ b/src/stacktrace_arm-inl.h @@ -102,7 +102,7 @@ void StacktraceArmDummyFunction() { __asm__ volatile(""); } // int max_depth: the size of the result (and sizes) array(s) // 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 { +static int GET_STACK_TRACE_OR_FRAMES { #ifdef __GNUC__ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); #else @@ -116,6 +116,8 @@ int GET_STACK_TRACE_OR_FRAMES { // stored in the stack frame. This works at least for gcc. StacktraceArmDummyFunction(); + skip_count++; // skip parent frame due to indirection in stacktrace.cc + int n = 0; while (sp && n < max_depth) { // The GetStackFrames routine is called when we are in some diff --git a/src/stacktrace_config.h b/src/stacktrace_config.h deleted file mode 100755 index 8b0fc32..0000000 --- a/src/stacktrace_config.h +++ /dev/null @@ -1,97 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -// Copyright (c) 2009, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --- -// Author: Paul Pluzhnikov -// -// Figure out which unwinder to use on a given platform. -// -// Defines STACKTRACE_INL_HEADER to the *-inl.h containing -// actual unwinder implementation. -// -// Defines STACKTRACE_SKIP_CONTEXT_ROUTINES if a separate -// GetStack{Trace,Frames}WithContext should not be provided. -// -// This header is "private" to stacktrace.cc and -// stacktrace_with_context.cc. -// -// DO NOT include it into any other files. - -#ifndef BASE_STACKTRACE_CONFIG_H_ -#define BASE_STACKTRACE_CONFIG_H_ - -#ifdef HAVE_FEATURES_H -#include <features.h> // for __UCLIBC__ -#endif - -// First, the i386 and x86_64 case. -#if (defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 2 -# if !defined(NO_FRAME_POINTER) -# define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h" -# define STACKTRACE_SKIP_CONTEXT_ROUTINES 1 -# elif defined(HAVE_LIBUNWIND_H) // a proxy for having libunwind installed -# define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h" -# define STACKTRACE_USES_LIBUNWIND 1 -# elif defined(__linux) -# error Cannnot calculate stack trace: need either libunwind or frame-pointers (see INSTALL file) -# else -# error Cannnot calculate stack trace: need libunwind (see INSTALL file) -# endif - -// The PowerPC case -#elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2 -# if !defined(NO_FRAME_POINTER) -# define STACKTRACE_INL_HEADER "stacktrace_powerpc-inl.h" -# else -# define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h" -# endif - -// The ARM case -#elif defined(__arm__) && __GNUC__ >= 2 -# if !defined(NO_FRAME_POINTER) -# define STACKTRACE_INL_HEADER "stacktrace_arm-inl.h" -# else -# error stacktrace without frame pointer is not supported on ARM -# endif - -// The MIPS case -#elif defined(__mips__) && __GNUC__ >= 2 -# if defined(__UCLIBC__) -# define STACKTRACE_INL_HEADER "stacktrace_instrument-inl.h" -# else -# define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h" -# endif -// The Windows case -- probably cygwin and mingw will use one of the -// x86-includes above, but if not, we can fall back to windows intrinsics. -#elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) -# define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h" - -#endif // all the cases -#endif // BASE_STACKTRACE_CONFIG_H_ diff --git a/src/stacktrace_generic-inl.h b/src/stacktrace_generic-inl.h index 5970d49..7d7c22d 100644 --- a/src/stacktrace_generic-inl.h +++ b/src/stacktrace_generic-inl.h @@ -60,13 +60,13 @@ // int max_depth: the size of the result (and sizes) array(s) // 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 { +static int GET_STACK_TRACE_OR_FRAMES { static const int kStackLength = 64; void * stack[kStackLength]; int size; size = backtrace(stack, kStackLength); - skip_count++; // we want to skip the current frame as well + skip_count += 2; // we want to skip the current and it's parent frame as well int result_count = size - skip_count; if (result_count < 0) result_count = 0; diff --git a/src/stacktrace_impl_setup-inl.h b/src/stacktrace_impl_setup-inl.h new file mode 100644 index 0000000..698c5b3 --- /dev/null +++ b/src/stacktrace_impl_setup-inl.h @@ -0,0 +1,94 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- +// NOTE: this is NOT to be #include-d normally. It's internal +// implementation detail of stacktrace.cc +// + +// Copyright (c) 2014, gperftools Contributors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --- +// Author: Aliaksey Kandratsenka <alk@tut.by> +// +// based on stacktrace.cc and stacktrace_config.h by Sanjay Ghemawat +// and Paul Pluzhnikov from Google Inc + +#define SIS_CONCAT2(a, b) a##b +#define SIS_CONCAT(a, b) SIS_CONCAT2(a,b) + +#define SIS_STRINGIFY(a) SIS_STRINGIFY2(a) +#define SIS_STRINGIFY2(a) #a + +#define IS_STACK_FRAMES 0 +#define IS_WITH_CONTEXT 0 +#define GET_STACK_TRACE_OR_FRAMES \ + SIS_CONCAT(GetStackTrace_, GST_SUFFIX)(void **result, int max_depth, int skip_count) +#include STACKTRACE_INL_HEADER +#undef IS_STACK_FRAMES +#undef IS_WITH_CONTEXT +#undef GET_STACK_TRACE_OR_FRAMES + +#define IS_STACK_FRAMES 1 +#define IS_WITH_CONTEXT 0 +#define GET_STACK_TRACE_OR_FRAMES \ + SIS_CONCAT(GetStackFrames_, GST_SUFFIX)(void **result, int *sizes, int max_depth, int skip_count) +#include STACKTRACE_INL_HEADER +#undef IS_STACK_FRAMES +#undef IS_WITH_CONTEXT +#undef GET_STACK_TRACE_OR_FRAMES + +#define IS_STACK_FRAMES 0 +#define IS_WITH_CONTEXT 1 +#define GET_STACK_TRACE_OR_FRAMES \ + SIS_CONCAT(GetStackTraceWithContext_, GST_SUFFIX)(void **result, int max_depth, \ + int skip_count, const void *ucp) +#include STACKTRACE_INL_HEADER +#undef IS_STACK_FRAMES +#undef IS_WITH_CONTEXT +#undef GET_STACK_TRACE_OR_FRAMES + +#define IS_STACK_FRAMES 1 +#define IS_WITH_CONTEXT 1 +#define GET_STACK_TRACE_OR_FRAMES \ + SIS_CONCAT(GetStackFramesWithContext_, GST_SUFFIX)(void **result, int *sizes, int max_depth, \ + int skip_count, const void *ucp) +#include STACKTRACE_INL_HEADER +#undef IS_STACK_FRAMES +#undef IS_WITH_CONTEXT +#undef GET_STACK_TRACE_OR_FRAMES + +static GetStackImplementation SIS_CONCAT(impl__,GST_SUFFIX) = { + SIS_CONCAT(GetStackFrames_, GST_SUFFIX), + SIS_CONCAT(GetStackFramesWithContext_, GST_SUFFIX), + SIS_CONCAT(GetStackTrace_, GST_SUFFIX), + SIS_CONCAT(GetStackTraceWithContext_, GST_SUFFIX), + SIS_STRINGIFY(GST_SUFFIX) +}; + +#undef SIS_CONCAT2 +#undef SIS_CONCAT diff --git a/src/stacktrace_instrument-inl.h b/src/stacktrace_instrument-inl.h index c99c4de..c631765 100755 --- a/src/stacktrace_instrument-inl.h +++ b/src/stacktrace_instrument-inl.h @@ -130,14 +130,14 @@ static int cyg_backtrace(void **buffer, int size) { // int max_depth: the size of the result (and sizes) array(s) // 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 { +static int GET_STACK_TRACE_OR_FRAMES { static const int kStackLength = 64; void * stack[kStackLength]; int size; memset(stack, 0, sizeof(stack)); size = cyg_backtrace(stack, kStackLength); - skip_count++; // we want to skip the current frame as well + skip_count += 2; // we want to skip the current and parent frame as well int result_count = size - skip_count; if (result_count < 0) result_count = 0; diff --git a/src/stacktrace_libunwind-inl.h b/src/stacktrace_libunwind-inl.h index d75bc18..6d56ace 100644 --- a/src/stacktrace_libunwind-inl.h +++ b/src/stacktrace_libunwind-inl.h @@ -78,7 +78,7 @@ static __thread int recursive; // int max_depth: the size of the result (and sizes) array(s) // 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 { +static int GET_STACK_TRACE_OR_FRAMES { void *ip; int n = 0; unw_cursor_t cursor; @@ -104,11 +104,11 @@ int GET_STACK_TRACE_OR_FRAMES { skip_count = 0; } else { unw_getcontext(&uc); - skip_count++; // Do not include current frame + skip_count += 2; // Do not include current and parent frame } #else unw_getcontext(&uc); - skip_count++; // Do not include current frame + skip_count += 2; // Do not include current and parent frame #endif int ret = unw_init_local(&cursor, &uc); diff --git a/src/stacktrace_powerpc-inl.h b/src/stacktrace_powerpc-inl.h index 756e075..811d6cc 100644 --- a/src/stacktrace_powerpc-inl.h +++ b/src/stacktrace_powerpc-inl.h @@ -126,7 +126,7 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); } // int max_depth: the size of the result (and sizes) array(s) // 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 { +static int GET_STACK_TRACE_OR_FRAMES { layout_ppc *current; int n; @@ -139,8 +139,9 @@ int GET_STACK_TRACE_OR_FRAMES { StacktracePowerPCDummyFunction(); n = 0; + skip_count++; // skip parent's frame due to indirection in + // stacktrace.cc while (current && n < max_depth) { - result[n] = current->return_addr; // The GetStackFrames routine is called when we are in some // informational context (the failure signal handler for example). @@ -148,16 +149,21 @@ int GET_STACK_TRACE_OR_FRAMES { // that is as complete as possible (even if it contains a few // bogus entries in some rare cases). layout_ppc *next = NextStackFrame<!IS_STACK_FRAMES>(current); -#if IS_STACK_FRAMES - if (next > current) { - sizes[n] = (uintptr_t)next - (uintptr_t)current; + if (skip_count > 0) { + skip_count--; } else { - // A frame-size of 0 is used to indicate unknown frame size. - sizes[n] = 0; - } + result[n] = current->return_addr; +#if IS_STACK_FRAMES + if (next > current) { + sizes[n] = (uintptr_t)next - (uintptr_t)current; + } else { + // A frame-size of 0 is used to indicate unknown frame size. + sizes[n] = 0; + } #endif + n++; + } current = next; - n++; } // It's possible the second-last stack frame can't return diff --git a/src/stacktrace_win32-inl.h b/src/stacktrace_win32-inl.h index 6c473fa..663e9a5 100644 --- a/src/stacktrace_win32-inl.h +++ b/src/stacktrace_win32-inl.h @@ -71,22 +71,37 @@ static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = (RtlCaptureStackBackTrace_Function*) GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); -PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth, - int skip_count) { +static int GetStackTrace_win32(void** result, int max_depth, + int skip_count) { if (!RtlCaptureStackBackTrace_fn) { // TODO(csilvers): should we log an error here? return 0; // can't find a stacktrace with no function to call } - return (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, + return (int)RtlCaptureStackBackTrace_fn(skip_count + 3, max_depth, result, 0); } -PERFTOOLS_DLL_DECL int GetStackFrames(void** /* pcs */, - int* /* sizes */, - int /* max_depth */, - int /* skip_count */) { +static int not_implemented(void) { assert(0 == "Not yet implemented"); return 0; } +static int GetStackFrames_win32(void** /* pcs */, + int* /* sizes */, + int /* max_depth */, + int /* skip_count */) { + return not_implemented(); +} + +static int GetStackFramesWithContext_win32(void** result, int* sizes, int max_depth, + int skip_count, const void *uc) { + return not_implemented(); +} + +static int GetStackTraceWithContext_win32(void** result, int max_depth, + int skip_count, const void *uc) { + return not_implemented(); +} + + #endif // BASE_STACKTRACE_WIN32_INL_H_ diff --git a/src/stacktrace_x86-inl.h b/src/stacktrace_x86-inl.h index f7c0095..46eb5d8 100644 --- a/src/stacktrace_x86-inl.h +++ b/src/stacktrace_x86-inl.h @@ -288,7 +288,7 @@ static void **NextStackFrame(void **old_sp, const void *uc) { // 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 { +static int GET_STACK_TRACE_OR_FRAMES { void **sp; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__ // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8. @@ -321,6 +321,8 @@ int GET_STACK_TRACE_OR_FRAMES { # error Using stacktrace_x86-inl.h on a non x86 architecture! #endif + skip_count++; // skip parent's frame due to indirection in stacktrace.cc + int n = 0; while (sp && n < max_depth) { if (*(sp+1) == reinterpret_cast<void *>(0)) { |