66#include " utils/replace_all.hpp"
77#include " snippets/snippet.hpp"
88
9+ #include < algorithm>
910#include < cstdio>
1011#include < string>
1112#include < functional>
@@ -69,6 +70,7 @@ CPPTRACE_BEGIN_NAMESPACE
6970 bool columns = true ;
7071 symbol_mode symbols = symbol_mode::full;
7172 bool show_filtered_frames = true ;
73+ bool hide_exception_machinery = true ;
7274 std::function<bool (const stacktrace_frame&)> filter;
7375 std::function<stacktrace_frame(stacktrace_frame)> transform;
7476 } options;
@@ -110,6 +112,9 @@ CPPTRACE_BEGIN_NAMESPACE
110112 void break_before_filename (bool do_break) {
111113 options.break_before_filename = do_break;
112114 }
115+ void hide_exception_machinery (bool do_hide) {
116+ options.hide_exception_machinery = do_hide;
117+ }
113118
114119 std::string format (
115120 const stacktrace_frame& frame,
@@ -213,6 +218,25 @@ CPPTRACE_BEGIN_NAMESPACE
213218 return do_color;
214219 }
215220
221+ size_t get_trace_start (const stacktrace& trace) const {
222+ if (!options.hide_exception_machinery ) {
223+ return 0 ;
224+ }
225+ // Look for c++ exception machinery and skip it if it's present, otherwise start at the beginning
226+ // On itanium this is identifiable by __cxa_throw
227+ // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html 2.4.1
228+ // On windows this is identifiable by CxxThrowException (maybe with an underscore?)
229+ // https://www.youtube.com/watch?v=COEv2kq_Ht8 40:10
230+ // https://github.com/CppCon/CppCon2018/blob/master/Presentations/unwinding_the_stack_exploring_how_cpp_exceptions_work_on_windows/unwinding_the_stack_exploring_how_cpp_exceptions_work_on_windows__james_mcnellis__cppcon_2018.pdf slide 157
231+ // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/cxxthrowexception?view=msvc-170
232+ auto it = std::find_if (trace.begin (), trace.end (), [] (const stacktrace_frame& frame) {
233+ return frame.symbol == " __cxa_throw"
234+ || frame.symbol == " CxxThrowException"
235+ || frame.symbol == " _CxxThrowException" ;
236+ });
237+ return it == trace.end () ? 0 : it - trace.begin () + 1 ;
238+ }
239+
216240 void print_internal (std::ostream& stream, const stacktrace_frame& input_frame, detail::optional<bool > color_override, size_t col_indent) const {
217241 bool color = should_do_color (stream, color_override);
218242 maybe_ensure_virtual_terminal_processing (stream, color);
@@ -235,14 +259,14 @@ CPPTRACE_BEGIN_NAMESPACE
235259 if (!options.header .empty ()) {
236260 stream << options.header << ' \n ' ;
237261 }
238- std::size_t counter = 0 ;
239262 const auto & frames = trace.frames ;
240263 if (frames.empty ()) {
241264 stream << " <empty trace>" ;
242265 return ;
243266 }
244267 const auto frame_number_width = detail::n_digits (static_cast <int >(frames.size ()) - 1 );
245- for (size_t i = 0 ; i < frames.size (); ++i) {
268+ std::size_t counter = 0 ;
269+ for (size_t i = get_trace_start (trace); i < frames.size (); ++i) {
246270 detail::optional<stacktrace_frame> transformed_frame;
247271 if (options.transform ) {
248272 transformed_frame = options.transform (frames[i]);
@@ -429,6 +453,10 @@ CPPTRACE_BEGIN_NAMESPACE
429453 pimpl->break_before_filename (do_break);
430454 return *this ;
431455 }
456+ formatter& formatter::hide_exception_machinery (bool do_hide) {
457+ pimpl->hide_exception_machinery (do_hide);
458+ return *this ;
459+ }
432460
433461 std::string formatter::format (const stacktrace_frame& frame) const {
434462 return pimpl->format (frame);
0 commit comments