arm.h (ASM_PREFERRED_EH_DATA_FORMAT): Define.

2011-09-13  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/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 (EXTRA_HEADERS): Set.
	* ginclude/unwind-arm-common.h: New file.

	libgcc/
	* config.host (tic6x-*-*): Add c6x/t-c6x-elf.  Set unwind_header.
	* unwind-c.c (PERSONALITY_FUNCTION): Use UNWIND_POINTER_REG.
	* unwind-arm-common.inc: New file.
	* 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/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.
	* config/c6x/t-c6x-elf: 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.

From-SVN: r178808
This commit is contained in:
Paul Brook 2011-09-13 12:48:33 +00:00 committed by Paul Brook
parent 3e0cef6ddd
commit 1e874273f8
26 changed files with 2226 additions and 1027 deletions

View File

@ -1,3 +1,22 @@
2011-09-13 Paul Brook <paul@codesourcery.com>
* 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/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 (EXTRA_HEADERS): Set.
* ginclude/unwind-arm-common.h: New file.
2011-09-13 Georg-Johann Lay <avr@gjlay.de>
PR target/50358

View File

@ -825,6 +825,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. */

View File

@ -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)

View File

@ -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

View File

@ -28,3 +28,4 @@ LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/arm/fp16.c
# Add the BPABI names.
SHLIB_MAPFILES += $(srcdir)/config/arm/libgcc-bpabi.ver
EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h

View File

@ -30,6 +30,7 @@ LIB1ASMFUNCS += \
_truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \
_fixsfsi _fixunssfsi
EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
# Include half-float helpers.
LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/arm/fp16.c

View File

@ -64,3 +64,4 @@
: "0" (_beg), "r" (_end), "r" (_flg), "r" (_scno)); \
}
#define ARM_TARGET2_DWARF_FORMAT DW_EH_PE_absptr

View File

@ -402,12 +402,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;
}
}
@ -5606,6 +5613,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. */
@ -5746,6 +5765,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

View File

@ -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) \

View File

@ -24,6 +24,7 @@ LIB1ASMFUNCS += _strasgi _strasgi_64plus _clzsi2 _clzdi2 _clz
LIB1ASMFUNCS += _push_rts _pop_rts _call_stub
LIB2FUNCS_EXCLUDE = _cmpdi2 _ucmpdi2 _gcc_bcmp _eprintf _clzsi _clzdi
EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
LIB2FUNCS_EXTRA = $(srcdir)/config/c6x/gef.c \
$(srcdir)/config/c6x/gtf.c \

View File

@ -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 */

View File

@ -1,3 +1,17 @@
2011-09-13 Paul Brook <paul@codesourcery.com>
* config.host (tic6x-*-*): Add c6x/t-c6x-elf. Set unwind_header.
* unwind-c.c (PERSONALITY_FUNCTION): Use UNWIND_POINTER_REG.
* unwind-arm-common.inc: New file.
* 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/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.
* config/c6x/t-c6x-elf: New file.
2011-08-23 Uros Bizjak <ubizjak@gmail.com>
* config/i386/64/sfp-machine.h (ASM_INVALID): New define.

View File

@ -790,7 +790,8 @@ spu-*-elf*)
tmake_file="t-fdpbit spu/t-elf"
;;
tic6x-*-*)
tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl t-softfp t-gnu-prefix"
tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl t-softfp t-gnu-prefix c6x/t-c6x-elf"
unwind_header=config/c6x/unwind-c6x.h
;;
v850*-*-*)
tmake_file=t-fdpbit

View File

@ -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)
switch (idx)
{
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;
case 0:
return (_uw) &__aeabi_unwind_cpp_pr0;
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;
}
}
case 1:
return (_uw) &__aeabi_unwind_cpp_pr1;
/* 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;
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 ();
}
return 0;
}
}
_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;
}
/* ABI defined personality routine entry points. */
_Unwind_Reason_Code

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,4 @@
LIB2ADDEH = $(srcdir)/config/c6x/unwind-c6x.c \
$(srcdir)/config/c6x/libunwind.S \
$(srcdir)/config/c6x/pr-support.c $(srcdir)/unwind-c.c

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -1,3 +1,15 @@
2011-09-13 Paul Brook <paul@codesourcery.com>
* 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.
2011-09-12 Daniel Krugler <daniel.kruegler@googlemail.com>
Paolo Carlini <paolo.carlini@oracle.com>

View File

@ -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

View File

@ -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,

View File

@ -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.