Add specialized terminate handler and add error handling info to the README. Also updated demo.
This commit is contained in:
parent
2e0fa880bc
commit
05c3f7160b
@ -106,6 +106,10 @@ else()
|
|||||||
check_support(HAS_STACKWALK has_stackwalk.cpp "" "dbghelp" "")
|
check_support(HAS_STACKWALK has_stackwalk.cpp "" "dbghelp" "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT WIN32 OR MINGW)
|
||||||
|
check_support(HAS_CXX_EXCEPTION_TYPE has_cxx_exception_type.cpp "" "" "")
|
||||||
|
endif()
|
||||||
|
|
||||||
# =============================================== Autoconfig unwinding ===============================================
|
# =============================================== Autoconfig unwinding ===============================================
|
||||||
# Unwind back-ends
|
# Unwind back-ends
|
||||||
if(
|
if(
|
||||||
@ -248,6 +252,10 @@ target_compile_options(
|
|||||||
|
|
||||||
# =============================================== Apply options to build ===============================================
|
# =============================================== Apply options to build ===============================================
|
||||||
|
|
||||||
|
if(HAS_CXX_EXCEPTION_TYPE)
|
||||||
|
target_compile_definitions(cpptrace PUBLIC CPPTRACE_HAS_CXX_EXCEPTION_TYPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
function(check_backtrace_error)
|
function(check_backtrace_error)
|
||||||
if(NOT HAS_BACKTRACE)
|
if(NOT HAS_BACKTRACE)
|
||||||
if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
|
if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
|
||||||
|
|||||||
29
README.md
29
README.md
@ -20,6 +20,7 @@ and Windows including MinGW and Cygwin environments. The goal: Make stack traces
|
|||||||
- [Raw Traces](#raw-traces)
|
- [Raw Traces](#raw-traces)
|
||||||
- [Utilities](#utilities)
|
- [Utilities](#utilities)
|
||||||
- [Traced Exceptions](#traced-exceptions)
|
- [Traced Exceptions](#traced-exceptions)
|
||||||
|
- [Exception handling with cpptrace](#exception-handling-with-cpptrace)
|
||||||
- [Notable Library Configurations](#notable-library-configurations)
|
- [Notable Library Configurations](#notable-library-configurations)
|
||||||
- [Notes About the Library and Future Work](#notes-about-the-library-and-future-work)
|
- [Notes About the Library and Future Work](#notes-about-the-library-and-future-work)
|
||||||
- [FAQ: What about C++23 `<stacktrace>`?](#faq-what-about-c23-stacktrace)
|
- [FAQ: What about C++23 `<stacktrace>`?](#faq-what-about-c23-stacktrace)
|
||||||
@ -226,6 +227,9 @@ performed.
|
|||||||
|
|
||||||
`cpptrace::isatty` and the fileno definitions are useful for deciding whether to use color when printing stack taces.
|
`cpptrace::isatty` and the fileno definitions are useful for deciding whether to use color when printing stack taces.
|
||||||
|
|
||||||
|
`cpptrace::register_terminate_handler()` is a helper function to set a custom `std::terminate` handler that prints a
|
||||||
|
stack trace from a cpptrace exception (more info below) and otherwise behaves like the normal terminate handler.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
std::string demangle(const std::string& name);
|
std::string demangle(const std::string& name);
|
||||||
@ -236,6 +240,8 @@ namespace cpptrace {
|
|||||||
extern const int stderr_fileno;
|
extern const int stderr_fileno;
|
||||||
extern const int stdout_fileno;
|
extern const int stdout_fileno;
|
||||||
|
|
||||||
|
void register_terminate_handler();
|
||||||
|
|
||||||
enum class cache_mode {
|
enum class cache_mode {
|
||||||
// Only minimal lookup tables
|
// Only minimal lookup tables
|
||||||
prioritize_memory,
|
prioritize_memory,
|
||||||
@ -300,6 +306,29 @@ namespace cpptrace {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Exception handling with cpptrace
|
||||||
|
|
||||||
|
To register a custom handler for `std::terminate` that prints a stack trace from a cpptrace exception and otherwise
|
||||||
|
behaves like the normal terminate handler.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
cpptrace::register_terminate_handler();
|
||||||
|
```
|
||||||
|
|
||||||
|
Working with cpptrace exceptions in your code:
|
||||||
|
```cpp
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(cpptrace::exception& e) {
|
||||||
|
// Prints the exception info and stack trace, conditionally enabling color codes depending on
|
||||||
|
// whether stderr is a terminal
|
||||||
|
std::cerr << "Error: " << e.get_raw_what() << '\n';
|
||||||
|
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Notable Library Configurations
|
## Notable Library Configurations
|
||||||
|
|
||||||
- `CPPTRACE_STATIC=On/Off`: Create cpptrace as a static library.
|
- `CPPTRACE_STATIC=On/Off`: Create cpptrace as a static library.
|
||||||
|
|||||||
6
cmake/has_cxx_exception_type.cpp
Normal file
6
cmake/has_cxx_exception_type.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <cxxabi.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::type_info* t = abi::__cxa_current_exception_type();
|
||||||
|
(void*) t;
|
||||||
|
}
|
||||||
@ -133,6 +133,8 @@ namespace cpptrace {
|
|||||||
CPPTRACE_API extern const int stderr_fileno;
|
CPPTRACE_API extern const int stderr_fileno;
|
||||||
CPPTRACE_API extern const int stdout_fileno;
|
CPPTRACE_API extern const int stdout_fileno;
|
||||||
|
|
||||||
|
CPPTRACE_API void register_terminate_handler();
|
||||||
|
|
||||||
enum class cache_mode {
|
enum class cache_mode {
|
||||||
// Only minimal lookup tables
|
// Only minimal lookup tables
|
||||||
prioritize_memory,
|
prioritize_memory,
|
||||||
|
|||||||
@ -14,8 +14,9 @@
|
|||||||
#include "unwind/unwind.hpp"
|
#include "unwind/unwind.hpp"
|
||||||
#include "demangle/demangle.hpp"
|
#include "demangle/demangle.hpp"
|
||||||
#include "platform/common.hpp"
|
#include "platform/common.hpp"
|
||||||
#include "platform/utils.hpp"
|
#include "platform/exception_type.hpp"
|
||||||
#include "platform/object.hpp"
|
#include "platform/object.hpp"
|
||||||
|
#include "platform/utils.hpp"
|
||||||
|
|
||||||
#define ESC "\033["
|
#define ESC "\033["
|
||||||
#define RESET ESC "0m"
|
#define RESET ESC "0m"
|
||||||
@ -328,6 +329,34 @@ namespace cpptrace {
|
|||||||
CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout);
|
CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout);
|
||||||
CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr);
|
CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr);
|
||||||
|
|
||||||
|
CPPTRACE_API [[noreturn]] void terminate_handler() {
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(std::current_exception());
|
||||||
|
} catch(cpptrace::exception& e) {
|
||||||
|
std::cerr << "Terminate called after throwing an instance of "
|
||||||
|
<< cpptrace::demangle(typeid(e).name())
|
||||||
|
<< ": "
|
||||||
|
<< e.get_raw_what()
|
||||||
|
<< '\n';
|
||||||
|
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
std::cerr << "Terminate called after throwing an instance of "
|
||||||
|
<< cpptrace::demangle(typeid(e).name())
|
||||||
|
<< ": "
|
||||||
|
<< e.what()
|
||||||
|
<< '\n';
|
||||||
|
} catch(...) {
|
||||||
|
std::cerr << "Terminate called after throwing an instance of "
|
||||||
|
<< detail::exception_type_name()
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
CPPTRACE_API void register_terminate_handler() {
|
||||||
|
std::set_terminate(terminate_handler);
|
||||||
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::atomic_bool absorb_trace_exceptions(true); // NOSONAR
|
std::atomic_bool absorb_trace_exceptions(true); // NOSONAR
|
||||||
std::atomic<enum cache_mode> cache_mode(cache_mode::prioritize_speed); // NOSONAR
|
std::atomic<enum cache_mode> cache_mode(cache_mode::prioritize_speed); // NOSONAR
|
||||||
|
|||||||
26
src/platform/exception_type.hpp
Normal file
26
src/platform/exception_type.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef EXCEPTION_TYPE_HPP
|
||||||
|
#define EXCEPTION_TYPE_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// libstdc++ and libc++
|
||||||
|
#if CPPTRACE_HAS_CXX_EXCEPTION_TYPE && defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_LIBCPP_VERSION)
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../demangle/demangle.hpp"
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
inline std::string exception_type_name() {
|
||||||
|
#if CPPTRACE_HAS_CXX_EXCEPTION_TYPE && defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_LIBCPP_VERSION)
|
||||||
|
std::type_info* t = abi::__cxa_current_exception_type();
|
||||||
|
return t ? detail::demangle(t->name()) : "<unknown>";
|
||||||
|
#else
|
||||||
|
return "<unknown>";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
void trace() {
|
void trace() {
|
||||||
cpptrace::generate_trace().print();
|
cpptrace::generate_trace().print();
|
||||||
throw cpptrace::exception_with_message("foobar");
|
throw cpptrace::logic_error("foobar");
|
||||||
}
|
}
|
||||||
|
|
||||||
void foo(int n) {
|
void foo(int n) {
|
||||||
@ -31,12 +31,8 @@ void function_one(int) {
|
|||||||
function_two(0, 0);
|
function_two(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() try {
|
int main() {
|
||||||
cpptrace::absorb_trace_exceptions(false);
|
cpptrace::absorb_trace_exceptions(false);
|
||||||
|
cpptrace::register_terminate_handler();
|
||||||
function_one(0);
|
function_one(0);
|
||||||
} catch(cpptrace::exception& e) {
|
|
||||||
std::cerr << "Error: "
|
|
||||||
<< e.get_raw_what()
|
|
||||||
<< '\n';
|
|
||||||
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user