From 75ca8259acea380d867f136738e3835250ea0855 Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Thu, 24 Nov 2011 20:03:52 +0000 Subject: Mostly-working ARM exceptions. Exception specifications are still broken - only the first is checked. --- src/dwarf_eh.h | 7 ++++++ src/exception.cc | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/unwind-arm.h | 10 ++++++--- src/unwind.h | 13 ++++++++++++ 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/dwarf_eh.h b/src/dwarf_eh.h index 35b9af1..02d8a11 100644 --- a/src/dwarf_eh.h +++ b/src/dwarf_eh.h @@ -193,6 +193,7 @@ static int64_t read_sleb128(dw_eh_ptr_t *data) static uint64_t read_value(char encoding, dw_eh_ptr_t *data) { enum dwarf_data_encoding type = get_encoding(encoding); + //fprintf(stderr, "Loading (encoding %x) from %p\n", (int)encoding, *data); uint64_t v; switch (type) { @@ -235,6 +236,7 @@ static uint64_t resolve_indirect_value(_Unwind_Context *c, int64_t v, dw_eh_ptr_t start) { + //fprintf(stderr, "resolving(encoding %x) from %p\n", (int)get_base(encoding), (void*)(intptr_t)v); switch (get_base(encoding)) { case DW_EH_PE_pcrel: @@ -251,6 +253,7 @@ static uint64_t resolve_indirect_value(_Unwind_Context *c, default: break; } + //fprintf(stderr, "is indirect %p\n", is_indirect(encoding)); // If this is an indirect value, then it is really the address of the real // value // TODO: Check whether this should really always be a pointer - it seems to @@ -332,6 +335,7 @@ static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context, // spec says, but does seem to be how G++ indicates this. lsda.type_table = 0; lsda.type_table_encoding = *data++; + //fprintf(stderr, "Type table Encoding: %x\n", (int)lsda.type_table_encoding); if (lsda.type_table_encoding != DW_EH_PE_omit) { v = read_uleb128(&data); @@ -340,6 +344,9 @@ static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context, lsda.type_table = type_table; //lsda.type_table = (uintptr_t*)(data + v); } +#if __arm__ + lsda.type_table_encoding = (DW_EH_PE_pcrel | DW_EH_PE_indirect); +#endif lsda.callsite_encoding = (enum dwarf_data_encoding)(*(data++)); diff --git a/src/exception.cc b/src/exception.cc index 1e60ee9..3b99735 100644 --- a/src/exception.cc +++ b/src/exception.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "typeinfo.h" #include "dwarf_eh.h" @@ -25,7 +26,7 @@ static void saveLandingPad(struct _Unwind_Context *context, ucb->barrier_cache.sp = _Unwind_GetGR(context, 13); ucb->barrier_cache.bitpattern[1] = (uint32_t)selector; ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad; -#else +#endif // Cache the results for the phase 2 unwind, if we found a handler // and this is not a foreign exception. if (ex) @@ -33,7 +34,6 @@ static void saveLandingPad(struct _Unwind_Context *context, ex->handlerSwitchValue = selector; ex->catchTemp = landingPad; } -#endif } /** @@ -119,6 +119,10 @@ struct __cxa_thread_info * in ABI spec [3.3.1]). */ int emergencyBuffersHeld; + /** + * The exception currently running in a cleanup. + */ + _Unwind_Exception *currentCleanup; /** * The public part of this structure, accessible from outside of this * module. @@ -580,9 +584,11 @@ static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exce case _URC_FATAL_PHASE1_ERROR: fprintf(stderr, "Fatal error during phase 1 unwinding\n"); break; +#ifndef __arm__ case _URC_FATAL_PHASE2_ERROR: fprintf(stderr, "Fatal error during phase 2 unwinding\n"); break; +#endif case _URC_END_OF_STACK: fprintf(stderr, "Terminating due to uncaught exception %p", (void*)thrown_exception); @@ -650,6 +656,7 @@ extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void(*dest)(void*)) { + fprintf(stderr, "Thrown exception: %p\n", thrown_exception); __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; ex->referenceCount = 1; @@ -757,6 +764,7 @@ static std::type_info *get_type_info_entry(_Unwind_Context *context, // Get the address of the record in the table. dw_eh_ptr_t record = lsda->type_table - dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter; + //record -= 4; dw_eh_ptr_t start = record; // Read the value, but it's probably an indirect reference... int64_t offset = read_value(lsda->type_table_encoding, &record); @@ -770,6 +778,7 @@ static std::type_info *get_type_info_entry(_Unwind_Context *context, } + /** * Checks the type signature found in a handler against the type of the thrown * object. If ex is 0 then it is assumed to be a foreign exception and only @@ -895,7 +904,14 @@ static handler_type check_action_record(_Unwind_Context *context, *selector = filter; while (*type_index) { +#ifdef __arm__ + //fprintf(stderr, "Filter: %d\n", filter); + std::type_info *handler_type = handler_type = get_type_info_entry(context, lsda, -filter - 1); + //fprintf(stderr, "Handler: %p\n", handler_type); + type_index++; +#else std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++)); +#endif // If the exception spec matches a permitted throw type for // this function, don't report a handler - we are allowed to // propagate this exception out. @@ -1023,6 +1039,8 @@ BEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0) action.action_record, realEx, &selector, ex->adjustedPtr); // Ignore handlers this time. if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); } + __cxa_thread_info *info = thread_info_fast(); + info->currentCleanup = exceptionObject; } else if (foreignException) { @@ -1066,6 +1084,7 @@ extern "C" void *__cxa_begin_catch(void *e) throw() extern "C" void *__cxa_begin_catch(void *e) #endif { + fprintf(stderr, "Entering catch\n"); // Decrement the uncaught exceptions count __cxa_eh_globals *globals = __cxa_get_globals(); globals->uncaughtExceptions--; @@ -1111,19 +1130,27 @@ extern "C" void *__cxa_begin_catch(void *e) ex->handlerCount++; } + fprintf(stderr, "Exception base pointer: %p\n", ((char*)exceptionObject + sizeof(_Unwind_Exception))); + fprintf(stderr, "Exception edjusted pointer: %p\n", ex->adjustedPtr); + fprintf(stderr, "Exception as int: %d\n", *(int*)((char*)exceptionObject + sizeof(_Unwind_Exception))); + return ex->adjustedPtr; } + fprintf(stderr, "Exception as int: %d\n", *(int*)((char*)exceptionObject + sizeof(_Unwind_Exception))); // exceptionObject is the pointer to the _Unwind_Exception within the // __cxa_exception. The throw object is after this return ((char*)exceptionObject + sizeof(_Unwind_Exception)); } + + /** * ABI function called when exiting a catch block. This will free the current * exception if it is no longer referenced in other catch blocks. */ extern "C" void __cxa_end_catch() { + fprintf(stderr, "Leaving catch\n"); // We can call the fast version here because the slow version is called in // __cxa_throw(), which must have been called before we end a catch block __cxa_eh_globals *globals = __cxa_get_globals_fast(); @@ -1169,6 +1196,20 @@ extern "C" void __cxa_end_catch() } } +/* +extern "C" void __cxa_end_cleanup(_Unwind_Exception* exceptionObject) +{ + _Unwind_Resume(0); +// fprintf(stderr, "Leaving cleanup\n"); +} + +extern "C" bool __cxa_begin_cleanup(_Unwind_Exception* exceptionObject) +{ + fprintf(stderr, "Entering cleanup\n"); + return true; +} +*/ + /** * ABI function. Returns the type of the current exception. */ @@ -1336,3 +1377,23 @@ namespace std return terminateHandler; } } +#ifdef __arm__ +extern "C" _Unwind_Exception *__cxa_get_cleanup(void) +{ + __cxa_thread_info *info = thread_info_fast(); + return info->currentCleanup; +} + +asm ( +".pushsection .text.__cxa_end_cleanup \n" +".global __cxa_end_cleanup \n" +".type __cxa_end_cleanup, \"function\" \n" +"__cxa_end_cleanup: \n" +" push {r1, r2, r3, r4} \n" +" bl __cxa_get_cleanup \n" +" push {r1, r2, r3, r4} \n" +" b _Unwind_Resume \n" +" bl abort \n" +".popsection \n" +); +#endif diff --git a/src/unwind-arm.h b/src/unwind-arm.h index e041cbf..f9ed429 100644 --- a/src/unwind-arm.h +++ b/src/unwind-arm.h @@ -116,6 +116,12 @@ extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *); extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *); extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *); +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *, + void *); +extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); +extern _Unwind_Reason_Code + _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *); + /** * The next set of functions are compatibility extensions, implementing Itanium * ABI functions on top of ARM ones. @@ -164,8 +170,6 @@ _Unwind_Reason_Code name(_Unwind_State state,\ struct _Unwind_Exception *exceptionObject,\ struct _Unwind_Context *context)\ {\ - fprintf(stderr, "LSDA: %p\n", (void*)_Unwind_GetLanguageSpecificData(context));\ - fprintf(stderr, "IP: %p\n", (void*)_Unwind_GetIP(context));\ int version = 1;\ uint64_t exceptionClass = exceptionObject->exception_class;\ int actions;\ @@ -192,6 +196,6 @@ _Unwind_Reason_Code name(_Unwind_State state,\ break;\ }\ }\ - _Unwind_SetGR (context, 12, (unsigned long)exceptionObject); + _Unwind_SetGR (context, 12, (unsigned long)exceptionObject);\ #define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context) diff --git a/src/unwind.h b/src/unwind.h index 76b6780..5089491 100644 --- a/src/unwind.h +++ b/src/unwind.h @@ -1,5 +1,18 @@ +#ifndef UNWIND_H_INCLUDED +#define UNWIND_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __arm__ #include "unwind-arm.h" #else #include "unwind-itanium.h" #endif + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3