mirror of
https://github.com/mhx/dwarfs.git
synced 2025-08-03 17:56:12 -04:00
refactor: make proper use of cpptrace
with ENABLE_STACKTRACE
This commit is contained in:
parent
6b7d07a5a8
commit
1fec8314da
@ -33,47 +33,58 @@
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
#include <dwarfs/config.h>
|
||||
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#endif
|
||||
|
||||
#include <dwarfs/source_location.h>
|
||||
|
||||
namespace dwarfs {
|
||||
|
||||
class error : public std::exception {
|
||||
public:
|
||||
char const* what() const noexcept override { return what_.c_str(); }
|
||||
|
||||
auto location() const { return loc_; }
|
||||
auto file() const { return loc_.file_name(); }
|
||||
auto line() const { return loc_.line(); }
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
cpptrace::stacktrace stacktrace() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
error(std::string_view s, source_location loc) noexcept;
|
||||
error(source_location loc) noexcept;
|
||||
|
||||
private:
|
||||
std::string what_;
|
||||
source_location loc_;
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
cpptrace::raw_trace trace_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class runtime_error : public error {
|
||||
public:
|
||||
runtime_error(std::string_view s, source_location loc) noexcept
|
||||
: error(s, loc) {}
|
||||
};
|
||||
runtime_error(std::string_view s, source_location loc);
|
||||
|
||||
class system_error : public std::system_error {
|
||||
public:
|
||||
system_error(source_location loc) noexcept;
|
||||
system_error(std::string_view s, source_location loc) noexcept;
|
||||
system_error(std::string_view s, int err, source_location loc) noexcept;
|
||||
system_error(int err, source_location loc) noexcept;
|
||||
|
||||
auto get_errno() const { return code().value(); }
|
||||
|
||||
auto location() const { return loc_; }
|
||||
auto file() const { return loc_.file_name(); }
|
||||
auto line() const { return loc_.line(); }
|
||||
char const* what() const noexcept override { return what_.c_str(); }
|
||||
|
||||
private:
|
||||
source_location loc_;
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
class system_error : public error {
|
||||
public:
|
||||
system_error(source_location loc);
|
||||
system_error(std::string_view s, source_location loc);
|
||||
system_error(std::string_view s, int err, source_location loc);
|
||||
system_error(int err, source_location loc);
|
||||
|
||||
char const* what() const noexcept override { return syserr_.what(); }
|
||||
std::error_code const& code() const noexcept { return syserr_.code(); }
|
||||
int get_errno() const { return code().value(); }
|
||||
|
||||
private:
|
||||
std::system_error syserr_;
|
||||
};
|
||||
|
||||
#define DWARFS_THROW(cls, ...) \
|
||||
@ -101,8 +112,6 @@ class system_error : public std::system_error {
|
||||
} \
|
||||
}()
|
||||
|
||||
void dump_exceptions();
|
||||
|
||||
[[noreturn]] void handle_nothrow(std::string_view expr, source_location loc);
|
||||
|
||||
[[noreturn]] void assertion_failed(std::string_view expr, std::string_view msg,
|
||||
|
@ -35,8 +35,11 @@
|
||||
|
||||
#include <dwarfs/config.h>
|
||||
|
||||
#ifdef DWARFS_USE_EXCEPTION_TRACER
|
||||
#include <folly/experimental/exception_tracer/ExceptionTracer.h>
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
#if __has_include(<cpptrace/formatting.hpp>)
|
||||
#include <cpptrace/formatting.hpp>
|
||||
#define DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <dwarfs/error.h>
|
||||
@ -55,40 +58,60 @@ namespace {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
error::error(std::string_view s, source_location loc) noexcept
|
||||
: what_{fmt::format("{} [{}:{}]", s, basename(loc.file_name()), loc.line())}
|
||||
, loc_{loc} {}
|
||||
|
||||
system_error::system_error(source_location loc) noexcept
|
||||
: system_error(errno, loc) {}
|
||||
|
||||
system_error::system_error(std::string_view s, source_location loc) noexcept
|
||||
: system_error(s, errno, loc) {}
|
||||
|
||||
system_error::system_error(std::string_view s, int err,
|
||||
source_location loc) noexcept
|
||||
: std::system_error(err, std::generic_category(), std::string(s))
|
||||
, loc_{loc} {}
|
||||
|
||||
system_error::system_error(int err, source_location loc) noexcept
|
||||
: std::system_error(err, std::generic_category())
|
||||
, loc_{loc} {}
|
||||
|
||||
void dump_exceptions() {
|
||||
#ifdef DWARFS_USE_EXCEPTION_TRACER
|
||||
auto exceptions = ::folly::exception_tracer::getCurrentExceptions();
|
||||
for (auto& exc : exceptions) {
|
||||
std::cerr << exc << "\n";
|
||||
}
|
||||
void print_stacktrace(std::ostream& os [[maybe_unused]]) {
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
auto trace = cpptrace::generate_trace();
|
||||
#ifdef DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
auto formatter = cpptrace::formatter{}.addresses(
|
||||
cpptrace::formatter::address_mode::object);
|
||||
formatter.print(os, trace, true);
|
||||
#else
|
||||
trace.print(os, true);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
error::error(source_location loc) noexcept
|
||||
: loc_{loc}
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
, trace_{cpptrace::generate_raw_trace()}
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
cpptrace::stacktrace error::stacktrace() const { return trace_.resolve(); }
|
||||
#endif
|
||||
|
||||
runtime_error::runtime_error(std::string_view s, source_location loc)
|
||||
: error{loc}
|
||||
, what_{fmt::format("[{}:{}] {}", basename(loc.file_name()), loc.line(),
|
||||
s)} {}
|
||||
|
||||
system_error::system_error(source_location loc)
|
||||
: system_error(errno, loc) {}
|
||||
|
||||
system_error::system_error(std::string_view s, source_location loc)
|
||||
: system_error(s, errno, loc) {}
|
||||
|
||||
system_error::system_error(std::string_view s, int err, source_location loc)
|
||||
: error{loc}
|
||||
, syserr_{err, std::generic_category(),
|
||||
fmt::format("[{}:{}] {}", basename(loc.file_name()), loc.line(),
|
||||
s)} {}
|
||||
|
||||
system_error::system_error(int err, source_location loc)
|
||||
: error{loc}
|
||||
, syserr_{err, std::generic_category(),
|
||||
fmt::format("[{}:{}]", basename(loc.file_name()), loc.line())} {}
|
||||
|
||||
void handle_nothrow(std::string_view expr, source_location loc) {
|
||||
std::cerr << "Expression `" << expr << "` threw `"
|
||||
<< exception_str(std::current_exception()) << "` in "
|
||||
<< loc.file_name() << "(" << loc.line() << ")\n";
|
||||
print_stacktrace(std::cerr);
|
||||
do_terminate();
|
||||
}
|
||||
|
||||
@ -96,12 +119,14 @@ void assertion_failed(std::string_view expr, std::string_view msg,
|
||||
source_location loc) {
|
||||
std::cerr << "Assertion `" << expr << "` failed in " << loc.file_name() << "("
|
||||
<< loc.line() << "): " << msg << "\n";
|
||||
print_stacktrace(std::cerr);
|
||||
do_terminate();
|
||||
}
|
||||
|
||||
void handle_panic(std::string_view msg, source_location loc) {
|
||||
std::cerr << "Panic: " << msg << " in " << loc.file_name() << "("
|
||||
<< loc.line() << ")\n";
|
||||
print_stacktrace(std::cerr);
|
||||
do_terminate();
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,10 @@
|
||||
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#if __has_include(<cpptrace/formatting.hpp>)
|
||||
#include <cpptrace/formatting.hpp>
|
||||
#define DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
@ -214,11 +218,19 @@ void stream_logger::write(level_type level, std::string_view output,
|
||||
}
|
||||
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
std::string stacktrace;
|
||||
std::vector<std::string_view> st_lines;
|
||||
std::string stacktrace;
|
||||
|
||||
if (enable_stack_trace_ || level == FATAL) {
|
||||
#ifdef DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
auto formatter = cpptrace::formatter{}
|
||||
.header({})
|
||||
.addresses(cpptrace::formatter::address_mode::object)
|
||||
.paths(cpptrace::formatter::path_mode::basename);
|
||||
stacktrace = formatter.format(cpptrace::generate_trace(), true);
|
||||
#else
|
||||
stacktrace = cpptrace::generate_trace().to_string(true);
|
||||
#endif
|
||||
split_to(stacktrace, '\n', st_lines);
|
||||
if (st_lines.back().empty()) {
|
||||
st_lines.pop_back();
|
||||
|
@ -64,7 +64,7 @@ TEST(error_test, runtime_error) {
|
||||
} catch (runtime_error const& e) {
|
||||
EXPECT_EQ("error_test.cpp",
|
||||
std::filesystem::path(e.file()).filename().string());
|
||||
EXPECT_EQ(fmt::format("my test error [error_test.cpp:{}]", e.line()),
|
||||
EXPECT_EQ(fmt::format("[error_test.cpp:{}] my test error", e.line()),
|
||||
std::string(e.what()));
|
||||
EXPECT_EQ(expected_line, e.line());
|
||||
} catch (...) {
|
||||
@ -81,7 +81,8 @@ TEST(error_test, system_error) {
|
||||
FAIL() << "expected system_error to be thrown";
|
||||
} catch (system_error const& e) {
|
||||
EXPECT_THAT(std::string(e.what()),
|
||||
::testing::MatchesRegex("my test system error: .*"));
|
||||
::testing::MatchesRegex(
|
||||
"\\[error_test\\.cpp:.*\\] my test system error: .*"));
|
||||
EXPECT_EQ("error_test.cpp",
|
||||
std::filesystem::path(e.file()).filename().string());
|
||||
EXPECT_EQ(EPERM, e.get_errno());
|
||||
|
@ -43,7 +43,7 @@ class global_metadata_test : public ::testing::Test {
|
||||
}
|
||||
|
||||
static auto throws_error(std::string_view msg) {
|
||||
return testing::ThrowsMessage<dwarfs::error>(testing::StartsWith(msg));
|
||||
return testing::ThrowsMessage<dwarfs::error>(testing::HasSubstr(msg));
|
||||
};
|
||||
|
||||
test_logger lgr;
|
||||
|
@ -1408,7 +1408,7 @@ int mkdwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
|
||||
|
||||
options.inode.categorizer_mgr.reset();
|
||||
}
|
||||
} catch (std::exception const& e) {
|
||||
} catch (dwarfs::error const& e) {
|
||||
LOG_ERROR << exception_str(e);
|
||||
return 1;
|
||||
}
|
||||
|
@ -30,6 +30,21 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <dwarfs/config.h>
|
||||
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
#include <cpptrace/from_current.hpp>
|
||||
#if __has_include(<cpptrace/formatting.hpp>)
|
||||
#include <cpptrace/formatting.hpp>
|
||||
#define DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
#endif
|
||||
#define DWARFS_TRY CPPTRACE_TRYZ
|
||||
#define DWARFS_CATCH CPPTRACE_CATCHZ
|
||||
#else
|
||||
#define DWARFS_TRY try
|
||||
#define DWARFS_CATCH catch
|
||||
#endif
|
||||
|
||||
#include <dwarfs/error.h>
|
||||
#include <dwarfs/tool/safe_main.h>
|
||||
#include <dwarfs/util.h>
|
||||
@ -37,7 +52,7 @@
|
||||
namespace dwarfs::tool {
|
||||
|
||||
int safe_main(std::function<int(void)> const& fn) {
|
||||
try {
|
||||
DWARFS_TRY {
|
||||
install_signal_handlers();
|
||||
setup_default_locale();
|
||||
#ifdef _WIN32
|
||||
@ -45,9 +60,19 @@ int safe_main(std::function<int(void)> const& fn) {
|
||||
#endif
|
||||
|
||||
return fn();
|
||||
} catch (...) {
|
||||
}
|
||||
DWARFS_CATCH(...) {
|
||||
std::cerr << "ERROR: " << exception_str(std::current_exception()) << "\n";
|
||||
dump_exceptions();
|
||||
#ifdef DWARFS_STACKTRACE_ENABLED
|
||||
auto stacktrace = cpptrace::from_current_exception();
|
||||
#ifdef DWARFS_CPPTRACE_HAS_FORMATTING
|
||||
auto formatter = cpptrace::formatter{}.addresses(
|
||||
cpptrace::formatter::address_mode::object);
|
||||
formatter.print(std::cerr, stacktrace, true);
|
||||
#else
|
||||
stacktrace.print(std::cerr, true);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user