stack_trace.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  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_BACKTRACE) || defined(OS_MACOSX)) || defined(CYGWIN) || \
  8. defined(OS_SOLARIS) || defined(OS_WIN)
  9. // noop
  10. namespace ROCKSDB_NAMESPACE {
  11. namespace port {
  12. void InstallStackTraceHandler() {}
  13. void PrintStack(int /*first_frames_to_skip*/) {}
  14. void PrintAndFreeStack(void* /*callstack*/, int /*num_frames*/) {}
  15. void* SaveStack(int* /*num_frames*/, int /*first_frames_to_skip*/) {
  16. return nullptr;
  17. }
  18. } // namespace port
  19. } // namespace ROCKSDB_NAMESPACE
  20. #else
  21. #include <cxxabi.h>
  22. #include <execinfo.h>
  23. #include <pthread.h>
  24. #include <unistd.h>
  25. #include <csignal>
  26. #include <cstdio>
  27. #include <cstdlib>
  28. #include <cstring>
  29. #ifdef OS_OPENBSD
  30. #include <sys/sysctl.h>
  31. #include <sys/wait.h>
  32. #endif // OS_OPENBSD
  33. #ifdef OS_FREEBSD
  34. #include <sys/sysctl.h>
  35. #include <sys/wait.h>
  36. #endif // OS_FREEBSD
  37. #ifdef OS_LINUX
  38. #include <sys/prctl.h>
  39. #include <sys/types.h>
  40. #include <sys/wait.h>
  41. #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 30)
  42. #include <sys/syscall.h>
  43. #define gettid() syscall(SYS_gettid)
  44. #endif // GLIBC version
  45. #endif // OS_LINUX
  46. #include <algorithm>
  47. #include <atomic>
  48. #include "port/lang.h"
  49. namespace ROCKSDB_NAMESPACE::port {
  50. namespace {
  51. #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || \
  52. defined(OS_GNU_KFREEBSD)
  53. const char* GetExecutableName() {
  54. static char name[1024];
  55. #if defined(OS_FREEBSD)
  56. int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
  57. size_t namesz = sizeof(name);
  58. auto ret = sysctl(mib, 4, name, &namesz, nullptr, 0);
  59. if (-1 == ret) {
  60. return nullptr;
  61. } else {
  62. return name;
  63. }
  64. #elif defined(OS_OPENBSD)
  65. int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV};
  66. size_t namesz = sizeof(name);
  67. char* bin[namesz];
  68. auto ret = sysctl(mib, 4, bin, &namesz, nullptr, 0);
  69. if (-1 == ret) {
  70. return nullptr;
  71. } else {
  72. return bin[0];
  73. }
  74. #else
  75. char link[1024];
  76. snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
  77. auto read = readlink(link, name, sizeof(name) - 1);
  78. if (-1 == read) {
  79. return nullptr;
  80. } else {
  81. name[read] = 0;
  82. return name;
  83. }
  84. #endif
  85. }
  86. void PrintStackTraceLine(const char* symbol, void* frame) {
  87. static const char* executable = GetExecutableName();
  88. if (symbol) {
  89. fprintf(stderr, "%s ", symbol);
  90. }
  91. if (executable) {
  92. // out source to addr2line, for the address translation
  93. const int kLineMax = 256;
  94. char cmd[kLineMax];
  95. snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable);
  96. auto f = popen(cmd, "r");
  97. if (f) {
  98. char line[kLineMax];
  99. while (fgets(line, sizeof(line), f)) {
  100. line[strlen(line) - 1] = 0; // remove newline
  101. fprintf(stderr, "%s\t", line);
  102. }
  103. pclose(f);
  104. }
  105. } else {
  106. fprintf(stderr, " %p", frame);
  107. }
  108. fprintf(stderr, "\n");
  109. }
  110. #elif defined(OS_MACOSX)
  111. void PrintStackTraceLine(const char* symbol, void* frame) {
  112. static int pid = getpid();
  113. // out source to atos, for the address translation
  114. const int kLineMax = 256;
  115. char cmd[kLineMax];
  116. snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid);
  117. auto f = popen(cmd, "r");
  118. if (f) {
  119. char line[kLineMax];
  120. while (fgets(line, sizeof(line), f)) {
  121. line[strlen(line) - 1] = 0; // remove newline
  122. fprintf(stderr, "%s\t", line);
  123. }
  124. pclose(f);
  125. } else if (symbol) {
  126. fprintf(stderr, "%s ", symbol);
  127. }
  128. fprintf(stderr, "\n");
  129. }
  130. #endif
  131. const char* GetLldbScriptSelectThread(long long tid) {
  132. // NOTE: called from a signal handler, so no heap allocation
  133. static char script[80];
  134. snprintf(script, sizeof(script),
  135. "script -l python -- lldb.process.SetSelectedThreadByID(%lld)", tid);
  136. return script;
  137. }
  138. } // namespace
  139. void PrintStack(void* frames[], int num_frames) {
  140. auto symbols = backtrace_symbols(frames, num_frames);
  141. for (int i = 0; i < num_frames; ++i) {
  142. fprintf(stderr, "#%-2d ", i);
  143. PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
  144. }
  145. free(symbols);
  146. }
  147. void PrintStack(int first_frames_to_skip) {
  148. // Default to getting stack traces with GDB, at least on Linux where we
  149. // know how to attach to a particular thread.
  150. //
  151. // * Address space layout randomization (ASLR) interferes with getting good
  152. // stack information from backtrace+addr2line. This is more likely to show
  153. // up with LIB_MODE=shared builds (when kernel.randomize_va_space >= 1)
  154. // but can also show up with LIB_MODE=static builds ((when
  155. // kernel.randomize_va_space == 2).
  156. // * It doesn't appear easy to detect when ASLR is in use.
  157. // * With DEBUG_LEVEL < 2, backtrace() can skip frames that are not skipped
  158. // in GDB.
  159. //
  160. // LLDB also available as an option
  161. bool lldb_stack_trace = getenv("ROCKSDB_LLDB_STACK") != nullptr;
  162. #if defined(OS_LINUX)
  163. // Default true, override with ROCKSDB_BACKTRACE_STACK=1
  164. bool gdb_stack_trace =
  165. !lldb_stack_trace && getenv("ROCKSDB_BACKTRACE_STACK") == nullptr;
  166. #else
  167. // Default false, override with ROCKSDB_GDB_STACK=1
  168. bool gdb_stack_trace = getenv("ROCKSDB_GDB_STACK") != nullptr;
  169. #endif
  170. // Also support invoking interactive debugger on stack trace, with this
  171. // envvar set to non-empty
  172. char* debug_env = getenv("ROCKSDB_DEBUG");
  173. bool debug = debug_env != nullptr && strlen(debug_env) > 0;
  174. if (!debug && getenv("ROCKSDB_NO_STACK") != nullptr) {
  175. // Skip stack trace
  176. return;
  177. }
  178. if (lldb_stack_trace || gdb_stack_trace || debug) {
  179. // Allow ouside debugger to attach, even with Yama security restrictions
  180. #ifdef PR_SET_PTRACER_ANY
  181. (void)prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
  182. #endif
  183. // Try to invoke GDB, either for stack trace or debugging.
  184. long long attach_pid = getpid();
  185. // NOTE: we're in a signal handler, so no heap allocation
  186. char attach_pid_str[20];
  187. snprintf(attach_pid_str, sizeof(attach_pid_str), "%lld", attach_pid);
  188. // `gdb -p PID` seems to always attach to main thread, but `gdb -p TID`
  189. // seems to be able to attach to a particular thread in a process, which
  190. // makes sense as the main thread TID == PID of the process.
  191. // But I haven't found that gdb capability documented anywhere, so leave
  192. // a back door to attach to main thread.
  193. long long gdb_attach_id = attach_pid;
  194. // Save current thread id before fork
  195. long long attach_tid = 0;
  196. #ifdef OS_LINUX
  197. attach_tid = gettid();
  198. if (getenv("ROCKSDB_DEBUG_USE_PID") == nullptr) {
  199. gdb_attach_id = attach_tid;
  200. }
  201. #endif
  202. char gdb_attach_id_str[20];
  203. snprintf(gdb_attach_id_str, sizeof(gdb_attach_id_str), "%lld",
  204. gdb_attach_id);
  205. pid_t child_pid = fork();
  206. if (child_pid == 0) {
  207. // child process
  208. if (debug) {
  209. if (strcmp(debug_env, "lldb") == 0) {
  210. fprintf(stderr, "Invoking LLDB for debugging (ROCKSDB_DEBUG=%s)...\n",
  211. debug_env);
  212. execlp(/*cmd in PATH*/ "lldb", /*arg0*/ "lldb", "-p", attach_pid_str,
  213. /*"-Q",*/ "-o", GetLldbScriptSelectThread(attach_tid),
  214. (char*)nullptr);
  215. return;
  216. } else {
  217. fprintf(stderr, "Invoking GDB for debugging (ROCKSDB_DEBUG=%s)...\n",
  218. debug_env);
  219. execlp(/*cmd in PATH*/ "gdb", /*arg0*/ "gdb", "-p", gdb_attach_id_str,
  220. (char*)nullptr);
  221. return;
  222. }
  223. } else {
  224. // Redirect child stdout to original stderr
  225. dup2(2, 1);
  226. // No child stdin (don't use pager)
  227. close(0);
  228. if (lldb_stack_trace) {
  229. fprintf(stderr, "Invoking LLDB for stack trace...\n");
  230. // Skip top ~4 frames here in PrintStack
  231. auto bt_in_lldb =
  232. "script -l python -- for f in lldb.thread.frames[4:]: print(f)";
  233. execlp(/*cmd in PATH*/ "lldb", /*arg0*/ "lldb", "-p", attach_pid_str,
  234. "-b", "-Q", "-o", GetLldbScriptSelectThread(attach_tid), "-o",
  235. bt_in_lldb, (char*)nullptr);
  236. } else {
  237. // gdb_stack_trace
  238. fprintf(stderr, "Invoking GDB for stack trace...\n");
  239. // Skip top ~4 frames here in PrintStack
  240. // See https://stackoverflow.com/q/40991943/454544
  241. auto bt_in_gdb =
  242. "frame apply level 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 "
  243. "21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 "
  244. "42 43 44 -q frame";
  245. // -n : Loading config files can apparently cause failures with the
  246. // other options here.
  247. // -batch : non-interactive; suppress banners as much as possible
  248. execlp(/*cmd in PATH*/ "gdb", /*arg0*/ "gdb", "-n", "-batch", "-p",
  249. gdb_attach_id_str, "-ex", bt_in_gdb, (char*)nullptr);
  250. }
  251. return;
  252. }
  253. } else {
  254. // parent process; wait for child
  255. int wstatus;
  256. waitpid(child_pid, &wstatus, 0);
  257. if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
  258. // Good
  259. return;
  260. }
  261. }
  262. fprintf(stderr, "GDB failed; falling back on backtrace+addr2line...\n");
  263. }
  264. const int kMaxFrames = 100;
  265. void* frames[kMaxFrames];
  266. int num_frames = (int)backtrace(frames, kMaxFrames);
  267. PrintStack(&frames[first_frames_to_skip], num_frames - first_frames_to_skip);
  268. }
  269. void PrintAndFreeStack(void* callstack, int num_frames) {
  270. PrintStack(static_cast<void**>(callstack), num_frames);
  271. free(callstack);
  272. }
  273. void* SaveStack(int* num_frames, int first_frames_to_skip) {
  274. const int kMaxFrames = 100;
  275. void* frames[kMaxFrames];
  276. int count = (int)backtrace(frames, kMaxFrames);
  277. *num_frames = count - first_frames_to_skip;
  278. void* callstack = malloc(sizeof(void*) * *num_frames);
  279. memcpy(callstack, &frames[first_frames_to_skip], sizeof(void*) * *num_frames);
  280. return callstack;
  281. }
  282. static std::atomic<uint64_t> g_thread_handling_stack_trace{0};
  283. static int g_recursion_count = 0;
  284. static std::atomic<bool> g_at_exit_called{false};
  285. static void StackTraceHandler(int sig) {
  286. fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig));
  287. // Crude recursive mutex with no signal-unsafe system calls, to avoid
  288. // re-entrance from multiple threads and avoid core dumping while trying
  289. // to print the stack trace.
  290. uint64_t tid = 0;
  291. {
  292. const auto ptid = pthread_self();
  293. // pthread_t is an opaque type
  294. memcpy(&tid, &ptid, std::min(sizeof(tid), sizeof(ptid)));
  295. // Essentially ensure non-zero
  296. ++tid;
  297. }
  298. for (;;) {
  299. uint64_t expected = 0;
  300. if (g_thread_handling_stack_trace.compare_exchange_strong(expected, tid)) {
  301. // Acquired mutex
  302. g_recursion_count = 0;
  303. break;
  304. }
  305. if (expected == tid) {
  306. ++g_recursion_count;
  307. fprintf(stderr, "Recursive call to stack trace handler (%d)\n",
  308. g_recursion_count);
  309. break;
  310. }
  311. // Sleep before trying again
  312. usleep(1000);
  313. }
  314. if (g_recursion_count > 2) {
  315. // Give up after too many recursions
  316. fprintf(stderr, "Too many recursive calls to stack trace handler (%d)\n",
  317. g_recursion_count);
  318. } else {
  319. if (g_at_exit_called.load(std::memory_order_acquire)) {
  320. fprintf(stderr, "In a race with process already exiting...\n");
  321. }
  322. // skip the top three signal handler related frames
  323. PrintStack(3);
  324. // Efforts to fix or suppress TSAN warnings "signal-unsafe call inside of
  325. // a signal" have failed, so just warn the user about them.
  326. #ifdef __SANITIZE_THREAD__
  327. fprintf(stderr,
  328. "==> NOTE: any above warnings about \"signal-unsafe call\" are\n"
  329. "==> ignorable, as they are expected when generating a stack\n"
  330. "==> trace because of a signal under TSAN. Consider why the\n"
  331. "==> signal was generated to begin with, and the stack trace\n"
  332. "==> in the TSAN warning can be useful for that. (The stack\n"
  333. "==> trace printed by the signal handler is likely obscured\n"
  334. "==> by TSAN output.)\n");
  335. #endif
  336. }
  337. // reset to default handler
  338. signal(sig, SIG_DFL);
  339. // re-signal to default handler (so we still get core dump if needed...)
  340. raise(sig);
  341. // release the mutex, in case this is somehow recoverable
  342. if (g_recursion_count > 0) {
  343. --g_recursion_count;
  344. } else {
  345. g_thread_handling_stack_trace.store(0, std::memory_order_release);
  346. }
  347. }
  348. static void AtExit() {
  349. // wait for stack trace handler to finish, if needed
  350. while (g_thread_handling_stack_trace.load(std::memory_order_acquire)) {
  351. usleep(1000);
  352. }
  353. g_at_exit_called.store(true, std::memory_order_release);
  354. }
  355. void InstallStackTraceHandler() {
  356. // just use the plain old signal as it's simple and sufficient
  357. // for this use case
  358. signal(SIGILL, StackTraceHandler);
  359. signal(SIGSEGV, StackTraceHandler);
  360. signal(SIGBUS, StackTraceHandler);
  361. signal(SIGABRT, StackTraceHandler);
  362. atexit(AtExit);
  363. // Allow ouside debugger to attach, even with Yama security restrictions.
  364. // This is needed even outside of PrintStack() so that external mechanisms
  365. // can dump stacks if they suspect that a test has hung.
  366. #ifdef PR_SET_PTRACER_ANY
  367. (void)prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
  368. #endif
  369. }
  370. } // namespace ROCKSDB_NAMESPACE::port
  371. #endif