aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc/config/c6x/pr-support.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/libgcc/config/c6x/pr-support.c')
-rw-r--r--gcc-4.9/libgcc/config/c6x/pr-support.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/gcc-4.9/libgcc/config/c6x/pr-support.c b/gcc-4.9/libgcc/config/c6x/pr-support.c
new file mode 100644
index 000000000..99f44d397
--- /dev/null
+++ b/gcc-4.9/libgcc/config/c6x/pr-support.c
@@ -0,0 +1,535 @@
+/* C6X ABI compliant unwinding routines
+ Copyright (C) 2011-2014 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, regno, 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];
+
+ if (i < 12 && nregs > 2
+ && (mask & (test << 1)) != 0
+ && unwind_frame_regs[11 - i] == 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 (i < 12 && nregs > 2
+ && (mask & (test << 1)) != 0
+ && unwind_frame_regs[11 - i] == 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[11 - 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;
+ int ret_reg = unwind_frame_regs[data & 0xf];
+
+ if (ret_reg != R_B3)
+ {
+ _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
+ _UVRSD_UINT32, &tmp);
+ _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &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, R_B3, _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;
+}