stacktrace.h 3.0 KB

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