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:
parent
3e0cef6ddd
commit
1e874273f8
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -64,3 +64,4 @@
|
||||
: "0" (_beg), "r" (_end), "r" (_flg), "r" (_scno)); \
|
||||
}
|
||||
|
||||
#define ARM_TARGET2_DWARF_FORMAT DW_EH_PE_absptr
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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 \
|
||||
|
251
gcc/ginclude/unwind-arm-common.h
Normal file
251
gcc/ginclude/unwind-arm-common.h
Normal 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 */
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
133
libgcc/config/c6x/libunwind.S
Normal file
133
libgcc/config/c6x/libunwind.S
Normal 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
|
534
libgcc/config/c6x/pr-support.c
Normal file
534
libgcc/config/c6x/pr-support.c
Normal 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 += offset;
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op == 0xd2)
|
||||
{
|
||||
/* vsp = vsp + 0x204 + (uleb128 << 2). */
|
||||
int shift;
|
||||
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
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, ®);
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ®);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reserved. */
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
|
||||
/* Implicit RETURN. */
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ®);
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, ®);
|
||||
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;
|
||||
}
|
4
libgcc/config/c6x/t-c6x-elf
Normal file
4
libgcc/config/c6x/t-c6x-elf
Normal 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
|
||||
|
224
libgcc/config/c6x/unwind-c6x.c
Normal file
224
libgcc/config/c6x/unwind-c6x.c
Normal 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);
|
||||
}
|
71
libgcc/config/c6x/unwind-c6x.h
Normal file
71
libgcc/config/c6x/unwind-c6x.h
Normal 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 */
|
810
libgcc/unwind-arm-common.inc
Normal file
810
libgcc/unwind-arm-common.inc
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user