stacktrace.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #ifndef _SCTL_STACKTRACE_H_
  2. #define _SCTL_STACKTRACE_H_
  3. #include <sctl/common.hpp>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <execinfo.h>
  9. #include <cxxabi.h>
  10. #ifdef __APPLE__
  11. #include <mach-o/dyld.h>
  12. #endif
  13. namespace SCTL_NAMESPACE {
  14. inline void print_stacktrace(FILE* out = stderr, int skip = 1) {
  15. // Get addresses
  16. void* addrlist[256];
  17. int addrlen = backtrace(addrlist, 255);
  18. for (int i = 0; i < addrlen; i++) addrlist[i] = (char*)addrlist[i] - 1;
  19. // Get symbols
  20. char** symbollist = backtrace_symbols(addrlist, addrlen);
  21. // Get filename
  22. char fname[10240];
  23. #ifdef __APPLE__
  24. uint32_t size = sizeof(fname);
  25. _NSGetExecutablePath(fname, &size);
  26. #elif __linux__
  27. ssize_t fname_len = ::readlink("/proc/self/exe", fname, sizeof(fname) - 1);
  28. fname[fname_len] = '\0';
  29. #endif
  30. // Print
  31. for (int i = skip; i < addrlen; i++) {
  32. // Get command
  33. char cmd[10240+256+43];
  34. #ifdef __APPLE__
  35. sprintf(cmd, "atos -o %s %p 2> /dev/null", fname, addrlist[i]); // on mac
  36. #elif __linux__
  37. sprintf(cmd, "addr2line -f -C -i -e %s %p 2> /dev/null", fname, addrlist[i]);
  38. #endif
  39. // Execute command
  40. FILE* pipe = popen(cmd, "r");
  41. if (!pipe) continue;
  42. char buffer0[10240];
  43. char buffer1[10240];
  44. char* fgets_ret0 = fgets(buffer0, sizeof(buffer0) - 1, pipe);
  45. char* fgets_ret1 = fgets(buffer1, sizeof(buffer1) - 1, pipe);
  46. for (int j = 0; j < (int)sizeof(buffer0) - 1; j++) {
  47. if (buffer0[j] == '\n') buffer0[j] = ' ';
  48. }
  49. for (int j = 0; j < (int)sizeof(buffer1) - 1; j++) {
  50. if (buffer1[j] == '\n') buffer1[j] = ' ';
  51. }
  52. pclose(pipe);
  53. // Print output
  54. if (fgets_ret0 != nullptr && fgets_ret1 != nullptr && buffer0[0] != '?' && buffer0[0] != '\0') {
  55. fprintf(out, "[%d] %s: %s\n", i - skip, buffer1, buffer0);
  56. } else {
  57. fprintf(out, "[%d] %p: %s\n", i - skip, addrlist[i], symbollist[i]);
  58. }
  59. }
  60. fprintf(stderr, "\n");
  61. }
  62. inline void abortHandler(int signum, siginfo_t* si, void* unused) {
  63. static bool first_time = true;
  64. SCTL_UNUSED(unused);
  65. SCTL_UNUSED(si);
  66. #pragma omp critical(SCTL_STACK_TRACE)
  67. if (first_time) {
  68. first_time = false;
  69. const char* name = nullptr;
  70. switch (signum) {
  71. case SIGABRT:
  72. name = "SIGABRT";
  73. break;
  74. case SIGSEGV:
  75. name = "SIGSEGV";
  76. break;
  77. case SIGBUS:
  78. name = "SIGBUS";
  79. break;
  80. case SIGILL:
  81. name = "SIGILL";
  82. break;
  83. case SIGFPE:
  84. name = "SIGFPE";
  85. break;
  86. }
  87. if (name)
  88. fprintf(stderr, "\nCaught signal %d (%s)\n", signum, name);
  89. else
  90. fprintf(stderr, "\nCaught signal %d\n", signum);
  91. print_stacktrace(stderr, 2);
  92. }
  93. exit(signum);
  94. }
  95. inline int SetSigHandler() {
  96. struct sigaction sa;
  97. sa.sa_flags = SA_RESTART | SA_SIGINFO;
  98. sa.sa_sigaction = abortHandler;
  99. sigemptyset(&sa.sa_mask);
  100. sigaction(SIGABRT, &sa, nullptr);
  101. sigaction(SIGSEGV, &sa, nullptr);
  102. sigaction(SIGBUS, &sa, nullptr);
  103. sigaction(SIGILL, &sa, nullptr);
  104. sigaction(SIGFPE, &sa, nullptr);
  105. sigaction(SIGPIPE, &sa, nullptr);
  106. return 0;
  107. }
  108. } // end namespace
  109. #endif // _SCTL_STACKTRACE_H_