|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | +#include "Framework/BacktraceHelpers.h" |
| 12 | +#include <climits> |
| 13 | +#include <cstddef> |
| 14 | +#include <cstdio> |
| 15 | +#include <cstdlib> |
| 16 | +#include <unistd.h> |
| 17 | +#include <cxxabi.h> |
| 18 | +#include <execinfo.h> |
| 19 | + |
| 20 | +namespace o2::framework |
| 21 | +{ |
| 22 | + |
| 23 | +void BacktraceHelpers::demangled_backtrace_symbols(void** stackTrace, unsigned int stackDepth, int fd) |
| 24 | +{ |
| 25 | + char** stackStrings; |
| 26 | + stackStrings = backtrace_symbols(stackTrace, stackDepth); |
| 27 | + char exe[PATH_MAX]; |
| 28 | + bool hasExe = false; |
| 29 | + int exeSize = 0; |
| 30 | + |
| 31 | +#if __linux__ |
| 32 | + exeSize = readlink("/proc/self/exe", exe, PATH_MAX); |
| 33 | + if (exeSize == -1) { |
| 34 | + dprintf(fd, "Unable to detect exectuable name\n"); |
| 35 | + hasExe = false; |
| 36 | + } else { |
| 37 | + dprintf(fd, "Executable is %.*s\n", exeSize, exe); |
| 38 | + hasExe = true; |
| 39 | + } |
| 40 | +#endif |
| 41 | + |
| 42 | + for (size_t i = 1; i < stackDepth; i++) { |
| 43 | + |
| 44 | + size_t sz = 64000; // 64K ought to be enough for our templates... |
| 45 | + char* function = static_cast<char*>(malloc(sz)); |
| 46 | + char *begin = nullptr, *end = nullptr; |
| 47 | + // find the last space and address offset surrounding the mangled name |
| 48 | +#if __APPLE__ |
| 49 | + for (char* j = stackStrings[i]; *j; ++j) { |
| 50 | + if (*j == ' ' && *(j + 1) != '+') { |
| 51 | + begin = j; |
| 52 | + } else if (*j == ' ' && *(j + 1) == '+') { |
| 53 | + end = j; |
| 54 | + break; |
| 55 | + } |
| 56 | + } |
| 57 | + bool tryAddr2Line = false; |
| 58 | +#else |
| 59 | + for (char* j = stackStrings[i]; j && *j; ++j) { |
| 60 | + if (*j == '(') { |
| 61 | + begin = j; |
| 62 | + } else if (*j == '+') { |
| 63 | + end = j; |
| 64 | + break; |
| 65 | + } |
| 66 | + } |
| 67 | + bool tryAddr2Line = true; |
| 68 | +#endif |
| 69 | + if (begin && end) { |
| 70 | + *begin++ = '\0'; |
| 71 | + *end = '\0'; |
| 72 | + // found our mangled name, now in [begin, end) |
| 73 | + |
| 74 | + int status; |
| 75 | + char* ret = abi::__cxa_demangle(begin, function, &sz, &status); |
| 76 | + if (ret) { |
| 77 | + // return value may be a realloc() of the input |
| 78 | + function = ret; |
| 79 | + dprintf(fd, " %s: %s\n", stackStrings[i], function); |
| 80 | + tryAddr2Line = false; |
| 81 | + } |
| 82 | + } |
| 83 | + if (tryAddr2Line) { |
| 84 | + // didn't find the mangled name, just print the whole line |
| 85 | + dprintf(fd, " %s: ", stackStrings[i]); |
| 86 | + if (stackTrace[i] && hasExe) { |
| 87 | + char syscom[4096 + PATH_MAX]; |
| 88 | + |
| 89 | + // Find c++filt from the environment |
| 90 | + // This is needed for platforms where we still need c++filt -r |
| 91 | + char const* cxxfilt = getenv("CXXFILT"); |
| 92 | + if (cxxfilt == nullptr) { |
| 93 | + cxxfilt = "c++filt"; |
| 94 | + } |
| 95 | + // Do the same for addr2line, just in case we wanted to pass some options |
| 96 | + char const* addr2line = getenv("ADDR2LINE"); |
| 97 | + if (addr2line == nullptr) { |
| 98 | + addr2line = "addr2line"; |
| 99 | + } |
| 100 | + snprintf(syscom, 4096, "%s %p -p -s -f -e %.*s 2>/dev/null | %s ", addr2line, stackTrace[i], exeSize, exe, cxxfilt); // last parameter is the name of this app |
| 101 | + |
| 102 | + FILE* fp; |
| 103 | + char path[1024]; |
| 104 | + |
| 105 | + fp = popen(syscom, "r"); |
| 106 | + if (fp == nullptr) { |
| 107 | + dprintf(fd, "-- no source could be retrieved --\n"); |
| 108 | + continue; |
| 109 | + } |
| 110 | + |
| 111 | + while (fgets(path, sizeof(path) - 1, fp) != nullptr) { |
| 112 | + dprintf(fd, " %s", path); |
| 113 | + } |
| 114 | + |
| 115 | + pclose(fp); |
| 116 | + } else { |
| 117 | + dprintf(fd, "-- no source avaliable --\n"); |
| 118 | + } |
| 119 | + } |
| 120 | + free(function); |
| 121 | + } |
| 122 | + free(stackStrings); // malloc()ed by backtrace_symbols |
| 123 | + fsync(fd); |
| 124 | +} |
| 125 | +} // namespace o2::framework |
0 commit comments