diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 337261e1..f1e06745 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -678,6 +678,28 @@ jobs: ninja ./unittest_module + unittest-windows-32-bit: + runs-on: windows-2022 + needs: unittest-windows + strategy: + fail-fast: false + matrix: + build_type: [Debug] + steps: + - uses: actions/checkout@v4 + - name: Enable Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1.13.0 + - name: build and test + run: | + mkdir build + cd build + cmake .. ` + -A Win32 ` + -DCPPTRACE_WERROR_BUILD=On ` + -DCPPTRACE_BUILD_TESTING=On + cmake --build . --config ${{matrix.build_type}} + ./${{matrix.build_type}}/unittest + unittest-windows-clangcl: runs-on: windows-2022 needs: unittest-windows diff --git a/include/cpptrace/from_current.hpp b/include/cpptrace/from_current.hpp index b9460a21..bad24c5f 100644 --- a/include/cpptrace/from_current.hpp +++ b/include/cpptrace/from_current.hpp @@ -41,15 +41,12 @@ CPPTRACE_BEGIN_NAMESPACE using type = void; }; - CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip); - #ifdef _MSC_VER - CPPTRACE_EXPORT bool matches_exception(EXCEPTION_POINTERS* exception_ptrs, const std::type_info& type_info); + CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE + void maybe_collect_trace(EXCEPTION_POINTERS* exception_ptrs, const std::type_info& type_info); template CPPTRACE_FORCE_NO_INLINE inline int exception_filter(EXCEPTION_POINTERS* exception_ptrs) { - if(matches_exception(exception_ptrs, typeid(E))) { - collect_current_trace(1); - } + maybe_collect_trace(exception_ptrs, typeid(E)); return EXCEPTION_CONTINUE_SEARCH; } class dont_return_from_try_catch_macros { @@ -57,7 +54,8 @@ CPPTRACE_BEGIN_NAMESPACE explicit dont_return_from_try_catch_macros() = default; }; #else - CPPTRACE_EXPORT bool check_can_catch(const std::type_info*, const std::type_info*, void**, unsigned); + CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE + void maybe_collect_trace(const std::type_info*, const std::type_info*, void**, unsigned); template class unwind_interceptor { public: @@ -68,9 +66,7 @@ CPPTRACE_BEGIN_NAMESPACE void** throw_obj, unsigned outer ) { - if(check_can_catch(&typeid(T), throw_type, throw_obj, outer)) { - collect_current_trace(1); - } + maybe_collect_trace(&typeid(T), throw_type, throw_obj, outer); return false; } }; diff --git a/src/from_current.cpp b/src/from_current.cpp index d0b59d65..b0f94eef 100644 --- a/src/from_current.cpp +++ b/src/from_current.cpp @@ -11,6 +11,7 @@ #include "utils/microfmt.hpp" #include "utils/utils.hpp" #include "logging.hpp" +#include "unwind/unwind.hpp" #ifndef _MSC_VER #include @@ -44,8 +45,7 @@ namespace detail { return rethrow_switch; } - CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip) { - auto trace = cpptrace::generate_raw_trace(skip + 1); + void save_current_trace(raw_trace trace) { if(get_rethrow_switch()) { saved_rethrow_trace = lazy_trace_holder(std::move(trace)); } else { @@ -54,6 +54,33 @@ namespace detail { } } + #if defined(_MSC_VER) && defined(CPPTRACE_UNWIND_WITH_DBGHELP) + CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip, EXCEPTION_POINTERS* exception_ptrs) { + try { + #if defined(_M_IX86) || defined(__i386__) + // skip one frame, first is CxxThrowException + (void)skip; + auto trace = raw_trace{detail::capture_frames(1, SIZE_MAX, exception_ptrs)}; + #else + (void)exception_ptrs; + auto trace = raw_trace{detail::capture_frames(skip + 1, SIZE_MAX)}; + #endif + save_current_trace(std::move(trace)); + } catch(...) { + detail::log_and_maybe_propagate_exception(std::current_exception()); + } + } + #else + CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip) { + try { + auto trace = raw_trace{detail::capture_frames(skip + 1, SIZE_MAX)}; + save_current_trace(std::move(trace)); + } catch(...) { + detail::log_and_maybe_propagate_exception(std::current_exception()); + } + } + #endif + #ifdef _MSC_VER // https://www.youtube.com/watch?v=COEv2kq_Ht8 // https://github.com/tpn/pdfs/blob/master/2018%20CppCon%20Unwinding%20the%20Stack%20-%20Exploring%20how%20C%2B%2B%20Exceptions%20work%20on%20Windows%20-%20James%20McNellis.pdf @@ -66,7 +93,7 @@ namespace detail { // - https://github.com/ecatmur/stacktrace-from-exception/blob/main/stacktrace-from-exception.cpp // - https://github.com/catboost/catboost/blob/master/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_msvc.ipp // - https://www.geoffchappell.com/studies/msvc/language/predefined/index.htm - #if defined _WIN64 + #ifdef _WIN64 #pragma pack(push, 4) struct CatchableType { std::uint32_t properties; @@ -85,19 +112,20 @@ namespace detail { }; #pragma warning(disable:4200) #if IS_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wc99-extensions" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wc99-extensions" #endif struct CatchableTypeArray { uint32_t nCatchableTypes; int32_t arrayOfCatchableTypes[]; }; #if IS_CLANG - #pragma clang diagnostic pop + #pragma clang diagnostic pop #endif #pragma warning (pop) #pragma pack(pop) #else + using CatchableTypeArray = ::_CatchableTypeArray; using CatchableType = ::_CatchableType; using ThrowInfo = ::_ThrowInfo; #endif @@ -583,14 +611,27 @@ CPPTRACE_BEGIN_NAMESPACE CPPTRACE_POP_EXTENSION_WARNINGS return false; } + CPPTRACE_FORCE_NO_INLINE + void maybe_collect_trace(EXCEPTION_POINTERS* exception_ptrs, const std::type_info& type_info) { + if(matches_exception(exception_ptrs, type_info)) { + #ifdef CPPTRACE_UNWIND_WITH_DBGHELP + collect_current_trace(2, exception_ptrs); + #else + collect_current_trace(2); + #endif + } + } #else - bool check_can_catch( + CPPTRACE_FORCE_NO_INLINE + void maybe_collect_trace( const std::type_info* type, const std::type_info* throw_type, void** throw_obj, unsigned outer ) { - return detail::can_catch(type, throw_type, throw_obj, outer); + if(detail::can_catch(type, throw_type, throw_obj, outer)) { + collect_current_trace(2); + } } void do_prepare_unwind_interceptor(const std::type_info& type_info, bool(*can_catch)(const std::type_info*, const std::type_info*, void**, unsigned)) { diff --git a/src/unwind/unwind.hpp b/src/unwind/unwind.hpp index d282f83e..a63b3293 100644 --- a/src/unwind/unwind.hpp +++ b/src/unwind/unwind.hpp @@ -6,6 +6,13 @@ #include #include +#ifdef CPPTRACE_UNWIND_WITH_DBGHELP + #define UNWIND_MAY_NEED_CONTEXT_RECORD + #define WIN32_LEAN_AND_MEAN + #include +#endif + + CPPTRACE_BEGIN_NAMESPACE namespace detail { #ifdef CPPTRACE_HARD_MAX_FRAMES @@ -14,8 +21,17 @@ namespace detail { constexpr std::size_t hard_max_frames = 400; #endif - CPPTRACE_FORCE_NO_INLINE - std::vector capture_frames(std::size_t skip, std::size_t max_depth); + #ifdef CPPTRACE_UNWIND_WITH_DBGHELP + CPPTRACE_FORCE_NO_INLINE + std::vector capture_frames( + std::size_t skip, + std::size_t max_depth, + EXCEPTION_POINTERS* exception_pointers = nullptr + ); + #else + CPPTRACE_FORCE_NO_INLINE + std::vector capture_frames(std::size_t skip, std::size_t max_depth); + #endif CPPTRACE_FORCE_NO_INLINE std::size_t safe_capture_frames(frame_ptr* buffer, std::size_t size, std::size_t skip, std::size_t max_depth); diff --git a/src/unwind/unwind_with_dbghelp.cpp b/src/unwind/unwind_with_dbghelp.cpp index 0d0a60aa..5e684f93 100644 --- a/src/unwind/unwind_with_dbghelp.cpp +++ b/src/unwind/unwind_with_dbghelp.cpp @@ -24,7 +24,11 @@ namespace detail { #pragma warning(disable: 4740) // warning C4740: flow in or out of inline asm code suppresses global optimization #endif CPPTRACE_FORCE_NO_INLINE - std::vector capture_frames(std::size_t skip, std::size_t max_depth) { + std::vector capture_frames( + std::size_t skip, + std::size_t max_depth, + EXCEPTION_POINTERS* exception_pointers + ) { skip++; // https://jpassing.com/2008/03/12/walking-the-stack-of-the-current-thread/ @@ -32,32 +36,36 @@ namespace detail { // GetThreadContext cannot be used on the current thread. // RtlCaptureContext doesn't work on i386 CONTEXT context; - #if defined(_M_IX86) || defined(__i386__) ZeroMemory(&context, sizeof(CONTEXT)); - context.ContextFlags = CONTEXT_CONTROL; - #if IS_MSVC - __asm { - label: - mov [context.Ebp], ebp; - mov [context.Esp], esp; - mov eax, [label]; - mov [context.Eip], eax; + if(exception_pointers) { + context = *exception_pointers->ContextRecord; + } else { + #if defined(_M_IX86) || defined(__i386__) + context.ContextFlags = CONTEXT_CONTROL; + #if IS_MSVC + __asm { + label: + mov [context.Ebp], ebp; + mov [context.Esp], esp; + mov eax, [label]; + mov [context.Eip], eax; + } + #else + asm( + "label:\n\t" + "mov{l %%ebp, %[cEbp] | %[cEbp], ebp};\n\t" + "mov{l %%esp, %[cEsp] | %[cEsp], esp};\n\t" + "mov{l $label, %%eax | eax, OFFSET label};\n\t" + "mov{l %%eax, %[cEip] | %[cEip], eax};\n\t" + : [cEbp] "=r" (context.Ebp), + [cEsp] "=r" (context.Esp), + [cEip] "=r" (context.Eip) + ); + #endif + #else + RtlCaptureContext(&context); + #endif } - #else - asm( - "label:\n\t" - "mov{l %%ebp, %[cEbp] | %[cEbp], ebp};\n\t" - "mov{l %%esp, %[cEsp] | %[cEsp], esp};\n\t" - "mov{l $label, %%eax | eax, OFFSET label};\n\t" - "mov{l %%eax, %[cEip] | %[cEip], eax};\n\t" - : [cEbp] "=r" (context.Ebp), - [cEsp] "=r" (context.Esp), - [cEip] "=r" (context.Eip) - ); - #endif - #else - RtlCaptureContext(&context); - #endif // Setup current frame STACKFRAME64 frame; ZeroMemory(&frame, sizeof(STACKFRAME64)); diff --git a/test/unit/lib/formatting.cpp b/test/unit/lib/formatting.cpp index 41547af8..ec63709d 100644 --- a/test/unit/lib/formatting.cpp +++ b/test/unit/lib/formatting.cpp @@ -17,6 +17,14 @@ using testing::ElementsAre; namespace { +#if !defined(_WIN32) || defined(_WIN64) + #define ADDR_PREFIX "00000000" + #define INLINED_TAG "(inlined) " +#else + #define ADDR_PREFIX "" + #define INLINED_TAG "(inlined) " +#endif + cpptrace::stacktrace make_test_stacktrace() { cpptrace::stacktrace trace; trace.frames.push_back({0x1, 0x1001, {20}, {30}, "foo.cpp", "foo()", false}); @@ -31,9 +39,9 @@ TEST(FormatterTest, Basic) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", - "#1 0x0000000000000002 in bar() at bar.cpp:30:40", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00000002 in bar() at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -48,9 +56,9 @@ TEST(FormatterTest, Inlines) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", - "#1 (inlined) in bar() at bar.cpp:30:40", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", + "#1 " INLINED_TAG " in bar() at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -63,9 +71,9 @@ TEST(FormatterTest, Header) { res, ElementsAre( "Stack trace:", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", - "#1 0x0000000000000002 in bar() at bar.cpp:30:40", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00000002 in bar() at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -78,9 +86,9 @@ TEST(FormatterTest, NoColumn) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20", - "#1 0x0000000000000002 in bar() at bar.cpp:30", - "#2 0x0000000000000003 in main at foo.cpp:40" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20", + "#1 0x" ADDR_PREFIX "00000002 in bar() at bar.cpp:30", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40" ) ); } @@ -93,9 +101,9 @@ TEST(FormatterTest, ObjectAddresses) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000001001 in foo() at foo.cpp:20:30", - "#1 0x0000000000001002 in bar() at bar.cpp:30:40", - "#2 0x0000000000001003 in main at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00001001 in foo() at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00001002 in bar() at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00001003 in main at foo.cpp:40:25" ) ); } @@ -128,10 +136,10 @@ TEST(FormatterTest, PathShortening) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", - "#1 0x0000000000000002 in bar() at bar.cpp:30:40", - "#2 0x0000000000000003 in main at foo.cpp:40:25", - "#3 0x0000000000000003 in main at baz.cpp:50:25" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00000002 in bar() at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25", + "#3 0x" ADDR_PREFIX "00000003 in main at baz.cpp:50:25" ) ); } @@ -150,7 +158,7 @@ TEST(FormatterTest, Snippets) { ElementsAre( "Stack trace (most recent call first):", // frame 1 - cpptrace::microfmt::format("#0 0x0000000000000001 in foo() at {}:{}:20", __FILE__, line), + cpptrace::microfmt::format("#0 0x" ADDR_PREFIX "00000001 in foo() at {}:{}:20", __FILE__, line), cpptrace::microfmt::format(" {}: cpptrace::stacktrace trace;", line - 2), cpptrace::microfmt::format(" {}: unsigned line = __LINE__ + 1;", line - 1), cpptrace::microfmt::format( @@ -163,7 +171,7 @@ TEST(FormatterTest, Snippets) { ), cpptrace::microfmt::format(" {}: auto formatter = cpptrace::formatter{{}}", line + 2), // frame 2 - cpptrace::microfmt::format("#1 0x0000000000000002 in foo() at {}:{}:20", __FILE__, line + 1), + cpptrace::microfmt::format("#1 0x" ADDR_PREFIX "00000002 in foo() at {}:{}:20", __FILE__, line + 1), cpptrace::microfmt::format(" {}: unsigned line = __LINE__ + 1;", line - 1), cpptrace::microfmt::format( " {}: trace.frames.push_back({0x1, 0x1001, {line}, {{20}}, __FILE__, \"foo()\", false});", @@ -184,7 +192,7 @@ TEST(FormatterTest, Snippets) { ElementsAre( "Stack trace (most recent call first):", // frame 1 - cpptrace::microfmt::format("#0 0x0000000000000001 in foo() at {}:{}:20", __FILE__, line), + cpptrace::microfmt::format("#0 0x" ADDR_PREFIX "00000001 in foo() at {}:{}:20", __FILE__, line), cpptrace::microfmt::format(" {}: unsigned line = __LINE__ + 1;", line - 1), cpptrace::microfmt::format( " {}: trace.frames.push_back({0x1, 0x1001, {line}, {{20}}, __FILE__, \"foo()\", false});", @@ -195,7 +203,7 @@ TEST(FormatterTest, Snippets) { line + 1 ), // frame 2 - cpptrace::microfmt::format("#1 0x0000000000000002 in foo() at {}:{}:20", __FILE__, line + 1), + cpptrace::microfmt::format("#1 0x" ADDR_PREFIX "00000002 in foo() at {}:{}:20", __FILE__, line + 1), cpptrace::microfmt::format( " {}: trace.frames.push_back({0x1, 0x1001, {line}, {{20}}, __FILE__, \"foo()\", false});", line @@ -218,9 +226,9 @@ TEST(FormatterTest, Colors) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 \x1B[34m0x0000000000000001\x1B[0m in \x1B[33mfoo()\x1B[0m at \x1B[32mfoo.cpp\x1B[0m:\x1B[34m20\x1B[0m:\x1B[34m30\x1B[0m", - "#1 \x1B[34m0x0000000000000002\x1B[0m in \x1B[33mbar()\x1B[0m at \x1B[32mbar.cpp\x1B[0m:\x1B[34m30\x1B[0m:\x1B[34m40\x1B[0m", - "#2 \x1B[34m0x0000000000000003\x1B[0m in \x1B[33mmain\x1B[0m at \x1B[32mfoo.cpp\x1B[0m:\x1B[34m40\x1B[0m:\x1B[34m25\x1B[0m" + "#0 \x1B[34m0x" ADDR_PREFIX "00000001\x1B[0m in \x1B[33mfoo()\x1B[0m at \x1B[32mfoo.cpp\x1B[0m:\x1B[34m20\x1B[0m:\x1B[34m30\x1B[0m", + "#1 \x1B[34m0x" ADDR_PREFIX "00000002\x1B[0m in \x1B[33mbar()\x1B[0m at \x1B[32mbar.cpp\x1B[0m:\x1B[34m30\x1B[0m:\x1B[34m40\x1B[0m", + "#2 \x1B[34m0x" ADDR_PREFIX "00000003\x1B[0m in \x1B[33mmain\x1B[0m at \x1B[32mfoo.cpp\x1B[0m:\x1B[34m40\x1B[0m:\x1B[34m25\x1B[0m" ) ); } @@ -235,9 +243,9 @@ TEST(FormatterTest, Filtering) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", "#1 (filtered)", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -253,8 +261,8 @@ TEST(FormatterTest, DontShowFilteredFrames) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -271,9 +279,9 @@ TEST(FormatterTest, Transforming) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in sym0 at foo.cpp:20:30", - "#1 0x0000000000000002 in sym1 at bar.cpp:30:40", - "#2 0x0000000000000003 in sym2 at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in sym0 at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00000002 in sym1 at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in sym2 at foo.cpp:40:25" ) ); @@ -281,7 +289,7 @@ TEST(FormatterTest, Transforming) { EXPECT_THAT( frame_res, ElementsAre( - "0x0000000000000002 in sym3 at bar.cpp:30:40" + "0x" ADDR_PREFIX "00000002 in sym3 at bar.cpp:30:40" ) ); } @@ -298,9 +306,9 @@ TEST(FormatterTest, TransformingRvalueRef) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in sym0 at foo.cpp:20:30", - "#1 0x0000000000000002 in sym1 at bar.cpp:30:40", - "#2 0x0000000000000003 in sym2 at foo.cpp:40:25" + "#0 0x" ADDR_PREFIX "00000001 in sym0 at foo.cpp:20:30", + "#1 0x" ADDR_PREFIX "00000002 in sym1 at bar.cpp:30:40", + "#2 0x" ADDR_PREFIX "00000003 in sym2 at foo.cpp:40:25" ) ); @@ -308,7 +316,7 @@ TEST(FormatterTest, TransformingRvalueRef) { EXPECT_THAT( frame_res, ElementsAre( - "0x0000000000000002 in sym3 at bar.cpp:30:40" + "0x" ADDR_PREFIX "00000002 in sym3 at bar.cpp:30:40" ) ); } @@ -324,9 +332,9 @@ TEST(FormatterTest, MoveSemantics) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", "#1 (filtered)", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); cpptrace::formatter formatter3; @@ -336,9 +344,9 @@ TEST(FormatterTest, MoveSemantics) { res2, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", "#1 (filtered)", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -354,9 +362,9 @@ TEST(FormatterTest, CopySemantics) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", "#1 (filtered)", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); cpptrace::formatter formatter3; @@ -366,9 +374,9 @@ TEST(FormatterTest, CopySemantics) { res2, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo() at foo.cpp:20:30", + "#0 0x" ADDR_PREFIX "00000001 in foo() at foo.cpp:20:30", "#1 (filtered)", - "#2 0x0000000000000003 in main at foo.cpp:40:25" + "#2 0x" ADDR_PREFIX "00000003 in main at foo.cpp:40:25" ) ); } @@ -383,7 +391,7 @@ TEST(FormatterTest, PrettySymbols) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo(std::__cxx11::basic_string, std::allocator >) at foo.cpp:20:30" + "#0 0x" ADDR_PREFIX "00000001 in foo(std::__cxx11::basic_string, std::allocator >) at foo.cpp:20:30" ) ); auto pretty_formatter = cpptrace::formatter{} @@ -393,7 +401,7 @@ TEST(FormatterTest, PrettySymbols) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in foo(std::string) at foo.cpp:20:30" + "#0 0x" ADDR_PREFIX "00000001 in foo(std::string) at foo.cpp:20:30" ) ); } @@ -408,7 +416,7 @@ TEST(FormatterTest, PrunedSymbols) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in ns::S::foo(int, int, int) at foo.cpp:20:30" + "#0 0x" ADDR_PREFIX "00000001 in ns::S::foo(int, int, int) at foo.cpp:20:30" ) ); auto pruned_formatter = cpptrace::formatter{} @@ -418,7 +426,7 @@ TEST(FormatterTest, PrunedSymbols) { res, ElementsAre( "Stack trace (most recent call first):", - "#0 0x0000000000000001 in ns::S::foo at foo.cpp:20:30" + "#0 0x" ADDR_PREFIX "00000001 in ns::S::foo at foo.cpp:20:30" ) ); }