|
3 | 3 | #include <algorithm>
|
4 | 4 | #include <cassert>
|
5 | 5 | #include <cstdlib>
|
| 6 | +#include <execinfo.h> |
6 | 7 | #include <functional>
|
7 | 8 | #include <iostream>
|
8 | 9 | #include <map>
|
9 | 10 | #include <memory>
|
10 | 11 | #include <optional>
|
| 12 | +#include <signal.h> |
11 | 13 | #include <string>
|
12 | 14 | #include <type_traits>
|
| 15 | +#include <unistd.h> |
13 | 16 | #include <utility>
|
14 | 17 | #include <vector>
|
15 | 18 |
|
@@ -58,6 +61,79 @@ namespace ioh::problem
|
58 | 61 | };
|
59 | 62 | } // namespace ioh::problem
|
60 | 63 |
|
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +void print_backtrace() { |
| 68 | + const int max_frames = 64; |
| 69 | + void* addrlist[max_frames + 1]; |
| 70 | + |
| 71 | + // retrieve current stack addresses |
| 72 | + int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); |
| 73 | + |
| 74 | + if (addrlen == 0) { |
| 75 | + std::cerr << " <empty, possibly corrupt>\n"; |
| 76 | + return; |
| 77 | + } |
| 78 | + |
| 79 | + // resolve addresses into strings containing "filename(function+address)", |
| 80 | + // this array must be free()-ed |
| 81 | + char** symbollist = backtrace_symbols(addrlist, addrlen); |
| 82 | + |
| 83 | + // allocate string which will be filled with the demangled function name |
| 84 | + size_t funcnamesize = 256; |
| 85 | + char* funcname = (char*)malloc(funcnamesize); |
| 86 | + |
| 87 | + // iterate over the returned symbol lines. skip the first, it is the |
| 88 | + // address of this function. |
| 89 | + for (int i = 1; i < addrlen; i++) { |
| 90 | + char *begin_name = nullptr, *begin_offset = nullptr, *end_offset = nullptr; |
| 91 | + |
| 92 | + // find parentheses and +address offset surrounding the mangled name |
| 93 | + for (char *p = symbollist[i]; *p; ++p) { |
| 94 | + if (*p == '(') |
| 95 | + begin_name = p; |
| 96 | + else if (*p == '+') |
| 97 | + begin_offset = p; |
| 98 | + else if (*p == ')' && begin_offset) { |
| 99 | + end_offset = p; |
| 100 | + break; |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + if (begin_name && begin_offset && end_offset && begin_name < begin_offset) { |
| 105 | + *begin_name++ = '\0'; |
| 106 | + *begin_offset++ = '\0'; |
| 107 | + *end_offset = '\0'; |
| 108 | + |
| 109 | + // mangle the function name |
| 110 | + int status; |
| 111 | + char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status); |
| 112 | + if (status == 0) { |
| 113 | + funcname = ret; // use possibly realloc()-ed string |
| 114 | + std::cerr << " " << symbollist[i] << " : " << funcname << "+" << begin_offset << "\n"; |
| 115 | + } else { |
| 116 | + // demangling failed, output function name as a C function with no arguments |
| 117 | + std::cerr << " " << symbollist[i] << " : " << begin_name << "()+" << begin_offset << "\n"; |
| 118 | + } |
| 119 | + } else { |
| 120 | + // couldn't parse the line, print the whole line |
| 121 | + std::cerr << " " << symbollist[i] << "\n"; |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + free(funcname); |
| 126 | + free(symbollist); |
| 127 | +} |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | + |
| 136 | + |
61 | 137 | namespace ioh::common
|
62 | 138 | {
|
63 | 139 |
|
@@ -142,11 +218,8 @@ namespace ioh::common
|
142 | 218 |
|
143 | 219 | if (already_defined) {
|
144 | 220 | std::string error_message = "Error: The name '" + name + "' has already been defined in the factory.";
|
145 |
| - |
146 |
| - // Output the error message to both std::cerr and std::cout |
147 | 221 | std::cerr << error_message << std::endl;
|
148 |
| - std::cout << error_message << std::endl; |
149 |
| - |
| 222 | + print_backtrace(); // Print the backtrace here |
150 | 223 | assert(!already_defined && name.c_str());
|
151 | 224 | }
|
152 | 225 |
|
|
0 commit comments