From: John Hodge Date: Fri, 6 Jun 2014 15:42:45 +0000 (+0800) Subject: Usermode/libc++ - Exception handling implemented (partially) X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=4f326e70fe6e02484ddcd012ef541107f96bbf95;p=tpg%2Facess2.git Usermode/libc++ - Exception handling implemented (partially) - Throwing and catching of single-inheritance exceptions working on x8 - MI not implemented - Exception specifcations not implemented --- diff --git a/Usermode/Libraries/libc++.so_src/Makefile b/Usermode/Libraries/libc++.so_src/Makefile index 82eaf7c2..e04b6700 100644 --- a/Usermode/Libraries/libc++.so_src/Makefile +++ b/Usermode/Libraries/libc++.so_src/Makefile @@ -15,6 +15,7 @@ USE_CXX_LINK := yes OBJ = misc.o new.o guard.o cxxabi.o typeinfo.o OBJ += string.o OBJ += exceptions.o exception_handling.o system_error.o +OBJ += gxx_personality.o DEPFILES := $(OBJ:%.o=%.d) BIN = libc++.so ifeq ($(ARCHDIR),native) diff --git a/Usermode/Libraries/libc++.so_src/cxxabi.cc b/Usermode/Libraries/libc++.so_src/cxxabi.cc index ad8adbde..bd35690a 100644 --- a/Usermode/Libraries/libc++.so_src/cxxabi.cc +++ b/Usermode/Libraries/libc++.so_src/cxxabi.cc @@ -49,3 +49,14 @@ extern "C" void __cxa_bad_typeid () //throw ::std::bad_typeid; } +extern "C" void* __dynamic_cast( + const void *sub, + const __cxxabiv1::__class_type_info *src, + const __cxxabiv1::__class_type_info *dst, + ptrdiff_t src2dst_offset + ) +{ + _SysDebug("TODO: __dynamic_cast %p %s to %s, hint=%p", sub, dst->name(), src->name(), src2dst_offset); + return NULL; +} + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling.cc b/Usermode/Libraries/libc++.so_src/exception_handling.cc index d5a22195..c327f847 100644 --- a/Usermode/Libraries/libc++.so_src/exception_handling.cc +++ b/Usermode/Libraries/libc++.so_src/exception_handling.cc @@ -1,4 +1,17 @@ /* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling.cc + * - Exception handling code (defined by C++ ABI) + * + * References: + * - LLVM Exception handling + * > http://llvm.org/docs/ExceptionHandling.html + * - Itanium C++ ABI + * >http://mentorembedded.github.io/cxx-abi/abi-eh.html + * - HP's "aC++" Document, Ch 7 "Exception Handling Tables" + * > http://mentorembedded.github.io/cxx-abi/exceptions.pdf */ #include #include @@ -6,7 +19,7 @@ #include #include #include -#include "exception_handling.h" +#include "exception_handling_cxxabi.h" #include @@ -76,13 +89,13 @@ extern "C" void __cxa_free_exception(void *thrown_exception) extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void*)) { - ::_SysDebug("__cxa_throw(%p,%p,%p) '%s'", thrown_exception, tinfo, dest, tinfo->name()); - ::_SysDebug("- by %p", __builtin_return_address(0)); + ::_SysDebug("__cxa_throw(%p,%p,%p) '%s' by %p", + thrown_exception, tinfo, dest, tinfo->name(), __builtin_return_address(0) + ); { const ::std::exception* e = reinterpret_cast(thrown_exception); ::_SysDebug("- e.what() = '%s'", e->what()); } - ::_SysDebug("- typeid(*tinfo) = %p", &typeid(*tinfo)); __cxa_exception *except = static_cast<__cxa_exception*>( thrown_exception ) - 1; @@ -90,19 +103,19 @@ extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void except->terminateHandler = 0; except->exceptionType = tinfo; except->exceptionDestructor = dest; - memcpy(&except->unwindHeader.exception_class, "Ac20C++\0", 8); + memcpy(&except->unwindHeader.exception_class, EXCEPTION_CLASS_ACESS, 8); __cxa_get_globals()->uncaughtExceptions ++; - int rv = _Unwind_RaiseException(thrown_exception); + int rv = _Unwind_RaiseException( &except->unwindHeader ); ::_SysDebug("__cxa_throw(%p,%s) :: UNCAUGHT %i", thrown_exception, tinfo->name(), rv); ::std::terminate(); } -extern "C" void *__cxa_begin_catch(void *exceptionObject) +extern "C" void *__cxa_begin_catch(_Unwind_Exception *exceptionObject) { - ::_SysDebug("__cxa_begin_catch(%p)", exceptionObject); - __cxa_exception *except = static_cast<__cxa_exception*>( exceptionObject ) - 1; + __cxa_exception *except = reinterpret_cast<__cxa_exception*>( exceptionObject+1 )-1; + ::_SysDebug("__cxa_begin_catch(%p) - except=%p", exceptionObject, except); except->handlerCount ++; @@ -111,7 +124,7 @@ extern "C" void *__cxa_begin_catch(void *exceptionObject) __cxa_get_globals_fast()->uncaughtExceptions --; - return except; + return except+1; } extern "C" void __cxa_end_catch() @@ -126,3 +139,4 @@ extern "C" void __cxa_end_catch() } } + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling.h b/Usermode/Libraries/libc++.so_src/exception_handling.h deleted file mode 100644 index 67fcd4c9..00000000 --- a/Usermode/Libraries/libc++.so_src/exception_handling.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - */ -#ifndef _EXCEPTION_HANLDING_H_ -#define _EXCEPTION_HANLDING_H_ - -typedef void *(unexpected_handler)(void); -typedef void *(terminate_handler)(void); - -struct _Unwind_Context; - -typedef enum { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8 -} _Unwind_Reason_Code; - -typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc); - -struct _Unwind_Exception -{ - uint64_t exception_class; - _Unwind_Exception_Cleanup_Fn exception_cleanup; - uint64_t private_1; - uint64_t private_2; -}; - -struct __cxa_exception -{ - std::type_info* exceptionType; - void (*exceptionDestructor)(void *); - unexpected_handler* unexpectedHandler; - terminate_handler* terminateHandler; - __cxa_exception* nextException; - - int handlerCount; - - int handlerSwitchValue; - const char* actionRecord; - const char* languageSpecificData; - void* catchTemp; - void* adjustedPtr; - - _Unwind_Exception unwindHeader; -}; - - -extern "C" void __cxa_call_unexpected(void *); -extern "C" void *__cxa_allocate_exception(size_t thrown_size); -extern "C" void __cxa_free_exception(void *thrown_exception); -extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void*)); -extern "C" void *__cxa_begin_catch(void *exceptionObject); -extern "C" void __cxa_end_catch(); - -extern "C" _Unwind_Reason_Code _Unwind_RaiseException(void *thrown_exception); - -#endif - diff --git a/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h b/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h new file mode 100644 index 00000000..536016ef --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h @@ -0,0 +1,59 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling_acxx.h + * - C++ Exception handling definions from HP's aC++ document + * + * Reference: http://mentorembedded.github.io/cxx-abi/exceptions.pdf + */ +#ifndef _EXCEPTION_HANLDING_ACXX_H_ +#define _EXCEPTION_HANLDING_ACXX_H_ + +/** + * \brief Language Specific Data Area + * \note Pointer obtained via _Unwind_GetLanguageSpecificData + */ +struct sLSDA_Header +{ + const void *Base; + uintptr_t LPStart; + uint8_t TTEncoding; + uintptr_t TypePtrBase; // base address for type pointers + uintptr_t TTBase; // Base address for type offsets + uint8_t CallSiteEncoding; + const void *CallSiteTable; + const void *ActionTable; +}; + +/* Pointer encodings, from dwarf2.h. */ +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +// - Data format (mask with 0x0F) +#define DW_EH_PE_fmtmask 0x0F +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 +// - Data maipulation (0x70) +#define DW_EH_PE_relmask 0x70 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +typedef uint64_t leb128u_t; +typedef int64_t leb128s_t; + + +#endif + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h b/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h new file mode 100644 index 00000000..69f37359 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h @@ -0,0 +1,88 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling_cxxabi.h + * - C++ Exception Handling definitions from the Itanium C++ ABI + */ +#ifndef _EXCEPTION_HANLDING_CXXABI_H_ +#define _EXCEPTION_HANLDING_CXXABI_H_ + +typedef void *(unexpected_handler)(void); +typedef void *(terminate_handler)(void); + +struct _Unwind_Context; + +typedef enum { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef int _Unwind_Action; +static const _Unwind_Action _UA_SEARCH_PHASE = 1; +static const _Unwind_Action _UA_CLEANUP_PHASE = 2; +static const _Unwind_Action _UA_HANDLER_FRAME = 4; +static const _Unwind_Action _UA_FORCE_UNWIND = 8; + +typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc); + +struct _Unwind_Exception +{ + uint64_t exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + uint64_t private_1; + uint64_t private_2; +}; + +struct __cxa_exception +{ + std::type_info* exceptionType; + void (*exceptionDestructor)(void *); + unexpected_handler* unexpectedHandler; + terminate_handler* terminateHandler; + __cxa_exception* nextException; + + int handlerCount; + + int handlerSwitchValue; + const char* actionRecord; + const char* languageSpecificData; + void* catchTemp; + void* adjustedPtr; + + _Unwind_Exception unwindHeader; +}; + +#define EXCEPTION_CLASS_ACESS "Ac20C++\0" + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int version, _Unwind_Action actions, uint64_t exception_class, struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context, void *stop_parameter); + +// Exports +extern "C" void __cxa_call_unexpected(void *); +extern "C" void *__cxa_allocate_exception(size_t thrown_size); +extern "C" void __cxa_free_exception(void *thrown_exception); +extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void*)); +extern "C" void *__cxa_begin_catch(_Unwind_Exception *exceptionObject); +extern "C" void __cxa_end_catch(); + +// Imports +extern "C" _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *exception_object); +extern "C" _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter); +extern "C" void _Unwind_DeleteException(struct _Unwind_Exception *exception_object); +extern "C" uint64_t _Unwind_GetGR(struct _Unwind_Context *context, int index); +extern "C" void _Unwind_SetGR(struct _Unwind_Context *context, int index, uint64_t new_value); +extern "C" uint64_t _Unwind_GetIP(struct _Unwind_Context *context); +extern "C" void _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value); +extern "C" uint64_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); +extern "C" uint64_t _Unwind_GetRegionStart(struct _Unwind_Context *context); + +#endif + + diff --git a/Usermode/Libraries/libc++.so_src/gxx_personality.cc b/Usermode/Libraries/libc++.so_src/gxx_personality.cc new file mode 100644 index 00000000..f571d773 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/gxx_personality.cc @@ -0,0 +1,450 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * gxx_personality.cc + * - Implementation of GNU C++ Exception handling "Personality" + */ +#include +#include // [u]intN_t +#include // abort +#include // memcmp +#include "exception_handling_acxx.h" +#include "exception_handling_cxxabi.h" +#include +#include +#include // __dynamic_cast + +// === PROTOTYPES === +extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); +static int get_frame_action(const sLSDA_Header &header, _Unwind_Context *context, const std::type_info *throw_type, + uint64_t &landingpad, int64_t &switch_value); +static bool exception_matches_single(const std::type_info *throw_type, const struct sLSDA_Header &header, int type_index); +static bool exception_matches_list(const std::type_info *throw_type, const struct sLSDA_Header &header, int list_index); +static void read_lsda_header(const void *&ptr, _Unwind_Context *context, struct sLSDA_Header *header); +static size_t _get_encoded_size(int encoding); +static uint64_t _get_base(uint8_t encoding, _Unwind_Context *context); +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding, uint64_t base); +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding); +template static T read(const void *&ptr); +static uint64_t _read_leb128u(const void *&ptr); +static int64_t _read_leb128s(const void *&ptr); + +// === CODE === +extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) +{ + //::_SysDebug("__gxx_personality_v0(%i, 0x%x, 0x%llx, ...)", version, actions, exceptionClass); + //::_SysDebug("__gxx_personality_v0(..., %p, %p)", exceptionObject, context); + + //if( exceptionObject ) { + // ::_SysDebug("exception_object: Class 0x%llx", exceptionObject->exception_class); + //} + //if( context ) + //{ + // ::_SysDebug("context: IP 0x%llx", _Unwind_GetIP(context)); + // ::_SysDebug("context: RegionStart 0x%llx", _Unwind_GetRegionStart(context)); + // ::_SysDebug("context: LangSpecData 0x%llx", _Unwind_GetLanguageSpecificData(context)); + //} + + if( version != 1 ) { + ::_SysDebug("%s: Unexpected version %i != exp 1", __func__, version); + return _URC_FATAL_PHASE1_ERROR; + } + + const void *lsda_ptr = (const void*)_Unwind_GetLanguageSpecificData(context); + struct sLSDA_Header header; + read_lsda_header(lsda_ptr, context, &header); + + const void *exception_object = exceptionObject + 1; + const __cxa_exception *exception_info = static_cast(exception_object) - 1; + std::type_info *throw_type = ( + memcmp(&exceptionClass,EXCEPTION_CLASS_ACESS,8) == 0 ? exception_info->exceptionType : NULL + ); + + uint64_t landingpad = 0; + int64_t switch_value = 0; + int frame_action = get_frame_action(header, context, throw_type, landingpad, switch_value); + + if( (actions & _UA_SEARCH_PHASE) && (actions & _UA_CLEANUP_PHASE) ) + { + _SysDebug("__gxx_personality_v0: ERROR Both _UA_SEARCH_PHASE and _UA_CLEANUP_PHASE set"); + abort(); + } + + // Search + if( actions & _UA_SEARCH_PHASE ) + { + // If a handler was found + if( frame_action == 2 ) { + // - return _URC_HANDLER_FOUND + _SysDebug("SEARCH: 0x%llx Handler %p(%i)", + _Unwind_GetIP(context), landingpad, switch_value); + return _URC_HANDLER_FOUND; + } + // - If no handler (either nothing, or cleanups), return _URC_CONTINUE_UNWIND + _SysDebug("SEARCH: 0x%llx no handler %p(%i)", + _Unwind_GetIP(context), landingpad, switch_value); + return _URC_CONTINUE_UNWIND; + } + + // Cleanup + if( actions & _UA_CLEANUP_PHASE ) + { + // No action, continue + if( frame_action == 0 ) { + return _URC_CONTINUE_UNWIND; + } + assert(landingpad); + + if( actions & _UA_FORCE_UNWIND ) + { + // Unwind forced, override switch_value to 0 + // - Disables any attempt to handle exception + switch_value = 0; + } + + _SysDebug("Install context IP=0x%x, R%i=%p/R%i=%i", + (uintptr_t)landingpad, + __builtin_eh_return_data_regno(0), exceptionObject, + __builtin_eh_return_data_regno(1), switch_value + ); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)exceptionObject); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), switch_value); + _Unwind_SetIP(context, landingpad); + return _URC_INSTALL_CONTEXT; + } + + _SysDebug("__gxx_personality_v0: Neither _UA_SEARCH_PHASE or _UA_CLEANUP_PHASE set"); + return _URC_FATAL_PHASE1_ERROR; +} + +int get_frame_action(const sLSDA_Header &header, _Unwind_Context *context, const std::type_info* throw_type, + uint64_t &landingpad, int64_t &switch_value) +{ + uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context); + _SysDebug("IP = 0x%llx + 0x%llx", _Unwind_GetRegionStart(context), ip); + // Check if there is a handler for this exception in this frame + // - Search call site table for this return address (corresponds to a try block) + uintptr_t cs_ldgpad; + uint64_t cs_action; + const void *lsda_ptr = header.CallSiteTable; + while( lsda_ptr < header.ActionTable ) + { + uintptr_t cs_start = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + uintptr_t cs_len = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + cs_ldgpad = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + cs_action = _read_leb128u(lsda_ptr); + + // If IP falls below this entry, it's not on the list + if( ip <= cs_start ) { + lsda_ptr = header.ActionTable; + break ; + } + if( ip > cs_start + cs_len ) + continue; + + break; + } + if( lsda_ptr > header.ActionTable ) { + _SysDebug("__gxx_personality_v0: Malformed Call Site Table, reading overran the end (%p>%p)", + lsda_ptr, header.ActionTable); + } + if( lsda_ptr >= header.ActionTable ) { + // No match! + _SysDebug("__gxx_personality_v0: No entry for IP 0x%x", ip); + return 0; + } + + // Found it + if( cs_ldgpad == 0 ) { + _SysDebug("No landingpad, hence no action"); + if( cs_action != 0 ) { + _SysDebug("%s: NOTICE cs_ldgpad==0 but cs_action(0x%llx)!=0", + __func__, cs_action); + } + return 0; + } + else if( cs_action == 0 ) { + _SysDebug("No action, cleanups only"); + switch_value = 0; + landingpad = header.LPStart + cs_ldgpad; + return 1; // 1 = cleanup only + } + else { + switch_value = 0; + landingpad = header.LPStart + cs_ldgpad; + // catch() handler + bool has_cleanups = false; // set to true to override return value + const void *action_list = (const char*)header.ActionTable + (cs_action-1); + for(;;) // broken by 0 length entry + { + leb128s_t filter = _read_leb128s(action_list); + leb128s_t disp = _read_leb128s(action_list); + _SysDebug("filter=%lli,disp=%lli", filter, disp); + if( filter == 0 ) + { + // Cleanup + has_cleanups = true; + } + else if( filter < 0 ) + { + // Exception specifcation + if( !exception_matches_list(throw_type, header, -filter) ) + { + switch_value = filter; + return 2; + } + } + else + { + // Catch + if( exception_matches_single(throw_type, header, filter) ) + { + switch_value = filter; + return 2; + } + } + + if( disp == 0 ) + break; + action_list = (const char*)action_list + disp-1; + } + + // If a cleanup request was seen, tell the caller that we want to handle it + if( has_cleanups ) { + return 1; // 1 = cleanup only + } + // Else, there's nothing here to handle + return 0; + } +} + +const ::std::type_info *get_type_info(const struct sLSDA_Header &header, int type_index) +{ + size_t encoded_size = _get_encoded_size(header.TTEncoding); + assert(encoded_size > 0); + const void *ptr = (const void*)(header.TTBase - encoded_size * type_index); + assert( header.TTBase ); + assert( ptr > header.ActionTable ); + + uintptr_t type_ptr = _read_encoded(ptr, NULL, header.TTEncoding, header.TypePtrBase); + _SysDebug("typeinfo_ptr = %p", type_ptr); + return reinterpret_cast< ::std::type_info* >(type_ptr); +} + +const ::std::type_info *get_exception_type(const void *exception_object) +{ + if( !exception_object ) + return NULL; + const struct _Unwind_Exception *u_execept = (const struct _Unwind_Exception*)exception_object; + const struct __cxa_exception *except = (const struct __cxa_exception*)(u_execept + 1) - 1; + if( memcmp(&except->unwindHeader.exception_class, EXCEPTION_CLASS_ACESS, 8) != 0 ) + return NULL; + + return except->exceptionType; +} + +bool exception_matches_single(const std::type_info *throw_type, const struct sLSDA_Header &header, int type_index) +{ + const ::std::type_info *catch_type = get_type_info(header, type_index); + + if( !catch_type ) + { + _SysDebug("catch(...)"); + return true; + } + else if( !throw_type ) + { + _SysDebug("threw UNK"); + return false; + } + else + { + _SysDebug("catch(%s), throw %s", catch_type->name(), throw_type->name()); + size_t ofs = 0; + if( !catch_type->__is_child(*throw_type, ofs) ) { + _SysDebug("> No match"); + return false; + } + + return true; + } +} +bool exception_matches_list(const std::type_info *throw_type, const struct sLSDA_Header &header, int list_index) +{ + _SysDebug("TODO: exception_matches_list %i", list_index); + (void)throw_type; + (void)header; + return true; +} + +template T read(const void *&ptr) +{ + T rv = *reinterpret_cast(ptr); + ptr = (const char*)ptr + sizeof(T); + return rv; +} + +static void read_lsda_header(const void *&ptr, _Unwind_Context *context, struct sLSDA_Header *header) +{ + header->Base = ptr; + + uint8_t start_encoding = read(ptr); + if( start_encoding == DW_EH_PE_omit ) + header->LPStart = _Unwind_GetRegionStart(context); + else + header->LPStart = _read_encoded(ptr, context, start_encoding); + + header->TTEncoding = read(ptr); + if( header->TTEncoding == DW_EH_PE_omit ) + header->TTBase = 0; + else { + ptrdiff_t tt_ofs = _read_leb128u(ptr); + header->TTBase = (uintptr_t)ptr + tt_ofs; + } + header->TypePtrBase = _get_base(header->TTEncoding, context); + + header->CallSiteEncoding = read(ptr); + uint64_t call_site_size = _read_leb128u(ptr); + header->CallSiteTable = ptr; + header->ActionTable = (const void*)( (uintptr_t)ptr + call_site_size ); + + #if 0 + ::_SysDebug("LSDA header:"); + ::_SysDebug("->LPStart = 0x%lx", header->LPStart); + ::_SysDebug("->TTEncoding = 0x%02x", header->TTEncoding); + ::_SysDebug("->TTBase = 0x%lx", header->TTBase); + ::_SysDebug("->CallSiteEncoding = 0x%02x", header->CallSiteEncoding); + ::_SysDebug("->CallSiteTable = %p", header->CallSiteTable); + ::_SysDebug("->ActionTable = %p", header->ActionTable); + #endif +} + +static size_t _get_encoded_size(int encoding) +{ + switch(encoding & DW_EH_PE_fmtmask) + { + case DW_EH_PE_absptr: // absolute + return sizeof(void*); + default: + _SysDebug("_get_encoded_size: Unknown encoding 0x%02x", encoding); + return 0; + } +} + +/* + * \brief Read a DWARF encoded pointer from the stream + */ +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding, uint64_t base) +{ + (void)context; + if( encoding == DW_EH_PE_aligned ) { + void **aligned = (void**)( ((uintptr_t)ptr + sizeof(void*) - 1) & -(sizeof(void*)-1) ); + ptr = (void*)( (uintptr_t)aligned + sizeof(void*) ); + return (uintptr_t)*aligned; + } + uint64_t rv; + uintptr_t orig_ptr = (uintptr_t)ptr; + switch(encoding & DW_EH_PE_fmtmask) + { + case DW_EH_PE_absptr: // absolute + rv = (uintptr_t)read(ptr); + break; + case DW_EH_PE_uleb128: + rv = _read_leb128u(ptr); + break; + case DW_EH_PE_sleb128: + rv = _read_leb128s(ptr); + break; + case DW_EH_PE_udata2: + rv = read(ptr); + break; + case DW_EH_PE_udata4: + rv = read(ptr); + break; + case DW_EH_PE_udata8: + rv = read(ptr); + break; + default: + ::_SysDebug("_read_encoded: Unknown encoding format 0x%x", encoding & DW_EH_PE_fmtmask); + ::abort(); + } + if( rv != 0 ) + { + if( (encoding & DW_EH_PE_relmask) == DW_EH_PE_pcrel ) { + rv += orig_ptr; + } + else { + rv += base; + } + + if( encoding & DW_EH_PE_indirect ) { + rv = (uintptr_t)*(void**)(uintptr_t)rv; + } + else { + // nothing + } + } + return rv; +} +static uint64_t _get_base(uint8_t encoding, _Unwind_Context *context) +{ + if( encoding == 0xFF ) + return 0; + switch(encoding & DW_EH_PE_relmask) + { + case DW_EH_PE_absptr: + case DW_EH_PE_pcrel: + case DW_EH_PE_aligned: + return 0; + //case DW_EH_PE_textrel: + //return _Unwind_GetTextRelBase(context); + //case DW_EH_PE_datarel: + //return _Unwind_GetDataRelBase(context); + case DW_EH_PE_funcrel: + return _Unwind_GetRegionStart(context); + default: + ::_SysDebug("_get_base: Unknown encoding relativity 0x%x", (encoding & DW_EH_PE_relmask)); + ::abort(); + } +} +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding) +{ + return _read_encoded(ptr, context, encoding, _get_base(encoding, context)); +} + +static uint64_t _read_leb128_raw(const void *&ptr, int *sizep) +{ + int size = 0; + uint64_t val = 0; + const uint8_t *ptr8 = static_cast(ptr); + do + { + val |= (*ptr8 & 0x7F) << (size*7); + size ++; + } while( *ptr8++ & 0x80 ); + + ptr = ptr8; + *sizep = size; + + return val; +} + +static uint64_t _read_leb128u(const void *&ptr) +{ + int unused_size; + return _read_leb128_raw(ptr, &unused_size); +} +static int64_t _read_leb128s(const void *&ptr) +{ + int size; + uint64_t val = _read_leb128_raw(ptr, &size); + if( size*7 <= 64 && (val & (1 << (size*7-1))) ) + { + val |= 0xFFFFFFFFFFFFFFFF << (size*7); + } + return val; +} + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h b/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h index a8e1f5ca..2fbe8979 100644 --- a/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h +++ b/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h @@ -8,6 +8,8 @@ #ifndef _LIBCXX__CXXABI_H_ #define _LIBCXX__CXXABI_H_ +#include + #include namespace __cxxabiv1 { @@ -71,6 +73,13 @@ public: }; }; +extern "C" void* __dynamic_cast( + const void *sub, + const __class_type_info *src, + const __class_type_info *dst, + ptrdiff_t src2dst_offset + ); + }; // namespace __cxxabiv1 #endif diff --git a/Usermode/Libraries/libc++.so_src/include_exp/typeinfo b/Usermode/Libraries/libc++.so_src/include_exp/typeinfo index c02d388b..fd823db1 100644 --- a/Usermode/Libraries/libc++.so_src/include_exp/typeinfo +++ b/Usermode/Libraries/libc++.so_src/include_exp/typeinfo @@ -19,9 +19,16 @@ public: bool operator!=(const type_info &) const; bool before(const type_info &) const; const char* name() const; + + // acess + bool __is_child(const type_info &, unsigned long&) const; private: type_info (const type_info& rhs); type_info& operator= (const type_info& rhs); + + // acess + bool is_class() const; + bool is_subclass() const; // CXX ABI const char *__type_name; diff --git a/Usermode/Libraries/libc++.so_src/misc.cc b/Usermode/Libraries/libc++.so_src/misc.cc index 8daa7d46..2ce7a517 100644 --- a/Usermode/Libraries/libc++.so_src/misc.cc +++ b/Usermode/Libraries/libc++.so_src/misc.cc @@ -6,6 +6,8 @@ * - Miscelanious functions */ #include +#include +#include extern "C" int SoMain() { @@ -18,11 +20,8 @@ extern "C" int SoMain() extern "C" void __cxa_pure_virtual() { // dunno -} - -extern "C" void __gxx_personality_v0() -{ - // TODO: Handle __gxx_personality_v0 somehow + ::_SysDebug("__cxa_pure_virtual by %p", __builtin_return_address(0)); + ::std::terminate(); } diff --git a/Usermode/Libraries/libc++.so_src/typeinfo.cc b/Usermode/Libraries/libc++.so_src/typeinfo.cc index c7cb5bc6..993df3cc 100644 --- a/Usermode/Libraries/libc++.so_src/typeinfo.cc +++ b/Usermode/Libraries/libc++.so_src/typeinfo.cc @@ -6,7 +6,9 @@ * - typeid and dynamic_cast */ #include +#include #include +#include namespace std { @@ -17,19 +19,19 @@ type_info::~type_info() bool type_info::operator==(const type_info& other) const { - _SysDebug("type_info::operator== - '%s' == '%s'", this->__type_name, other.__type_name); + //_SysDebug("type_info::operator== - '%s' == '%s'", this->__type_name, other.__type_name); return this->__type_name == other.__type_name; } bool type_info::operator!=(const type_info& other) const { - _SysDebug("type_info::operator!= - '%s' != '%s'", this->__type_name, other.__type_name); + //_SysDebug("type_info::operator!= - '%s' != '%s'", this->__type_name, other.__type_name); return this->__type_name != other.__type_name; } bool type_info::before(const type_info& other) const { - _SysDebug("type_info::before - '%s' < '%s'", this->__type_name, other.__type_name); + //_SysDebug("type_info::before - '%s' < '%s'", this->__type_name, other.__type_name); return this->__type_name < other.__type_name; } @@ -49,5 +51,69 @@ type_info& type_info::operator=(const type_info& rhs) return *this; } +bool type_info::is_class() const +{ + if( typeid(*this) == typeid(::__cxxabiv1::__class_type_info) ) + return true; + if( is_subclass() ) + return true; + return false; +} + +bool type_info::is_subclass() const +{ + if( typeid(*this) == typeid(::__cxxabiv1::__si_class_type_info) ) + return true; + if( typeid(*this) == typeid(::__cxxabiv1::__vmi_class_type_info) ) + return true; + return false; +} + +// Acess-defined +bool type_info::__is_child(const type_info &poss_child, unsigned long &offset) const +{ + // Check #1: Child is same type + if( poss_child == *this ) { + offset = 0; + return true; + } + + _SysDebug("typeids = this:%s , poss_child:%s", typeid(*this).name(), typeid(poss_child).name()); + + // Check #2: This type must be a class + if( !this->is_class() ) { + return false; + } + // Check #3: Child class must be a subclass + if( !poss_child.is_subclass() ) { + return false; + } + + if( typeid(poss_child) == typeid(::__cxxabiv1::__si_class_type_info) ) { + auto &si_poss_child = reinterpret_cast(poss_child); + // Single inheritance + _SysDebug("type_info::__is_child - Single inheritance"); + return __is_child( *si_poss_child.__base_type, offset ); + } + else if( typeid(poss_child) == typeid(::__cxxabiv1::__vmi_class_type_info) ) { + // Multiple inheritance + _SysDebug("TODO: type_info::__is_child - Multiple inheritance"); + abort(); + } + else { + // Oops! + _SysDebug("ERROR: type_info::__is_child - Reported subclass type, but not a subclass %s", + typeid(poss_child).name() + ); + abort(); + } +} + + +// NOTE: Not defined by the C++ ABI, but is similar to one defined by GCC (__cxa_type_match +//bool __acess_type_match(std::typeinfo& possibly_derived, const std::typeinfo& base_type) +//{ +// return false; +//} }; // namespace std