stack_trace.cc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. #include "port/stack_trace.h"
  7. #if defined(ROCKSDB_LITE) || !(defined(ROCKSDB_BACKTRACE) || defined(OS_MACOSX)) || \
  8. defined(CYGWIN) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
  9. // noop
  10. namespace ROCKSDB_NAMESPACE {
  11. namespace port {
  12. void InstallStackTraceHandler() {}
  13. void PrintStack(int /*first_frames_to_skip*/) {}
  14. } // namespace port
  15. } // namespace ROCKSDB_NAMESPACE
  16. #else
  17. #include <execinfo.h>
  18. #include <signal.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <cxxabi.h>
  24. namespace ROCKSDB_NAMESPACE {
  25. namespace port {
  26. namespace {
  27. #if defined(OS_LINUX) || defined(OS_FREEBSD)
  28. const char* GetExecutableName() {
  29. static char name[1024];
  30. char link[1024];
  31. snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
  32. auto read = readlink(link, name, sizeof(name) - 1);
  33. if (-1 == read) {
  34. return nullptr;
  35. } else {
  36. name[read] = 0;
  37. return name;
  38. }
  39. }
  40. void PrintStackTraceLine(const char* symbol, void* frame) {
  41. static const char* executable = GetExecutableName();
  42. if (symbol) {
  43. fprintf(stderr, "%s ", symbol);
  44. }
  45. if (executable) {
  46. // out source to addr2line, for the address translation
  47. const int kLineMax = 256;
  48. char cmd[kLineMax];
  49. snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable);
  50. auto f = popen(cmd, "r");
  51. if (f) {
  52. char line[kLineMax];
  53. while (fgets(line, sizeof(line), f)) {
  54. line[strlen(line) - 1] = 0; // remove newline
  55. fprintf(stderr, "%s\t", line);
  56. }
  57. pclose(f);
  58. }
  59. } else {
  60. fprintf(stderr, " %p", frame);
  61. }
  62. fprintf(stderr, "\n");
  63. }
  64. #elif defined(OS_MACOSX)
  65. void PrintStackTraceLine(const char* symbol, void* frame) {
  66. static int pid = getpid();
  67. // out source to atos, for the address translation
  68. const int kLineMax = 256;
  69. char cmd[kLineMax];
  70. snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid);
  71. auto f = popen(cmd, "r");
  72. if (f) {
  73. char line[kLineMax];
  74. while (fgets(line, sizeof(line), f)) {
  75. line[strlen(line) - 1] = 0; // remove newline
  76. fprintf(stderr, "%s\t", line);
  77. }
  78. pclose(f);
  79. } else if (symbol) {
  80. fprintf(stderr, "%s ", symbol);
  81. }
  82. fprintf(stderr, "\n");
  83. }
  84. #endif
  85. } // namespace
  86. void PrintStack(int first_frames_to_skip) {
  87. const int kMaxFrames = 100;
  88. void* frames[kMaxFrames];
  89. auto num_frames = backtrace(frames, kMaxFrames);
  90. auto symbols = backtrace_symbols(frames, num_frames);
  91. for (int i = first_frames_to_skip; i < num_frames; ++i) {
  92. fprintf(stderr, "#%-2d ", i - first_frames_to_skip);
  93. PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
  94. }
  95. free(symbols);
  96. }
  97. static void StackTraceHandler(int sig) {
  98. // reset to default handler
  99. signal(sig, SIG_DFL);
  100. fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig));
  101. // skip the top three signal handler related frames
  102. PrintStack(3);
  103. // re-signal to default handler (so we still get core dump if needed...)
  104. raise(sig);
  105. }
  106. void InstallStackTraceHandler() {
  107. // just use the plain old signal as it's simple and sufficient
  108. // for this use case
  109. signal(SIGILL, StackTraceHandler);
  110. signal(SIGSEGV, StackTraceHandler);
  111. signal(SIGBUS, StackTraceHandler);
  112. signal(SIGABRT, StackTraceHandler);
  113. }
  114. } // namespace port
  115. } // namespace ROCKSDB_NAMESPACE
  116. #endif