diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index f38087a..bc1390b 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -105,39 +104,29 @@ namespace cpptrace { } std::string stacktrace_frame::to_string() const { - std::ostringstream oss; - oss << *this; - return std::move(oss).str(); - } - - std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) { - stream - << std::hex - << "0x" - << std::setw(2 * sizeof(frame_ptr)) - << std::setfill('0') - << frame.raw_address - << std::dec - << std::setfill(' '); - if(!frame.symbol.empty()) { - stream - << " in " - << frame.symbol; + std::string str; + if(is_inline) { + str += microfmt::format("{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)"); + } else { + str += microfmt::format("0x{<{}:0h}", 2 * sizeof(frame_ptr), raw_address); } - if(!frame.filename.empty()) { - stream - << " at " - << frame.filename; - if(frame.line.has_value()) { - stream - << ":" - << frame.line.value(); - if(frame.column.has_value()) { - stream << frame.column.value(); + if(!symbol.empty()) { + str += microfmt::format(" in {}", symbol); + } + if(!filename.empty()) { + str += microfmt::format(" at {}", filename); + if(line.has_value()) { + str += microfmt::format(":{}", line.value()); + if(column.has_value()) { + str += microfmt::format(":{}", column.value()); } } } - return stream; + return str; + } + + std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) { + return stream << frame.to_string(); } CPPTRACE_FORCE_NO_INLINE @@ -173,56 +162,25 @@ namespace cpptrace { const auto green = color ? GREEN : ""; const auto yellow = color ? YELLOW : ""; const auto blue = color ? BLUE : ""; - stream - << '#' - << std::setw(static_cast(frame_number_width)) - << std::left - << counter - << std::right - << " "; + std::string line = microfmt::format("#{<{}} ", frame_number_width, counter); if(frame.is_inline) { - stream - << std::setw(2 * sizeof(frame_ptr) + 2) - << "(inlined)"; + line += microfmt::format("{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)"); } else { - stream - << std::hex - << blue - << "0x" - << std::setw(2 * sizeof(frame_ptr)) - << std::setfill('0') - << frame.raw_address - << std::dec - << std::setfill(' ') - << reset; + line += microfmt::format("{}0x{<{}:0h}{}", blue, 2 * sizeof(frame_ptr), frame.raw_address, reset); } if(!frame.symbol.empty()) { - stream - << " in " - << yellow - << frame.symbol - << reset; + line += microfmt::format(" in {}{}{}", yellow, frame.symbol, reset); } if(!frame.filename.empty()) { - stream - << " at " - << green - << frame.filename - << reset; + line += microfmt::format(" at {}{}{}", green, frame.filename, reset); if(frame.line.has_value()) { - stream - << ":" - << blue - << frame.line.value() - << reset; + line += microfmt::format(":{}{}{}", blue, frame.line.value(), reset); if(frame.column.has_value()) { - stream << ':' - << blue - << std::to_string(frame.column.value()) - << reset; + line += microfmt::format(":{}{}{}", blue, frame.column.value(), reset); } } } + stream << line; } void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const { @@ -233,10 +191,10 @@ namespace cpptrace { ) { detail::enable_virtual_terminal_processing_if_needed(); } - stream<<(header ? header : "Stack trace (most recent call first):") << '\n'; + stream << (header ? header : "Stack trace (most recent call first):") << '\n'; std::size_t counter = 0; if(frames.empty()) { - stream<<"" << '\n'; + stream << "\n"; return; } const auto frame_number_width = detail::n_digits(static_cast(frames.size()) - 1); @@ -269,10 +227,10 @@ namespace cpptrace { ) { detail::enable_virtual_terminal_processing_if_needed(); } - stream<<(header ? header : "Stack trace (most recent call first):") << '\n'; + stream << (header ? header : "Stack trace (most recent call first):") << '\n'; std::size_t counter = 0; if(frames.empty()) { - stream<<"" << '\n'; + stream << "" << '\n'; return; } const auto frame_number_width = detail::n_digits(static_cast(frames.size()) - 1); @@ -433,29 +391,28 @@ namespace cpptrace { try { auto ptr = std::current_exception(); if(ptr == nullptr) { - std::cerr << "terminate called without an active exception\n"; + fputs("terminate called without an active exception", stderr); print_terminate_trace(); } else { std::rethrow_exception(ptr); } } catch(cpptrace::exception& e) { - std::cerr << "Terminate called after throwing an instance of " - << demangle(typeid(e).name()) - << ": " - << e.message() - << '\n'; + microfmt::print( + stderr, + "Terminate called after throwing an instance of {}: {}\n", + demangle(typeid(e).name()), + e.message() + ); e.trace().print(std::cerr, isatty(stderr_fileno)); } catch(std::exception& e) { - std::cerr << "Terminate called after throwing an instance of " - << demangle(typeid(e).name()) - << ": " - << e.what() - << '\n'; + microfmt::print( + stderr, "Terminate called after throwing an instance of {}: {}\n", demangle(typeid(e).name()), e.what() + ); print_terminate_trace(); } catch(...) { - std::cerr << "Terminate called after throwing an instance of " - << detail::exception_type_name() - << "\n"; + microfmt::print( + stderr, "Terminate called after throwing an instance of {}\n", detail::exception_type_name() + ); print_terminate_trace(); } std::flush(std::cerr); diff --git a/src/snippets/snippet.cpp b/src/snippets/snippet.cpp index 660d375..83b61d7 100644 --- a/src/snippets/snippet.cpp +++ b/src/snippets/snippet.cpp @@ -130,7 +130,7 @@ namespace detail { snippet += YELLOW; } auto line_str = std::to_string(line); - snippet += std::string(margin_width - std::min(line_str.size(), margin_width), ' ') + line_str + ": "; + snippet += microfmt::format("{>{}}: ", margin_width, line_str); if(color && line == target_line) { snippet += RESET; } diff --git a/src/symbols/symbols_with_addr2line.cpp b/src/symbols/symbols_with_addr2line.cpp index 842ddd6..5bcbb7a 100644 --- a/src/symbols/symbols_with_addr2line.cpp +++ b/src/symbols/symbols_with_addr2line.cpp @@ -289,12 +289,15 @@ namespace addr2line { } std::string address_input; for(const auto& pair : entries_vec) { - address_input += to_hex(pair.first.get().object_address); + address_input += microfmt::format( + "{:h}{}", + pair.first.get().object_address, #if !IS_WINDOWS - address_input += '\n'; + '\n' #else - address_input += ' '; + ' ' #endif + ); } auto output = split(trim(resolve_addresses(address_input, object_name)), "\n"); VERIFY(output.size() == entries_vec.size()); diff --git a/src/symbols/symbols_with_libdwarf.cpp b/src/symbols/symbols_with_libdwarf.cpp index 929eebf..23cbcdf 100644 --- a/src/symbols/symbols_with_libdwarf.cpp +++ b/src/symbols/symbols_with_libdwarf.cpp @@ -429,6 +429,9 @@ namespace libdwarf { ASSERT(tag && (tag.unwrap_value() == DW_TAG_subprogram || tag.unwrap_value() == DW_TAG_inlined_subroutine)); // get_inlines_info is recursive and recurses into dies with pc ranges matching the pc we're looking for, // however, because I wouldn't want anything stack overflowing I'm breaking the recursion out into a loop + // while looping when we find the target die we need to be able to store a die somewhere that doesn't die + // at the end of the list traversal, we'll use this as a holder for it + die_object current_obj_holder(dbg, nullptr); optional> current_die = die; while(current_die.has_value()) { auto child = current_die.unwrap().get().get_child(); @@ -438,7 +441,7 @@ namespace libdwarf { optional> target_die; walk_die_list( child.unwrap_value(), - [this, &cu_die, pc, dwversion, &inlines, &target_die] (const die_object& die) { + [this, &cu_die, pc, dwversion, &inlines, &target_die, ¤t_obj_holder] (const die_object& die) { auto tag = die.get_tag(); if(!tag) { tag.drop_error(); @@ -490,7 +493,8 @@ namespace libdwarf { name.value_or(""), true }); - target_die = die; + current_obj_holder = die.clone(); + target_die = current_obj_holder; return false; } else { return true; diff --git a/src/utils/error.hpp b/src/utils/error.hpp index 0dc6e3f..26a0d8d 100644 --- a/src/utils/error.hpp +++ b/src/utils/error.hpp @@ -62,14 +62,14 @@ namespace detail { if(message == "") { throw internal_error( "Cpptrace {} failed at {}:{}: {}\n" - " %s(%s);\n", + " {}({});\n", action, location.file, location.line, signature, name, expression ); } else { throw internal_error( "Cpptrace {} failed at {}:{}: {}: {}\n" - " %s(%s);\n", + " {}({});\n", action, location.file, location.line, signature, message.c_str(), name, expression ); diff --git a/src/utils/microfmt.hpp b/src/utils/microfmt.hpp index 3642071..30c939c 100644 --- a/src/utils/microfmt.hpp +++ b/src/utils/microfmt.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -320,6 +321,12 @@ namespace microfmt { void print(std::ostream& ostream, const S& fmt, Args&&... args) { ostream< + void print(std::FILE* stream, const S& fmt, Args&&... args) { + auto str = format(fmt, args...); + fwrite(str.data(), 1, str.size(), stream); + } } #endif diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index ce6a0b3..3c82b75 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -107,12 +107,6 @@ namespace detail { return str.substr(left, right - left); } - inline std::string to_hex(std::uintptr_t addr) { - std::stringstream sstream; - sstream<