Usermode/libc++ - Exception handling implemented (partially)
authorJohn Hodge <[email protected]>
Fri, 6 Jun 2014 15:42:45 +0000 (23:42 +0800)
committerJohn Hodge <[email protected]>
Fri, 6 Jun 2014 15:42:45 +0000 (23:42 +0800)
- Throwing and catching of single-inheritance exceptions working on x8
- MI not implemented
- Exception specifcations not implemented

Usermode/Libraries/libc++.so_src/Makefile
Usermode/Libraries/libc++.so_src/cxxabi.cc
Usermode/Libraries/libc++.so_src/exception_handling.cc
Usermode/Libraries/libc++.so_src/exception_handling.h [deleted file]
Usermode/Libraries/libc++.so_src/exception_handling_acxx.h [new file with mode: 0644]
Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h [new file with mode: 0644]
Usermode/Libraries/libc++.so_src/gxx_personality.cc [new file with mode: 0644]
Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h
Usermode/Libraries/libc++.so_src/include_exp/typeinfo
Usermode/Libraries/libc++.so_src/misc.cc
Usermode/Libraries/libc++.so_src/typeinfo.cc

index 82eaf7c..e04b670 100644 (file)
@@ -15,6 +15,7 @@ USE_CXX_LINK := yes
 OBJ  = misc.o new.o guard.o cxxabi.o typeinfo.o\r
 OBJ += string.o\r
 OBJ += exceptions.o exception_handling.o system_error.o\r
+OBJ += gxx_personality.o\r
 DEPFILES := $(OBJ:%.o=%.d)\r
 BIN = libc++.so\r
 ifeq ($(ARCHDIR),native)\r
index ad8adbd..bd35690 100644 (file)
@@ -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;
+}
+
index d5a2219..c327f84 100644 (file)
@@ -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 <typeinfo>
 #include <cstdint>
@@ -6,7 +19,7 @@
 #include <cstdlib>
 #include <cstring>
 #include <exception>
-#include "exception_handling.h"
+#include "exception_handling_cxxabi.h"
 
 #include <acess/sys.h>
 
@@ -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<const ::std::exception*>(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 (file)
index 67fcd4c..0000000
+++ /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 (file)
index 0000000..536016e
--- /dev/null
@@ -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 (file)
index 0000000..69f3735
--- /dev/null
@@ -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 (file)
index 0000000..f571d77
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Acess2 C++ Support Library
+ * - By John Hodge (thePowersGang)
+ *
+ * gxx_personality.cc
+ * - Implementation of GNU C++ Exception handling "Personality"
+ */
+#include <typeinfo>
+#include <cstdint>     // [u]intN_t
+#include <cstdlib>     // abort
+#include <cstring>     // memcmp
+#include "exception_handling_acxx.h"
+#include "exception_handling_cxxabi.h"
+#include <acess/sys.h>
+#include <cassert>
+#include <cxxabi.h>    // __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 <typename T> 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<const __cxa_exception*>(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 <typename T> T read(const void *&ptr)
+{
+       T rv = *reinterpret_cast<const T*>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<void*>(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<uint16_t>(ptr);
+               break;
+       case DW_EH_PE_udata4:
+               rv = read<uint32_t>(ptr);
+               break;
+       case DW_EH_PE_udata8:
+               rv = read<uint64_t>(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<const uint8_t*>(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;
+}
+
index a8e1f5c..2fbe897 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _LIBCXX__CXXABI_H_
 #define _LIBCXX__CXXABI_H_
 
+#include <cstddef>
+
 #include <typeinfo>
 
 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
index c02d388..fd823db 100644 (file)
@@ -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;
index 8daa7d4..2ce7a51 100644 (file)
@@ -6,6 +6,8 @@
  * - Miscelanious functions
  */
 #include <string.h>
+#include <acess/sys.h>
+#include <exception>
 
 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();
 }
 
 
index c7cb5bc..993df3c 100644 (file)
@@ -6,7 +6,9 @@
  * - typeid and dynamic_cast
  */
 #include <typeinfo>
+#include <cxxabi.h>
 #include <acess/sys.h>
+#include <cstdlib>
 
 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<const ::__cxxabiv1::__si_class_type_info&>(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

UCC git Repository :: git.ucc.asn.au