-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathexc_handling.cpp
118 lines (93 loc) · 3.58 KB
/
exc_handling.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2022, Eugene Gershnik
// SPDX-License-Identifier: BSD-3-Clause
#include "exc_handling.h"
#if __has_include(<execinfo.h>) //moronic Alpine/MUSL have no backtrace and no replacement
#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
using CodePtr = void (*)(void);
// static auto demangle_free = [](char * ptr) {
// free(ptr);
// };
// using demangled_string = std::unique_ptr<char, decltype(demangle_free)>;
class Backtrace {
public:
Backtrace() = default;
[[gnu::always_inline]] void fill(size_t skip) {
int res = backtrace(reinterpret_cast<void **>(s_backtraceBuffer.data()), static_cast<int>(s_backtraceBuffer.size()));
if (res > 0 && size_t(res) > skip) {
m_pointers.assign(s_backtraceBuffer.begin() + skip, s_backtraceBuffer.begin() + size_t(res) - skip);
} else {
m_pointers.clear();
}
}
template<class OutIt>
void print(OutIt dest) const {
fmt::format_to(dest, "--------\n");
for (auto ptr: m_pointers)
{
auto addr = reinterpret_cast</*const*/ void *>(ptr);
fmt::format_to(dest, " {:p}", addr);
Dl_info info{};
if (dladdr(addr, &info))
{
// if (info.dli_sname)
// {
// int stat = 0;
// demangled_string demangled(abi::__cxa_demangle(info.dli_sname, 0, 0, &stat), demangle_free);
// size_t offset = intptr_t(addr) - intptr_t(info.dli_saddr);
// fmt::format_to(dest, " {} + {}", (demangled ? demangled.get() : info.dli_sname), offset);
// }
if (info.dli_fname)
{
size_t offset = intptr_t(addr) - intptr_t(info.dli_fbase);
const char * basename = strrchr(info.dli_fname, '/');
fmt::format_to(dest, " {} + 0x{:X}", (basename ? basename + 1 : info.dli_fname), offset);
}
}
fmt::format_to(dest, "\n");
}
fmt::format_to(dest, "--------\n");
}
private:
std::vector<CodePtr> m_pointers;
static thread_local std::array<CodePtr, 256> s_backtraceBuffer;
};
thread_local std::array<CodePtr, 256> Backtrace::s_backtraceBuffer;
thread_local std::vector<Backtrace> g_backtraces;
extern "C" {
#if HAVE_ABI_CXA_THROW
#define CXA_THROW abi::__cxa_throw
#else
#define CXA_THROW __cxa_throw
#endif
[[gnu::noinline]] __attribute__((__visibility__("default"))) __attribute__ ((noreturn))
void CXA_THROW(void * ex, std::type_info * info, void (*dest)(void *)) {
auto currentIdx = std::uncaught_exceptions();
g_backtraces.resize(currentIdx + 1);
g_backtraces[currentIdx].fill(/*skip=*/1);
using __cxa_throw_t = decltype(&CXA_THROW);
static __cxa_throw_t __attribute__ ((noreturn)) realCxaThrow = (__cxa_throw_t)dlsym(RTLD_NEXT, "__cxa_throw");
realCxaThrow(ex, info, dest);
}
}
template<class OutIt>
static void doPrintCaughtExceptionBacktrace(OutIt dest) {
auto currentIdx = std::uncaught_exceptions();
if (size_t(currentIdx) > g_backtraces.size()) {
fmt::format_to(dest, " <not available>\n");
return;
}
const Backtrace & backtrace = g_backtraces[currentIdx];
backtrace.print(dest);
}
auto formatCaughtExceptionBacktrace() -> std::string {
std::string ret = "Backtrace:\n";
doPrintCaughtExceptionBacktrace(std::back_inserter(ret));
return ret;
}
#else
auto formatCaughtExceptionBacktrace() -> std::string {
return {};
}
#endif