summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbwilson <bwilson@138bc75d-0d04-0410-961f-82ee72b054a4>2007-11-13 22:41:50 +0000
committerbwilson <bwilson@138bc75d-0d04-0410-961f-82ee72b054a4>2007-11-13 22:41:50 +0000
commit8e98a0f8990b5961338ac29ddee38f543d6c1590 (patch)
treea5fc28e4335068f95fba5d755544b3369c28b81e
parentdf1b18e1e253042a427f68ce20b6cebccd0fcde4 (diff)
downloadgcc-8e98a0f8990b5961338ac29ddee38f543d6c1590.tar.gz
* config/xtensa/unwind-dw2-xtensa.c: New.
* config/xtensa/unwind-dw2-xtensa.h: New. * config/xtensa/xtensa.h (MUST_USE_SJLJ_EXCEPTIONS): Remove. (DWARF2_UNWIND_INFO): Remove. (DWARF_FRAME_REGISTERS): Define. (EH_RETURN_DATA_REGNO): Define. * config/xtensa/xtensa.md (UNSPECV_EH_RETURN): Define. (eh_return): New. * config/xtensa/t-xtensa (LIB2ADDEH): Define. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@130160 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/xtensa/t-xtensa2
-rw-r--r--gcc/config/xtensa/unwind-dw2-xtensa.c546
-rw-r--r--gcc/config/xtensa/unwind-dw2-xtensa.h57
-rw-r--r--gcc/config/xtensa/xtensa.h11
-rw-r--r--gcc/config/xtensa/xtensa.md21
6 files changed, 646 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b3bac1f53af..d4517ad5646 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2007-11-13 Sterling Augustine <sterling@tensilica.com>
+ Bob Wilson <bob.wilson@acm.org>
+
+ * config/xtensa/unwind-dw2-xtensa.c: New.
+ * config/xtensa/unwind-dw2-xtensa.h: New.
+ * config/xtensa/xtensa.h (MUST_USE_SJLJ_EXCEPTIONS): Remove.
+ (DWARF2_UNWIND_INFO): Remove.
+ (DWARF_FRAME_REGISTERS): Define.
+ (EH_RETURN_DATA_REGNO): Define.
+ * config/xtensa/xtensa.md (UNSPECV_EH_RETURN): Define.
+ (eh_return): New.
+ * config/xtensa/t-xtensa (LIB2ADDEH): Define.
+
2007-11-13 Jakub Jelinek <jakub@redhat.com>
* doc/invoke.texi: Fix description of -fsched-stalled-insns=0,
diff --git a/gcc/config/xtensa/t-xtensa b/gcc/config/xtensa/t-xtensa
index 5db4f7c66ce..b0a7e8115e4 100644
--- a/gcc/config/xtensa/t-xtensa
+++ b/gcc/config/xtensa/t-xtensa
@@ -11,6 +11,8 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \
_truncdfsf2 _extendsfdf2
LIB2FUNCS_EXTRA = $(srcdir)/config/xtensa/lib2funcs.S
+LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \
+ $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
$(T)crti.o: $(srcdir)/config/xtensa/crti.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.c b/gcc/config/xtensa/unwind-dw2-xtensa.c
new file mode 100644
index 00000000000..1dd4f9dee3f
--- /dev/null
+++ b/gcc/config/xtensa/unwind-dw2-xtensa.c
@@ -0,0 +1,546 @@
+/* DWARF2 exception handling and frame unwinding for Xtensa.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2007
+ Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC 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 2, or (at your option)
+ any later version.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ GCC 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "dwarf2.h"
+#include "unwind.h"
+#ifdef __USING_SJLJ_EXCEPTIONS__
+# define NO_SIZE_OF_ENCODED_VALUE
+#endif
+#include "unwind-pe.h"
+#include "unwind-dw2-fde.h"
+#include "unwind-dw2-xtensa.h"
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+
+/* The standard CIE and FDE structures work fine for Xtensa but the
+ variable-size register window save areas are not a good fit for the rest
+ of the standard DWARF unwinding mechanism. Nor is that mechanism
+ necessary, since the register save areas are always in fixed locations
+ in each stack frame. This file is a stripped down and customized version
+ of the standard DWARF unwinding code. It needs to be customized to have
+ builtin logic for finding the save areas and also to track the stack
+ pointer value (besides the CFA) while unwinding since the primary save
+ area is located below the stack pointer. It is stripped down to reduce
+ code size and ease the maintenance burden of tracking changes in the
+ standard version of the code. */
+
+#ifndef DWARF_REG_TO_UNWIND_COLUMN
+#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
+#endif
+
+#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF
+
+/* This is the register and unwind state for a particular frame. This
+ provides the information necessary to unwind up past a frame and return
+ to its caller. */
+struct _Unwind_Context
+{
+ /* Track register window save areas of 4 registers each, instead of
+ keeping separate addresses for the individual registers. */
+ _Unwind_Word *reg[4];
+
+ void *cfa;
+ void *sp;
+ void *ra;
+
+ /* Cache the 2 high bits to replace the window size in return addresses. */
+ _Unwind_Word ra_high_bits;
+
+ void *lsda;
+ struct dwarf_eh_bases bases;
+ /* Signal frame context. */
+#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
+ _Unwind_Word flags;
+ /* 0 for now, can be increased when further fields are added to
+ struct _Unwind_Context. */
+ _Unwind_Word version;
+};
+
+
+/* Read unaligned data from the instruction buffer. */
+
+union unaligned
+{
+ void *p;
+} __attribute__ ((packed));
+
+static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
+static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
+ _Unwind_FrameState *);
+
+static inline void *
+read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
+
+static inline _Unwind_Word
+_Unwind_IsSignalFrame (struct _Unwind_Context *context)
+{
+ return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
+}
+
+static inline void
+_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
+{
+ if (val)
+ context->flags |= SIGNAL_FRAME_BIT;
+ else
+ context->flags &= ~SIGNAL_FRAME_BIT;
+}
+
+/* Get the value of register INDEX as saved in CONTEXT. */
+
+inline _Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *context, int index)
+{
+ _Unwind_Word *ptr;
+
+ index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ ptr = context->reg[index >> 2] + (index & 3);
+
+ return *ptr;
+}
+
+/* Get the value of the CFA as saved in CONTEXT. */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->cfa;
+}
+
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */
+
+inline void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+ _Unwind_Word *ptr;
+
+ index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ ptr = context->reg[index >> 2] + (index & 3);
+
+ *ptr = val;
+}
+
+/* Retrieve the return address for CONTEXT. */
+
+inline _Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->ra;
+}
+
+/* Retrieve the return address and flag whether that IP is before
+ or after first not yet fully executed instruction. */
+
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = _Unwind_IsSignalFrame (context);
+ return (_Unwind_Ptr) context->ra;
+}
+
+/* Overwrite the return address for CONTEXT with VAL. */
+
+inline void
+_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
+{
+ context->ra = (void *) val;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
+{
+ return context->lsda;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bases.func;
+}
+
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+ struct dwarf_eh_bases bases;
+ const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
+ if (fde)
+ return bases.func;
+ else
+ return NULL;
+}
+
+_Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bases.dbase;
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bases.tbase;
+}
+
+#ifdef MD_UNWIND_SUPPORT
+#include MD_UNWIND_SUPPORT
+#endif
+
+/* Extract any interesting information from the CIE for the translation
+ unit F belongs to. Return a pointer to the byte after the augmentation,
+ or NULL if we encountered an undecipherable augmentation. */
+
+static const unsigned char *
+extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ const unsigned char *aug = cie->augmentation;
+ const unsigned char *p = aug + strlen ((const char *)aug) + 1;
+ const unsigned char *ret = NULL;
+ _uleb128_t utmp;
+ _sleb128_t stmp;
+
+ /* g++ v2 "eh" has pointer immediately following augmentation string,
+ so it must be handled first. */
+ if (aug[0] == 'e' && aug[1] == 'h')
+ {
+ fs->eh_ptr = read_pointer (p);
+ p += sizeof (void *);
+ aug += 2;
+ }
+
+ /* Immediately following the augmentation are the code and
+ data alignment and return address column. */
+ p = read_uleb128 (p, &utmp);
+ p = read_sleb128 (p, &stmp);
+ if (cie->version == 1)
+ fs->retaddr_column = *p++;
+ else
+ {
+ p = read_uleb128 (p, &utmp);
+ fs->retaddr_column = (_Unwind_Word)utmp;
+ }
+ fs->lsda_encoding = DW_EH_PE_omit;
+
+ /* If the augmentation starts with 'z', then a uleb128 immediately
+ follows containing the length of the augmentation field following
+ the size. */
+ if (*aug == 'z')
+ {
+ p = read_uleb128 (p, &utmp);
+ ret = p + utmp;
+
+ fs->saw_z = 1;
+ ++aug;
+ }
+
+ /* Iterate over recognized augmentation subsequences. */
+ while (*aug != '\0')
+ {
+ /* "L" indicates a byte showing how the LSDA pointer is encoded. */
+ if (aug[0] == 'L')
+ {
+ fs->lsda_encoding = *p++;
+ aug += 1;
+ }
+
+ /* "R" indicates a byte indicating how FDE addresses are encoded. */
+ else if (aug[0] == 'R')
+ {
+ fs->fde_encoding = *p++;
+ aug += 1;
+ }
+
+ /* "P" indicates a personality routine in the CIE augmentation. */
+ else if (aug[0] == 'P')
+ {
+ _Unwind_Ptr personality;
+
+ p = read_encoded_value (context, *p, p + 1, &personality);
+ fs->personality = (_Unwind_Personality_Fn) personality;
+ aug += 1;
+ }
+
+ /* "S" indicates a signal frame. */
+ else if (aug[0] == 'S')
+ {
+ fs->signal_frame = 1;
+ aug += 1;
+ }
+
+ /* Otherwise we have an unknown augmentation string.
+ Bail unless we saw a 'z' prefix. */
+ else
+ return ret;
+ }
+
+ return ret ? ret : p;
+}
+
+/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
+ its caller and decode it into FS. This function also sets the
+ lsda member of CONTEXT, as it is really information
+ about the caller's frame. */
+
+static _Unwind_Reason_Code
+uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ const struct dwarf_fde *fde;
+ const struct dwarf_cie *cie;
+ const unsigned char *aug;
+ int window_size;
+ _Unwind_Word *ra_ptr;
+
+ memset (fs, 0, sizeof (*fs));
+ context->lsda = 0;
+
+ ra_ptr = context->reg[0];
+ if (ra_ptr && *ra_ptr == 0)
+ return _URC_END_OF_STACK;
+
+ fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
+ &context->bases);
+ if (fde == NULL)
+ {
+#ifdef MD_FALLBACK_FRAME_STATE_FOR
+ _Unwind_Reason_Code reason;
+ /* Couldn't find frame unwind info for this function. Try a
+ target-specific fallback mechanism. This will necessarily
+ not provide a personality routine or LSDA. */
+ reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs);
+ if (reason != _URC_END_OF_STACK)
+ return reason;
+ /* The frame was not recognized and handled by the fallback function,
+ but it is not really the end of the stack. Fall through here and
+ unwind it anyway. */
+#endif
+ fs->pc = context->ra;
+ }
+ else
+ {
+ fs->pc = context->bases.func;
+
+ cie = get_cie (fde);
+ if (extract_cie_info (cie, context, fs) == NULL)
+ /* CIE contained unknown augmentation. */
+ return _URC_FATAL_PHASE1_ERROR;
+
+ /* Locate augmentation for the fde. */
+ aug = (const unsigned char *) fde + sizeof (*fde);
+ aug += 2 * size_of_encoded_value (fs->fde_encoding);
+ if (fs->saw_z)
+ {
+ _uleb128_t i;
+ aug = read_uleb128 (aug, &i);
+ }
+ if (fs->lsda_encoding != DW_EH_PE_omit)
+ {
+ _Unwind_Ptr lsda;
+
+ aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
+ context->lsda = (void *) lsda;
+ }
+ }
+
+ /* Find the window size from the high bits of the return address. */
+ if (ra_ptr)
+ window_size = (*ra_ptr >> 30) * 4;
+ else
+ window_size = 8;
+
+ fs->retaddr_column = window_size;
+
+ return _URC_NO_REASON;
+}
+
+static void
+uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ struct _Unwind_Context orig_context = *context;
+ _Unwind_Word *sp, *cfa, *next_cfa;
+ int i;
+
+ if (fs->signal_frame)
+ {
+ cfa = (_Unwind_Word *) fs->signal_regs[1];
+ next_cfa = (_Unwind_Word *) cfa[-3];
+
+ for (i = 0; i < 4; i++)
+ context->reg[i] = fs->signal_regs + (i << 2);
+ }
+ else
+ {
+ int window_size = fs->retaddr_column >> 2;
+
+ sp = (_Unwind_Word *) orig_context.sp;
+ cfa = (_Unwind_Word *) orig_context.cfa;
+ next_cfa = (_Unwind_Word *) cfa[-3];
+
+ /* Registers a0-a3 are in the save area below sp. */
+ context->reg[0] = sp - 4;
+
+ /* Find the extra save area below next_cfa. */
+ for (i = 1; i < window_size; i++)
+ context->reg[i] = next_cfa - 4 * (1 + window_size - i);
+
+ /* Remaining registers rotate from previous save areas. */
+ for (i = window_size; i < 4; i++)
+ context->reg[i] = orig_context.reg[i - window_size];
+ }
+
+ context->sp = cfa;
+ context->cfa = next_cfa;
+
+ _Unwind_SetSignalFrame (context, fs->signal_frame);
+}
+
+/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
+ of its caller. Update CONTEXT to refer to the caller as well. Note
+ that the lsda member is not updated here, but later in
+ uw_frame_state_for. */
+
+static void
+uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ uw_update_context_1 (context, fs);
+
+ /* Compute the return address now, since the return address column
+ can change from frame to frame. */
+ context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column)
+ & XTENSA_RA_FIELD_MASK) | context->ra_high_bits);
+}
+
+static void
+uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ uw_update_context (context, fs);
+}
+
+/* Fill in CONTEXT for top-of-stack. The only valid registers at this
+ level will be the return address and the CFA. */
+
+#define uw_init_context(CONTEXT) \
+ do \
+ { \
+ __builtin_unwind_init (); \
+ uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \
+ __builtin_return_address (0)); \
+ } \
+ while (0)
+
+static void
+uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa,
+ void *outer_ra)
+{
+ void *ra = __builtin_return_address (0);
+ void *cfa = __builtin_dwarf_cfa ();
+ _Unwind_FrameState fs;
+
+ memset (context, 0, sizeof (struct _Unwind_Context));
+ context->ra = ra;
+
+ memset (&fs, 0, sizeof (fs));
+ fs.retaddr_column = 8;
+ context->sp = cfa;
+ context->cfa = outer_cfa;
+ context->ra_high_bits =
+ ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK;
+ uw_update_context_1 (context, &fs);
+
+ context->ra = outer_ra;
+}
+
+
+/* Install TARGET into CURRENT so that we can return to it. This is a
+ macro because __builtin_eh_return must be invoked in the context of
+ our caller. */
+
+#define uw_install_context(CURRENT, TARGET) \
+ do \
+ { \
+ long offset = uw_install_context_1 ((CURRENT), (TARGET)); \
+ void *handler = __builtin_frob_return_addr ((TARGET)->ra); \
+ __builtin_eh_return (offset, handler); \
+ } \
+ while (0)
+
+static long
+uw_install_context_1 (struct _Unwind_Context *current,
+ struct _Unwind_Context *target)
+{
+ long i;
+
+ /* The eh_return insn assumes a window size of 8, so don't bother copying
+ the save areas for registers a8-a15 since they won't be reloaded. */
+ for (i = 0; i < 2; ++i)
+ {
+ void *c = current->reg[i];
+ void *t = target->reg[i];
+
+ if (t && c && t != c)
+ memcpy (c, t, 4 * sizeof (_Unwind_Word));
+ }
+
+ return 0;
+}
+
+static inline _Unwind_Ptr
+uw_identify_context (struct _Unwind_Context *context)
+{
+ return _Unwind_GetCFA (context);
+}
+
+
+#include "unwind.inc"
+
+#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
+alias (_Unwind_Backtrace);
+alias (_Unwind_DeleteException);
+alias (_Unwind_FindEnclosingFunction);
+alias (_Unwind_ForcedUnwind);
+alias (_Unwind_GetDataRelBase);
+alias (_Unwind_GetTextRelBase);
+alias (_Unwind_GetCFA);
+alias (_Unwind_GetGR);
+alias (_Unwind_GetIP);
+alias (_Unwind_GetLanguageSpecificData);
+alias (_Unwind_GetRegionStart);
+alias (_Unwind_RaiseException);
+alias (_Unwind_Resume);
+alias (_Unwind_Resume_or_Rethrow);
+alias (_Unwind_SetGR);
+alias (_Unwind_SetIP);
+#endif
+
+#endif /* !USING_SJLJ_EXCEPTIONS */
diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.h b/gcc/config/xtensa/unwind-dw2-xtensa.h
new file mode 100644
index 00000000000..99341172eac
--- /dev/null
+++ b/gcc/config/xtensa/unwind-dw2-xtensa.h
@@ -0,0 +1,57 @@
+/* DWARF2 frame unwind data structure for Xtensa.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2007
+ Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC 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 2, or (at your option)
+ any later version.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ GCC 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* A target can override (perhaps for backward compatibility) how
+ many dwarf2 columns are unwound. */
+#ifndef DWARF_FRAME_REGISTERS
+#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
+#endif
+
+/* Xtensa's variable-size register window save areas can be unwound without
+ any unwind info. This is a stripped down version of the standard DWARF
+ _Unwind_FrameState. */
+typedef struct
+{
+ /* The PC described by the current frame state. */
+ void *pc;
+
+ /* The information we care about from the CIE/FDE. */
+ _Unwind_Personality_Fn personality;
+ _Unwind_Word retaddr_column;
+ unsigned char fde_encoding;
+ unsigned char lsda_encoding;
+ unsigned char saw_z;
+ unsigned char signal_frame;
+ void *eh_ptr;
+
+ /* Saved registers for a signal frame. */
+ _Unwind_Word *signal_regs;
+} _Unwind_FrameState;
+
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index 4b9e58335de..7887345f9f5 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -1062,12 +1062,15 @@ typedef struct xtensa_args
/* How to start an assembler comment. */
#define ASM_COMMENT_START "#"
-/* Generate DWARF2 unwind info to get the DW_AT_frame_base set correctly,
- even though we don't yet use it for unwinding. */
-#define MUST_USE_SJLJ_EXCEPTIONS 1
-#define DWARF2_UNWIND_INFO 1
+/* Exception handling. Xtensa uses much of the standard DWARF2 unwinding
+ machinery, but the variable size register window save areas are too
+ complicated to efficiently describe with CFI entries. The CFA must
+ still be specified in DWARF so that DW_AT_frame_base is set correctly
+ for debugging. */
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 0)
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (0)
+#define DWARF_FRAME_REGISTERS 16
+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + 2 : INVALID_REGNUM)
/* Xtensa constant pool breaks the devices in crtstuff.c to control
section in where code resides. We have to write it as asm code. Use
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 98ebb09d46e..37e29e70039 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -35,6 +35,7 @@
(UNSPECV_MEMW 3)
(UNSPECV_S32RI 4)
(UNSPECV_S32C1I 5)
+ (UNSPECV_EH_RETURN 6)
])
;; This code iterator allows signed and unsigned widening multiplications
@@ -1600,6 +1601,26 @@
DONE;
})
+;; Stuff an address into the return address register along with the window
+;; size in the high bits. Because we don't have the window size of the
+;; previous frame, assume the function called out with a CALL8 since that
+;; is what compilers always use. Note: __builtin_frob_return_addr has
+;; already been applied to the handler, but the generic version doesn't
+;; allow us to frob it quite enough, so we just frob here.
+
+(define_insn_and_split "eh_return"
+ [(set (reg:SI A0_REG)
+ (unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
+ UNSPECV_EH_RETURN))
+ (clobber (match_scratch:SI 1 "=r"))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (match_dup 1) (ashift:SI (match_dup 0) (const_int 2)))
+ (set (match_dup 1) (plus:SI (match_dup 1) (const_int 2)))
+ (set (reg:SI A0_REG) (rotatert:SI (match_dup 1) (const_int 2)))]
+ "")
+
;; Setting up a frame pointer is tricky for Xtensa because GCC doesn't
;; know if a frame pointer is required until the reload pass, and
;; because there may be an incoming argument value in the hard frame