I have a program that throws an uncaught exception somewhere. All I get is a report of an exception being thrown, and no information as to where it was thrown. It seems illo
You can mark main tight places in your code as noexcept to locate an exception, then use libunwind (just add -lunwind to linker parameters) (tested with clang++ 3.6):
demagle.hpp:
#pragma once
char const *
get_demangled_name(char const * const symbol) noexcept;
demangle.cpp:
#include "demangle.hpp"
#include
#include
#include
namespace
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#pragma clang diagnostic ignored "-Wexit-time-destructors"
std::unique_ptr< char, decltype(std::free) & > demangled_name{nullptr, std::free};
#pragma clang diagnostic pop
}
char const *
get_demangled_name(char const * const symbol) noexcept
{
if (!symbol) {
return "";
}
int status = -4;
demangled_name.reset(abi::__cxa_demangle(symbol, demangled_name.release(), nullptr, &status));
return ((status == 0) ? demangled_name.get() : symbol);
}
backtrace.hpp:
#pragma once
#include
void
backtrace(std::ostream & _out) noexcept;
backtrace.cpp:
#include "backtrace.hpp"
#include
#include
#include
#include
#include
#define UNW_LOCAL_ONLY
#include
namespace
{
void
print_reg(std::ostream & _out, unw_word_t reg) noexcept
{
constexpr std::size_t address_width = std::numeric_limits< std::uintptr_t >::digits / 4;
_out << "0x" << std::setfill('0') << std::setw(address_width) << reg;
}
char symbol[1024];
}
void
backtrace(std::ostream & _out) noexcept
{
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
_out << std::hex << std::uppercase;
while (0 < unw_step(&cursor)) {
unw_word_t ip = 0;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (ip == 0) {
break;
}
unw_word_t sp = 0;
unw_get_reg(&cursor, UNW_REG_SP, &sp);
print_reg(_out, ip);
_out << ": (SP:";
print_reg(_out, sp);
_out << ") ";
unw_word_t offset = 0;
if (unw_get_proc_name(&cursor, symbol, sizeof(symbol), &offset) == 0) {
_out << "(" << get_demangled_name(symbol) << " + 0x" << offset << ")\n\n";
} else {
_out << "-- error: unable to obtain symbol name for this frame\n\n";
}
}
_out << std::flush;
}
backtrace_on_terminate.hpp:
#include "demangle.hpp"
#include "backtrace.hpp"
#include
#include
#include
#include
#include
#include
#include
namespace
{
[[noreturn]]
void
backtrace_on_terminate() noexcept;
static_assert(std::is_same< std::terminate_handler, decltype(&backtrace_on_terminate) >{});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#pragma clang diagnostic ignored "-Wexit-time-destructors"
std::unique_ptr< std::remove_pointer_t< std::terminate_handler >, decltype(std::set_terminate) & > terminate_handler{std::set_terminate(backtrace_on_terminate), std::set_terminate};
#pragma clang diagnostic pop
[[noreturn]]
void
backtrace_on_terminate() noexcept
{
std::set_terminate(terminate_handler.release()); // to avoid infinite looping if any
backtrace(std::clog);
if (std::exception_ptr ep = std::current_exception()) {
try {
std::rethrow_exception(ep);
} catch (std::exception const & e) {
std::clog << "backtrace: unhandled exception std::exception:what(): " << e.what() << std::endl;
} catch (...) {
if (std::type_info * et = abi::__cxa_current_exception_type()) {
std::clog << "backtrace: unhandled exception type: " << get_demangled_name(et->name()) << std::endl;
} else {
std::clog << "backtrace: unhandled unknown exception" << std::endl;
}
}
}
std::_Exit(EXIT_FAILURE); // change to desired return code
}
}
There is good article concerning the issue.