Instead of printing "<unknown>" in the ostream output, we could set that
string in the stacktrace_entry::_Info object, so that description()
returns that. Returning an empty string from that function seems simpler
for users to handle and decide on their own behaviour, rather than
having to parse "<unknown>".
With this change locations that don't have a source file look like this:
18# __libc_start_call_main at [0x7fd6568f6574]
19# __libc_start_main@GLIBC_2.2.5 at [0x7fd6568f6627]
20# _start at [0x4006a4]
Instead of:
18# __libc_start_call_main at :0
19# __libc_start_main@GLIBC_2.2.5 at :0
20# _start at :0
The string representation of a default constructed stacktrace_entry is
now "<unknown>" instead of an empty string.
libstdc++-v3/ChangeLog:
* include/std/stacktrace (stacktrace_entry::_Print_pc): New
struct for writing native handle to ostream.
(operator<<(ostream&, const stacktrace_entry&)): Improve output
when description() or source_file() returns an empty string,
or the stacktrace_entry is invalid.
(operator<<(ostream&, const basic_stacktrace<A>&)): Use
size_type of the correct specialization.
---
Tested x86_64-linux.
Any ideas for improving the output further?
We need to implement std::formatter specializations for these types too,
which could just call the to_string overloads, or could do something
smarter.
libstdc++-v3/include/std/stacktrace | 34 +++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/libstdc++-v3/include/std/stacktrace
b/libstdc++-v3/include/std/stacktrace
index b9e260e19f89..61aea57ec0d3 100644
--- a/libstdc++-v3/include/std/stacktrace
+++ b/libstdc++-v3/include/std/stacktrace
@@ -134,6 +134,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend ostream&
operator<<(ostream&, const stacktrace_entry&);
+ struct _Print_pc
+ {
+ native_handle_type _M_pc;
+
+ friend ostream&
+ operator<<(ostream& __os, _Print_pc __pc)
+ {
+ if (__pc._M_pc != (native_handle_type)-1) [[likely]]
+ __os << "[0x" << std::hex << __pc._M_pc << std::dec << ']';
+ else
+ __os << "<unknown>";
+ return __os;
+ }
+ };
+
// Type-erased wrapper for the fields of a stacktrace entry.
// This type is independent of which std::string ABI is in use.
struct _Info
@@ -683,13 +698,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline ostream&
operator<<(ostream& __os, const stacktrace_entry& __f)
{
+ using _Pc = stacktrace_entry::_Print_pc;
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;
+ if (__desc.empty()) [[unlikely]]
+ __os << "<unknown>";
+ else
+ __os << __desc;
+ __os << string_view(" at ");
+ if (__file.empty()) [[unlikely]]
+ __os << _Pc{__f.native_handle()};
+ else
+ __os << __file << ':' << __line;
}
+ else
+ __os << _Pc{__f.native_handle()};
return __os;
}
@@ -697,7 +722,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';
--
2.51.0