Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 1 | // -*- 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. |
| 68 | struct 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 | |
| 155 | static 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) |
| 189 | static GetStackImplementation *get_stack_impl = &impl__instrument; |
| 190 | #elif defined(HAVE_GST_win32) |
| 191 | static GetStackImplementation *get_stack_impl = &impl__win32; |
| 192 | #elif defined(HAVE_GST_x86) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND) |
| 193 | static GetStackImplementation *get_stack_impl = &impl__x86; |
| 194 | #elif defined(HAVE_GST_ppc) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND) |
| 195 | static GetStackImplementation *get_stack_impl = &impl__ppc; |
| 196 | #elif defined(HAVE_GST_libunwind) |
| 197 | static GetStackImplementation *get_stack_impl = &impl__libunwind; |
| 198 | #elif defined(HAVE_GST_arm) |
| 199 | static GetStackImplementation *get_stack_impl = &impl__arm; |
| 200 | #elif defined(HAVE_GST_generic) |
| 201 | static 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 | |
| 216 | static int ATTRIBUTE_NOINLINE frame_forcer(int rv) { |
| 217 | return rv; |
| 218 | } |
| 219 | |
| 220 | PERFTOOLS_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 | |
| 225 | PERFTOOLS_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 | |
| 232 | PERFTOOLS_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 | |
| 237 | PERFTOOLS_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 | |
| 243 | static 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 | |
| 258 | static 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 | |
| 270 | REGISTER_MODULE_INITIALIZER(stacktrace_init_default_stack_impl, init_default_stack_impl()); |