diff mbox

C6X unwinding/exception handling

Message ID 201108041531.58790.paul@codesourcery.com
State New
Headers show

Commit Message

Paul Brook Aug. 4, 2011, 2:31 p.m. UTC
C6X uses an unwinding/exception handling echeme very similar to that defined 
by the ARM EABI.  The core of the unwinder is the same, so I've pulled it out 
into a common file.

Other than the obvious target specific bits, the main compiler visible 
difference is that the C6X assembler generates the unwinding tables from DWARF 
.cfi directives, rather than the separate set of directives used by the ARM 
assembler.

The libstdc++ changes probably deserve a bit of explanation. The ttype_base 
field was clearly used in an early draft of the ARM EABI, and the current ARM 
definition is a compatible subset of that used by C6X.  
_GLIBCXX_OVERRIDE_TTYPE_ENCODING is an unfortunate hack because when doing the 
ARM implementation I failed to realise ttype_encoding was the same thing as 
R_ARM_TARGET2.  We now have a lot of ARM binaries floating around with that 
field set incorrectly, so it's either this or an ABI bump.

Ok?

Paul

2011-08-04  Paul Brook  <paul@codesourcery.com>
 
	gcc/
	* config/arm/arm.h (ASM_PREFERRED_EH_DATA_FORMAT): Define.
	(ARM_TARGET2_DWARF_FORMAT): Provide default definition.
	* config/arm/linux-eabi.h (ARM_TARGET2_DWARF_FORMAT): Define.
	* config/arm/symbian.h (ARM_TARGET2_DWARF_FORMAT): Define.
	* config/arm/uclinux-eabi.h(ARM_TARGET2_DWARF_FORMAT): Define.
	* config/arm/t-bpabi (EXTRA_HEADERS): Add unwind-arm-common.h.
	* config/arm/t-symbian (EXTRA_HEADERS): Add unwind-arm-common.h.
	* config/arm/unwind-arm.c: Use unwind-arm-common.inc.
	* config/arm/unwind-arm.h: Use unwind-arm-common.h.
	(_GLIBCXX_OVERRIDE_TTYPE_ENCODING): Define.
	* config/c6x/c6x.c (c6x_output_file_unwind): Don't rely on dwarf2 code
	enabling unwind tables.
	(c6x_debug_unwind_info): New function.
	(TARGET_ARM_EABI_UNWINDER): Define.
	(TARGET_DEBUG_UNWIND_INFO): Define.
	* config/c6x/c6x.h (DWARF_FRAME_RETURN_COLUMN): Define.
	(TARGET_EXTRA_CFI_SECTION): Remove.
	* config/c6x/t-c6x-elf (LIB2ADDEH, UNWIND_H, EXTRA_HEADERS): Set.
	* config/c6x/libunwind.S: New file.
	* config/c6x/pr-support.c: New file.
	* config/c6x/unwind-c6x.c: New file.
	* config/c6x/unwind-c6x.h: New file.
	* unwind-c.c (PERSONALITY_FUNCTION): Use UNWIND_POINTER_REG.
	* ginclude/unwind-arm-common.h: New file.

	libstdc++-v3/
	* libsupc++/eh_arm.cc (__cxa_end_cleanup): Add C6X implementation.
	* libsupc++/eh_call.cc (__cxa_call_unexpected): Set rtti_base.
	* libsupc++/eh_personality.cc (NO_SIZE_OF_ENCODED_VALUE): Remove
	__ARM_EABI_UNWINDER__ check.
	(parse_lsda_header): Check _GLIBCXX_OVERRIDE_TTYPE_ENCODING.
	(get_ttype_entry): Use generic implementation on ARM EABI.
	(check_exception_spec): Use _Unwind_decode_typeinfo_ptr and
	UNWIND_STACK_REG.
	(PERSONALITY_FUNCTION): Set ttype_base.  Use UNWIND_STACK_REG and
	UNWIND_POINTER_REG.

Comments

Bernd Schmidt Aug. 5, 2011, 9:34 p.m. UTC | #1
On 08/04/11 16:31, Paul Brook wrote:
> C6X uses an unwinding/exception handling echeme very similar to that defined 
> by the ARM EABI.  The core of the unwinder is the same, so I've pulled it out 
> into a common file.
> 
> Other than the obvious target specific bits, the main compiler visible 
> difference is that the C6X assembler generates the unwinding tables from DWARF 
> .cfi directives, rather than the separate set of directives used by the ARM 
> assembler.
> 
> The libstdc++ changes probably deserve a bit of explanation. The ttype_base 
> field was clearly used in an early draft of the ARM EABI, and the current ARM 
> definition is a compatible subset of that used by C6X.  
> _GLIBCXX_OVERRIDE_TTYPE_ENCODING is an unfortunate hack because when doing the 
> ARM implementation I failed to realise ttype_encoding was the same thing as 
> R_ARM_TARGET2.  We now have a lot of ARM binaries floating around with that 
> field set incorrectly, so it's either this or an ABI bump.

Just for the record, no objections to the C6X parts of the patch if the
rest is approved.

It would probably help to say what kind of testing you did on ARM.


Bernd
diff mbox

Patch

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 3810f9e..2260785 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -810,6 +810,16 @@  extern int arm_arch_thumb_hwdiv;
 #define ARM_EH_STACKADJ_REGNUM	2
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (SImode, ARM_EH_STACKADJ_REGNUM)
 
+#ifndef ARM_TARGET2_DWARF_FORMAT
+#define ARM_TARGET2_DWARF_FORMAT DW_EH_PE_pcrel
+
+/* ttype entries (the only interesting data references used)
+   use TARGET2 relocations.  */
+#define ASM_PREFERRED_EH_DATA_FORMAT(code, data) \
+  (((code) == 0 && (data) == 1 && ARM_UNWIND_INFO) ? ARM_TARGET2_DWARF_FORMAT \
+			       : DW_EH_PE_absptr)
+#endif
+
 /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
    as an invisible last argument (possible since varargs don't exist in
    Pascal), so the following is not true.  */
diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
index 921af3d..a383095 100644
--- a/gcc/config/arm/linux-eabi.h
+++ b/gcc/config/arm/linux-eabi.h
@@ -101,3 +101,5 @@ 
    is used.  */
 #undef  CLEAR_INSN_CACHE
 #define CLEAR_INSN_CACHE(BEG, END) not_used
+
+#define ARM_TARGET2_DWARF_FORMAT (DW_EH_PE_pcrel | DW_EH_PE_indirect)
diff --git a/gcc/config/arm/symbian.h b/gcc/config/arm/symbian.h
index b24c6ec..fa2ed84 100644
--- a/gcc/config/arm/symbian.h
+++ b/gcc/config/arm/symbian.h
@@ -98,3 +98,5 @@ 
 #define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P false
 
 #define TARGET_DEFAULT_WORD_RELOCATIONS 1
+
+#define ARM_TARGET2_DWARF_FORMAT DW_EH_PE_absptr
diff --git a/gcc/config/arm/t-bpabi b/gcc/config/arm/t-bpabi
index 78812b3..adabbad 100644
--- a/gcc/config/arm/t-bpabi
+++ b/gcc/config/arm/t-bpabi
@@ -26,6 +26,7 @@  LIB2FUNCS_EXTRA = $(srcdir)/config/arm/bpabi.c \
 LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/arm/fp16.c
 
 UNWIND_H = $(srcdir)/config/arm/unwind-arm.h
+EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
 LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \
   $(srcdir)/config/arm/libunwind.S \
   $(srcdir)/config/arm/pr-support.c $(srcdir)/unwind-c.c
diff --git a/gcc/config/arm/t-symbian b/gcc/config/arm/t-symbian
index 3be83f4..d5abfa7 100644
--- a/gcc/config/arm/t-symbian
+++ b/gcc/config/arm/t-symbian
@@ -32,6 +32,7 @@  LIB1ASMFUNCS += \
 
 # Include the gcc personality routine
 UNWIND_H = $(srcdir)/config/arm/unwind-arm.h
+EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
 LIB2ADDEH = $(srcdir)/unwind-c.c $(srcdir)/config/arm/pr-support.c
 
 # Include half-float helpers.
diff --git a/gcc/config/arm/uclinux-eabi.h b/gcc/config/arm/uclinux-eabi.h
index 4455288..c106c98 100644
--- a/gcc/config/arm/uclinux-eabi.h
+++ b/gcc/config/arm/uclinux-eabi.h
@@ -64,3 +64,4 @@ 
 		    : "0" (_beg), "r" (_end), "r" (_flg), "r" (_scno));	\
 }
 
+#define ARM_TARGET2_DWARF_FORMAT DW_EH_PE_absptr
diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c
index 90d258d..1e8ca61 100644
--- a/gcc/config/arm/unwind-arm.c
+++ b/gcc/config/arm/unwind-arm.c
@@ -23,44 +23,15 @@ 
 
 #include "unwind.h"
 
-/* We add a prototype for abort here to avoid creating a dependency on
-   target headers.  */
-extern void abort (void);
-
-/* Definitions for C++ runtime support routines.  We make these weak
-   declarations to avoid pulling in libsupc++ unnecessarily.  */
-typedef unsigned char bool;
-
-typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
-enum __cxa_type_match_result
-  {
-    ctm_failed = 0,
-    ctm_succeeded = 1,
-    ctm_succeeded_with_ptr_to_base = 2
-  };
-
-void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
-bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
-enum __cxa_type_match_result __attribute__((weak)) __cxa_type_match
-  (_Unwind_Control_Block *ucbp, const type_info *rttip,
-   bool is_reference, void **matched_object);
-
-_Unwind_Ptr __attribute__((weak))
-__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *);
-
 /* Misc constants.  */
 #define R_IP	12
 #define R_SP	13
 #define R_LR	14
 #define R_PC	15
 
-#define EXIDX_CANTUNWIND 1
-#define uint32_highbit (((_uw) 1) << 31)
-
-#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1)
-#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
-#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
-#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4)
+#define VRS_PC(vrs) ((vrs)->core.r[R_PC])
+#define VRS_SP(vrs) ((vrs)->core.r[R_SP])
+#define VRS_RETURN(vrs) ((vrs)->core.r[R_LR])
 
 struct core_regs
 {
@@ -102,20 +73,6 @@  struct wmmxc_regs
   _uw wc[4];
 };
 
-/* Unwind descriptors.  */
-
-typedef struct
-{
-  _uw16 length;
-  _uw16 offset;
-} EHT16;
-
-typedef struct
-{
-  _uw length;
-  _uw offset;
-} EHT32;
-
 /* The ABI specifies that the unwind routines may only use core registers,
    except when actually manipulating coprocessor state.  This allows
    us to write one implementation that works on all platforms by
@@ -154,21 +111,6 @@  typedef struct
   struct core_regs core;
 } phase2_vrs;
 
-
-/* An exception index table entry.  */
-
-typedef struct __EIT_entry
-{
-  _uw fnoffset;
-  _uw content;
-} __EIT_entry;
-
-/* Assembly helper functions.  */
-
-/* Restore core register state.  Never returns.  */
-void __attribute__((noreturn)) restore_core_regs (struct core_regs *);
-
-
 /* Coprocessor register state manipulation functions.  */
 
 /* Routines for FLDMX/FSTMX format...  */
@@ -209,15 +151,7 @@  restore_non_core_regs (phase1_vrs * vrs)
     __gnu_Unwind_Restore_WMMXC (&vrs->wmmxc);
 }
 
-/* A better way to do this would probably be to compare the absolute address
-   with a segment relative relocation of the same symbol.  */
-
-extern int __text_start;
-extern int __data_start;
-
-/* The exception index table location.  */
-extern __EIT_entry __exidx_start;
-extern __EIT_entry __exidx_end;
+#include "unwind-arm-common.inc"
 
 /* ABI defined personality routines.  */
 extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State,
@@ -547,715 +481,25 @@  selfrel_offset31 (const _uw *p)
   return offset + (_uw) p;
 }
 
-
-/* Perform a binary search for RETURN_ADDRESS in TABLE.  The table contains
-   NREC entries.  */
-
-static const __EIT_entry *
-search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address)
+static _uw
+__gnu_unwind_get_pr_addr (int idx)
 {
-  _uw next_fn;
-  _uw this_fn;
-  int n, left, right;
-
-  if (nrec == 0)
-    return (__EIT_entry *) 0;
-
-  left = 0;
-  right = nrec - 1;
-
-  while (1)
-    {
-      n = (left + right) / 2;
-      this_fn = selfrel_offset31 (&table[n].fnoffset);
-      if (n != nrec - 1)
-	next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1;
-      else
-	next_fn = (_uw)0 - 1;
-
-      if (return_address < this_fn)
-	{
-	  if (n == left)
-	    return (__EIT_entry *) 0;
-	  right = n - 1;
-	}
-      else if (return_address <= next_fn)
-	return &table[n];
-      else
-	left = n + 1;
-    }
-}
-
-/* Find the exception index table eintry for the given address.
-   Fill in the relevant fields of the UCB.
-   Returns _URC_FAILURE if an error occurred, _URC_OK on success.  */
-
-static _Unwind_Reason_Code
-get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address)
-{
-  const __EIT_entry * eitp;
-  int nrec;
-  
-  /* The return address is the address of the instruction following the
-     call instruction (plus one in thumb mode).  If this was the last
-     instruction in the function the address will lie in the following
-     function.  Subtract 2 from the address so that it points within the call
-     instruction itself.  */
-  return_address -= 2;
-
-  if (__gnu_Unwind_Find_exidx)
-    {
-      eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address,
-							    &nrec);
-      if (!eitp)
-	{
-	  UCB_PR_ADDR (ucbp) = 0;
-	  return _URC_FAILURE;
-	}
-    }
-  else
+  switch (idx)
     {
-      eitp = &__exidx_start;
-      nrec = &__exidx_end - &__exidx_start;
-    }
-
-  eitp = search_EIT_table (eitp, nrec, return_address);
+    case 0:
+      return (_uw) &__aeabi_unwind_cpp_pr0;
 
-  if (!eitp)
-    {
-      UCB_PR_ADDR (ucbp) = 0;
-      return _URC_FAILURE;
-    }
-  ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset);
+    case 1:
+      return (_uw) &__aeabi_unwind_cpp_pr1;
 
-  /* Can this frame be unwound at all?  */
-  if (eitp->content == EXIDX_CANTUNWIND)
-    {
-      UCB_PR_ADDR (ucbp) = 0;
-      return _URC_END_OF_STACK;
-    }
-
-  /* Obtain the address of the "real" __EHT_Header word.  */
-
-  if (eitp->content & uint32_highbit)
-    {
-      /* It is immediate data.  */
-      ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
-      ucbp->pr_cache.additional = 1;
-    }
-  else
-    {
-      /* The low 31 bits of the content field are a self-relative
-	 offset to an _Unwind_EHT_Entry structure.  */
-      ucbp->pr_cache.ehtp =
-	(_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content);
-      ucbp->pr_cache.additional = 0;
-    }
-
-  /* Discover the personality routine address.  */
-  if (*ucbp->pr_cache.ehtp & (1u << 31))
-    {
-      /* One of the predefined standard routines.  */
-      _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf;
-      if (idx == 0)
-	UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr0;
-      else if (idx == 1)
-	UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr1;
-      else if (idx == 2)
-	UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr2;
-      else
-	{ /* Failed */
-	  UCB_PR_ADDR (ucbp) = 0;
-	  return _URC_FAILURE;
-	}
-    } 
-  else
-    {
-      /* Execute region offset to PR */
-      UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp);
-    }
-  return _URC_OK;
-}
-
-
-/* Perform phase2 unwinding.  VRS is the initial virtual register state.  */
-
-static void __attribute__((noreturn))
-unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs)
-{
-  _Unwind_Reason_Code pr_result;
-
-  do
-    {
-      /* Find the entry for this routine.  */
-      if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK)
-	abort ();
-
-      UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC];
-
-      /* Call the pr to decide what to do.  */
-      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs);
-    }
-  while (pr_result == _URC_CONTINUE_UNWIND);
-  
-  if (pr_result != _URC_INSTALL_CONTEXT)
-    abort();
-  
-  restore_core_regs (&vrs->core);
-}
-
-/* Perform phase2 forced unwinding.  */
-
-static _Unwind_Reason_Code
-unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs,
-		      int resuming)
-{
-  _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp);
-  void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp);
-  _Unwind_Reason_Code pr_result = 0;
-  /* We use phase1_vrs here even though we do not demand save, for the
-     prev_sp field.  */
-  phase1_vrs saved_vrs, next_vrs;
-
-  /* Save the core registers.  */
-  saved_vrs.core = entry_vrs->core;
-  /* We don't need to demand-save the non-core registers, because we
-     unwind in a single pass.  */
-  saved_vrs.demand_save_flags = 0;
-
-  /* Unwind until we reach a propagation barrier.  */
-  do
-    {
-      _Unwind_State action;
-      _Unwind_Reason_Code entry_code;
-      _Unwind_Reason_Code stop_code;
-
-      /* Find the entry for this routine.  */
-      entry_code = get_eit_entry (ucbp, saved_vrs.core.r[R_PC]);
-
-      if (resuming)
-	{
-	  action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND;
-	  resuming = 0;
-	}
-      else
-	action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND;
-
-      if (entry_code == _URC_OK)
-	{
-	  UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC];
-
-	  next_vrs = saved_vrs;
-
-	  /* Call the pr to decide what to do.  */
-	  pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	    (action, ucbp, (void *) &next_vrs);
-
-	  saved_vrs.prev_sp = next_vrs.core.r[R_SP];
-	}
-      else
-	{
-	  /* Treat any failure as the end of unwinding, to cope more
-	     gracefully with missing EH information.  Mixed EH and
-	     non-EH within one object will usually result in failure,
-	     because the .ARM.exidx tables do not indicate the end
-	     of the code to which they apply; but mixed EH and non-EH
-	     shared objects should return an unwind failure at the
-	     entry of a non-EH shared object.  */
-	  action |= _US_END_OF_STACK;
-
-	  saved_vrs.prev_sp = saved_vrs.core.r[R_SP];
-	}
-
-      stop_code = stop_fn (1, action, ucbp->exception_class, ucbp,
-			   (void *)&saved_vrs, stop_arg);
-      if (stop_code != _URC_NO_REASON)
-	return _URC_FAILURE;
-
-      if (entry_code != _URC_OK)
-	return entry_code;
-
-      saved_vrs = next_vrs;
-    }
-  while (pr_result == _URC_CONTINUE_UNWIND);
-
-  if (pr_result != _URC_INSTALL_CONTEXT)
-    {
-      /* Some sort of failure has occurred in the pr and probably the
-	 pr returned _URC_FAILURE.  */
-      return _URC_FAILURE;
-    }
-
-  restore_core_regs (&saved_vrs.core);
-}
-
-/* This is a very limited implementation of _Unwind_GetCFA.  It returns
-   the stack pointer as it is about to be unwound, and is only valid
-   while calling the stop function during forced unwinding.  If the
-   current personality routine result is going to run a cleanup, this
-   will not be the CFA; but when the frame is really unwound, it will
-   be.  */
-
-_Unwind_Word
-_Unwind_GetCFA (_Unwind_Context *context)
-{
-  return ((phase1_vrs *) context)->prev_sp;
-}
-
-/* Perform phase1 unwinding.  UCBP is the exception being thrown, and
-   entry_VRS is the register state on entry to _Unwind_RaiseException.  */
-
-_Unwind_Reason_Code
-__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *);
-
-_Unwind_Reason_Code
-__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp,
-			     phase2_vrs * entry_vrs)
-{
-  phase1_vrs saved_vrs;
-  _Unwind_Reason_Code pr_result;
-
-  /* Set the pc to the call site.  */
-  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
-
-  /* Save the core registers.  */
-  saved_vrs.core = entry_vrs->core;
-  /* Set demand-save flags.  */
-  saved_vrs.demand_save_flags = ~(_uw) 0;
-  
-  /* Unwind until we reach a propagation barrier.  */
-  do
-    {
-      /* Find the entry for this routine.  */
-      if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK)
-	return _URC_FAILURE;
-
-      /* Call the pr to decide what to do.  */
-      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs);
-    }
-  while (pr_result == _URC_CONTINUE_UNWIND);
-
-  /* We've unwound as far as we want to go, so restore the original
-     register state.  */
-  restore_non_core_regs (&saved_vrs);
-  if (pr_result != _URC_HANDLER_FOUND)
-    {
-      /* Some sort of failure has occurred in the pr and probably the
-	 pr returned _URC_FAILURE.  */
-      return _URC_FAILURE;
-    }
-  
-  unwind_phase2 (ucbp, entry_vrs);
-}
-
-/* Resume unwinding after a cleanup has been run.  UCBP is the exception
-   being thrown and ENTRY_VRS is the register state on entry to
-   _Unwind_Resume.  */
-_Unwind_Reason_Code
-__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *,
-			   _Unwind_Stop_Fn, void *, phase2_vrs *);
-
-_Unwind_Reason_Code
-__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp,
-			   _Unwind_Stop_Fn stop_fn, void *stop_arg,
-			   phase2_vrs *entry_vrs)
-{
-  UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn;
-  UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg;
-
-  /* Set the pc to the call site.  */
-  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
-
-  return unwind_phase2_forced (ucbp, entry_vrs, 0);
-}
-
-_Unwind_Reason_Code
-__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *);
-
-_Unwind_Reason_Code
-__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs)
-{
-  _Unwind_Reason_Code pr_result;
-
-  /* Recover the saved address.  */
-  entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp);
-
-  if (UCB_FORCED_STOP_FN (ucbp))
-    {
-      unwind_phase2_forced (ucbp, entry_vrs, 1);
-
-      /* We can't return failure at this point.  */
-      abort ();
-    }
-
-  /* Call the cached PR.  */
-  pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs);
-
-  switch (pr_result)
-    {
-    case _URC_INSTALL_CONTEXT:
-      /* Upload the registers to enter the landing pad.  */
-      restore_core_regs (&entry_vrs->core);
-
-    case _URC_CONTINUE_UNWIND:
-      /* Continue unwinding the next frame.  */
-      unwind_phase2 (ucbp, entry_vrs);
+    case 2:
+      return (_uw) &__aeabi_unwind_cpp_pr2;
 
     default:
-      abort ();
-    }
-}
-
-_Unwind_Reason_Code
-__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *);
-
-_Unwind_Reason_Code
-__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp,
-				phase2_vrs * entry_vrs)
-{
-  if (!UCB_FORCED_STOP_FN (ucbp))
-    return __gnu_Unwind_RaiseException (ucbp, entry_vrs);
-
-  /* Set the pc to the call site.  */
-  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
-  /* Continue unwinding the next frame.  */
-  return unwind_phase2_forced (ucbp, entry_vrs, 0);
-}
-
-/* Clean up an exception object when unwinding is complete.  */
-void
-_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused)))
-{
-}
-
-
-/* Get the _Unwind_Control_Block from an _Unwind_Context.  */
-
-static inline _Unwind_Control_Block *
-unwind_UCB_from_context (_Unwind_Context * context)
-{
-  return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
-}
-
-
-/* Free an exception.  */
-
-void
-_Unwind_DeleteException (_Unwind_Exception * exc)
-{
-  if (exc->exception_cleanup)
-    (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
-}
-
-
-/* Perform stack backtrace through unwind data.  */
-_Unwind_Reason_Code
-__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
-		       phase2_vrs * entry_vrs);
-_Unwind_Reason_Code
-__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
-		       phase2_vrs * entry_vrs)
-{
-  phase1_vrs saved_vrs;
-  _Unwind_Reason_Code code;
-
-  _Unwind_Control_Block ucb;
-  _Unwind_Control_Block *ucbp = &ucb;
-
-  /* Set the pc to the call site.  */
-  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
-
-  /* Save the core registers.  */
-  saved_vrs.core = entry_vrs->core;
-  /* Set demand-save flags.  */
-  saved_vrs.demand_save_flags = ~(_uw) 0;
-  
-  do
-    {
-      /* Find the entry for this routine.  */
-      if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK)
-	{
-	  code = _URC_FAILURE;
-	  break;
-	}
-
-      /* 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.  */
-      _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp);
-
-      /* Call trace function.  */
-      if ((*trace) ((_Unwind_Context *) &saved_vrs, trace_argument) 
-	  != _URC_NO_REASON)
-	{
-	  code = _URC_FAILURE;
-	  break;
-	}
-
-      /* Call the pr to decide what to do.  */
-      code = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, 
-	 ucbp, (void *) &saved_vrs);
-    }
-  while (code != _URC_END_OF_STACK
-	 && code != _URC_FAILURE);
-
-  restore_non_core_regs (&saved_vrs);
-  return code;
-}
-
-
-/* Common implementation for ARM ABI defined personality routines.
-   ID is the index of the personality routine, other arguments are as defined
-   by __aeabi_unwind_cpp_pr{0,1,2}.  */
-
-static _Unwind_Reason_Code
-__gnu_unwind_pr_common (_Unwind_State state,
-			_Unwind_Control_Block *ucbp,
-			_Unwind_Context *context,
-			int id)
-{
-  __gnu_unwind_state uws;
-  _uw *data;
-  _uw offset;
-  _uw len;
-  _uw rtti_count;
-  int phase2_call_unexpected_after_unwind = 0;
-  int in_range = 0;
-  int forced_unwind = state & _US_FORCE_UNWIND;
-
-  state &= _US_ACTION_MASK;
-
-  data = (_uw *) ucbp->pr_cache.ehtp;
-  uws.data = *(data++);
-  uws.next = data;
-  if (id == 0)
-    {
-      uws.data <<= 8;
-      uws.words_left = 0;
-      uws.bytes_left = 3;
-    }
-  else
-    {
-      uws.words_left = (uws.data >> 16) & 0xff;
-      uws.data <<= 16;
-      uws.bytes_left = 2;
-      data += uws.words_left;
-    }
-
-  /* Restore the saved pointer.  */
-  if (state == _US_UNWIND_FRAME_RESUME)
-    data = (_uw *) ucbp->cleanup_cache.bitpattern[0];
-
-  if ((ucbp->pr_cache.additional & 1) == 0)
-    {
-      /* Process descriptors.  */
-      while (*data)
-	{
-	  _uw addr;
-	  _uw fnstart;
-
-	  if (id == 2)
-	    {
-	      len = ((EHT32 *) data)->length;
-	      offset = ((EHT32 *) data)->offset;
-	      data += 2;
-	    }
-	  else
-	    {
-	      len = ((EHT16 *) data)->length;
-	      offset = ((EHT16 *) data)->offset;
-	      data++;
-	    }
-
-	  fnstart = ucbp->pr_cache.fnstart + (offset & ~1);
-	  addr = _Unwind_GetGR (context, R_PC);
-	  in_range = (fnstart <= addr && addr < fnstart + (len & ~1));
-
-	  switch (((offset & 1) << 1) | (len & 1))
-	    {
-	    case 0:
-	      /* Cleanup.  */
-	      if (state != _US_VIRTUAL_UNWIND_FRAME
-		  && in_range)
-		{
-		  /* Cleanup in range, and we are running cleanups.  */
-		  _uw lp;
-
-		  /* Landing pad address is 31-bit pc-relative offset.  */
-		  lp = selfrel_offset31 (data);
-		  data++;
-		  /* Save the exception data pointer.  */
-		  ucbp->cleanup_cache.bitpattern[0] = (_uw) data;
-		  if (!__cxa_begin_cleanup (ucbp))
-		    return _URC_FAILURE;
-		  /* Setup the VRS to enter the landing pad.  */
-		  _Unwind_SetGR (context, R_PC, lp);
-		  return _URC_INSTALL_CONTEXT;
-		}
-	      /* Cleanup not in range, or we are in stage 1.  */
-	      data++;
-	      break;
-
-	    case 1:
-	      /* Catch handler.  */
-	      if (state == _US_VIRTUAL_UNWIND_FRAME)
-		{
-		  if (in_range)
-		    {
-		      /* Check for a barrier.  */
-		      _uw rtti;
-		      bool is_reference = (data[0] & uint32_highbit) != 0;
-		      void *matched;
-		      enum __cxa_type_match_result match_type;
-
-		      /* Check for no-throw areas.  */
-		      if (data[1] == (_uw) -2)
-			return _URC_FAILURE;
-
-		      /* The thrown object immediately follows the ECB.  */
-		      matched = (void *)(ucbp + 1);
-		      if (data[1] != (_uw) -1)
-			{
-			  /* Match a catch specification.  */
-			  rtti = _Unwind_decode_target2 ((_uw) &data[1]);
-			  match_type = __cxa_type_match (ucbp,
-							 (type_info *) rtti,
-							 is_reference,
-							 &matched);
-			}
-		      else
-			match_type = ctm_succeeded;
-
-		      if (match_type)
-			{
-			  ucbp->barrier_cache.sp =
-			    _Unwind_GetGR (context, R_SP);
-			  // ctm_succeeded_with_ptr_to_base really
-			  // means _c_t_m indirected the pointer
-			  // object.  We have to reconstruct the
-			  // additional pointer layer by using a temporary.
-			  if (match_type == ctm_succeeded_with_ptr_to_base)
-			    {
-			      ucbp->barrier_cache.bitpattern[2]
-				= (_uw) matched;
-			      ucbp->barrier_cache.bitpattern[0]
-				= (_uw) &ucbp->barrier_cache.bitpattern[2];
-			    }
-			  else
-			    ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
-			  ucbp->barrier_cache.bitpattern[1] = (_uw) data;
-			  return _URC_HANDLER_FOUND;
-			}
-		    }
-		  /* Handler out of range, or not matched.  */
-		}
-	      else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
-		       && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
-		{
-		  /* Matched a previous propagation barrier.  */
-		  _uw lp;
-
-		  /* Setup for entry to the handler.  */
-		  lp = selfrel_offset31 (data);
-		  _Unwind_SetGR (context, R_PC, lp);
-		  _Unwind_SetGR (context, 0, (_uw) ucbp);
-		  return _URC_INSTALL_CONTEXT;
-		}
-	      /* Catch handler not matched.  Advance to the next descriptor.  */
-	      data += 2;
-	      break;
-
-	    case 2:
-	      rtti_count = data[0] & 0x7fffffff;
-	      /* Exception specification.  */
-	      if (state == _US_VIRTUAL_UNWIND_FRAME)
-		{
-		  if (in_range && (!forced_unwind || !rtti_count))
-		    {
-		      /* Match against the exception specification.  */
-		      _uw i;
-		      _uw rtti;
-		      void *matched;
-
-		      for (i = 0; i < rtti_count; i++)
-			{
-			  matched = (void *)(ucbp + 1);
-			  rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]);
-			  if (__cxa_type_match (ucbp, (type_info *) rtti, 0,
-						&matched))
-			    break;
-			}
-
-		      if (i == rtti_count)
-			{
-			  /* Exception does not match the spec.  */
-			  ucbp->barrier_cache.sp =
-			    _Unwind_GetGR (context, R_SP);
-			  ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
-			  ucbp->barrier_cache.bitpattern[1] = (_uw) data;
-			  return _URC_HANDLER_FOUND;
-			}
-		    }
-		  /* Handler out of range, or exception is permitted.  */
-		}
-	      else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
-		       && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
-		{
-		  /* Matched a previous propagation barrier.  */
-		  _uw lp;
-		  /* Record the RTTI list for __cxa_call_unexpected.  */
-		  ucbp->barrier_cache.bitpattern[1] = rtti_count;
-		  ucbp->barrier_cache.bitpattern[2] = 0;
-		  ucbp->barrier_cache.bitpattern[3] = 4;
-		  ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1];
-
-		  if (data[0] & uint32_highbit)
-		    {
-		      data += rtti_count + 1;
-		      /* Setup for entry to the handler.  */
-		      lp = selfrel_offset31 (data);
-		      data++;
-		      _Unwind_SetGR (context, R_PC, lp);
-		      _Unwind_SetGR (context, 0, (_uw) ucbp);
-		      return _URC_INSTALL_CONTEXT;
-		    }
-		  else
-		    phase2_call_unexpected_after_unwind = 1;
-		}
-	      if (data[0] & uint32_highbit)
-		data++;
-	      data += rtti_count + 1;
-	      break;
-
-	    default:
-	      /* Should never happen.  */
-	      return _URC_FAILURE;
-	    }
-	  /* Finished processing this descriptor.  */
-	}
-    }
-
-  if (__gnu_unwind_execute (context, &uws) != _URC_OK)
-    return _URC_FAILURE;
-
-  if (phase2_call_unexpected_after_unwind)
-    {
-      /* Enter __cxa_unexpected as if called from the call site.  */
-      _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC));
-      _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected);
-      return _URC_INSTALL_CONTEXT;
-    }
-
-  return _URC_CONTINUE_UNWIND;
+      return 0;
+    } 
 }
 
-
 /* ABI defined personality routine entry points.  */
 
 _Unwind_Reason_Code
diff --git a/gcc/config/arm/unwind-arm.h b/gcc/config/arm/unwind-arm.h
index 1a51d8d..4300c8e 100644
--- a/gcc/config/arm/unwind-arm.h
+++ b/gcc/config/arm/unwind-arm.h
@@ -28,198 +28,18 @@ 
 #ifndef UNWIND_ARM_H
 #define UNWIND_ARM_H
 
-#define __ARM_EABI_UNWINDER__ 1
+#include "unwind-arm-common.h"
+
+#define UNWIND_STACK_REG 13
+/* Use IP as a scratch register within the personality routine.  */
+#define UNWIND_POINTER_REG 12
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-  typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
-  typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
-  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
-  typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
-  typedef _Unwind_Word _uw;
-  typedef unsigned _uw64 __attribute__((mode(__DI__)));
-  typedef unsigned _uw16 __attribute__((mode(__HI__)));
-  typedef unsigned _uw8 __attribute__((mode(__QI__)));
-
-  typedef enum
-    {
-      _URC_OK = 0,       /* operation completed successfully */
-      _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
-      _URC_END_OF_STACK = 5,
-      _URC_HANDLER_FOUND = 6,
-      _URC_INSTALL_CONTEXT = 7,
-      _URC_CONTINUE_UNWIND = 8,
-      _URC_FAILURE = 9   /* unspecified failure of some kind */
-    }
-  _Unwind_Reason_Code;
-
-  typedef enum
-    {
-      _US_VIRTUAL_UNWIND_FRAME = 0,
-      _US_UNWIND_FRAME_STARTING = 1,
-      _US_UNWIND_FRAME_RESUME = 2,
-      _US_ACTION_MASK = 3,
-      _US_FORCE_UNWIND = 8,
-      _US_END_OF_STACK = 16
-    }
-  _Unwind_State;
-
-  /* Provided only for compatibility with existing code.  */
-  typedef int _Unwind_Action;
-#define _UA_SEARCH_PHASE	1
-#define _UA_CLEANUP_PHASE	2
-#define _UA_HANDLER_FRAME	4
-#define _UA_FORCE_UNWIND	8
-#define _UA_END_OF_STACK	16
-#define _URC_NO_REASON 	_URC_OK
-
-  typedef struct _Unwind_Control_Block _Unwind_Control_Block;
-  typedef struct _Unwind_Context _Unwind_Context;
-  typedef _uw _Unwind_EHT_Header;
-
-
-  /* UCB: */
-
-  struct _Unwind_Control_Block
-    {
-      char exception_class[8];
-      void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
-      /* Unwinder cache, private fields for the unwinder's use */
-      struct
-	{
-	  _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */
-	  _uw reserved2;  /* Personality routine address */
-	  _uw reserved3;  /* Saved callsite address */
-	  _uw reserved4;  /* Forced unwind stop arg */
-	  _uw reserved5;
-	}
-      unwinder_cache;
-      /* Propagation barrier cache (valid after phase 1): */
-      struct
-	{
-	  _uw sp;
-	  _uw bitpattern[5];
-	}
-      barrier_cache;
-      /* Cleanup cache (preserved over cleanup): */
-      struct
-	{
-	  _uw bitpattern[4];
-	}
-      cleanup_cache;
-      /* Pr cache (for pr's benefit): */
-      struct
-	{
-	  _uw fnstart;			/* function start address */
-	  _Unwind_EHT_Header *ehtp;	/* pointer to EHT entry header word */
-	  _uw additional;		/* additional data */
-	  _uw reserved1;
-	}
-      pr_cache;
-      long long int :0;	/* Force alignment to 8-byte boundary */
-    };
-
-  /* Virtual Register Set*/
-
-  typedef enum
-    {
-      _UVRSC_CORE = 0,      /* integer register */
-      _UVRSC_VFP = 1,       /* vfp */
-      _UVRSC_FPA = 2,       /* fpa */
-      _UVRSC_WMMXD = 3,     /* Intel WMMX data register */
-      _UVRSC_WMMXC = 4      /* Intel WMMX control register */
-    }
-  _Unwind_VRS_RegClass;
-
-  typedef enum
-    {
-      _UVRSD_UINT32 = 0,
-      _UVRSD_VFPX = 1,
-      _UVRSD_FPAX = 2,
-      _UVRSD_UINT64 = 3,
-      _UVRSD_FLOAT = 4,
-      _UVRSD_DOUBLE = 5
-    }
-  _Unwind_VRS_DataRepresentation;
-
-  typedef enum
-    {
-      _UVRSR_OK = 0,
-      _UVRSR_NOT_IMPLEMENTED = 1,
-      _UVRSR_FAILED = 2
-    }
-  _Unwind_VRS_Result;
-
-  /* Frame unwinding state.  */
-  typedef struct
-    {
-      /* The current word (bytes packed msb first).  */
-      _uw data;
-      /* Pointer to the next word of data.  */
-      _uw *next;
-      /* The number of bytes left in this word.  */
-      _uw8 bytes_left;
-      /* The number of words pointed to by ptr.  */
-      _uw8 words_left;
-    }
-  __gnu_unwind_state;
-
-  typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State,
-      _Unwind_Control_Block *, _Unwind_Context *);
-
-  _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
-                                     _uw, _Unwind_VRS_DataRepresentation,
-                                     void *);
-
-  _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
-                                     _uw, _Unwind_VRS_DataRepresentation,
-                                     void *);
-
-  _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
-                                     _uw, _Unwind_VRS_DataRepresentation);
-
-
-  /* Support functions for the PR.  */
-#define _Unwind_Exception _Unwind_Control_Block
-  typedef char _Unwind_Exception_Class[8];
-
-  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
-  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
-
-  /* These two should never be used.  */
-  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
-  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
-
-  /* Interface functions: */
-  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
-  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
-  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
-
-  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
-       (int, _Unwind_Action, _Unwind_Exception_Class,
-	_Unwind_Control_Block *, struct _Unwind_Context *, void *);
-  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
-					    _Unwind_Stop_Fn, void *);
-  /* @@@ Use unwind data to perform a stack backtrace.  The trace callback
-     is called for every stack frame in the call chain, but no cleanup
-     actions are performed.  */
-  typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
-  _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn,
-					void*);
-
-  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
-  void _Unwind_Complete(_Unwind_Control_Block *ucbp);
-  void _Unwind_DeleteException (_Unwind_Exception *);
-
-  _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
-					  _Unwind_Context *);
-  _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *,
-					    __gnu_unwind_state *);
-
   /* Decode an R_ARM_TARGET2 relocation.  */
   static inline _Unwind_Word
-  _Unwind_decode_target2 (_Unwind_Word ptr)
+  _Unwind_decode_typeinfo_ptr (_Unwind_Word base, _Unwind_Word ptr)
     {
       _Unwind_Word tmp;
 
@@ -230,50 +50,32 @@  extern "C" {
 
 #if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__)
       /* Pc-relative indirect.  */
+#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | DW_EH_PE_indirect)
       tmp += ptr;
       tmp = *(_Unwind_Word *) tmp;
 #elif defined(__symbian__) || defined(__uClinux__)
+#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_absptr)
       /* Absolute pointer.  Nothing more to do.  */
 #else
+#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel)
       /* Pc-relative pointer.  */
       tmp += ptr;
 #endif
       return tmp;
     }
 
-  static inline _Unwind_Word
-  _Unwind_GetGR (_Unwind_Context *context, int regno)
+  static inline _Unwind_Reason_Code
+  __gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
     {
-      _uw val;
-      _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
-      return val;
+      return _URC_FAILURE;
     }
-
   /* Return the address of the instruction, not the actual IP value.  */
 #define _Unwind_GetIP(context) \
   (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
 
-#define _Unwind_GetIPInfo(context, ip_before_insn) \
-  (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
-
-  static inline void
-  _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
-    {
-      _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
-    }
-
-  /* The dwarf unwinder doesn't understand arm/thumb state.  We assume the
-     landing pad uses the same instruction set as the call site.  */
 #define _Unwind_SetIP(context, val) \
   _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
 
-/* leb128 type numbers have a potentially unlimited size.
-   The target of the following definitions of _sleb128_t and _uleb128_t
-   is to have efficient data types large enough to hold the leb128 type
-   numbers used in the unwind code.  */
-typedef long _sleb128_t;
-typedef unsigned long _uleb128_t;
-
 #ifdef __cplusplus
 }   /* extern "C" */
 #endif
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
index deb2f53..75d9e5a 100644
--- a/gcc/config/c6x/c6x.c
+++ b/gcc/config/c6x/c6x.c
@@ -379,12 +379,19 @@  c6x_output_file_unwind (FILE * f)
   if (done_cfi_sections)
     return;
 
-  /* Output a .cfi_sections directive if we aren't
-     already doing so for debug info.  */
-  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
-	    && dwarf2out_do_frame ())
+  /* Output a .cfi_sections directive.  */
+  if (dwarf2out_do_frame ())
     {
-      asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
+      if (flag_unwind_tables || flag_exceptions)
+	{
+	  if (write_symbols == DWARF2_DEBUG
+	      || write_symbols == VMS_AND_DWARF2_DEBUG)
+	    asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
+	  else
+	    asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
+	}
+      else
+	asm_fprintf (f, "\t.cfi_sections .debug_frame\n");
       done_cfi_sections = true;
     }
 }
@@ -5423,6 +5430,18 @@  c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
 
   gcc_unreachable ();
 }
+
+/* Target unwind frame info is generated from dwarf CFI directives, so
+   always output dwarf2 unwind info.  */
+
+static enum unwind_info_type
+c6x_debug_unwind_info (void)
+{
+  if (flag_unwind_tables || flag_exceptions)
+    return UI_DWARF2;
+
+  return default_debug_unwind_info ();
+}
 
 /* Target Structure.  */
 
@@ -5557,6 +5576,13 @@  c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
 #undef TARGET_ASM_TTYPE
 #define TARGET_ASM_TTYPE c6x_output_ttype
 
+/* The C6x ABI follows the ARM EABI exception handling rules.  */
+#undef TARGET_ARM_EABI_UNWINDER
+#define TARGET_ARM_EABI_UNWINDER true
+
+#undef TARGET_DEBUG_UNWIND_INFO
+#define TARGET_DEBUG_UNWIND_INFO  c6x_debug_unwind_info
+
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
 
diff --git a/gcc/config/c6x/c6x.h b/gcc/config/c6x/c6x.h
index 5d34d59..36a5c3d 100644
--- a/gcc/config/c6x/c6x.h
+++ b/gcc/config/c6x/c6x.h
@@ -329,6 +329,7 @@  enum reg_class
 /* Before the prologue, the return address is in the B3 register.  */
 #define RETURN_ADDR_REGNO REG_B3
 #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, RETURN_ADDR_REGNO)
+#define DWARF_FRAME_RETURN_COLUMN	DWARF_FRAME_REGNUM (RETURN_ADDR_REGNO)
 
 #define RETURN_ADDR_RTX(COUNT, FRAME) c6x_return_addr_rtx (COUNT)
 
@@ -459,8 +460,6 @@  struct GTY(()) machine_function
 #define TARG_VEC_PERMUTE_COST        1
 #endif
 
-/* Exception handling.  */
-#define TARGET_EXTRA_CFI_SECTION(unwind) ((unwind) ? ".c6xabi.exidx" : NULL)
 /* ttype entries (the only interesting data references used) are
    sb-relative got-indirect (aka .ehtype).  */
 #define ASM_PREFERRED_EH_DATA_FORMAT(code, data) \
diff --git a/gcc/config/c6x/libunwind.S b/gcc/config/c6x/libunwind.S
new file mode 100644
index 0000000..d37ea57
--- /dev/null
+++ b/gcc/config/c6x/libunwind.S
@@ -0,0 +1,133 @@ 
+.text
+.macro do_call fn
+#ifdef _TMS320C6400_PLUS
+	callp	.s2	(\fn), B3
+#elif defined(_TMS320C6400)
+	call	.s2	(\fn)
+	addkpc	.s2	9f, B3, 0
+	nop		4
+9f:
+#else
+	call	.s2	(\fn)
+	mhkl	.s2	9f, B3
+	mhkh	.s2	9f, B3
+	nop		3
+9f:
+#endif
+.endm
+.align 2
+.global restore_core_regs
+.type restore_core_regs, STT_FUNC
+restore_core_regs:
+	mv	.s2x	A4, B4
+	ldw	.d1t1	*+A4[0], A0
+	|| ldw	.d2t2	*++B4[16], B0
+	ldw	.d1t1	*+A4[1], A1
+	|| ldw	.d2t2	*+B4[1], B1
+	ldw	.d1t1	*+A4[2], A2
+	|| ldw	.d2t2	*+B4[2], B2
+	ldw	.d1t1	*+A4[3], A3
+	|| ldw	.d2t2	*+B4[3], B3
+	;; Base registers are loaded later
+	ldw	.d1t1	*+A4[5], A5
+	|| ldw	.d2t2	*+B4[5], B5
+	ldw	.d1t1	*+A4[6], A6
+	|| ldw	.d2t2	*+B4[6], B6
+	ldw	.d1t1	*+A4[7], A7
+	|| ldw	.d2t2	*+B4[7], B7
+	ldw	.d1t1	*+A4[8], A8
+	|| ldw	.d2t2	*+B4[8], B8
+	ldw	.d1t1	*+A4[9], A9
+	|| ldw	.d2t2	*+B4[9], B9
+	;; load PC into B10 so that it is ready for the branch
+	ldw	.d2t2	*+B4[16], B10
+	ldw	.d1t1	*+A4[11], A11
+	|| ldw	.d2t2	*+B4[11], B11
+	ldw	.d1t1	*+A4[12], A12
+	|| ldw	.d2t2	*+B4[12], B12
+	ldw	.d1t1	*+A4[13], A13
+	|| ldw	.d2t2	*+B4[13], B13
+	ldw	.d1t1	*+A4[14], A14
+	|| ldw	.d2t2	*+B4[14], B14
+	;; Loads have 4 delay slots.  Take advantage of this to restore the
+	;; scratch registers and stack pointer before the base registers
+	;; disappear.  We also need to make sure no interrupts occur,
+	;; so put the whole thing in the delay slots of a dummy branch
+	;; We can not move the ret earlier as that would cause it to occur
+	;; before the last load completes
+	b	.s1	(1f)
+	ldw	.d1t1	*+A4[4], A4
+	|| ldw	.d2t2	*+B4[4], B4
+	ldw	.d1t1	*+A4[15], A15
+	|| ldw	.d2t2	*+B4[15], B15
+	ret	.s2	B10
+	ldw	.d1t1	*+A4[10], A10
+	|| ldw	.d2t2	*+B4[10], B10
+	nop		1
+1:
+	nop		3
+.size restore_core_regs, . - restore_core_regs
+
+.macro UNWIND_WRAPPER name argreg argside
+.global \name
+.type \name, STT_FUNC
+\name:
+	# Create saved register state: flags,A0-A15,B0-B15,PC = 136 bytes.
+	# Plus 4 (rounded to 8) for saving return.
+	addk	.s2	-144, B15
+	stw	.d2t1	A0, *+B15[2]
+	stw	.d2t1	A1, *+B15[3]
+	stw	.d2t1	A2, *+B15[4]
+	stw	.d2t1	A3, *+B15[5]
+	stw	.d2t1	A4, *+B15[6]
+	stw	.d2t1	A5, *+B15[7]
+	stw	.d2t1	A6, *+B15[8]
+	stw	.d2t1	A7, *+B15[9]
+	stw	.d2t1	A8, *+B15[10]
+	stw	.d2t1	A9, *+B15[11]
+	stw	.d2t1	A10, *+B15[12]
+	stw	.d2t1	A11, *+B15[13]
+	stw	.d2t1	A12, *+B15[14]
+	stw	.d2t1	A13, *+B15[15]
+	stw	.d2t1	A14, *+B15[16]
+	stw	.d2t1	A15, *+B15[17]
+	mv	.s1x	B15, A0
+	addk	.s1	144, A0
+	stw	.d2t2	B0, *+B15[18]
+	stw	.d2t2	B1, *+B15[19]
+	stw	.d2t2	B2, *+B15[20]
+	stw	.d2t2	B3, *+B15[21]
+	stw	.d2t2	B4, *+B15[22]
+	stw	.d2t2	B5, *+B15[23]
+	stw	.d2t2	B6, *+B15[24]
+	stw	.d2t2	B7, *+B15[25]
+	stw	.d2t2	B8, *+B15[26]
+	stw	.d2t2	B9, *+B15[27]
+	stw	.d2t2	B10, *+B15[28]
+	stw	.d2t2	B11, *+B15[29]
+	stw	.d2t2	B12, *+B15[30]
+	stw	.d2t2	B13, *+B15[31]
+	stw	.d2t2	B14, *+B15[32]
+	stw	.d2t1	A0, *+B15[33]
+	stw	.d2t1	A0, *+B15[34]
+	# Zero demand saved flags
+	mvk	.s1	0, A0
+	stw	.d2t1	A0, *+B15[1]
+	# Save return address, setup additional argument and call fucntion
+	stw	.d2t2	B3, *+B15[35]
+	add	.d\argside	B15, 4, \argreg
+	do_call	__gnu\name
+	# Restore stack and return
+	ldw	.d2t2	*+B15[35], B3
+	addk	.s2	144, B15
+	nop		3
+	ret	.s2	B3
+	nop		5
+.size \name, . - \name
+.endm
+
+UNWIND_WRAPPER _Unwind_RaiseException B4 2
+UNWIND_WRAPPER _Unwind_Resume B4 2
+UNWIND_WRAPPER _Unwind_Resume_or_Rethrow B4 2
+UNWIND_WRAPPER _Unwind_ForcedUnwind B6 2
+UNWIND_WRAPPER _Unwind_Backtrace A6 1x
diff --git a/gcc/config/c6x/pr-support.c b/gcc/config/c6x/pr-support.c
new file mode 100644
index 0000000..6375013
--- /dev/null
+++ b/gcc/config/c6x/pr-support.c
@@ -0,0 +1,534 @@ 
+/* C6X ABI compliant unwinding routines
+   Copyright (C) 2011 Free Software Foundation, Inc.
+ 
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "unwind.h"
+
+/* We add a prototype for abort here to avoid creating a dependency on
+   target headers.  */
+extern void abort (void);
+
+typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
+
+/* Misc constants.  */
+#define R_A0 0
+#define R_A1 1
+#define R_A2 2
+#define R_A3 3
+#define R_A4 4
+#define R_A5 5
+#define R_A6 6
+#define R_A7 7
+#define R_A8 8
+#define R_A9 9
+#define R_A10 10
+#define R_A11 11
+#define R_A12 12
+#define R_A13 13
+#define R_A14 14
+#define R_A15 15
+#define R_B0 16
+#define R_B1 17
+#define R_B2 18
+#define R_B3 19
+#define R_B4 20
+#define R_B5 21
+#define R_B6 22
+#define R_B7 23
+#define R_B8 24
+#define R_B9 25
+#define R_B10 26
+#define R_B11 27
+#define R_B12 28
+#define R_B13 29
+#define R_B14 30
+#define R_B15 31
+
+#define R_SP R_B15
+#define R_PC 33
+
+#define uint32_highbit (((_uw) 1) << 31)
+
+void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
+
+/* Unwind descriptors.  */
+
+typedef struct
+{
+  _uw16 length;
+  _uw16 offset;
+} EHT16;
+
+typedef struct
+{
+  _uw length;
+  _uw offset;
+} EHT32;
+
+/* Calculate the address encoded by a 31-bit self-relative offset at address
+   P.  Copy of routine in unwind-arm.c.  */
+
+static inline _uw
+selfrel_offset31 (const _uw *p)
+{
+  _uw offset;
+
+  offset = *p;
+  /* Sign extend to 32 bits.  */
+  if (offset & (1 << 30))
+    offset |= 1u << 31;
+
+  return offset + (_uw) p;
+}
+
+
+/* Personality routine helper functions.  */
+
+#define CODE_FINISH (0xe7)
+
+/* Return the next byte of unwinding information, or CODE_FINISH if there is
+   no data remaining.  */
+static inline _uw8
+next_unwind_byte (__gnu_unwind_state * uws)
+{
+  _uw8 b;
+
+  if (uws->bytes_left == 0)
+    {
+      /* Load another word */
+      if (uws->words_left == 0)
+	return CODE_FINISH; /* Nothing left.  */
+      uws->words_left--;
+      uws->data = *(uws->next++);
+      uws->bytes_left = 3;
+    }
+  else
+    uws->bytes_left--;
+
+  /* Extract the most significant byte.  */
+  b = (uws->data >> 24) & 0xff;
+  uws->data <<= 8;
+  return b;
+}
+
+static void
+unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
+{
+#ifdef _BIG_ENDIAN
+  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr + 1);
+  _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr);
+#else
+  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr);
+  _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr + 1);
+#endif
+}
+
+static const int
+unwind_frame_regs[13] = 
+{
+  R_A15, R_B15, R_B14, R_B13, R_B12, R_B11, R_B10, R_B3,
+  R_A14, R_A13, R_A12, R_A11, R_A10
+};
+
+static void
+pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
+{
+  int size;
+  _uw test;
+  int i;
+  int regno;
+  int regno2;
+  int nregs;
+
+  size = 0;
+  nregs = __builtin_popcount (mask);
+  for (i = 0; i < 13; i++)
+    {
+      test = 1 << i;
+      if ((mask & test) == 0)
+	continue;
+
+      regno = unwind_frame_regs[12 - i];
+      /* The last slot is a sigle word, so cannot store a register pair.  */
+      if (nregs > 2)
+	regno2 = unwind_frame_regs[13 - i];
+      else
+	regno2 = 0xff;
+
+      if ((mask & (test << 1)) != 0 && regno2 == regno + 1 && (regno & 1) == 0)
+	{
+	  i++;
+	  nregs--;
+	}
+
+      nregs--;
+      size += 2;
+    }
+
+  if (!inc_sp)
+    ptr -= size;
+
+  /* SP points just past the end of the stack.  */
+  ptr += 2;
+  nregs = __builtin_popcount (mask);
+  for (i = 0; i < 13; i++)
+    {
+      test = 1 << i;
+      if ((mask & test) == 0)
+	continue;
+
+      regno = unwind_frame_regs[12 - i];
+      if (nregs > 2)
+	regno2 = unwind_frame_regs[13 - i];
+      else
+	regno2 = 0xff;
+
+      if ((mask & (test << 1)) != 0 && regno2 == regno + 1 && (regno & 1) == 0)
+	{
+	  /* Register pair.  */
+	  unwind_restore_pair (context, regno, ptr);
+	  i++;
+	  nregs--;
+	}
+      else
+	{
+	  /* Single register with padding.  */
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
+	}
+
+      nregs--;
+      ptr += 2;
+    }
+
+  ptr -= 2;
+  if ((mask & (1 << 11)) == 0)
+    _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+}
+
+static void
+pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
+{
+  int i;
+  int regno;
+  int nregs;
+
+  nregs = __builtin_popcount (mask);
+
+  if (!inc_sp)
+    ptr -= nregs;
+  else if (nregs & 1)
+    ptr++;
+
+  ptr++;
+  for (i = 0; i < 13; i++)
+    {
+      if ((mask & (1 << i)) == 0)
+	continue;
+      regno = unwind_frame_regs[12 - i];
+      if (i < 12 && unwind_frame_regs[13 - i] == (regno + 1)
+	  && (mask & (1 << (i + 1))) != 0
+	  && (((_uw)ptr) & 4) == 0
+	  && (regno & 1) == 0)
+	{
+	  unwind_restore_pair (context, regno, ptr);
+	  i++;
+	  ptr += 2;
+	}
+      else
+	{
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
+			   ptr);
+	  ptr++;
+	}
+    }
+
+  ptr--;
+  if ((mask & (1 << 11)) == 0)
+    _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+}
+
+/* Unwind a 24-bit encoded frame.  */
+_Unwind_Reason_Code
+__gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
+{
+  _uw offset;
+  _uw mask;
+  _uw *ptr;
+  _uw tmp;
+
+  mask = (data >> 4) & 0x1fff;
+
+  offset = (data >> 17) & 0x7f;
+  if (offset == 0x7f)
+    _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
+  else
+    {
+      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+      ptr += offset * 2;
+    }
+
+
+  if (compact)
+    pop_compact_frame (context, mask, ptr, offset != 0x7f);
+  else
+    pop_frame (context, mask, ptr, offset != 0x7f);
+
+  _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
+		   _UVRSD_UINT32, &tmp);
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
+
+  return _URC_OK;
+}
+
+static void
+unwind_pop_rts (_Unwind_Context * context)
+{
+  _uw *ptr;
+
+  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+#ifdef _BIG_ENDIAN
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 1);
+#else
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 2);
+#endif
+  ptr += 3;
+  unwind_restore_pair (context, R_A10, ptr);
+  ptr += 2;
+  unwind_restore_pair (context, R_B10, ptr);
+  ptr += 2;
+  unwind_restore_pair (context, R_A12, ptr);
+  ptr += 2;
+  unwind_restore_pair (context, R_B12, ptr);
+  ptr += 2;
+  unwind_restore_pair (context, R_A14, ptr);
+  ptr += 2;
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B14, _UVRSD_UINT32, ptr);
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+  /* PC will be set by implicit RETURN opcode.  */
+}
+
+/* Execute the unwinding instructions described by UWS.  */
+_Unwind_Reason_Code
+__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
+{
+  _uw op;
+  int inc_sp;
+  _uw reg;
+  _uw *ptr;
+
+  inc_sp = 1;
+  for (;;)
+    {
+      op = next_unwind_byte (uws);
+      if (op == CODE_FINISH)
+	{
+	  /* Drop out of the loop.  */
+	  break;
+	}
+      if ((op & 0xc0) == 0)
+	{
+	  /* sp += (imm6 << 3) + 8.  */
+	  _uw offset;
+
+	  offset = ((op & 0x3f) << 3) + 8;
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+	  reg += offset;
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+	  continue;
+	}
+
+      if (op == 0xd2)
+	{
+	  /* vsp = vsp + 0x204 + (uleb128 << 2).  */
+	  int shift;
+
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+	  op = next_unwind_byte (uws);
+	  shift = 3;
+	  while (op & 0x80)
+	    {
+	      reg += ((op & 0x7f) << shift);
+	      shift += 7;
+	      op = next_unwind_byte (uws);
+	    }
+	  reg += ((op & 0x7f) << shift) + 0x408;
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+	  continue;
+	}
+
+      if ((op & 0xe0) == 0x80)
+	{
+	  /* POP bitmask */
+	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
+
+	  if (mask == 0)
+	    {
+	      /* CANTUNWIND */
+	      return _URC_FAILURE;
+	    }
+
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+	  pop_frame (context, mask, ptr, inc_sp);
+	  continue;
+	}
+
+      if ((op & 0xe0) == 0xa0)
+	{
+	  /* POP bitmask (compact) */
+	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
+
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+	  pop_compact_frame (context, mask, ptr, inc_sp);
+	  continue;
+	}
+
+      if ((op & 0xf0) == 0xc0)
+	{
+	  /* POP registers */
+	  int nregs = op & 0xf;
+
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
+	  while (nregs > 0)
+	    {
+	      op = next_unwind_byte (uws);
+	      if ((op >> 4) != 0xf)
+		{
+		  reg = unwind_frame_regs[op >> 4];
+		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
+				   ptr);
+		  nregs--;
+		}
+	      ptr--;
+	      if ((op & 0xf) != 0xf)
+		{
+		  reg = unwind_frame_regs[op & 0xf];
+		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
+				   ptr);
+		  nregs--;
+		}
+	      ptr--;
+	    }
+
+	  continue;
+	}
+
+      if (op == 0xd0)
+	{
+	  /* MV FP, SP */
+	  inc_sp = 0;
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &reg);
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+	  continue;
+	}
+
+      if (op == 0xd1)
+	{
+	  /* __cx6abi_pop_rts */
+	  unwind_pop_rts (context);
+	  break;
+	}
+
+      if ((op & 0xf0) == 0xe0)
+	{
+	  /* B3 = reg.  RETURN case alreadh handled above.  */
+	  int regno = unwind_frame_regs[op & 0xf];
+
+	  _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &reg);
+	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
+	  continue;
+	}
+      
+      /* Reserved.  */
+      return _URC_FAILURE;
+    }
+
+  /* Implicit RETURN.  */
+  _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
+  _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &reg);
+  return _URC_OK;
+}
+
+
+/* Execute the unwinding instructions associated with a frame.  UCBP and
+   CONTEXT are the current exception object and virtual CPU state
+   respectively.  */
+
+_Unwind_Reason_Code
+__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
+{
+  _uw *ptr;
+  __gnu_unwind_state uws;
+
+  ptr = (_uw *) ucbp->pr_cache.ehtp;
+  /* Skip over the personality routine address.  */
+  ptr++;
+  /* Setup the unwinder state.  */
+  uws.data = (*ptr) << 8;
+  uws.next = ptr + 1;
+  uws.bytes_left = 3;
+  uws.words_left = ((*ptr) >> 24) & 0xff;
+
+  return __gnu_unwind_execute (context, &uws);
+}
+
+/* Data segment base pointer corresponding to the function catching
+   the exception.  */
+
+_Unwind_Ptr
+_Unwind_GetDataRelBase (_Unwind_Context *context)
+{
+  return _Unwind_GetGR (context, R_B14);
+}
+
+/* This should never be used.  */
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
+{
+  abort ();
+}
+
+/* Only used by gcc personality routines, so can rely on a value they hid
+   there earlier.  */
+_Unwind_Ptr
+_Unwind_GetRegionStart (_Unwind_Context *context)
+{
+  _Unwind_Control_Block *ucbp;
+ 
+  ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
+  return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (_Unwind_Context *context)
+{
+  _Unwind_Control_Block *ucbp;
+  _uw *ptr;
+ 
+  ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
+  ptr = (_uw *) ucbp->pr_cache.ehtp;
+  /* Skip the personality routine address.  */
+  ptr++;
+  /* Skip the unwind opcodes.  */
+  ptr += (((*ptr) >> 24) & 0xff) + 1;
+
+  return ptr;
+}
diff --git a/gcc/config/c6x/t-c6x-elf b/gcc/config/c6x/t-c6x-elf
index ed28642..a03e84e 100644
--- a/gcc/config/c6x/t-c6x-elf
+++ b/gcc/config/c6x/t-c6x-elf
@@ -24,6 +24,11 @@  LIB1ASMFUNCS += _strasgi _strasgi_64plus _clzsi2 _clzdi2 _clz
 LIB1ASMFUNCS += _push_rts _pop_rts _call_stub
 
 LIB2FUNCS_EXCLUDE = _cmpdi2 _ucmpdi2 _gcc_bcmp _eprintf _clzsi _clzdi
+LIB2ADDEH = $(srcdir)/config/c6x/unwind-c6x.c \
+  $(srcdir)/config/c6x/libunwind.S \
+  $(srcdir)/config/c6x/pr-support.c $(srcdir)/unwind-c.c
+UNWIND_H = $(srcdir)/config/c6x/unwind-c6x.h
+EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
 
 LIB2FUNCS_EXTRA = $(srcdir)/config/c6x/gef.c \
                   $(srcdir)/config/c6x/gtf.c \
diff --git a/gcc/config/c6x/unwind-c6x.c b/gcc/config/c6x/unwind-c6x.c
new file mode 100644
index 0000000..da2f79b
--- /dev/null
+++ b/gcc/config/c6x/unwind-c6x.c
@@ -0,0 +1,224 @@ 
+/* C6X EABI compliant unwinding routines.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "unwind.h"
+
+/* Misc constants.  */
+#define NUM_SAVED_REGS 32
+#define R_B0 16
+#define R_B3 (R_B0 + 3)
+#define R_B15 (R_B0 + 15)
+#define R_SP R_B15
+#define R_LR R_B3
+#define R_PC 33
+
+#define VRS_PC(vrs) ((vrs)->core.pc)
+#define VRS_SP(vrs) ((vrs)->core.reg[R_SP])
+#define VRS_RETURN(vrs) ((vrs)->core.reg[R_B3])
+
+struct core_regs
+{
+  _uw reg[NUM_SAVED_REGS];
+  _uw pc;
+};
+
+typedef struct
+{
+  /* The first fields must be the same as a phase2_vrs.  */
+  _uw demand_save_flags; /* Currently always zero.  */
+  struct core_regs core;
+  _uw prev_sp; /* Only valid during forced unwinding.  */
+} phase1_vrs;
+
+/* This must match the structure created by the assembly wrappers.  */
+typedef struct
+{
+  _uw demand_save_flags;
+  struct core_regs core;
+} phase2_vrs;
+
+/* Coprocessor register state manipulation functions.  */
+
+/* Restore coprocessor state after phase1 unwinding.  */
+static void
+restore_non_core_regs (phase1_vrs * vrs __attribute__((unused)))
+{
+}
+
+#include "unwind-arm-common.inc"
+
+/* ABI defined personality routines.  */
+extern _Unwind_Reason_Code __c6xabi_unwind_cpp_pr0 (_Unwind_State,
+    _Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak));
+extern _Unwind_Reason_Code __c6xabi_unwind_cpp_pr1 (_Unwind_State,
+    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+extern _Unwind_Reason_Code __c6xabi_unwind_cpp_pr2 (_Unwind_State,
+    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+extern _Unwind_Reason_Code __c6xabi_unwind_cpp_pr3 (_Unwind_State,
+    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+extern _Unwind_Reason_Code __c6xabi_unwind_cpp_pr4 (_Unwind_State,
+    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+
+/* ABI defined routine to store a virtual register to memory.  */
+
+_Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context,
+				    _Unwind_VRS_RegClass regclass,
+				    _uw regno,
+				    _Unwind_VRS_DataRepresentation representation,
+				    void *valuep)
+{
+  phase1_vrs *vrs = (phase1_vrs *) context;
+
+  switch (regclass)
+    {
+    case _UVRSC_CORE:
+      if (representation != _UVRSD_UINT32)
+	return _UVRSR_FAILED;
+      if (regno == R_PC)
+	{
+	  *(_uw *) valuep = vrs->core.pc;
+	  return _UVRSR_OK;
+	}
+      if (regno >= NUM_SAVED_REGS)
+	return _UVRSR_FAILED;
+      *(_uw *) valuep = vrs->core.reg[regno];
+      return _UVRSR_OK;
+
+    default:
+      return _UVRSR_FAILED;
+    }
+}
+
+
+/* ABI defined function to load a virtual register from memory.  */
+
+_Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context,
+				    _Unwind_VRS_RegClass regclass,
+				    _uw regno,
+				    _Unwind_VRS_DataRepresentation representation,
+				    void *valuep)
+{
+  phase1_vrs *vrs = (phase1_vrs *) context;
+
+  switch (regclass)
+    {
+    case _UVRSC_CORE:
+      if (representation != _UVRSD_UINT32)
+	return _UVRSR_FAILED;
+      if (regno == R_PC)
+	{
+	  vrs->core.pc = *(_uw *) valuep;
+	  return _UVRSR_OK;
+	}
+      if (regno >= NUM_SAVED_REGS)
+	return _UVRSR_FAILED;
+
+      vrs->core.reg[regno] = *(_uw *) valuep;
+      return _UVRSR_OK;
+
+    default:
+      return _UVRSR_FAILED;
+    }
+}
+
+
+/* Core unwinding functions.  */
+
+/* Calculate the address encoded by a 31-bit self-relative offset at address
+   P.  */
+static inline _uw
+selfrel_offset31 (const _uw *p)
+{
+  _uw offset;
+
+  offset = *p << 1;
+  return offset + (_uw) p;
+}
+
+
+static _uw
+__gnu_unwind_get_pr_addr (int idx)
+{
+  switch (idx)
+    {
+    case 0:
+      return (_uw) &__c6xabi_unwind_cpp_pr0;
+
+    case 1:
+      return (_uw) &__c6xabi_unwind_cpp_pr1;
+
+    case 2:
+      return (_uw) &__c6xabi_unwind_cpp_pr2;
+
+    case 3:
+      return (_uw) &__c6xabi_unwind_cpp_pr3;
+
+    case 4:
+      return (_uw) &__c6xabi_unwind_cpp_pr4;
+
+    default:
+       return 0;
+    }
+}
+
+
+/* ABI defined personality routine entry points.  */
+
+_Unwind_Reason_Code
+__c6xabi_unwind_cpp_pr0 (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context)
+{
+  return __gnu_unwind_pr_common (state, ucbp, context, 0);
+}
+
+_Unwind_Reason_Code
+__c6xabi_unwind_cpp_pr1 (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context)
+{
+  return __gnu_unwind_pr_common (state, ucbp, context, 1);
+}
+
+_Unwind_Reason_Code
+__c6xabi_unwind_cpp_pr2 (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context)
+{
+  return __gnu_unwind_pr_common (state, ucbp, context, 2);
+}
+
+_Unwind_Reason_Code
+__c6xabi_unwind_cpp_pr3 (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context)
+{
+  return __gnu_unwind_pr_common (state, ucbp, context, 3);
+}
+
+_Unwind_Reason_Code
+__c6xabi_unwind_cpp_pr4 (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context)
+{
+  return __gnu_unwind_pr_common (state, ucbp, context, 4);
+}
diff --git a/gcc/config/c6x/unwind-c6x.h b/gcc/config/c6x/unwind-c6x.h
new file mode 100644
index 0000000..3d6c73e
--- /dev/null
+++ b/gcc/config/c6x/unwind-c6x.h
@@ -0,0 +1,71 @@ 
+/* Header file for the C6X EABI unwinder
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Language-independent unwinder header public defines.  This contains both
+   ABI defined objects, and GNU support routines.  */
+
+#ifndef UNWIND_C6X_H
+#define UNWIND_C6X_H
+
+/* Not really the ARM EABI, but pretty close.  */
+#include "unwind-arm-common.h"
+
+#define UNWIND_STACK_REG 31
+/* Use A0 as a scratch register within the personality routine.  */
+#define UNWIND_POINTER_REG 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  _Unwind_Reason_Code __gnu_unwind_24bit (_Unwind_Context *, _uw, int);
+
+  /* Decode an EH table reference to a typeinfo object.  */
+  static inline _Unwind_Word
+  _Unwind_decode_typeinfo_ptr (_Unwind_Ptr base, _Unwind_Word ptr)
+    {
+      _Unwind_Word tmp;
+
+      tmp = *(_Unwind_Word *) ptr;
+      /* Zero values are always NULL.  */
+      if (!tmp)
+	return 0;
+
+      /* SB-relative indirect.  Propagate the bottom 2 bits, which can
+	 contain referenceness information in gnu unwinding tables.  */
+      tmp += base;
+      tmp = *(_Unwind_Word *) (tmp & ~(_Unwind_Word)3) | (tmp & 3);
+      return tmp;
+    }
+
+#define _Unwind_GetIP(context) \
+  (_Unwind_GetGR (context, 33))
+
+
+#define _Unwind_SetIP(context, val) \
+  _Unwind_SetGR (context, 33, val)
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+#endif /* defined UNWIND_ARM_H */
diff --git a/gcc/ginclude/unwind-arm-common.h b/gcc/ginclude/unwind-arm-common.h
new file mode 100644
index 0000000..9587270
--- /dev/null
+++ b/gcc/ginclude/unwind-arm-common.h
@@ -0,0 +1,251 @@ 
+/* Header file for the ARM EABI and C6X unwinders
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
+   Free Software Foundation, Inc.
+   Contributed by Paul Brook
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Language-independent unwinder header public defines.  This contains both
+   ABI defined objects, and GNU support routines.  */
+
+#ifndef UNWIND_ARM_COMMON_H
+#define UNWIND_ARM_COMMON_H
+
+#define __ARM_EABI_UNWINDER__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+  typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+  typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+  typedef _Unwind_Word _uw;
+  typedef unsigned _uw64 __attribute__((mode(__DI__)));
+  typedef unsigned _uw16 __attribute__((mode(__HI__)));
+  typedef unsigned _uw8 __attribute__((mode(__QI__)));
+
+  typedef enum
+    {
+      _URC_OK = 0,       /* operation completed successfully */
+      _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+      _URC_END_OF_STACK = 5,
+      _URC_HANDLER_FOUND = 6,
+      _URC_INSTALL_CONTEXT = 7,
+      _URC_CONTINUE_UNWIND = 8,
+      _URC_FAILURE = 9   /* unspecified failure of some kind */
+    }
+  _Unwind_Reason_Code;
+
+  typedef enum
+    {
+      _US_VIRTUAL_UNWIND_FRAME = 0,
+      _US_UNWIND_FRAME_STARTING = 1,
+      _US_UNWIND_FRAME_RESUME = 2,
+      _US_ACTION_MASK = 3,
+      _US_FORCE_UNWIND = 8,
+      _US_END_OF_STACK = 16
+    }
+  _Unwind_State;
+
+  /* Provided only for compatibility with existing code.  */
+  typedef int _Unwind_Action;
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+#define _UA_END_OF_STACK	16
+#define _URC_NO_REASON 	_URC_OK
+
+  typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+  typedef struct _Unwind_Context _Unwind_Context;
+  typedef _uw _Unwind_EHT_Header;
+
+
+  /* UCB: */
+
+  struct _Unwind_Control_Block
+    {
+      char exception_class[8];
+      void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
+      /* Unwinder cache, private fields for the unwinder's use */
+      struct
+	{
+	  _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */
+	  _uw reserved2;  /* Personality routine address */
+	  _uw reserved3;  /* Saved callsite address */
+	  _uw reserved4;  /* Forced unwind stop arg */
+	  _uw reserved5;
+	}
+      unwinder_cache;
+      /* Propagation barrier cache (valid after phase 1): */
+      struct
+	{
+	  _uw sp;
+	  _uw bitpattern[5];
+	}
+      barrier_cache;
+      /* Cleanup cache (preserved over cleanup): */
+      struct
+	{
+	  _uw bitpattern[4];
+	}
+      cleanup_cache;
+      /* Pr cache (for pr's benefit): */
+      struct
+	{
+	  _uw fnstart;			/* function start address */
+	  _Unwind_EHT_Header *ehtp;	/* pointer to EHT entry header word */
+	  _uw additional;		/* additional data */
+	  _uw reserved1;
+	}
+      pr_cache;
+      long long int :0;	/* Force alignment to 8-byte boundary */
+    };
+
+  /* Virtual Register Set*/
+
+  typedef enum
+    {
+      _UVRSC_CORE = 0,      /* integer register */
+      _UVRSC_VFP = 1,       /* vfp */
+      _UVRSC_FPA = 2,       /* fpa */
+      _UVRSC_WMMXD = 3,     /* Intel WMMX data register */
+      _UVRSC_WMMXC = 4      /* Intel WMMX control register */
+    }
+  _Unwind_VRS_RegClass;
+
+  typedef enum
+    {
+      _UVRSD_UINT32 = 0,
+      _UVRSD_VFPX = 1,
+      _UVRSD_FPAX = 2,
+      _UVRSD_UINT64 = 3,
+      _UVRSD_FLOAT = 4,
+      _UVRSD_DOUBLE = 5
+    }
+  _Unwind_VRS_DataRepresentation;
+
+  typedef enum
+    {
+      _UVRSR_OK = 0,
+      _UVRSR_NOT_IMPLEMENTED = 1,
+      _UVRSR_FAILED = 2
+    }
+  _Unwind_VRS_Result;
+
+  /* Frame unwinding state.  */
+  typedef struct
+    {
+      /* The current word (bytes packed msb first).  */
+      _uw data;
+      /* Pointer to the next word of data.  */
+      _uw *next;
+      /* The number of bytes left in this word.  */
+      _uw8 bytes_left;
+      /* The number of words pointed to by ptr.  */
+      _uw8 words_left;
+    }
+  __gnu_unwind_state;
+
+  typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State,
+      _Unwind_Control_Block *, _Unwind_Context *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation,
+                                     void *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation,
+                                     void *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation);
+
+
+  /* Support functions for the PR.  */
+#define _Unwind_Exception _Unwind_Control_Block
+  typedef char _Unwind_Exception_Class[8];
+
+  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
+  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
+
+  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
+  /* This should never be used.  */
+  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
+
+  /* Interface functions: */
+  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
+  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
+  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
+
+  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+       (int, _Unwind_Action, _Unwind_Exception_Class,
+	_Unwind_Control_Block *, struct _Unwind_Context *, void *);
+  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
+					    _Unwind_Stop_Fn, void *);
+  /* @@@ Use unwind data to perform a stack backtrace.  The trace callback
+     is called for every stack frame in the call chain, but no cleanup
+     actions are performed.  */
+  typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
+  _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn,
+					void*);
+
+  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+  void _Unwind_Complete(_Unwind_Control_Block *ucbp);
+  void _Unwind_DeleteException (_Unwind_Exception *);
+
+  _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
+					  _Unwind_Context *);
+  _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *,
+					    __gnu_unwind_state *);
+
+  static inline _Unwind_Word
+  _Unwind_GetGR (_Unwind_Context *context, int regno)
+    {
+      _uw val;
+      _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+      return val;
+    }
+
+#define _Unwind_GetIPInfo(context, ip_before_insn) \
+  (*ip_before_insn = 0, _Unwind_GetIP (context))
+
+  static inline void
+  _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
+    {
+      _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+    }
+
+  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
+  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
+
+/* leb128 type numbers have a potentially unlimited size.
+   The target of the following definitions of _sleb128_t and _uleb128_t
+   is to have efficient data types large enough to hold the leb128 type
+   numbers used in the unwind code.  */
+typedef long _sleb128_t;
+typedef unsigned long _uleb128_t;
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+#endif /* defined UNWIND_ARM_COMMON_H */
diff --git a/gcc/unwind-arm-common.inc b/gcc/unwind-arm-common.inc
new file mode 100644
index 0000000..04bfd8b
--- /dev/null
+++ b/gcc/unwind-arm-common.inc
@@ -0,0 +1,810 @@ 
+/* Common unwinding code for ARM EABI and C6X.
+   Copyright (C) 2004, 2005, 2009, 2011 Free Software Foundation, Inc.
+   Contributed by Paul Brook
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "unwind.h"
+
+/* We add a prototype for abort here to avoid creating a dependency on
+   target headers.  */
+extern void abort (void);
+
+/* Definitions for C++ runtime support routines.  We make these weak
+   declarations to avoid pulling in libsupc++ unnecessarily.  */
+typedef unsigned char bool;
+
+typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
+enum __cxa_type_match_result
+  {
+    ctm_failed = 0,
+    ctm_succeeded = 1,
+    ctm_succeeded_with_ptr_to_base = 2
+  };
+
+void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
+bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
+enum __cxa_type_match_result __attribute__((weak)) __cxa_type_match
+  (_Unwind_Control_Block *ucbp, const type_info *rttip,
+   bool is_reference, void **matched_object);
+
+_Unwind_Ptr __attribute__((weak))
+__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *);
+
+#define EXIDX_CANTUNWIND 1
+#define uint32_highbit (((_uw) 1) << 31)
+
+#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1)
+#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
+#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
+#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4)
+
+/* Unwind descriptors.  */
+
+typedef struct
+{
+  _uw16 length;
+  _uw16 offset;
+} EHT16;
+
+typedef struct
+{
+  _uw length;
+  _uw offset;
+} EHT32;
+
+/* An exception index table entry.  */
+
+typedef struct __EIT_entry
+{
+  _uw fnoffset;
+  _uw content;
+} __EIT_entry;
+
+/* Assembly helper functions.  */
+
+/* Restore core register state.  Never returns.  */
+void __attribute__((noreturn)) restore_core_regs (struct core_regs *);
+
+
+/* Restore coprocessor state after phase1 unwinding.  */
+static void restore_non_core_regs (phase1_vrs * vrs);
+
+/* A better way to do this would probably be to compare the absolute address
+   with a segment relative relocation of the same symbol.  */
+
+extern int __text_start;
+extern int __data_start;
+
+/* The exception index table location.  */
+extern __EIT_entry __exidx_start;
+extern __EIT_entry __exidx_end;
+
+/* Core unwinding functions.  */
+
+/* Calculate the address encoded by a 31-bit self-relative offset at address
+   P.  */
+static inline _uw selfrel_offset31 (const _uw *p);
+
+static _uw __gnu_unwind_get_pr_addr (int idx);
+
+/* Perform a binary search for RETURN_ADDRESS in TABLE.  The table contains
+   NREC entries.  */
+
+static const __EIT_entry *
+search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address)
+{
+  _uw next_fn;
+  _uw this_fn;
+  int n, left, right;
+
+  if (nrec == 0)
+    return (__EIT_entry *) 0;
+
+  left = 0;
+  right = nrec - 1;
+
+  while (1)
+    {
+      n = (left + right) / 2;
+      this_fn = selfrel_offset31 (&table[n].fnoffset);
+      if (n != nrec - 1)
+	next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1;
+      else
+	next_fn = (_uw)0 - 1;
+
+      if (return_address < this_fn)
+	{
+	  if (n == left)
+	    return (__EIT_entry *) 0;
+	  right = n - 1;
+	}
+      else if (return_address <= next_fn)
+	return &table[n];
+      else
+	left = n + 1;
+    }
+}
+
+/* Find the exception index table eintry for the given address.
+   Fill in the relevant fields of the UCB.
+   Returns _URC_FAILURE if an error occurred, _URC_OK on success.  */
+
+static _Unwind_Reason_Code
+get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address)
+{
+  const __EIT_entry * eitp;
+  int nrec;
+  
+  /* The return address is the address of the instruction following the
+     call instruction (plus one in thumb mode).  If this was the last
+     instruction in the function the address will lie in the following
+     function.  Subtract 2 from the address so that it points within the call
+     instruction itself.  */
+  return_address -= 2;
+
+  if (__gnu_Unwind_Find_exidx)
+    {
+      eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address,
+							    &nrec);
+      if (!eitp)
+	{
+	  UCB_PR_ADDR (ucbp) = 0;
+	  return _URC_FAILURE;
+	}
+    }
+  else
+    {
+      eitp = &__exidx_start;
+      nrec = &__exidx_end - &__exidx_start;
+    }
+
+  eitp = search_EIT_table (eitp, nrec, return_address);
+
+  if (!eitp)
+    {
+      UCB_PR_ADDR (ucbp) = 0;
+      return _URC_FAILURE;
+    }
+  ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset);
+
+  /* Can this frame be unwound at all?  */
+  if (eitp->content == EXIDX_CANTUNWIND)
+    {
+      UCB_PR_ADDR (ucbp) = 0;
+      return _URC_END_OF_STACK;
+    }
+
+  /* Obtain the address of the "real" __EHT_Header word.  */
+
+  if (eitp->content & uint32_highbit)
+    {
+      /* It is immediate data.  */
+      ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
+      ucbp->pr_cache.additional = 1;
+    }
+  else
+    {
+      /* The low 31 bits of the content field are a self-relative
+	 offset to an _Unwind_EHT_Entry structure.  */
+      ucbp->pr_cache.ehtp =
+	(_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content);
+      ucbp->pr_cache.additional = 0;
+    }
+
+  /* Discover the personality routine address.  */
+  if (*ucbp->pr_cache.ehtp & (1u << 31))
+    {
+      /* One of the predefined standard routines.  */
+      _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf;
+      UCB_PR_ADDR (ucbp) = __gnu_unwind_get_pr_addr (idx);
+      if (UCB_PR_ADDR (ucbp) == 0)
+	{
+	  /* Failed */
+	  return _URC_FAILURE;
+	}
+    } 
+  else
+    {
+      /* Execute region offset to PR */
+      UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp);
+    }
+  return _URC_OK;
+}
+
+
+/* Perform phase2 unwinding.  VRS is the initial virtual register state.  */
+
+static void __attribute__((noreturn))
+unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs)
+{
+  _Unwind_Reason_Code pr_result;
+
+  do
+    {
+      /* Find the entry for this routine.  */
+      if (get_eit_entry (ucbp, VRS_PC(vrs)) != _URC_OK)
+	abort ();
+
+      UCB_SAVED_CALLSITE_ADDR (ucbp) = VRS_PC(vrs);
+
+      /* Call the pr to decide what to do.  */
+      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	(_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs);
+    }
+  while (pr_result == _URC_CONTINUE_UNWIND);
+  
+  if (pr_result != _URC_INSTALL_CONTEXT)
+    abort();
+  
+  restore_core_regs (&vrs->core);
+}
+
+/* Perform phase2 forced unwinding.  */
+
+static _Unwind_Reason_Code
+unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs,
+		      int resuming)
+{
+  _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp);
+  void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp);
+  _Unwind_Reason_Code pr_result = 0;
+  /* We use phase1_vrs here even though we do not demand save, for the
+     prev_sp field.  */
+  phase1_vrs saved_vrs, next_vrs;
+
+  /* Save the core registers.  */
+  saved_vrs.core = entry_vrs->core;
+  /* We don't need to demand-save the non-core registers, because we
+     unwind in a single pass.  */
+  saved_vrs.demand_save_flags = 0;
+
+  /* Unwind until we reach a propagation barrier.  */
+  do
+    {
+      _Unwind_State action;
+      _Unwind_Reason_Code entry_code;
+      _Unwind_Reason_Code stop_code;
+
+      /* Find the entry for this routine.  */
+      entry_code = get_eit_entry (ucbp, VRS_PC (&saved_vrs));
+
+      if (resuming)
+	{
+	  action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND;
+	  resuming = 0;
+	}
+      else
+	action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND;
+
+      if (entry_code == _URC_OK)
+	{
+	  UCB_SAVED_CALLSITE_ADDR (ucbp) = VRS_PC (&saved_vrs);
+
+	  next_vrs = saved_vrs;
+
+	  /* Call the pr to decide what to do.  */
+	  pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	    (action, ucbp, (void *) &next_vrs);
+
+	  saved_vrs.prev_sp = VRS_SP (&next_vrs);
+	}
+      else
+	{
+	  /* Treat any failure as the end of unwinding, to cope more
+	     gracefully with missing EH information.  Mixed EH and
+	     non-EH within one object will usually result in failure,
+	     because the .ARM.exidx tables do not indicate the end
+	     of the code to which they apply; but mixed EH and non-EH
+	     shared objects should return an unwind failure at the
+	     entry of a non-EH shared object.  */
+	  action |= _US_END_OF_STACK;
+
+	  saved_vrs.prev_sp = VRS_SP (&saved_vrs);
+	}
+
+      stop_code = stop_fn (1, action, ucbp->exception_class, ucbp,
+			   (void *)&saved_vrs, stop_arg);
+      if (stop_code != _URC_NO_REASON)
+	return _URC_FAILURE;
+
+      if (entry_code != _URC_OK)
+	return entry_code;
+
+      saved_vrs = next_vrs;
+    }
+  while (pr_result == _URC_CONTINUE_UNWIND);
+
+  if (pr_result != _URC_INSTALL_CONTEXT)
+    {
+      /* Some sort of failure has occurred in the pr and probably the
+	 pr returned _URC_FAILURE.  */
+      return _URC_FAILURE;
+    }
+
+  restore_core_regs (&saved_vrs.core);
+}
+
+/* This is a very limited implementation of _Unwind_GetCFA.  It returns
+   the stack pointer as it is about to be unwound, and is only valid
+   while calling the stop function during forced unwinding.  If the
+   current personality routine result is going to run a cleanup, this
+   will not be the CFA; but when the frame is really unwound, it will
+   be.  */
+
+_Unwind_Word
+_Unwind_GetCFA (_Unwind_Context *context)
+{
+  return ((phase1_vrs *) context)->prev_sp;
+}
+
+/* Perform phase1 unwinding.  UCBP is the exception being thrown, and
+   entry_VRS is the register state on entry to _Unwind_RaiseException.  */
+
+_Unwind_Reason_Code
+__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp,
+			     phase2_vrs * entry_vrs)
+{
+  phase1_vrs saved_vrs;
+  _Unwind_Reason_Code pr_result;
+
+  /* Set the pc to the call site.  */
+  VRS_PC (entry_vrs) = VRS_RETURN(entry_vrs);
+
+  /* Save the core registers.  */
+  saved_vrs.core = entry_vrs->core;
+  /* Set demand-save flags.  */
+  saved_vrs.demand_save_flags = ~(_uw) 0;
+  
+  /* Unwind until we reach a propagation barrier.  */
+  do
+    {
+      /* Find the entry for this routine.  */
+      if (get_eit_entry (ucbp, VRS_PC (&saved_vrs)) != _URC_OK)
+	return _URC_FAILURE;
+
+      /* Call the pr to decide what to do.  */
+      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	(_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs);
+    }
+  while (pr_result == _URC_CONTINUE_UNWIND);
+
+  /* We've unwound as far as we want to go, so restore the original
+     register state.  */
+  restore_non_core_regs (&saved_vrs);
+  if (pr_result != _URC_HANDLER_FOUND)
+    {
+      /* Some sort of failure has occurred in the pr and probably the
+	 pr returned _URC_FAILURE.  */
+      return _URC_FAILURE;
+    }
+  
+  unwind_phase2 (ucbp, entry_vrs);
+}
+
+/* Resume unwinding after a cleanup has been run.  UCBP is the exception
+   being thrown and ENTRY_VRS is the register state on entry to
+   _Unwind_Resume.  */
+_Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *,
+			   _Unwind_Stop_Fn, void *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp,
+			   _Unwind_Stop_Fn stop_fn, void *stop_arg,
+			   phase2_vrs *entry_vrs)
+{
+  UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn;
+  UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg;
+
+  /* Set the pc to the call site.  */
+  VRS_PC (entry_vrs) = VRS_RETURN(entry_vrs);
+
+  return unwind_phase2_forced (ucbp, entry_vrs, 0);
+}
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs)
+{
+  _Unwind_Reason_Code pr_result;
+
+  /* Recover the saved address.  */
+  VRS_PC (entry_vrs) = UCB_SAVED_CALLSITE_ADDR (ucbp);
+
+  if (UCB_FORCED_STOP_FN (ucbp))
+    {
+      unwind_phase2_forced (ucbp, entry_vrs, 1);
+
+      /* We can't return failure at this point.  */
+      abort ();
+    }
+
+  /* Call the cached PR.  */
+  pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	(_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs);
+
+  switch (pr_result)
+    {
+    case _URC_INSTALL_CONTEXT:
+      /* Upload the registers to enter the landing pad.  */
+      restore_core_regs (&entry_vrs->core);
+
+    case _URC_CONTINUE_UNWIND:
+      /* Continue unwinding the next frame.  */
+      unwind_phase2 (ucbp, entry_vrs);
+
+    default:
+      abort ();
+    }
+}
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp,
+				phase2_vrs * entry_vrs)
+{
+  if (!UCB_FORCED_STOP_FN (ucbp))
+    return __gnu_Unwind_RaiseException (ucbp, entry_vrs);
+
+  /* Set the pc to the call site.  */
+  VRS_PC (entry_vrs) = VRS_RETURN (entry_vrs);
+  /* Continue unwinding the next frame.  */
+  return unwind_phase2_forced (ucbp, entry_vrs, 0);
+}
+
+/* Clean up an exception object when unwinding is complete.  */
+void
+_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused)))
+{
+}
+
+
+/* Free an exception.  */
+
+void
+_Unwind_DeleteException (_Unwind_Exception * exc)
+{
+  if (exc->exception_cleanup)
+    (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+
+/* Perform stack backtrace through unwind data.  */
+_Unwind_Reason_Code
+__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
+		       phase2_vrs * entry_vrs);
+_Unwind_Reason_Code
+__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
+		       phase2_vrs * entry_vrs)
+{
+  phase1_vrs saved_vrs;
+  _Unwind_Reason_Code code;
+
+  _Unwind_Control_Block ucb;
+  _Unwind_Control_Block *ucbp = &ucb;
+
+  /* Set the pc to the call site.  */
+  VRS_PC (entry_vrs) = VRS_RETURN (entry_vrs);
+
+  /* Save the core registers.  */
+  saved_vrs.core = entry_vrs->core;
+  /* Set demand-save flags.  */
+  saved_vrs.demand_save_flags = ~(_uw) 0;
+  
+  do
+    {
+      /* Find the entry for this routine.  */
+      if (get_eit_entry (ucbp, VRS_PC (&saved_vrs)) != _URC_OK)
+	{
+	  code = _URC_FAILURE;
+	  break;
+	}
+
+      /* 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.  */
+      _Unwind_SetGR((_Unwind_Context *)&saved_vrs, UNWIND_POINTER_REG, (_Unwind_Ptr) ucbp);
+
+      /* Call trace function.  */
+      if ((*trace) ((_Unwind_Context *) &saved_vrs, trace_argument) 
+	  != _URC_NO_REASON)
+	{
+	  code = _URC_FAILURE;
+	  break;
+	}
+
+      /* Call the pr to decide what to do.  */
+      code = ((personality_routine) UCB_PR_ADDR (ucbp))
+	(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, 
+	 ucbp, (void *) &saved_vrs);
+    }
+  while (code != _URC_END_OF_STACK
+	 && code != _URC_FAILURE);
+
+  restore_non_core_regs (&saved_vrs);
+  return code;
+}
+
+
+/* Common implementation for ARM ABI defined personality routines.
+   ID is the index of the personality routine, other arguments are as defined
+   by __aeabi_unwind_cpp_pr{0,1,2}.  */
+
+static _Unwind_Reason_Code
+__gnu_unwind_pr_common (_Unwind_State state,
+			_Unwind_Control_Block *ucbp,
+			_Unwind_Context *context,
+			int id)
+{
+  __gnu_unwind_state uws;
+  _uw *data;
+  _uw offset;
+  _uw len;
+  _uw rtti_count;
+  int phase2_call_unexpected_after_unwind = 0;
+  int in_range = 0;
+  int forced_unwind = state & _US_FORCE_UNWIND;
+
+  state &= _US_ACTION_MASK;
+
+  data = (_uw *) ucbp->pr_cache.ehtp;
+  uws.data = *(data++);
+  uws.next = data;
+  if (id == 0)
+    {
+      uws.data <<= 8;
+      uws.words_left = 0;
+      uws.bytes_left = 3;
+    }
+  else
+    {
+      uws.words_left = (uws.data >> 16) & 0xff;
+      uws.data <<= 16;
+      uws.bytes_left = 2;
+      data += uws.words_left;
+    }
+
+  /* Restore the saved pointer.  */
+  if (state == _US_UNWIND_FRAME_RESUME)
+    data = (_uw *) ucbp->cleanup_cache.bitpattern[0];
+
+  if ((ucbp->pr_cache.additional & 1) == 0)
+    {
+      /* Process descriptors.  */
+      while (*data)
+	{
+	  _uw addr;
+	  _uw fnstart;
+
+	  if (id == 2)
+	    {
+	      len = ((EHT32 *) data)->length;
+	      offset = ((EHT32 *) data)->offset;
+	      data += 2;
+	    }
+	  else
+	    {
+	      len = ((EHT16 *) data)->length;
+	      offset = ((EHT16 *) data)->offset;
+	      data++;
+	    }
+
+	  fnstart = ucbp->pr_cache.fnstart + (offset & ~1);
+	  addr = _Unwind_GetGR (context, R_PC);
+	  in_range = (fnstart <= addr && addr < fnstart + (len & ~1));
+
+	  switch (((offset & 1) << 1) | (len & 1))
+	    {
+	    case 0:
+	      /* Cleanup.  */
+	      if (state != _US_VIRTUAL_UNWIND_FRAME
+		  && in_range)
+		{
+		  /* Cleanup in range, and we are running cleanups.  */
+		  _uw lp;
+
+		  /* Landing pad address is 31-bit pc-relative offset.  */
+		  lp = selfrel_offset31 (data);
+		  data++;
+		  /* Save the exception data pointer.  */
+		  ucbp->cleanup_cache.bitpattern[0] = (_uw) data;
+		  if (!__cxa_begin_cleanup (ucbp))
+		    return _URC_FAILURE;
+		  /* Setup the VRS to enter the landing pad.  */
+		  _Unwind_SetGR (context, R_PC, lp);
+		  return _URC_INSTALL_CONTEXT;
+		}
+	      /* Cleanup not in range, or we are in stage 1.  */
+	      data++;
+	      break;
+
+	    case 1:
+	      /* Catch handler.  */
+	      if (state == _US_VIRTUAL_UNWIND_FRAME)
+		{
+		  if (in_range)
+		    {
+		      /* Check for a barrier.  */
+		      _uw rtti;
+		      bool is_reference = (data[0] & uint32_highbit) != 0;
+		      void *matched;
+		      enum __cxa_type_match_result match_type;
+
+		      /* Check for no-throw areas.  */
+		      if (data[1] == (_uw) -2)
+			return _URC_FAILURE;
+
+		      /* The thrown object immediately follows the ECB.  */
+		      matched = (void *)(ucbp + 1);
+		      if (data[1] != (_uw) -1)
+			{
+			  /* Match a catch specification.  */
+			  rtti = _Unwind_decode_typeinfo_ptr (0,
+							      (_uw) &data[1]);
+			  match_type = __cxa_type_match (ucbp,
+							 (type_info *) rtti,
+							 is_reference,
+							 &matched);
+			}
+		      else
+			match_type = ctm_succeeded;
+
+		      if (match_type)
+			{
+			  ucbp->barrier_cache.sp =
+			    _Unwind_GetGR (context, R_SP);
+			  // ctm_succeeded_with_ptr_to_base really
+			  // means _c_t_m indirected the pointer
+			  // object.  We have to reconstruct the
+			  // additional pointer layer by using a temporary.
+			  if (match_type == ctm_succeeded_with_ptr_to_base)
+			    {
+			      ucbp->barrier_cache.bitpattern[2]
+				= (_uw) matched;
+			      ucbp->barrier_cache.bitpattern[0]
+				= (_uw) &ucbp->barrier_cache.bitpattern[2];
+			    }
+			  else
+			    ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
+			  ucbp->barrier_cache.bitpattern[1] = (_uw) data;
+			  return _URC_HANDLER_FOUND;
+			}
+		    }
+		  /* Handler out of range, or not matched.  */
+		}
+	      else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
+		       && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
+		{
+		  /* Matched a previous propagation barrier.  */
+		  _uw lp;
+
+		  /* Setup for entry to the handler.  */
+		  lp = selfrel_offset31 (data);
+		  _Unwind_SetGR (context, R_PC, lp);
+		  _Unwind_SetGR (context, 0, (_uw) ucbp);
+		  return _URC_INSTALL_CONTEXT;
+		}
+	      /* Catch handler not matched.  Advance to the next descriptor.  */
+	      data += 2;
+	      break;
+
+	    case 2:
+	      rtti_count = data[0] & 0x7fffffff;
+	      /* Exception specification.  */
+	      if (state == _US_VIRTUAL_UNWIND_FRAME)
+		{
+		  if (in_range && (!forced_unwind || !rtti_count))
+		    {
+		      /* Match against the exception specification.  */
+		      _uw i;
+		      _uw rtti;
+		      void *matched;
+
+		      for (i = 0; i < rtti_count; i++)
+			{
+			  matched = (void *)(ucbp + 1);
+			  rtti = _Unwind_decode_typeinfo_ptr (0,
+			      (_uw) &data[i + 1]);
+			  if (__cxa_type_match (ucbp, (type_info *) rtti, 0,
+						&matched))
+			    break;
+			}
+
+		      if (i == rtti_count)
+			{
+			  /* Exception does not match the spec.  */
+			  ucbp->barrier_cache.sp =
+			    _Unwind_GetGR (context, R_SP);
+			  ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
+			  ucbp->barrier_cache.bitpattern[1] = (_uw) data;
+			  return _URC_HANDLER_FOUND;
+			}
+		    }
+		  /* Handler out of range, or exception is permitted.  */
+		}
+	      else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
+		       && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
+		{
+		  /* Matched a previous propagation barrier.  */
+		  _uw lp;
+		  /* Record the RTTI list for __cxa_call_unexpected.  */
+		  ucbp->barrier_cache.bitpattern[1] = rtti_count;
+		  ucbp->barrier_cache.bitpattern[2] = 0;
+		  ucbp->barrier_cache.bitpattern[3] = 4;
+		  ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1];
+
+		  if (data[0] & uint32_highbit)
+		    {
+		      data += rtti_count + 1;
+		      /* Setup for entry to the handler.  */
+		      lp = selfrel_offset31 (data);
+		      data++;
+		      _Unwind_SetGR (context, R_PC, lp);
+		      _Unwind_SetGR (context, 0, (_uw) ucbp);
+		      return _URC_INSTALL_CONTEXT;
+		    }
+		  else
+		    phase2_call_unexpected_after_unwind = 1;
+		}
+	      if (data[0] & uint32_highbit)
+		data++;
+	      data += rtti_count + 1;
+	      break;
+
+	    default:
+	      /* Should never happen.  */
+	      return _URC_FAILURE;
+	    }
+	  /* Finished processing this descriptor.  */
+	}
+    }
+
+  if (id >= 3)
+    {
+      /* 24-bit ecoding */
+      if (__gnu_unwind_24bit (context, uws.data, id == 4) != _URC_OK)
+	return _URC_FAILURE;
+    }
+  else
+    {
+      if (__gnu_unwind_execute (context, &uws) != _URC_OK)
+	return _URC_FAILURE;
+    }
+    
+  if (phase2_call_unexpected_after_unwind)
+    {
+      /* Enter __cxa_unexpected as if called from the call site.  */
+      _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC));
+      _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected);
+      return _URC_INSTALL_CONTEXT;
+    }
+
+  return _URC_CONTINUE_UNWIND;
+}
diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c
index 86b9f55..bd4941d 100644
--- a/gcc/unwind-c.c
+++ b/gcc/unwind-c.c
@@ -130,10 +130,10 @@  PERSONALITY_FUNCTION (int version,
 
   /* 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.  */
+     the exception header (UCB).  To avoid rewriting everything we make a
+     virtual scratch register point at the UCB.  */
   ip = (_Unwind_Ptr) ue_header;
-  _Unwind_SetGR (context, 12, ip);
+  _Unwind_SetGR (context, UNWIND_POINTER_REG, ip);
 #else
   if (version != 1)
     return _URC_FATAL_PHASE1_ERROR;
diff --git a/libstdc++-v3/libsupc++/eh_arm.cc b/libstdc++-v3/libsupc++/eh_arm.cc
index e7ba2e5..0f0b026 100644
--- a/libstdc++-v3/libsupc++/eh_arm.cc
+++ b/libstdc++-v3/libsupc++/eh_arm.cc
@@ -155,6 +155,49 @@  __gnu_end_cleanup(void)
   return &header->unwindHeader;
 }
 
+#ifdef __TMS320C6X__
+// Assembly wrapper to call __gnu_end_cleanup without clobbering
+// function arguments to _Unwind_Resume.
+asm (".global __cxa_end_cleanup\n"
+"	.type __cxa_end_cleanup, \"function\"\n"
+"__cxa_end_cleanup:\n"
+"	stw	.d2t2	B9, *B15--[10]\n"
+"	stw	.d2t2	B8, *+B15[9]\n"
+"	stw	.d2t2	B7, *+B15[8]\n"
+"	stw	.d2t2	B6, *+B15[7]\n"
+"	stw	.d2t2	B5, *+B15[6]\n"
+"	stw	.d2t2	B4, *+B15[5]\n"
+"	stw	.d2t1	A9, *+B15[4]\n"
+"	stw	.d2t1	A8, *+B15[3]\n"
+"	stw	.d2t1	A7, *+B15[2]\n"
+"	stw	.d2t1	A6, *+B15[1]\n"
+#ifdef _TMS320C6400_PLUS
+"	callp	.s2	(__gnu_end_cleanup), B3\n"
+#elif defined(_TMS320C6400)
+"	call	.s2	(__gnu_end_cleanup)\n"
+"	addkpc	.s2	1f, B3, 0\n"
+"	nop		4\n"
+"1:\n"
+#else
+"	call	.s2	(__gnu_end_cleanup)\n"
+"	mvkl	.s2	1f, B3\n"
+"	mvkh	.s2	1f, B3\n"
+"	nop		3\n"
+"1:\n"
+#endif
+"	ldw	.d2t1	*+B15[1], A6\n"
+"	ldw	.d2t1	*+B15[2], A7\n"
+"	ldw	.d2t1	*+B15[3], A8\n"
+"	ldw	.d2t1	*+B15[4], A9\n"
+"	ldw	.d2t2	*+B15[5], B4\n"
+"	ldw	.d2t2	*+B15[6], B5\n"
+"	ldw	.d2t2	*+B15[7], B6\n"
+"	ldw	.d2t2	*+B15[8], B7\n"
+"	ldw	.d2t2	*+B15[9], B8\n"
+"	ldw	.d2t2	*++B15[10], B9\n"
+"	b	.s2	_Unwind_Resume\n"
+"	nop		5\n");
+#else
 // Assembly wrapper to call __gnu_end_cleanup without clobbering r1-r3.
 // Also push r4 to preserve stack alignment.
 #ifdef __thumb__
@@ -179,5 +222,6 @@  asm ("  .pushsection .text.__cxa_end_cleanup\n"
 "	bl\t_Unwind_Resume @ Never returns\n"
 "	.popsection\n");
 #endif
+#endif
 
 #endif
diff --git a/libstdc++-v3/libsupc++/eh_call.cc b/libstdc++-v3/libsupc++/eh_call.cc
index f519f35..a6a55a4 100644
--- a/libstdc++-v3/libsupc++/eh_call.cc
+++ b/libstdc++-v3/libsupc++/eh_call.cc
@@ -73,6 +73,7 @@  __cxa_call_unexpected(void* exc_obj_in)
   int rtti_count = 0;
   _Unwind_Word rtti_stride = 0;
   _Unwind_Word* rtti_list = NULL;
+  _Unwind_Ptr rtti_base = 0;
   bool foreign_exception;
   std::unexpected_handler unexpectedHandler = NULL;
   std::terminate_handler terminateHandler = NULL;
@@ -84,7 +85,7 @@  __cxa_call_unexpected(void* exc_obj_in)
       unexpectedHandler = xh->unexpectedHandler;
       terminateHandler = xh->terminateHandler;
       rtti_count = exc_obj->barrier_cache.bitpattern[1];
-
+      rtti_base = (_Unwind_Ptr) exc_obj->barrier_cache.bitpattern[2];
       rtti_stride = exc_obj->barrier_cache.bitpattern[3];
       rtti_list = (_Unwind_Word*) exc_obj->barrier_cache.bitpattern[4];
       foreign_exception = false;
@@ -134,7 +135,7 @@  __cxa_call_unexpected(void* exc_obj_in)
 	  _Unwind_Word offset;
 
 	  offset = (_Unwind_Word) &rtti_list[n * (rtti_stride >> 2)];
-	  offset = _Unwind_decode_target2(offset);
+	  offset = _Unwind_decode_typeinfo_ptr(rtti_base, offset);
 	  catch_type = (const std::type_info*) (offset);
 
 	  if (__cxa_type_match(&new_xh->unwindHeader, catch_type, false,
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc
index 19c2044..729d688 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -30,11 +30,8 @@ 
 #include <cxxabi.h>
 #include "unwind-cxx.h"
 
-using namespace __cxxabiv1;
 
-#ifdef __ARM_EABI_UNWINDER__
-#define NO_SIZE_OF_ENCODED_VALUE
-#endif
+using namespace __cxxabiv1;
 
 #include "unwind-pe.h"
 
@@ -70,6 +67,11 @@  parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
   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;
     }
@@ -85,21 +87,22 @@  parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
   return p;
 }
 
-#ifdef __ARM_EABI_UNWINDER__
-
 // Return an element from a type table.
 
-static const std::type_info*
-get_ttype_entry(lsda_header_info* info, _uleb128_t i)
+static const std::type_info *
+get_ttype_entry (lsda_header_info *info, _uleb128_t i)
 {
   _Unwind_Ptr ptr;
 
-  ptr = (_Unwind_Ptr) (info->TType - (i * 4));
-  ptr = _Unwind_decode_target2(ptr);
-  
+  i *= size_of_encoded_value (info->ttype_encoding);
+  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
+				info->TType - i, &ptr);
+
   return reinterpret_cast<const std::type_info *>(ptr);
 }
 
+#ifdef __ARM_EABI_UNWINDER__
+
 // The ABI provides a routine for matching exception object types.
 typedef _Unwind_Control_Block _throw_typet;
 #define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \
@@ -127,7 +130,7 @@  check_exception_spec(lsda_header_info* info, _throw_typet* throw_type,
       if (tmp == 0)
         return false;
 
-      tmp = _Unwind_decode_target2((_Unwind_Word) e);
+      tmp = _Unwind_decode_typeinfo_ptr(info->ttype_base, (_Unwind_Word) e);
 
       // Match a ttype entry.
       catch_type = reinterpret_cast<const std::type_info*>(tmp);
@@ -157,7 +160,7 @@  save_caught_exception(struct _Unwind_Exception* ue_header,
 		      const unsigned char* action_record
 			__attribute__((__unused__)))
 {
-    ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13);
+    ue_header->barrier_cache.sp = _Unwind_GetGR(context, UNWIND_STACK_REG);
     ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr;
     ue_header->barrier_cache.bitpattern[1]
       = (_uw) handler_switch_value;
@@ -205,20 +208,6 @@  empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value)
 typedef const std::type_info _throw_typet;
 
 
-// Return an element from a type table.
-
-static const std::type_info *
-get_ttype_entry (lsda_header_info *info, _uleb128_t i)
-{
-  _Unwind_Ptr ptr;
-
-  i *= size_of_encoded_value (info->ttype_encoding);
-  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
-				info->TType - i, &ptr);
-
-  return reinterpret_cast<const std::type_info *>(ptr);
-}
-
 // Given the thrown type THROW_TYPE, pointer to a variable containing a
 // pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
 // compare against, return whether or not there is a match and if so,
@@ -390,7 +379,8 @@  PERSONALITY_FUNCTION (int version,
     case _US_UNWIND_FRAME_STARTING:
       actions = _UA_CLEANUP_PHASE;
       if (!(state & _US_FORCE_UNWIND)
-	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context,
+							  UNWIND_STACK_REG))
 	actions |= _UA_HANDLER_FRAME;
       break;
 
@@ -410,10 +400,10 @@  PERSONALITY_FUNCTION (int version,
 
   // 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.
+  // the exception header (UCB).  To avoid rewriting everything we make a
+  // virtual scratch register point at the UCB.
   ip = (_Unwind_Ptr) ue_header;
-  _Unwind_SetGR(context, 12, ip);
+  _Unwind_SetGR(context, UNWIND_POINTER_REG, ip);
 #else
   __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
 
@@ -679,6 +669,8 @@  PERSONALITY_FUNCTION (int version,
       if (handler_switch_value < 0)
 	{
 	  parse_lsda_header (context, language_specific_data, &info);
+	  info.ttype_base = base_of_encoded_value (info.ttype_encoding,
+						   context);
 
 #ifdef __ARM_EABI_UNWINDER__
 	  const _Unwind_Word* e;
@@ -692,8 +684,8 @@  PERSONALITY_FUNCTION (int version,
 
 	  // Count.
 	  ue_header->barrier_cache.bitpattern[1] = n;
-	  // Base (obsolete)
-	  ue_header->barrier_cache.bitpattern[2] = 0;
+	  // Base
+	  ue_header->barrier_cache.bitpattern[2] = info.ttype_base;
 	  // Stride.
 	  ue_header->barrier_cache.bitpattern[3] = 4;
 	  // List head.