blob: 999863c16db2bc93936bbb304e2c63061da9622c [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2005, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Author: Sanjay Ghemawat
33//
34// Produce stack trace.
35//
36// There are three different ways we can try to get the stack trace:
37//
38// 1) Our hand-coded stack-unwinder. This depends on a certain stack
39// layout, which is used by gcc (and those systems using a
40// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
41// It uses the frame pointer to do its work.
42//
43// 2) The libunwind library. This is still in development, and as a
44// separate library adds a new dependency, abut doesn't need a frame
45// pointer. It also doesn't call malloc.
46//
47// 3) The gdb unwinder -- also the one used by the c++ exception code.
48// It's obviously well-tested, but has a fatal flaw: it can call
49// malloc() from the unwinder. This is a problem because we're
50// trying to use the unwinder to instrument malloc().
51//
52// Note: if you add a new implementation here, make sure it works
53// correctly when GetStackTrace() is called with max_depth == 0.
54// Some code may do that.
55
56#include <config.h>
57#include <stdlib.h> // for getenv
58#include <string.h> // for strcmp
59#include <stdio.h> // for fprintf
60#include "gperftools/stacktrace.h"
61#include "base/commandlineflags.h"
62#include "base/googleinit.h"
63
64
65// we're using plain struct and not class to avoid any possible issues
66// during initialization. Struct of pointers is easy to init at
67// link-time.
68struct GetStackImplementation {
69 int (*GetStackFramesPtr)(void** result, int* sizes, int max_depth,
70 int skip_count);
71
72 int (*GetStackFramesWithContextPtr)(void** result, int* sizes, int max_depth,
73 int skip_count, const void *uc);
74
75 int (*GetStackTracePtr)(void** result, int max_depth,
76 int skip_count);
77
78 int (*GetStackTraceWithContextPtr)(void** result, int max_depth,
79 int skip_count, const void *uc);
80
81 const char *name;
82};
83
84#if HAVE_DECL_BACKTRACE
85#define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h"
86#define GST_SUFFIX generic
87#include "stacktrace_impl_setup-inl.h"
88#undef GST_SUFFIX
89#undef STACKTRACE_INL_HEADER
90#define HAVE_GST_generic
91#endif
92
93// libunwind uses __thread so we check for both libunwind.h and
94// __thread support
95#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_TLS)
96#define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h"
97#define GST_SUFFIX libunwind
98#include "stacktrace_impl_setup-inl.h"
99#undef GST_SUFFIX
100#undef STACKTRACE_INL_HEADER
101#define HAVE_GST_libunwind
102#endif // HAVE_LIBUNWIND_H
103
104#if defined(__i386__) || defined(__x86_64__)
105#define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h"
106#define GST_SUFFIX x86
107#include "stacktrace_impl_setup-inl.h"
108#undef GST_SUFFIX
109#undef STACKTRACE_INL_HEADER
110#define HAVE_GST_x86
111#endif // i386 || x86_64
112
113#if defined(__ppc__) || defined(__PPC__)
114#if defined(__linux__)
115#define STACKTRACE_INL_HEADER "stacktrace_powerpc-linux-inl.h"
116#else
117#define STACKTRACE_INL_HEADER "stacktrace_powerpc-darwin-inl.h"
118#endif
119#define GST_SUFFIX ppc
120#include "stacktrace_impl_setup-inl.h"
121#undef GST_SUFFIX
122#undef STACKTRACE_INL_HEADER
123#define HAVE_GST_ppc
124#endif
125
126#if defined(__arm__)
127#define STACKTRACE_INL_HEADER "stacktrace_arm-inl.h"
128#define GST_SUFFIX arm
129#include "stacktrace_impl_setup-inl.h"
130#undef GST_SUFFIX
131#undef STACKTRACE_INL_HEADER
132#define HAVE_GST_arm
133#endif
134
135#ifdef TCMALLOC_ENABLE_INSTRUMENT_STACKTRACE
136#define STACKTRACE_INL_HEADER "stacktrace_instrument-inl.h"
137#define GST_SUFFIX instrument
138#include "stacktrace_impl_setup-inl.h"
139#undef GST_SUFFIX
140#undef STACKTRACE_INL_HEADER
141#define HAVE_GST_instrument
142#endif
143
144// The Windows case -- probably cygwin and mingw will use one of the
145// x86-includes above, but if not, we can fall back to windows intrinsics.
146#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__)
147#define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h"
148#define GST_SUFFIX win32
149#include "stacktrace_impl_setup-inl.h"
150#undef GST_SUFFIX
151#undef STACKTRACE_INL_HEADER
152#define HAVE_GST_win32
153#endif
154
155static GetStackImplementation *all_impls[] = {
156#ifdef HAVE_GST_generic
157 &impl__generic,
158#endif
159#ifdef HAVE_GST_libunwind
160 &impl__libunwind,
161#endif
162#ifdef HAVE_GST_x86
163 &impl__x86,
164#endif
165#ifdef HAVE_GST_arm
166 &impl__arm,
167#endif
168#ifdef HAVE_GST_ppc
169 &impl__ppc,
170#endif
171#ifdef HAVE_GST_instrument
172 &impl__instrument,
173#endif
174#ifdef HAVE_GST_win32
175 &impl__win32,
176#endif
177 NULL
178};
179
180// ppc and i386 implementations prefer arch-specific asm implementations.
181// arm's asm implementation is broken
182#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__PPC__)
183#if !defined(NO_FRAME_POINTER)
184#define TCMALLOC_DONT_PREFER_LIBUNWIND
185#endif
186#endif
187
188#if defined(HAVE_GST_instrument)
189static GetStackImplementation *get_stack_impl = &impl__instrument;
190#elif defined(HAVE_GST_win32)
191static GetStackImplementation *get_stack_impl = &impl__win32;
192#elif defined(HAVE_GST_x86) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND)
193static GetStackImplementation *get_stack_impl = &impl__x86;
194#elif defined(HAVE_GST_ppc) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND)
195static GetStackImplementation *get_stack_impl = &impl__ppc;
196#elif defined(HAVE_GST_libunwind)
197static GetStackImplementation *get_stack_impl = &impl__libunwind;
198#elif defined(HAVE_GST_arm)
199static GetStackImplementation *get_stack_impl = &impl__arm;
200#elif defined(HAVE_GST_generic)
201static GetStackImplementation *get_stack_impl = &impl__generic;
202#elif 0
203// This is for the benefit of code analysis tools that may have
204// trouble with the computed #include above.
205# include "stacktrace_x86-inl.h"
206# include "stacktrace_libunwind-inl.h"
207# include "stacktrace_generic-inl.h"
208# include "stacktrace_powerpc-inl.h"
209# include "stacktrace_win32-inl.h"
210# include "stacktrace_arm-inl.h"
211# include "stacktrace_instrument-inl.h"
212#else
213#error Cannot calculate stack trace: will need to write for your environment
214#endif
215
216static int ATTRIBUTE_NOINLINE frame_forcer(int rv) {
217 return rv;
218}
219
220PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth,
221 int skip_count) {
222 return frame_forcer(get_stack_impl->GetStackFramesPtr(result, sizes, max_depth, skip_count));
223}
224
225PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
226 int skip_count, const void *uc) {
227 return frame_forcer(get_stack_impl->GetStackFramesWithContextPtr(
228 result, sizes, max_depth,
229 skip_count, uc));
230}
231
232PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
233 int skip_count) {
234 return frame_forcer(get_stack_impl->GetStackTracePtr(result, max_depth, skip_count));
235}
236
237PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth,
238 int skip_count, const void *uc) {
239 return frame_forcer(get_stack_impl->GetStackTraceWithContextPtr(
240 result, max_depth, skip_count, uc));
241}
242
243static void init_default_stack_impl_inner(void) {
244 char *val = getenv("TCMALLOC_STACKTRACE_METHOD");
245 if (!val || !*val) {
246 return;
247 }
248 for (GetStackImplementation **p = all_impls; *p; p++) {
249 GetStackImplementation *c = *p;
250 if (strcmp(c->name, val) == 0) {
251 get_stack_impl = c;
252 return;
253 }
254 }
255 fprintf(stderr, "Unknown or unsupported stacktrace method requested: %s. Ignoring it\n", val);
256}
257
258static void init_default_stack_impl(void) {
259 init_default_stack_impl_inner();
260 if (EnvToBool("TCMALLOC_STACKTRACE_METHOD_VERBOSE", false)) {
261 fprintf(stderr, "Chosen stacktrace method is %s\nSupported methods:\n", get_stack_impl->name);
262 for (GetStackImplementation **p = all_impls; *p; p++) {
263 GetStackImplementation *c = *p;
264 fprintf(stderr, "* %s\n", c->name);
265 }
266 fputs("\n", stderr);
267 }
268}
269
270REGISTER_MODULE_INITIALIZER(stacktrace_init_default_stack_impl, init_default_stack_impl());