| 251 | #endif |
| 252 | |
| 253 | void wf::print_trace(bool fast_mode) |
| 254 | { |
| 255 | if (!fast_mode) |
| 256 | { |
| 257 | #if HAS_ASAN |
| 258 | // We run with asan: use __sanitizer_print_stack_trace to cause ASAN to print a nice stacktrace, |
| 259 | // which is better than what we can come up with. |
| 260 | __sanitizer_print_stack_trace(); |
| 261 | return; |
| 262 | #endif |
| 263 | } |
| 264 | |
| 265 | void *addrlist[MAX_FRAMES]; |
| 266 | int addrlen = backtrace(addrlist, MAX_FRAMES); |
| 267 | if (addrlen == 0) |
| 268 | { |
| 269 | LOGE("Failed to determine backtrace, recompile with ASAN!"); |
| 270 | |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | char **symbollist = backtrace_symbols(addrlist, addrlen); |
| 275 | |
| 276 | for (int i = 1; i < addrlen; i++) |
| 277 | { |
| 278 | auto result = demangle_function(symbollist[i]); |
| 279 | |
| 280 | std::ostringstream line; |
| 281 | line << '#' << std::left << std::setw(2) << i << " "; |
| 282 | if (HAS_ADDR2LINE && !fast_mode && result.address.size() && |
| 283 | result.executable.size()) |
| 284 | { |
| 285 | auto source = locate_source_file(result); |
| 286 | line << source.function_name << " " << source.function_source; |
| 287 | } else if (result.function_name.size()) |
| 288 | { |
| 289 | line << result.function_name << " at " << result.address; |
| 290 | } else |
| 291 | { |
| 292 | line << symbollist[i]; |
| 293 | } |
| 294 | |
| 295 | auto contents = line.str(); |
| 296 | if (contents.size() && (contents.back() == '\n')) |
| 297 | { |
| 298 | contents.pop_back(); |
| 299 | } |
| 300 | |
| 301 | wf::log::log_plain(wf::log::LOG_LEVEL_ERROR, contents); |
| 302 | } |
| 303 | |
| 304 | free(symbollist); |
| 305 | } |
| 306 | |
| 307 | #else // has <execinfo.h> |
| 308 | void wf::print_trace(bool) |
nothing calls this directly
no test coverage detected