From: Jonathan Wakely Date: Wed, 15 Oct 2025 19:10:34 +0000 (+0100) Subject: libstdc++: Improve ostream output for std::stacktrace X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=08b2c542e4d0c223f50e46692bccf0c2ebbe3454;p=thirdparty%2Fgcc.git libstdc++: Improve ostream output for std::stacktrace With this change stacktrace entries always output the frame address, and source file information no longer results in " at :0", e.g. 16# myfunc(int) at /tmp/bt.cc:48 [0x4008b7] 17# main at /tmp/bt.cc:61 [0x40091a] 18# __libc_start_call_main [0x7efc3d6d3574] 19# __libc_start_main@GLIBC_2.2.5 [0x7efc3d6d3627] 20# _start [0x400684] This replaces the previous output: 16# myfunc(int) at /tmp/bt.cc:48 17# main at /tmp/bt.cc:61 18# __libc_start_call_main at :0 19# __libc_start_main@GLIBC_2.2.5 at :0 20# _start at :0 A change that is not visible in the examples above is that for a non-empty stacktrace_entry, we now print "" for the function name if description() returns an empty string. For an empty (e.g. default constructed) stacktrace_entry the entire string representation is now "" instead of an empty string. Instead of printing "" for the function name, we could set that string in the stacktrace_entry::_Info object, so that description() returns "" and then operator<< wouldn't need to handle an empty description() string. However, returning an empty string from that function seems simpler for users to detect, rather than having to parse "". We could also choose a different string for an empty stacktrace_entry, maybe "" or "", but "" seems good. libstdc++-v3/ChangeLog: * include/std/stacktrace (operator<<(ostream&, const stacktrace_entry&)): Improve output when description() or source_file() returns an empty string, or the stacktrace_entry is invalid. Append frame address to output. (operator<<(ostream&, const basic_stacktrace&)): Use the size_type of the correct specialization. Reviewed-by: Tomasz KamiƄski Reviewed-by: Nathan Myers --- diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index b9e260e19f8..587a163e976 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -683,13 +683,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline ostream& operator<<(ostream& __os, const stacktrace_entry& __f) { + if (!__f) [[unlikely]] + return __os << ""; + string __desc, __file; int __line; - if (__f._M_get_info(&__desc, &__file, &__line)) + if (__f._M_get_info(&__desc, &__file, &__line)) [[likely]] { - __os.width(4); - __os << __desc << " at " << __file << ':' << __line; + __os << ' '; + if (__desc.empty()) [[unlikely]] + __os << ""; + else + __os << __desc; + if (!__file.empty()) [[likely]] + __os << " at " << __file << ':' << __line; } + + struct _Flag_guard // Set and restore hex format + { + _Flag_guard(ios& __s) : _M_ios(__s) { } + ~_Flag_guard() { _M_ios.setf(_M_f); } + + ios& _M_ios; + ios::fmtflags _M_f = _M_ios.setf(ios::hex, ios::basefield); + }; + _Flag_guard __g(__os); + __os << " [0x" << __f.native_handle() << ']'; return __os; } @@ -697,7 +716,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline ostream& operator<<(ostream& __os, const basic_stacktrace<_Allocator>& __st) { - for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i) + using size_type = typename basic_stacktrace<_Allocator>::size_type; + for (size_type __i = 0, __size = __st.size(); __i < __size; ++__i) { __os.width(4); __os << __i << "# " << __st[__i] << '\n';