// Functions for Exception Support for Java.
-/* Copyright (C) 1998, 1999, 2001 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2001, 2002, 2006, 2010, 2011
+ Free Software Foundation
This file is part of libgcj.
#include <java/lang/Class.h>
#include <java/lang/NullPointerException.h>
+#include <gnu/gcj/RawData.h>
#include <gcj/cni.h>
#include <jvm.h>
-#include "unwind.h"
-
-\f
-// More nastiness: the GC wants to define TRUE and FALSE. We don't
-// need the Java definitions (themselves a hack), so we undefine them.
-#undef TRUE
-#undef FALSE
-
-extern "C"
+// unwind-pe.h uses std::abort(), but sometimes we compile libjava
+// without libstdc++-v3. The following hack forces it to use
+// stdlib.h's abort().
+namespace std
{
-#include <gc_priv.h>
-#include <gc_mark.h>
-#include <include/gc_gcj.h>
-};
+ __attribute__ ((__noreturn__)) void
+ abort ()
+ {
+ ::abort ();
+ }
+}
+#include "unwind.h"
-\f
struct alignment_test_struct
{
char space;
_Unwind_Exception unwindHeader;
};
+#ifdef __ARM_EABI_UNWINDER__
+// This is the exception class we report -- "GNUCJAVA".
+
+const _Unwind_Exception_Class __gcj_exception_class
+ = {'G', 'N', 'U', 'C', 'J', 'A', 'V', 'A'};
+
+static inline java_exception_header *
+get_exception_header_from_ue (_Unwind_Exception *exc)
+{
+ return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
+}
+
+extern "C" void __cxa_begin_cleanup (_Unwind_Exception*);
+
+#else // !__ARM_EABI_UNWINDER__
// This is the exception class we report -- "GNUCJAVA".
const _Unwind_Exception_Class __gcj_exception_class
= ((((((((_Unwind_Exception_Class) 'G'
{
return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
}
+#endif // !__ARM_EABI_UNWINDER__
/* Perform a throw, Java style. Throw will unwind through this call,
so there better not be any handlers or exception thrown here. */
extern "C" void
_Jv_Throw (jthrowable value)
{
- /* FIXME: Use the proper API to the collector. */
java_exception_header *xh
- = static_cast<java_exception_header *>(GC_malloc (sizeof (*xh)));
+ = static_cast<java_exception_header *>(_Jv_AllocRawObj (sizeof (*xh)));
if (value == NULL)
value = new java::lang::NullPointerException ();
xh->value = value;
- xh->unwindHeader.exception_class = __gcj_exception_class;
+ memcpy (&xh->unwindHeader.exception_class, &__gcj_exception_class,
+ sizeof xh->unwindHeader.exception_class);
xh->unwindHeader.exception_cleanup = NULL;
/* We're happy with setjmp/longjmp exceptions or region-based
exception handlers: entry points are provided here for both. */
- _Unwind_Reason_Code code;
#ifdef SJLJ_EXCEPTIONS
- code = _Unwind_SjLj_RaiseException (&xh->unwindHeader);
+ _Unwind_SjLj_RaiseException (&xh->unwindHeader);
#else
- code = _Unwind_RaiseException (&xh->unwindHeader);
+ _Unwind_RaiseException (&xh->unwindHeader);
#endif
/* If code == _URC_END_OF_STACK, then we reached top of stack without
recover. As is the way of such things, almost certainly we will have
crashed before now, rather than actually being able to diagnose the
problem. */
- abort ();
+ abort();
}
\f
-// ??? These ought to go somewhere else dwarf2 or dwarf2eh related.
-
-// Pointer encodings.
-#define DW_EH_PE_absptr 0x00
-#define DW_EH_PE_omit 0xff
-
-#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
-
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-
-static unsigned int
-size_of_encoded_value (unsigned char encoding)
-{
- switch (encoding & 0x07)
- {
- case DW_EH_PE_absptr:
- return sizeof (void *);
- case DW_EH_PE_udata2:
- return 2;
- case DW_EH_PE_udata4:
- return 4;
- case DW_EH_PE_udata8:
- return 8;
- }
- abort ();
-}
-
-static const unsigned char *
-read_encoded_value (_Unwind_Context *context, unsigned char encoding,
- const unsigned char *p, _Unwind_Ptr *val)
-{
- union unaligned
- {
- void *ptr;
- unsigned u2 __attribute__ ((mode (HI)));
- unsigned u4 __attribute__ ((mode (SI)));
- unsigned u8 __attribute__ ((mode (DI)));
- signed s2 __attribute__ ((mode (HI)));
- signed s4 __attribute__ ((mode (SI)));
- signed s8 __attribute__ ((mode (DI)));
- } __attribute__((__packed__));
-
- union unaligned *u = (union unaligned *) p;
- _Unwind_Ptr result;
-
- switch (encoding & 0x0f)
- {
- case DW_EH_PE_absptr:
- result = (_Unwind_Ptr) u->ptr;
- p += sizeof (void *);
- break;
-
- case DW_EH_PE_uleb128:
- {
- unsigned int shift = 0;
- unsigned char byte;
-
- result = 0;
- do
- {
- byte = *p++;
- result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
- shift += 7;
- }
- while (byte & 0x80);
- }
- break;
-
- case DW_EH_PE_sleb128:
- {
- unsigned int shift = 0;
- unsigned char byte;
-
- result = 0;
- do
- {
- byte = *p++;
- result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
- shift += 7;
- }
- while (byte & 0x80);
-
- if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
- result |= -(1L << shift);
- }
- break;
-
- case DW_EH_PE_udata2:
- result = u->u2;
- p += 2;
- break;
- case DW_EH_PE_udata4:
- result = u->u4;
- p += 4;
- break;
- case DW_EH_PE_udata8:
- result = u->u8;
- p += 8;
- break;
-
- case DW_EH_PE_sdata2:
- result = u->s2;
- p += 2;
- break;
- case DW_EH_PE_sdata4:
- result = u->s4;
- p += 4;
- break;
- case DW_EH_PE_sdata8:
- result = u->s8;
- p += 8;
- break;
-
- default:
- abort ();
- }
-
- if (result != 0)
- switch (encoding & 0xf0)
- {
- case DW_EH_PE_absptr:
- break;
-
- case DW_EH_PE_pcrel:
- // Define as relative to the beginning of the pointer.
- result += (_Unwind_Ptr) u;
- break;
-
- case DW_EH_PE_textrel:
- case DW_EH_PE_datarel:
- // FIXME.
- abort ();
-
- case DW_EH_PE_funcrel:
- result += _Unwind_GetRegionStart (context);
- break;
-
- default:
- abort ();
- }
-
- *val = result;
- return p;
-}
-
-static inline const unsigned char *
-read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
-{
- return read_encoded_value (0, DW_EH_PE_uleb128, p, val);
-}
-
-static inline const unsigned char *
-read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
-{
- return read_encoded_value (0, DW_EH_PE_sleb128, p, val);
-}
-
+#include "unwind-pe.h"
\f
struct lsda_header_info
{
parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
lsda_header_info *info)
{
- _Unwind_Ptr tmp;
+ _uleb128_t tmp;
unsigned char lpstart_encoding;
info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
info->ttype_encoding = *p++;
if (info->ttype_encoding != DW_EH_PE_omit)
{
+#if _GLIBCXX_OVERRIDE_TTYPE_ENCODING
+ /* Older ARM EABI toolchains set this value incorrectly, so use a
+ hardcoded OS-specific format. */
+ info->ttype_encoding = _GLIBCXX_OVERRIDE_TTYPE_ENCODING;
+#endif
p = read_uleb128 (p, &tmp);
info->TType = p + tmp;
}
return p;
}
-static jclass
+static void **
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
{
_Unwind_Ptr ptr;
i *= size_of_encoded_value (info->ttype_encoding);
read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
- return reinterpret_cast<jclass>(ptr);
+ return reinterpret_cast<void **>(ptr);
}
-
// Using a different personality function name causes link failures
// when trying to mix code using different exception handling models.
#ifdef SJLJ_EXCEPTIONS
#define PERSONALITY_FUNCTION __gcj_personality_v0
#endif
+#ifdef __ARM_EABI_UNWINDER__
+
+#define CONTINUE_UNWINDING \
+ do \
+ { \
+ if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
+ return _URC_FAILURE; \
+ return _URC_CONTINUE_UNWIND; \
+ } \
+ while (0)
+
+extern "C" _Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State state,
+ struct _Unwind_Exception* ue_header,
+ struct _Unwind_Context* context)
+#else
+
+#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
+
extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
_Unwind_Action actions,
_Unwind_Exception_Class exception_class,
struct _Unwind_Exception *ue_header,
struct _Unwind_Context *context)
+
+#endif
{
java_exception_header *xh = get_exception_header_from_ue (ue_header);
int handler_switch_value;
bool saw_cleanup;
bool saw_handler;
+ bool foreign_exception;
+ int ip_before_insn = 0;
+
+#ifdef __ARM_EABI_UNWINDER__
+ _Unwind_Action actions;
+
+ switch (state & _US_ACTION_MASK)
+ {
+ case _US_VIRTUAL_UNWIND_FRAME:
+ actions = _UA_SEARCH_PHASE;
+ break;
+
+ case _US_UNWIND_FRAME_STARTING:
+ actions = _UA_CLEANUP_PHASE;
+ if (!(state & _US_FORCE_UNWIND)
+ && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+ actions |= _UA_HANDLER_FRAME;
+ break;
+
+ case _US_UNWIND_FRAME_RESUME:
+ CONTINUE_UNWINDING;
+ break;
+
+ default:
+ std::abort();
+ }
+ actions |= state & _US_FORCE_UNWIND;
+
+ // We don't know which runtime we're working with, so can't check this.
+ // However the ABI routines hide this from us, and we don't actually need
+ // to know.
+ foreign_exception = false;
+ // The dwarf unwinder assumes the context structure holds things like the
+ // function and LSDA pointers. The ARM implementation caches these in
+ // the exception header (UCB). To avoid rewriting everything we make the
+ // virtual IP register point at the UCB.
+ ip = (_Unwind_Ptr) ue_header;
+ _Unwind_SetGR(context, 12, ip);
+#else
// Interface version check.
if (version != 1)
return _URC_FATAL_PHASE1_ERROR;
+ foreign_exception = exception_class != __gcj_exception_class;
+#endif
// Shortcut for phase 2 found handler for domestic exception.
if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
- && exception_class == __gcj_exception_class)
+ && !foreign_exception)
{
handler_switch_value = xh->handlerSwitchValue;
landing_pad = xh->landingPad;
goto install_context;
}
- // FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of
+ // FIXME: In Phase 1, record _Unwind_GetIPInfo in xh->obj as a part of
// the stack trace for this exception. This will only collect Java
// frames, but perhaps that is acceptable.
- // FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site
+ // FIXME2: _Unwind_GetIPInfo is nonsensical for SJLJ, being a call-site
// index instead of a PC value. We could perhaps arrange for
// _Unwind_GetRegionStart to return context->fc->jbuf[1], which
// is the address of the handler label for __builtin_longjmp, but
// If no LSDA, then there are no handlers or cleanups.
if (! language_specific_data)
- return _URC_CONTINUE_UNWIND;
+ CONTINUE_UNWINDING;
// Parse the LSDA header.
p = parse_lsda_header (context, language_specific_data, &info);
- ip = _Unwind_GetIP (context) - 1;
+#ifdef HAVE_GETIPINFO
+ ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+ ip = _Unwind_GetIP (context);
+#endif
+ if (! ip_before_insn)
+ --ip;
landing_pad = 0;
action_record = 0;
handler_switch_value = 0;
return _URC_CONTINUE_UNWIND;
else
{
- _Unwind_Ptr cs_lp, cs_action;
+ _uleb128_t cs_lp, cs_action;
do
{
p = read_uleb128 (p, &cs_lp);
// Search the call-site table for the action associated with this IP.
while (p < info.action_table)
{
- _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
+ _Unwind_Ptr cs_start, cs_len, cs_lp;
+ _uleb128_t cs_action;
// Note that all call-site encodings are "absolute" displacements.
p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
// If ip is not present in the table, C++ would call terminate.
// ??? It is perhaps better to tweek the LSDA so that no-action
// is mapped to no-entry for Java.
- return _URC_CONTINUE_UNWIND;
+ CONTINUE_UNWINDING;
found_something:
saw_cleanup = false;
else
{
// Otherwise we have a catch handler.
- signed long ar_filter, ar_disp;
+ _sleb128_t ar_filter, ar_disp;
while (1)
{
- _Unwind_Ptr tmp;
-
p = action_record;
- p = read_sleb128 (p, &tmp); ar_filter = tmp;
- read_sleb128 (p, &tmp); ar_disp = tmp;
+ p = read_sleb128 (p, &ar_filter);
+ read_sleb128 (p, &ar_disp);
if (ar_filter == 0)
{
// During forced unwinding, we only run cleanups. With a
// foreign exception class, we have no class info to match.
else if ((actions & _UA_FORCE_UNWIND)
- || exception_class != __gcj_exception_class)
+ || foreign_exception)
;
else if (ar_filter > 0)
{
// Positive filter values are handlers.
- jclass catch_type = get_ttype_entry (context, &info, ar_filter);
+ void **catch_word = get_ttype_entry (context, &info, ar_filter);
+ jclass catch_type = (jclass)*catch_word;
- // The catch_type is either a (java::lang::Class*) or
- // is one more than a (Utf8Const*).
- if ((size_t)catch_type & 1)
- catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL);
+ // FIXME: This line is a kludge to work around exception
+ // handlers written in C++, which don't yet use indirect
+ // dispatch.
+ if (catch_type == *(void **)&java::lang::Class::class$)
+ catch_type = (jclass)catch_word;
if (_Jv_IsInstanceOf (xh->value, catch_type))
{
}
if (! saw_handler && ! saw_cleanup)
- return _URC_CONTINUE_UNWIND;
+ CONTINUE_UNWINDING;
if (actions & _UA_SEARCH_PHASE)
{
if (! saw_handler)
- return _URC_CONTINUE_UNWIND;
+ CONTINUE_UNWINDING;
// For domestic exceptions, we cache data from phase 1 for phase 2.
- if (exception_class == __gcj_exception_class)
+ if (! foreign_exception)
{
xh->handlerSwitchValue = handler_switch_value;
xh->landingPad = landing_pad;
_Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
handler_switch_value);
_Unwind_SetIP (context, landing_pad);
+#ifdef __ARM_EABI_UNWINDER__
+ if (saw_cleanup)
+ __cxa_begin_cleanup(ue_header);
+#endif
return _URC_INSTALL_CONTEXT;
}