How do I find where an exception was thrown in C++?

后端 未结 7 1321
[愿得一人]
[愿得一人] 2020-11-28 18:55

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

7条回答
  •  甜味超标
    2020-11-28 19:37

    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.

提交回复
热议问题