// -*- C++ -*- (c) 2016 Vladimír Štill // based on documentation at https://mentorembedded.github.io/cxx-abi/abi-eh.html #include #include #include #include #include #include #include #include #include using namespace __cxxabiv1; struct _Unwind_Context; void _Unwind_SetGR( _Unwind_Context *ctx, int index, uintptr_t value ); void _Unwind_SetIP( _Unwind_Context *ctx, uintptr_t value ); uintptr_t _Unwind_GetGR( _Unwind_Context *ctx, int index ); uintptr_t _Unwind_GetIP( _Unwind_Context *ctx ); extern "C" void __gxx_personality_v0(); _Unwind_Reason_Code _Unwind_RaiseException( _Unwind_Exception *exception ) { __cxa_exception *e = reinterpret_cast< __cxa_exception * >( exception + 1 ) - 1; int handler = 0; bool handlerFound = false; _VM_LP_Info *lp = 0; typedef void (*Personality)(); Personality personality = 0; e->adjustedPtr = &e->unwindHeader + 1; auto eType = static_cast< const __shim_type_info * >( e->exceptionType ); /* TODO: Check nativeness of e */ _VM_Frame *frame = reinterpret_cast< _VM_Frame * >( __vm_control( _VM_CA_Get, _VM_CR_Frame ) )->parent, *destination = nullptr; for ( ; !handlerFound && frame; frame = frame->parent ) { lp = __vm_landingpad( frame ); if ( !lp ) continue; if ( (lp->cleanup || lp->clause_count) && !destination ) destination = frame; int cc = lp->clause_count; for ( int i = 0; i < cc; i ++ ) { int type_id = lp->clause[i].type_id; if ( type_id > 0 ) { auto tag = static_cast< const __shim_type_info * >( lp->clause[i].tag ); if ( !tag || tag == eType || tag->can_catch( eType, e->adjustedPtr ) ) { handler = type_id; handlerFound = true; personality = Personality( lp->personality ); break; // found the right lp, stop looking } } else { /* type id negative: abs( type_id ) - 1 is length of filter array */ int specSize = -(type_id + 1); auto tags = static_cast< const __shim_type_info ** >( lp->clause[ i ].tag ); bool match = false; for ( int j = 0; !match && j < specSize; ++j ) { match = tags[ j ]->can_catch( eType, e->adjustedPtr ); } if ( !match ) { handlerFound = true; handler = -1; personality = Personality( lp->personality ); break; } } } __vm_obj_free( lp ); } if ( !frame || !handlerFound ) { return _URC_END_OF_STACK; } e->handlerSwitchValue = handler; if ( personality && personality != __gxx_personality_v0 ) { __dios_fault( _VM_F_Control, "unknown personality" ); return _URC_FATAL_PHASE2_ERROR; } __vm_unwind( destination, exception, handler ); } void _Unwind_Resume( _Unwind_Exception *exception ); void _Unwind_DeleteException( _Unwind_Exception *exception ) { if ( exception->exception_cleanup != nullptr ) (*exception->exception_cleanup)( _URC_FOREIGN_EXCEPTION_CAUGHT, exception ); } uintptr_t _Unwind_GetLanguageSpecificData( _Unwind_Context *ctx ); uintptr_t _Unwind_GetRegionStart( _Unwind_Context *ctx );