stacktrace.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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. // Author: Sanjay Ghemawat
  32. //
  33. // Produce stack trace.
  34. //
  35. // There are three different ways we can try to get the stack trace:
  36. //
  37. // 1) Our hand-coded stack-unwinder. This depends on a certain stack
  38. // layout, which is used by gcc (and those systems using a
  39. // gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
  40. // It uses the frame pointer to do its work.
  41. //
  42. // 2) The libunwind library. This is still in development, and as a
  43. // separate library adds a new dependency, abut doesn't need a frame
  44. // pointer. It also doesn't call malloc.
  45. //
  46. // 3) The gdb unwinder -- also the one used by the c++ exception code.
  47. // It's obviously well-tested, but has a fatal flaw: it can call
  48. // malloc() from the unwinder. This is a problem because we're
  49. // trying to use the unwinder to instrument malloc().
  50. //
  51. // Note: if you add a new implementation here, make sure it works
  52. // correctly when GetStackTrace() is called with max_depth == 0.
  53. // Some code may do that.
  54. #include <config.h>
  55. #include <stdlib.h> // for getenv
  56. #include <string.h> // for strcmp
  57. #include <stdio.h> // for fprintf
  58. #include "gperftools/stacktrace.h"
  59. #include "base/commandlineflags.h"
  60. #include "base/googleinit.h"
  61. // we're using plain struct and not class to avoid any possible issues
  62. // during initialization. Struct of pointers is easy to init at
  63. // link-time.
  64. struct GetStackImplementation {
  65. int (*GetStackFramesPtr)(void** result, int* sizes, int max_depth,
  66. int skip_count);
  67. int (*GetStackFramesWithContextPtr)(void** result, int* sizes, int max_depth,
  68. int skip_count, const void *uc);
  69. int (*GetStackTracePtr)(void** result, int max_depth,
  70. int skip_count);
  71. int (*GetStackTraceWithContextPtr)(void** result, int max_depth,
  72. int skip_count, const void *uc);
  73. const char *name;
  74. };
  75. #if HAVE_DECL_BACKTRACE
  76. #define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h"
  77. #define GST_SUFFIX generic
  78. #include "stacktrace_impl_setup-inl.h"
  79. #undef GST_SUFFIX
  80. #undef STACKTRACE_INL_HEADER
  81. #define HAVE_GST_generic
  82. #endif
  83. #ifdef HAVE_UNWIND_BACKTRACE
  84. #define STACKTRACE_INL_HEADER "stacktrace_libgcc-inl.h"
  85. #define GST_SUFFIX libgcc
  86. #include "stacktrace_impl_setup-inl.h"
  87. #undef GST_SUFFIX
  88. #undef STACKTRACE_INL_HEADER
  89. #define HAVE_GST_libgcc
  90. #endif
  91. // libunwind uses __thread so we check for both libunwind.h and
  92. // __thread support
  93. #if defined(HAVE_LIBUNWIND_H) && defined(HAVE_TLS)
  94. #define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h"
  95. #define GST_SUFFIX libunwind
  96. #include "stacktrace_impl_setup-inl.h"
  97. #undef GST_SUFFIX
  98. #undef STACKTRACE_INL_HEADER
  99. #define HAVE_GST_libunwind
  100. #endif // HAVE_LIBUNWIND_H
  101. #if defined(__i386__) || defined(__x86_64__)
  102. #define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h"
  103. #define GST_SUFFIX x86
  104. #include "stacktrace_impl_setup-inl.h"
  105. #undef GST_SUFFIX
  106. #undef STACKTRACE_INL_HEADER
  107. #define HAVE_GST_x86
  108. #endif // i386 || x86_64
  109. #if defined(__ppc__) || defined(__PPC__)
  110. #if defined(__linux__)
  111. #define STACKTRACE_INL_HEADER "stacktrace_powerpc-linux-inl.h"
  112. #else
  113. #define STACKTRACE_INL_HEADER "stacktrace_powerpc-darwin-inl.h"
  114. #endif
  115. #define GST_SUFFIX ppc
  116. #include "stacktrace_impl_setup-inl.h"
  117. #undef GST_SUFFIX
  118. #undef STACKTRACE_INL_HEADER
  119. #define HAVE_GST_ppc
  120. #endif
  121. #if defined(__arm__)
  122. #define STACKTRACE_INL_HEADER "stacktrace_arm-inl.h"
  123. #define GST_SUFFIX arm
  124. #include "stacktrace_impl_setup-inl.h"
  125. #undef GST_SUFFIX
  126. #undef STACKTRACE_INL_HEADER
  127. #define HAVE_GST_arm
  128. #endif
  129. #ifdef TCMALLOC_ENABLE_INSTRUMENT_STACKTRACE
  130. #define STACKTRACE_INL_HEADER "stacktrace_instrument-inl.h"
  131. #define GST_SUFFIX instrument
  132. #include "stacktrace_impl_setup-inl.h"
  133. #undef GST_SUFFIX
  134. #undef STACKTRACE_INL_HEADER
  135. #define HAVE_GST_instrument
  136. #endif
  137. // The Windows case -- probably cygwin and mingw will use one of the
  138. // x86-includes above, but if not, we can fall back to windows intrinsics.
  139. #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__)
  140. #define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h"
  141. #define GST_SUFFIX win32
  142. #include "stacktrace_impl_setup-inl.h"
  143. #undef GST_SUFFIX
  144. #undef STACKTRACE_INL_HEADER
  145. #define HAVE_GST_win32
  146. #endif
  147. static GetStackImplementation *all_impls[] = {
  148. #ifdef HAVE_GST_libgcc
  149. &impl__libgcc,
  150. #endif
  151. #ifdef HAVE_GST_generic
  152. &impl__generic,
  153. #endif
  154. #ifdef HAVE_GST_libunwind
  155. &impl__libunwind,
  156. #endif
  157. #ifdef HAVE_GST_x86
  158. &impl__x86,
  159. #endif
  160. #ifdef HAVE_GST_arm
  161. &impl__arm,
  162. #endif
  163. #ifdef HAVE_GST_ppc
  164. &impl__ppc,
  165. #endif
  166. #ifdef HAVE_GST_instrument
  167. &impl__instrument,
  168. #endif
  169. #ifdef HAVE_GST_win32
  170. &impl__win32,
  171. #endif
  172. NULL
  173. };
  174. // ppc and i386 implementations prefer arch-specific asm implementations.
  175. // arm's asm implementation is broken
  176. #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__PPC__)
  177. #if !defined(NO_FRAME_POINTER)
  178. #define TCMALLOC_DONT_PREFER_LIBUNWIND
  179. #endif
  180. #endif
  181. static bool get_stack_impl_inited;
  182. #if defined(HAVE_GST_instrument)
  183. static GetStackImplementation *get_stack_impl = &impl__instrument;
  184. #elif defined(HAVE_GST_win32)
  185. static GetStackImplementation *get_stack_impl = &impl__win32;
  186. #elif defined(HAVE_GST_x86) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND)
  187. static GetStackImplementation *get_stack_impl = &impl__x86;
  188. #elif defined(HAVE_GST_ppc) && defined(TCMALLOC_DONT_PREFER_LIBUNWIND)
  189. static GetStackImplementation *get_stack_impl = &impl__ppc;
  190. #elif defined(HAVE_GST_libunwind)
  191. static GetStackImplementation *get_stack_impl = &impl__libunwind;
  192. #elif defined(HAVE_GST_libgcc)
  193. static GetStackImplementation *get_stack_impl = &impl__libgcc;
  194. #elif defined(HAVE_GST_generic)
  195. static GetStackImplementation *get_stack_impl = &impl__generic;
  196. #elif defined(HAVE_GST_arm)
  197. static GetStackImplementation *get_stack_impl = &impl__arm;
  198. #elif 0
  199. // This is for the benefit of code analysis tools that may have
  200. // trouble with the computed #include above.
  201. # include "stacktrace_x86-inl.h"
  202. # include "stacktrace_libunwind-inl.h"
  203. # include "stacktrace_generic-inl.h"
  204. # include "stacktrace_powerpc-inl.h"
  205. # include "stacktrace_win32-inl.h"
  206. # include "stacktrace_arm-inl.h"
  207. # include "stacktrace_instrument-inl.h"
  208. #else
  209. #error Cannot calculate stack trace: will need to write for your environment
  210. #endif
  211. static int ATTRIBUTE_NOINLINE frame_forcer(int rv) {
  212. return rv;
  213. }
  214. static void init_default_stack_impl_inner(void);
  215. namespace tcmalloc {
  216. bool EnterStacktraceScope(void);
  217. void LeaveStacktraceScope(void);
  218. }
  219. namespace {
  220. using tcmalloc::EnterStacktraceScope;
  221. using tcmalloc::LeaveStacktraceScope;
  222. class StacktraceScope {
  223. bool stacktrace_allowed;
  224. public:
  225. StacktraceScope() {
  226. stacktrace_allowed = true;
  227. stacktrace_allowed = EnterStacktraceScope();
  228. }
  229. bool IsStacktraceAllowed() {
  230. return stacktrace_allowed;
  231. }
  232. ~StacktraceScope() {
  233. if (stacktrace_allowed) {
  234. LeaveStacktraceScope();
  235. }
  236. }
  237. };
  238. }
  239. PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth,
  240. int skip_count) {
  241. StacktraceScope scope;
  242. if (!scope.IsStacktraceAllowed()) {
  243. return 0;
  244. }
  245. init_default_stack_impl_inner();
  246. return frame_forcer(get_stack_impl->GetStackFramesPtr(result, sizes, max_depth, skip_count));
  247. }
  248. PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
  249. int skip_count, const void *uc) {
  250. StacktraceScope scope;
  251. if (!scope.IsStacktraceAllowed()) {
  252. return 0;
  253. }
  254. init_default_stack_impl_inner();
  255. return frame_forcer(get_stack_impl->GetStackFramesWithContextPtr(
  256. result, sizes, max_depth,
  257. skip_count, uc));
  258. }
  259. PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
  260. int skip_count) {
  261. StacktraceScope scope;
  262. if (!scope.IsStacktraceAllowed()) {
  263. return 0;
  264. }
  265. init_default_stack_impl_inner();
  266. return frame_forcer(get_stack_impl->GetStackTracePtr(result, max_depth, skip_count));
  267. }
  268. PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth,
  269. int skip_count, const void *uc) {
  270. StacktraceScope scope;
  271. if (!scope.IsStacktraceAllowed()) {
  272. return 0;
  273. }
  274. init_default_stack_impl_inner();
  275. return frame_forcer(get_stack_impl->GetStackTraceWithContextPtr(
  276. result, max_depth, skip_count, uc));
  277. }
  278. static void init_default_stack_impl_inner(void) {
  279. if (get_stack_impl_inited) {
  280. return;
  281. }
  282. get_stack_impl_inited = true;
  283. char *val = getenv("TCMALLOC_STACKTRACE_METHOD");
  284. if (!val || !*val) {
  285. return;
  286. }
  287. for (GetStackImplementation **p = all_impls; *p; p++) {
  288. GetStackImplementation *c = *p;
  289. if (strcmp(c->name, val) == 0) {
  290. get_stack_impl = c;
  291. return;
  292. }
  293. }
  294. fprintf(stderr, "Unknown or unsupported stacktrace method requested: %s. Ignoring it\n", val);
  295. }
  296. static void init_default_stack_impl(void) {
  297. init_default_stack_impl_inner();
  298. if (EnvToBool("TCMALLOC_STACKTRACE_METHOD_VERBOSE", false)) {
  299. fprintf(stderr, "Chosen stacktrace method is %s\nSupported methods:\n", get_stack_impl->name);
  300. for (GetStackImplementation **p = all_impls; *p; p++) {
  301. GetStackImplementation *c = *p;
  302. fprintf(stderr, "* %s\n", c->name);
  303. }
  304. fputs("\n", stderr);
  305. }
  306. }
  307. REGISTER_MODULE_INITIALIZER(stacktrace_init_default_stack_impl, init_default_stack_impl());