summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chisnall <dchisnall@pathscale.com>2011-11-24 20:03:52 +0000
committerDavid Chisnall <dchisnall@pathscale.com>2011-11-24 20:03:52 +0000
commit75ca8259acea380d867f136738e3835250ea0855 (patch)
tree9a3bb29ee4866c62ee5e0d784b81719751cbfb06
parentfa252d2522b4972ac2fdc376e4200db3234d9d3a (diff)
downloadlibcxxrt-75ca8259acea380d867f136738e3835250ea0855.tar.gz
libcxxrt-75ca8259acea380d867f136738e3835250ea0855.tar.bz2
libcxxrt-75ca8259acea380d867f136738e3835250ea0855.tar.xz
Mostly-working ARM exceptions.
Exception specifications are still broken - only the first is checked.
-rw-r--r--src/dwarf_eh.h7
-rw-r--r--src/exception.cc65
-rw-r--r--src/unwind-arm.h10
-rw-r--r--src/unwind.h13
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 <dlfcn.h>
#include <stdio.h>
#include <string.h>
+#include <stdint.h>
#include <pthread.h>
#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
}
/**
@@ -120,6 +120,10 @@ struct __cxa_thread_info
*/
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