summaryrefslogtreecommitdiff
path: root/src/cxa_default_handlers.cpp
blob: f2e36b4bc8312dfea57538732590d195fb5aa39a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//===------------------------- cxa_default_handlers.cpp -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
// This file implements the default terminate_handler and unexpected_handler.
//===----------------------------------------------------------------------===//

#include <stdexcept>
#include <new>
#include <exception>
#include <cstdlib>
#include "abort_message.h"
#include "cxxabi.h"
#include "cxa_handlers.hpp"
#include "cxa_exception.hpp"
#include "private_typeinfo.h"

static const char* cause = "uncaught";

__attribute__((noreturn))
static void demangling_terminate_handler()
{
    // If there might be an uncaught exception
    using namespace __cxxabiv1;
    __cxa_eh_globals* globals = __cxa_get_globals_fast();
    if (globals)
    {
        __cxa_exception* exception_header = globals->caughtExceptions;
        // If there is an uncaught exception
        if (exception_header)
        {
            _Unwind_Exception* unwind_exception =
                reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
            bool native_exception =
                (unwind_exception->exception_class   & get_vendor_and_language) == 
                                 (kOurExceptionClass & get_vendor_and_language);
            if (native_exception)
            {
                void* thrown_object =
                    unwind_exception->exception_class == kOurDependentExceptionClass ?
                        ((__cxa_dependent_exception*)exception_header)->primaryException :
                        exception_header + 1;
                const __shim_type_info* thrown_type =
                    static_cast<const __shim_type_info*>(exception_header->exceptionType);
                // Try to get demangled name of thrown_type
                int status;
                char buf[1024];
                size_t len = sizeof(buf);
                const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
                if (status != 0)
                    name = thrown_type->name();
                // If the uncaught exception can be caught with std::exception&
                const __shim_type_info* catch_type =
				 static_cast<const __shim_type_info*>(&typeid(std::exception));
                if (catch_type->can_catch(thrown_type, thrown_object))
                {
                    // Include the what() message from the exception
                    const std::exception* e = static_cast<const std::exception*>(thrown_object);
                    abort_message("terminating with %s exception of type %s: %s",
                                  cause, name, e->what());
                }
                else
                    // Else just note that we're terminating with an exception
                    abort_message("terminating with %s exception of type %s",
                                   cause, name);
            }
            else
                // Else we're terminating with a foreign exception
                abort_message("terminating with %s foreign exception", cause);
        }
    }
    // Else just note that we're terminating
    abort_message("terminating");
}

__attribute__((noreturn))
static void demangling_unexpected_handler()
{
    cause = "unexpected";
    std::terminate();
}

#if !defined(LIBCXXABI_SILENT_TERMINATE)
static std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
#else
static std::terminate_handler default_terminate_handler = std::abort;
static std::terminate_handler default_unexpected_handler = std::terminate;
#endif

//
// Global variables that hold the pointers to the current handler
//
_LIBCXXABI_DATA_VIS
std::terminate_handler __cxa_terminate_handler = default_terminate_handler;

_LIBCXXABI_DATA_VIS
std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;

// In the future these will become:
// std::atomic<std::terminate_handler>  __cxa_terminate_handler(default_terminate_handler);
// std::atomic<std::unexpected_handler> __cxa_unexpected_handler(default_unexpected_handler);

namespace std
{

unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
    if (func == 0)
        func = default_unexpected_handler;
    return __atomic_exchange_n(&__cxa_unexpected_handler, func,
                               __ATOMIC_ACQ_REL);
//  Using of C++11 atomics this should be rewritten
//  return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel);
}

terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
    if (func == 0)
        func = default_terminate_handler;
    return __atomic_exchange_n(&__cxa_terminate_handler, func,
                               __ATOMIC_ACQ_REL);
//  Using of C++11 atomics this should be rewritten
//  return __cxa_terminate_handler.exchange(func, memory_order_acq_rel);
}

}