summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAliaksey Kandratsenka <alk@tut.by>2014-02-08 15:30:36 -0800
committerAliaksey Kandratsenka <alk@tut.by>2014-02-16 19:22:06 -0800
commit90ba15d1f2f6704af96f62ce1e8c5f214697bab1 (patch)
tree52c0481abd9ad93aa9ee7dd603335cc2b7dd966d
parent33f6781d64af88ea23698a084188d8c2ab94ecb1 (diff)
downloadgperftools-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-xMakefile.am2
-rw-r--r--configure.ac2
-rw-r--r--src/stacktrace.cc245
-rw-r--r--src/stacktrace_arm-inl.h4
-rwxr-xr-xsrc/stacktrace_config.h97
-rw-r--r--src/stacktrace_generic-inl.h4
-rw-r--r--src/stacktrace_impl_setup-inl.h94
-rwxr-xr-xsrc/stacktrace_instrument-inl.h4
-rw-r--r--src/stacktrace_libunwind-inl.h6
-rw-r--r--src/stacktrace_powerpc-inl.h24
-rw-r--r--src/stacktrace_win32-inl.h29
-rw-r--r--src/stacktrace_x86-inl.h4
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)) {