Merge branch 'dev' into jr/more-thorough-error-handling
This commit is contained in:
commit
d8b9f45a24
129
src/cpptrace.cpp
129
src/cpptrace.cpp
@ -4,8 +4,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
@ -105,39 +104,29 @@ namespace cpptrace {
|
||||
}
|
||||
|
||||
std::string stacktrace_frame::to_string() const {
|
||||
std::ostringstream oss;
|
||||
oss << *this;
|
||||
return std::move(oss).str();
|
||||
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(!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 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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
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<int>(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 {
|
||||
@ -236,7 +194,7 @@ namespace cpptrace {
|
||||
stream << (header ? header : "Stack trace (most recent call first):") << '\n';
|
||||
std::size_t counter = 0;
|
||||
if(frames.empty()) {
|
||||
stream<<"<empty trace>" << '\n';
|
||||
stream << "<empty trace>\n";
|
||||
return;
|
||||
}
|
||||
const auto frame_number_width = detail::n_digits(static_cast<int>(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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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<std::reference_wrapper<const die_object>> current_die = die;
|
||||
while(current_die.has_value()) {
|
||||
auto child = current_die.unwrap().get().get_child();
|
||||
@ -438,7 +441,7 @@ namespace libdwarf {
|
||||
optional<std::reference_wrapper<const die_object>> 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;
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@ -320,6 +321,12 @@ namespace microfmt {
|
||||
void print(std::ostream& ostream, const S& fmt, Args&&... args) {
|
||||
ostream<<format(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void print(std::FILE* stream, const S& fmt, Args&&... args) {
|
||||
auto str = format(fmt, args...);
|
||||
fwrite(str.data(), 1, str.size(), stream);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -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<<std::hex<<addr;
|
||||
return std::move(sstream).str();
|
||||
}
|
||||
|
||||
inline bool is_little_endian() {
|
||||
std::uint16_t num = 0x1;
|
||||
const auto* ptr = (std::uint8_t*)#
|
||||
|
||||
Loading…
Reference in New Issue
Block a user