#ifdef __EMSCRIPTEN__ #include "cxxabi.h" #include "cxa_exception.h" #include "private_typeinfo.h" #include #include // #include // #include #include namespace __cxxabiv1 { // Utility routines static inline __cxa_exception* cxa_exception_from_thrown_object(void* thrown_object) { return static_cast<__cxa_exception*>(thrown_object) - 1; } // Note: This is never called when exception_header is masquerading as a // __cxa_dependent_exception. static inline void* thrown_object_from_cxa_exception(__cxa_exception* exception_header) { return static_cast(exception_header + 1); } // Get the exception object from the unwind pointer. // Relies on the structure layout, where the unwind pointer is right in // front of the user's exception object static inline __cxa_exception* cxa_exception_from_unwind_exception( _Unwind_Exception* unwind_exception) { return cxa_exception_from_thrown_object(unwind_exception + 1); } #ifdef __WASM_EXCEPTIONS__ struct __cxa_dependent_exception; uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception); static bool isDependentException(_Unwind_Exception* unwind_exception) { return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; } #endif extern "C" { void* __thrown_object_from_unwind_exception( _Unwind_Exception* unwind_exception) { __cxa_exception* exception_header = cxa_exception_from_unwind_exception(unwind_exception); return thrown_object_from_cxa_exception(exception_header); } // Given a thrown_object, puts the information about its type and message into // 'type' and 'message' output parameters. 'type' will contain the string // representation of the type of the exception, e.g., 'int'. 'message' will // contain the result of 'std::exception::what()' method if the type of the // exception is a subclass of std::exception; otherwise it will be NULL. The // caller is responsible for freeing 'type' buffer and also 'message' buffer, if // it is not NULL. void __get_exception_message(void* thrown_object, char** type, char** message) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); const __shim_type_info* thrown_type = static_cast(exception_header->exceptionType); const char* type_name = thrown_type->name(); int status = 0; char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status); if (status == 0 && demangled_buf) { *type = demangled_buf; } else { if (demangled_buf) { free(demangled_buf); } *type = (char*)malloc(strlen(type_name) + 1); strcpy(*type, type_name); } *message = NULL; const __shim_type_info* catch_type = static_cast(&typeid(std::exception)); int can_catch = catch_type->can_catch(thrown_type, thrown_object); if (can_catch) { #if __WASM_EXCEPTIONS__ if (isDependentException(&exception_header->unwindHeader)) { thrown_object = reinterpret_cast<__cxa_dependent_exception*>(exception_header) ->primaryException; // can_catch can adjust thrown_object ptr, so rerun it [[maybe_unused]] bool ret = catch_type->can_catch(thrown_type, thrown_object); assert(ret); } #endif const char* what = static_cast(thrown_object)->what(); *message = (char*)malloc(strlen(what) + 1); strcpy(*message, what); } } // Returns a message saying that execution was terminated due to an exception. // This message is freshly malloc'd and should be freed. char* __get_exception_terminate_message(void* thrown_object) { char* type; char* message; __get_exception_message(thrown_object, &type, &message); char* result; if (message != NULL) { asprintf( &result, "terminating with uncaught exception %s: %s", type, message); free(message); } else { asprintf(&result, "terminating with uncaught exception of type %s", type); } free(type); return result; } #ifdef __WASM_EXCEPTIONS__ void __increment_uncaught_exception() throw() { __cxa_get_globals()->uncaughtExceptions += 1; } void __decrement_uncaught_exception() throw() { __cxa_get_globals()->uncaughtExceptions -= 1; } #endif } // extern "C" } // namespace __cxxabiv1 #endif // __EMSCRIPTEN__