stacktrace.h 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #ifndef _PVFMM_STACKTRACE_H_
  2. #define _PVFMM_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. namespace pvfmm {
  10. inline void print_stacktrace(FILE* out = stderr, int skip = 1) {
  11. // Get addresses
  12. void* addrlist[256];
  13. int addrlen = backtrace(addrlist, 255);
  14. for (int i = 0; i < addrlen; i++) addrlist[i] = (char*)addrlist[i] - 1;
  15. // Get symbols
  16. char** symbollist = backtrace_symbols(addrlist, addrlen);
  17. // Get filename
  18. char fname[10240];
  19. ssize_t fname_len = ::readlink("/proc/self/exe", fname, sizeof(fname) - 1);
  20. fname[fname_len] = '\0';
  21. // Print
  22. for (int i = skip; i < addrlen; i++) {
  23. // Get command
  24. char cmd[10240];
  25. sprintf(cmd, "addr2line -f -C -i -e %s %016p", fname, addrlist[i]);
  26. // Execute command
  27. FILE* pipe = popen(cmd, "r");
  28. if (!pipe) continue;
  29. char buffer0[10240];
  30. char buffer1[10240];
  31. fgets(buffer0, sizeof(buffer0) - 1, pipe);
  32. fgets(buffer1, sizeof(buffer1) - 1, pipe);
  33. for (int j = 0; j < sizeof(buffer0) - 1; j++) {
  34. if (buffer0[j] == '\n') buffer0[j] = ' ';
  35. }
  36. for (int j = 0; j < sizeof(buffer1) - 1; j++) {
  37. if (buffer1[j] == '\n') buffer1[j] = ' ';
  38. }
  39. pclose(pipe);
  40. // Print output
  41. if (buffer0[0] != '?') {
  42. fprintf(out, "[%d] %s: %s\n", i - skip, buffer1, buffer0);
  43. } else {
  44. fprintf(out, "[%d] %016p: %s\n", i - skip, addrlist[i], symbollist[i]);
  45. }
  46. }
  47. fprintf(stderr, "\n");
  48. }
  49. inline void abortHandler(int signum, siginfo_t* si, void* unused) {
  50. static bool first_time = true;
  51. UNUSED(unused);
  52. UNUSED(si);
  53. #pragma omp critical(STACK_TRACE)
  54. if (first_time) {
  55. first_time = false;
  56. const char* name = NULL;
  57. switch (signum) {
  58. case SIGABRT:
  59. name = "SIGABRT";
  60. break;
  61. case SIGSEGV:
  62. name = "SIGSEGV";
  63. break;
  64. case SIGBUS:
  65. name = "SIGBUS";
  66. break;
  67. case SIGILL:
  68. name = "SIGILL";
  69. break;
  70. case SIGFPE:
  71. name = "SIGFPE";
  72. break;
  73. }
  74. if (name)
  75. fprintf(stderr, "\nCaught signal %d (%s)\n", signum, name);
  76. else
  77. fprintf(stderr, "\nCaught signal %d\n", signum);
  78. print_stacktrace(stderr, 2);
  79. }
  80. exit(signum);
  81. }
  82. inline int SetSigHandler() {
  83. struct sigaction sa;
  84. sa.sa_flags = SA_RESTART | SA_SIGINFO;
  85. sa.sa_sigaction = abortHandler;
  86. sigemptyset(&sa.sa_mask);
  87. sigaction(SIGABRT, &sa, NULL);
  88. sigaction(SIGSEGV, &sa, NULL);
  89. sigaction(SIGBUS, &sa, NULL);
  90. sigaction(SIGILL, &sa, NULL);
  91. sigaction(SIGFPE, &sa, NULL);
  92. sigaction(SIGPIPE, &sa, NULL);
  93. return 0;
  94. }
  95. } // end namespace
  96. #endif // _PVFMM_STACKTRACE_H_