terminate_handler.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
#include "crucible/boot/terminate_handler.hpp" #include "crucible/core/arrays.hpp" #include "crucible/core/backtrace.hpp" #include "crucible/core/format.hpp" namespace crucible::boot::terminate_handler { [[noreturn]] auto abort_with_detailed_backtrace(core::arrays::DynamicArray<core::backtrace::DetailedStackFrame> const &frames) -> void { auto print_detailed_stack_frame { [i = 0](core::backtrace::DetailedStackFrame const &frame) mutable -> void { std::cerr << "• #" << i << ": " << frame.describe() << "\n"; ++i; } }; std::cerr << "Full backtrace of the calling thread:\n" << "─────────────────────────────────────\n"; frames .iterate() .for_each_do(print_detailed_stack_frame); std::cerr << "\n"; std::abort(); } auto print_failed_detailed_backtrace(core::backtrace::Error const &error) -> void { std::cerr << "Failed to get full backtrace of the calling thread:\n" << "───────────────────────────────────────────────────\n" << "• " << error.describe() << "\n" << "\n"; } [[noreturn]] auto abort_with_simple_backtrace(core::arrays::DynamicArray<core::backtrace::SimpleStackFrame> const &frames) -> void { auto print_simple_stack_frame { [i = 0](core::backtrace::SimpleStackFrame const &frame) mutable -> void { std::cerr << "• #" << i << ": " << frame.describe() << "\n"; ++i; } }; std::cerr << "Simple backtrace of the calling thread:\n" << "───────────────────────────────────────\n"; frames .iterate() .for_each_do(print_simple_stack_frame); std::cerr << "\n"; std::abort(); } auto print_failed_simple_backtrace(core::backtrace::Error const &error) -> void { std::cerr << "Failed to get simple backtrace of the calling thread:\n" << "─────────────────────────────────────────────────────\n" << "• " << error.describe() << "\n" << "\n"; } auto handle_terminate() -> void { std::cerr <<"\n" << "╭────────────────────────────────────────────────────────────╮\n" << "│ std::terminate() called (this is a crash!) │\n" << "│ │\n" << "│ Here's all the information I could find about the problem: │\n" << "╰────────────────────────────────────────────────────────────╯\n" << "\n"; auto const exception { std::current_exception() }; try { if (exception) { std::rethrow_exception(exception); } std::cerr << "No std::exception objects are currently being thrown in the calling thread\n" << "──────────────────────────────────────────────────────────────────────────\n" << "\n"; } catch (std::exception const &e) { std::cerr << "Uncaught std::exception object in the calling thread:\n" << "─────────────────────────────────────────────────────\n" << "• typeid(): " << core::format::format_std_type_info(typeid(e)) << "\n" << "• what(): " << e.what() << "\n" << "\n"; } // `abort_with_detailed_backtrace()` will exit if we end up calling it auto const detailed_backtrace { core::backtrace::take_detailed_snapshot() }; detailed_backtrace.resolve(print_failed_detailed_backtrace, abort_with_detailed_backtrace); // `abort_with_simple_backtrace()` will exit if we end up calling it auto const simple_backtrace { core::backtrace::take_simple_snapshot() }; simple_backtrace.resolve(print_failed_simple_backtrace, abort_with_simple_backtrace); // If we failed both backtraces, just give up std::abort(); } }