Makefile.in: Set and use UNWIND_H.
2005-06-28 Paul Brook <paul@codesourcery.com> gcc/ * Makefile.in: Set and use UNWIND_H. Install as unwind.h. * c-decl.c (finish_decl): Call default_init_unwind_resume_libfunc. * except.c (add_ehspec_entry): Generate arm eabi filter lists. (assign_filter_values): Ditto. (output_ttype): New function. (output_function_exception_table): Use output_ttype. Generate arm eabi filter lists. (default_init_unwind_resume_libfunc): New function. * except.h (default_init_unwind_resume_libfunc): Add prototype. * optabs.c (init_optabs): Don't set unwind_resume_libfunc. * opts.c (decode_options): Use targetm.unwind_tables_default. * target-def.h (TARGET_ASM_TTYPE): Provide and use definition. (TARGET_ARM_EABI_UNWINDER, TARGET_UNWIND_TABLES_DEFAULT): Ditto. * target.h (struct gcc_target): Add asm.ttype, unwind_tables_default and arm_eabi_unwinder. * unwind-c.c: Support Arm EABI unwinder. * unwind.h: Rename ... * unwind-generic.h: ... To this. * doc/tm.texi (TARGET_ASM_TTYPE, TARGET_ARM_EABI_UNWINDER): Document. (TARGET_UNWID_TABLES_DEFAULT): Document. * config/arm/arm-protos.h (arm_output_fn_unwind): Add prototype. * config/arm/arm.c (arm_unwind_emit, arm_output_ttype): New functions. (TARGET_UNWIND_EMIT, TARGET_ASM_TTYPE, TARGET_ARM_EABI_UNWINDER): Define. (thumb_pushpop, thumb_output_function_prologue): Output unwinding directives. (arm_unwind_emit_stm, arm_unwind_emit_set): New functions. * config/arm/arm.h (MUST_USE_SJLJ_EXCEPTIONS): Only define when !TARGET_UNWIND_INFO. (ARM_OUTPUT_FN_UNWIND, ARM_EABI_UNWIND_TABLES): Define. * config/arm/bpabi.h (TARGET_UNWIND_INFO): Define. * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME, ASM_DECLARE_FUNCTION_SIZE): Use ARM_OUTPUT_FN_UNWIND. * config/arm/lib1funcs.asm: Include libunwind.S. * config/arm/libgcc-bpabi.ver: Add unwinding routines. * config/arm/libunwind.S: New file. * config/arm/pr-support.c: New file. * config/arm/t-bpabi (LIB1ASMFUNCS): Add _unwind. (UNWIND_H, LIB2ADDEH, LIB2ADDEHDEP): Set. * config/arm/t-symbian (UNWIND_H, LIB2ADDEH, LIB2ADDEHDEP): Set. * config/arm/unwind-arm.c: New file. * config/arm/unwind-arm.h: New file. * config/i386/t-netware (USER_H): Remove unwind.h. * config/ia64/ia64.h (TARGET_UNWIND_TABLES_DEFAULT): Define. gcc/cp/ * Make-lang.in (cp/except.o): Depend on $(TARGET_H) * except.c: Include target.h. (init_exception_processing): Initialize unwind_resume_libfunc. * doc/tm.texi: Document TARGET_ASM_TTYPE gcc/ada/ * misc.c (gnat_init_gcc_eh): Call default_init_unwind_resume_libfunc. gcc/java/ * decl.c (java_init_decl_processing): Call default_init_unwind_resume_libfunc. gcc/objc/ * objc-act.c (objc_init_exceptions): Call default_init_unwind_resume_libfunc. libstdc++/ * acinclude.m4 (GLIBCXX_ENABLE_SJLJ_EXCEPTIONS): Check for __cxa_end_cleanup. * libsupc++/Makefile.am (sources): Add eh_call.c and eh_arm.c. * libsupc++/eh_arm.cc: New file. * libsupc++/eh_call.cc: New file. * libsupc++/eh_catch.cc (__cxa_get_exception_ptr): Use __gxx_caught_object. (__cxa_begin_catch): Ditto. Use __is_gxx_exception_class. Call _Unwind_Complete when using the ARM EABI. (__cxa_end_catch): Use __is_gxx_exception_class. * libsupc++/eh_personality.cc: Define NO_SIZE_OF_ENCODED_VALUE when using the ARM EABI. (save_caught_exception, restore_caught_exception): New functions. (_throw_typet): New typedef. (get_ttype_entry, get_adjusted_ptr, check_exception_spec): Add ARM EABI implementations. (PERSONALITY_FUNCTION): Use new functions. Addd support for ARM EABI unwinding libary. (__cxa_unexpected): Disable when using the ARM EABI. * libsupc++/eh_throw.cc (__cxa_throw): Use __GXX_INIT_EXCEPTION_CLASS. (__cxa_rethrow): Use __is_gxx_exception_class. Call _Unwind_RaiseException when using the ARM EABI. * libsupc++/unwind-cxx.h (struct __cxa_exception): Add fields for ARM EABI semantics. (struct __cxa_eh_globals): Ditto. (__cxa_call_terminate): Add prototype. (__cxa_type_match, __cxa_begin_cleanup, __cxa_end_cleanup): Add prototypes. (__get_exception_header_from_obj, __get_exception_header_from_ue): Move earlier in file. (__is_gxx_exception_class, __GXX_INIT_EXCEPTION_CLASS, __gxx_caught_object): New functions. * aclocal.m4: Regenerate. * configure: Regenerate. * Makefile.in: Regenerate. * include/Makefile.in: Regenerate. * libmath/Makefile.in: Regenerate. * libsupc++/Makefile.in: Regenerate. * po/Makefile.in: Regenerate. * src/Makefie.in: Regenerate. * testsuite/makefile.in: Regenerate. From-SVN: r101389
This commit is contained in:
parent
57e84f1840
commit
2a75c0b6d2
116
gcc/config/arm/libunwind.S
Normal file
116
gcc/config/arm/libunwind.S
Normal file
@ -0,0 +1,116 @@
|
||||
/* Support functions for the unwinder.
|
||||
Copyright (C) 2003, 2004 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef L_unwind
|
||||
|
||||
.macro UNPREFIX name
|
||||
.global SYM (\name)
|
||||
EQUIV SYM (\name), SYM (__\name)
|
||||
.endm
|
||||
|
||||
/* r0 points to a 16-word block. Upload these values to the actual core
|
||||
state. */
|
||||
ARM_FUNC_START restore_core_regs
|
||||
/* We must use sp as the base register when restoring sp. Push the
|
||||
last 3 registers onto the top of the current stack to achieve
|
||||
this. */
|
||||
add r1, r0, #52
|
||||
ldmia r1, {r3, r4, r5} /* {sp, lr, pc}. */
|
||||
#ifdef __INTERWORKING__
|
||||
/* Restore pc into ip. */
|
||||
mov r2, r5
|
||||
stmfd sp!, {r2, r3, r4}
|
||||
#else
|
||||
stmfd sp!, {r3, r4, r5}
|
||||
#endif
|
||||
/* Don't bother restoring ip. */
|
||||
ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp}
|
||||
/* Pop the three registers we pushed earlier. */
|
||||
#ifdef __INTERWORKING__
|
||||
ldmfd sp, {ip, sp, lr}
|
||||
bx ip
|
||||
#else
|
||||
ldmfd sp, {sp, lr, pc}
|
||||
#endif
|
||||
FUNC_END restore_core_regs
|
||||
UNPREFIX restore_core_regs
|
||||
|
||||
/* Load VFP registers d0-d15 from the address in r0. */
|
||||
ARM_FUNC_START gnu_Unwind_Restore_VFP
|
||||
/* Use the generic coprocessor form so that gas doesn't complain
|
||||
on soft-float targets. */
|
||||
ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */
|
||||
RET
|
||||
|
||||
/* Store VFR regsters d0-d15 to the address in r0. */
|
||||
ARM_FUNC_START gnu_Unwind_Save_VFP
|
||||
/* Use the generic coprocessor form so that gas doesn't complain
|
||||
on soft-float targets. */
|
||||
stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */
|
||||
RET
|
||||
|
||||
/* Wrappers to save core registers, then call the real routine. */
|
||||
|
||||
.macro UNWIND_WRAPPER name
|
||||
ARM_FUNC_START \name
|
||||
/* Create a phase2_vrs structure. */
|
||||
/* Split reg push in two to ensure the correct value for sp. */
|
||||
stmfd sp!, {sp, lr, pc}
|
||||
stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip}
|
||||
|
||||
/* Demand-save flags, plus an extra word for alignment. */
|
||||
mov r3, #0
|
||||
stmfd sp!, {r2, r3}
|
||||
|
||||
/* Point r1 at the block. Pass r0 unchanged. */
|
||||
add r1, sp, #4
|
||||
#if defined(__thumb__)
|
||||
/* Switch back to thumb mode to avoid interworking hassle. */
|
||||
adr ip, .L1_\name
|
||||
orr ip, ip, #1
|
||||
bx ip
|
||||
.thumb
|
||||
.L1_\name:
|
||||
bl SYM (__gnu\name) __PLT__
|
||||
ldr r3, [sp, #64]
|
||||
add sp, #72
|
||||
bx r3
|
||||
#else
|
||||
bl SYM (__gnu\name) __PLT__
|
||||
ldr lr, [sp, #64]
|
||||
add sp, sp, #72
|
||||
RET
|
||||
#endif
|
||||
FUNC_END \name
|
||||
UNPREFIX \name
|
||||
.endm
|
||||
|
||||
UNWIND_WRAPPER _Unwind_RaiseException
|
||||
UNWIND_WRAPPER _Unwind_Resume
|
||||
|
||||
#endif /* L_unwind */
|
377
gcc/config/arm/pr-support.c
Normal file
377
gcc/config/arm/pr-support.c
Normal file
@ -0,0 +1,377 @@
|
||||
/* ARM EABI compliant unwinding routines
|
||||
Copyright (C) 2004, 2005 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
#include "unwind.h"
|
||||
|
||||
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
|
||||
|
||||
/* Misc constants. */
|
||||
#define R_IP 12
|
||||
#define R_SP 13
|
||||
#define R_LR 14
|
||||
#define R_PC 15
|
||||
|
||||
#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 (0xb0)
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Execute the unwinding instructions described by UWS. */
|
||||
_Unwind_Reason_Code
|
||||
__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
|
||||
{
|
||||
_uw op;
|
||||
int set_pc;
|
||||
_uw reg;
|
||||
|
||||
set_pc = 0;
|
||||
for (;;)
|
||||
{
|
||||
op = next_unwind_byte (uws);
|
||||
if (op == CODE_FINISH)
|
||||
{
|
||||
/* If we haven't already set pc then copy it from lr. */
|
||||
if (!set_pc)
|
||||
{
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
|
||||
®);
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
|
||||
®);
|
||||
set_pc = 1;
|
||||
}
|
||||
/* Drop out of the loop. */
|
||||
break;
|
||||
}
|
||||
if ((op & 0x80) == 0)
|
||||
{
|
||||
/* vsp = vsp +- (imm6 << 2 + 4). */
|
||||
_uw offset;
|
||||
|
||||
offset = ((op & 0x3f) << 2) + 4;
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
if (op & 0x40)
|
||||
reg -= offset;
|
||||
else
|
||||
reg += offset;
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((op & 0xf0) == 0x80)
|
||||
{
|
||||
op = (op << 8) | next_unwind_byte (uws);
|
||||
if (op == 0x8000)
|
||||
{
|
||||
/* Refuse to unwind. */
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
/* Pop r4-r15 under mask. */
|
||||
op = (op << 4) & 0xfff0;
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
if (op & (1 << R_PC))
|
||||
set_pc = 1;
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xf0) == 0x90)
|
||||
{
|
||||
op &= 0xf;
|
||||
if (op == 13 || op == 15)
|
||||
/* Reserved. */
|
||||
return _URC_FAILURE;
|
||||
/* vsp = r[nnnn]. */
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®);
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xf0) == 0xa0)
|
||||
{
|
||||
/* Pop r4-r[4+nnn], [lr]. */
|
||||
_uw mask;
|
||||
|
||||
mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
|
||||
if (op & 8)
|
||||
mask |= (1 << R_LR);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xf0) == 0xb0)
|
||||
{
|
||||
/* op == 0xb0 already handled. */
|
||||
if (op == 0xb1)
|
||||
{
|
||||
op = next_unwind_byte (uws);
|
||||
if (op == 0 || ((op & 0xf0) != 0))
|
||||
/* Spare. */
|
||||
return _URC_FAILURE;
|
||||
/* Pop r0-r4 under mask. */
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (op == 0xb2)
|
||||
{
|
||||
/* vsp = vsp + 0x204 + (uleb128 << 2). */
|
||||
int shift;
|
||||
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
|
||||
®);
|
||||
op = next_unwind_byte (uws);
|
||||
shift = 2;
|
||||
while (op & 0x80)
|
||||
{
|
||||
reg += ((op & 0x7f) << shift);
|
||||
shift += 7;
|
||||
op = next_unwind_byte (uws);
|
||||
}
|
||||
reg += ((op & 0x7f) << shift) + 0x204;
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
|
||||
®);
|
||||
continue;
|
||||
}
|
||||
if (op == 0xb3)
|
||||
{
|
||||
/* Pop VFP registers with fldmx. */
|
||||
op = next_unwind_byte (uws);
|
||||
op = ((op & 0xf0) << 12) | (op & 0xf);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xfc) == 0xb4)
|
||||
{
|
||||
/* Pop FPA E[4]-E[4+nn]. */
|
||||
op = 0x40000 | ((op & 3) + 1);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
/* op & 0xf8 == 0xb8. */
|
||||
/* Pop VFP D[8]-D[8+nnn] with fldmx. */
|
||||
op = 0x80000 | ((op & 7) + 1);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xf0) == 0xc0)
|
||||
{
|
||||
if (op == 0xc6)
|
||||
{
|
||||
/* Pop iWMMXt D registers. */
|
||||
op = next_unwind_byte (uws);
|
||||
op = ((op & 0xf0) << 12) | (op & 0xf);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (op == 0xc7)
|
||||
{
|
||||
op = next_unwind_byte (uws);
|
||||
if (op == 0 || (op & 0xf0) != 0)
|
||||
/* Spare. */
|
||||
return _URC_FAILURE;
|
||||
/* Pop iWMMXt wCGR{3,2,1,0} under mask. */
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if ((op & 0xf8) == 0xc0)
|
||||
{
|
||||
/* Pop iWMMXt wR[10]-wR[10+nnn]. */
|
||||
op = 0xa0000 | ((op & 0xf) + 1);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (op == 0xc8)
|
||||
{
|
||||
/* Pop FPA registers. */
|
||||
op = next_unwind_byte (uws);
|
||||
op = ((op & 0xf0) << 12) | (op & 0xf);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
if (op == 0xc9)
|
||||
{
|
||||
/* Pop VFP registers with fldmd. */
|
||||
op = next_unwind_byte (uws);
|
||||
op = ((op & 0xf0) << 12) | (op & 0xf);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
/* Spare. */
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
if ((op & 0xf8) == 0xd0)
|
||||
{
|
||||
/* Pop VFP D[8]-D[8+nnn] with fldmd. */
|
||||
op = 0x80000 | ((op & 7) + 1);
|
||||
if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
|
||||
!= _UVRSR_OK)
|
||||
return _URC_FAILURE;
|
||||
continue;
|
||||
}
|
||||
/* Spare. */
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Get the start address of the function being unwound. */
|
||||
|
||||
_Unwind_Ptr
|
||||
_Unwind_GetRegionStart (_Unwind_Context * context)
|
||||
{
|
||||
_Unwind_Control_Block *ucbp;
|
||||
|
||||
ucbp = unwind_UCB_from_context (context);
|
||||
return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
|
||||
}
|
||||
|
||||
/* Find the Language specific exception data. */
|
||||
|
||||
void *
|
||||
_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
|
||||
{
|
||||
_Unwind_Control_Block *ucbp;
|
||||
_uw *ptr;
|
||||
|
||||
/* Get a pointer to the exception table entry. */
|
||||
ucbp = unwind_UCB_from_context (context);
|
||||
ptr = (_uw *) ucbp->pr_cache.ehtp;
|
||||
/* Skip the personality routine address. */
|
||||
ptr++;
|
||||
/* Skip the unwind opcodes. */
|
||||
ptr += (((*ptr) >> 24) & 0xff) + 1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
855
gcc/config/arm/unwind-arm.c
Normal file
855
gcc/config/arm/unwind-arm.c
Normal file
@ -0,0 +1,855 @@
|
||||
/* ARM EABI compliant unwinding routines.
|
||||
Copyright (C) 2004, 2005 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
#include "unwind.h"
|
||||
|
||||
/* Definitions for C++ runtime support routines. We make these weak
|
||||
declarations to avoid pulling in libsupc++ unneccesarily. */
|
||||
typedef unsigned char bool;
|
||||
|
||||
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
|
||||
|
||||
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
|
||||
bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
|
||||
bool __attribute__((weak)) __cxa_type_match(_Unwind_Control_Block *ucbp,
|
||||
const type_info *rttip,
|
||||
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_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
|
||||
#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
|
||||
|
||||
struct core_regs
|
||||
{
|
||||
_uw r[16];
|
||||
};
|
||||
|
||||
/* We use normal integer types here to avoid the compiler generating
|
||||
coprocessor instructions. */
|
||||
struct vfp_regs
|
||||
{
|
||||
_uw64 d[16];
|
||||
_uw pad;
|
||||
};
|
||||
|
||||
struct fpa_reg
|
||||
{
|
||||
_uw w[3];
|
||||
};
|
||||
|
||||
struct fpa_regs
|
||||
{
|
||||
struct fpa_reg f[8];
|
||||
};
|
||||
|
||||
/* 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
|
||||
demand-saving coprocessor registers.
|
||||
|
||||
During unwinding we hold the coprocessor state in the actual hardware
|
||||
registers and allocate demand-save areas for use during phase1
|
||||
unwinding. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* The first fields must be the same as a phase2_vrs. */
|
||||
_uw demand_save_flags;
|
||||
struct core_regs core;
|
||||
struct vfp_regs vfp;
|
||||
struct fpa_regs fpa;
|
||||
} phase1_vrs;
|
||||
|
||||
#define DEMAND_SAVE_VFP 1
|
||||
|
||||
/* This must match the structure created by the assembly wrappers. */
|
||||
typedef struct
|
||||
{
|
||||
_uw demand_save_flags;
|
||||
struct core_regs core;
|
||||
} phase2_vrs;
|
||||
|
||||
|
||||
/* An exeption 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. */
|
||||
|
||||
void __gnu_Unwind_Save_VFP (struct vfp_regs * p);
|
||||
void __gnu_Unwind_Restore_VFP (struct vfp_regs * p);
|
||||
|
||||
/* Restore coprocessor state after phase1 unwinding. */
|
||||
static void
|
||||
restore_non_core_regs (phase1_vrs * vrs)
|
||||
{
|
||||
if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0)
|
||||
__gnu_Unwind_Restore_VFP (&vrs->vfp);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* ABI defined personality routines. */
|
||||
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State,
|
||||
_Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak));
|
||||
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1 (_Unwind_State,
|
||||
_Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
|
||||
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2 (_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
|
||||
|| regno > 15)
|
||||
return _UVRSR_FAILED;
|
||||
*(_uw *) valuep = vrs->core.r[regno];
|
||||
return _UVRSR_OK;
|
||||
|
||||
case _UVRSC_VFP:
|
||||
case _UVRSC_FPA:
|
||||
case _UVRSC_WMMXD:
|
||||
case _UVRSC_WMMXC:
|
||||
return _UVRSR_NOT_IMPLEMENTED;
|
||||
|
||||
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
|
||||
|| regno > 15)
|
||||
return _UVRSR_FAILED;
|
||||
|
||||
vrs->core.r[regno] = *(_uw *) valuep;
|
||||
return _UVRSR_OK;
|
||||
|
||||
case _UVRSC_VFP:
|
||||
case _UVRSC_FPA:
|
||||
case _UVRSC_WMMXD:
|
||||
case _UVRSC_WMMXC:
|
||||
return _UVRSR_NOT_IMPLEMENTED;
|
||||
|
||||
default:
|
||||
return _UVRSR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ABI defined function to pop registers off the stack. */
|
||||
|
||||
_Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
|
||||
_Unwind_VRS_RegClass regclass,
|
||||
_uw discriminator,
|
||||
_Unwind_VRS_DataRepresentation representation)
|
||||
{
|
||||
phase1_vrs *vrs = (phase1_vrs *) context;
|
||||
|
||||
switch (regclass)
|
||||
{
|
||||
case _UVRSC_CORE:
|
||||
{
|
||||
_uw *ptr;
|
||||
_uw mask;
|
||||
int i;
|
||||
|
||||
if (representation != _UVRSD_UINT32)
|
||||
return _UVRSR_FAILED;
|
||||
|
||||
mask = discriminator & 0xffff;
|
||||
ptr = (_uw *) vrs->core.r[R_SP];
|
||||
/* Pop the requested registers. */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
vrs->core.r[i] = *(ptr++);
|
||||
}
|
||||
/* Writeback the stack pointer value if it wasn't restored. */
|
||||
if ((mask & (1 << R_SP)) == 0)
|
||||
vrs->core.r[R_SP] = (_uw) ptr;
|
||||
}
|
||||
return _UVRSR_OK;
|
||||
|
||||
case _UVRSC_VFP:
|
||||
{
|
||||
_uw start = discriminator >> 16;
|
||||
_uw count = discriminator & 0xffff;
|
||||
struct vfp_regs tmp;
|
||||
_uw *sp;
|
||||
_uw *dest;
|
||||
|
||||
if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
|
||||
|| start + count > 16)
|
||||
return _UVRSR_FAILED;
|
||||
|
||||
if (vrs->demand_save_flags & DEMAND_SAVE_VFP)
|
||||
{
|
||||
/* Demand-save resisters for stage1. */
|
||||
vrs->demand_save_flags &= ~DEMAND_SAVE_VFP;
|
||||
__gnu_Unwind_Save_VFP (&vrs->vfp);
|
||||
}
|
||||
|
||||
/* Restore the registers from the stack. Do this by saving the
|
||||
current VFP registers to a memory area, moving the in-memory
|
||||
values into that area, and restoring from the whole area.
|
||||
For _UVRSD_VFPX we assume FSTMX standard format 1. */
|
||||
__gnu_Unwind_Save_VFP (&tmp);
|
||||
|
||||
/* The stack address is only guaranteed to be word aligned, so
|
||||
we can't use doubleword copies. */
|
||||
sp = (_uw *) vrs->core.r[R_SP];
|
||||
dest = (_uw *) &tmp.d[start];
|
||||
count *= 2;
|
||||
while (count--)
|
||||
*(dest++) = *(sp++);
|
||||
|
||||
/* Skip the pad word */
|
||||
if (representation == _UVRSD_VFPX)
|
||||
sp++;
|
||||
|
||||
/* Set the new stack pointer. */
|
||||
vrs->core.r[R_SP] = (_uw) sp;
|
||||
|
||||
/* Reload the registers. */
|
||||
__gnu_Unwind_Restore_VFP (&tmp);
|
||||
}
|
||||
return _UVRSR_OK;
|
||||
|
||||
case _UVRSC_FPA:
|
||||
case _UVRSC_WMMXD:
|
||||
case _UVRSC_WMMXC:
|
||||
return _UVRSR_NOT_IMPLEMENTED;
|
||||
|
||||
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;
|
||||
/* Sign extend to 32 bits. */
|
||||
if (offset & (1 << 30))
|
||||
offset |= 1u << 31;
|
||||
|
||||
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)
|
||||
{
|
||||
_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);
|
||||
else
|
||||
next_fn = ~(_uw) 0;
|
||||
|
||||
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 occured, _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_FAILURE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
if (pr_result != _URC_CONTINUE_UNWIND)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pr_result != _URC_INSTALL_CONTEXT)
|
||||
abort();
|
||||
|
||||
restore_core_regs (&vrs->core);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
for (;;)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
if (pr_result != _URC_CONTINUE_UNWIND)
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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_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);
|
||||
|
||||
/* 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 ();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
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-relatvie 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;
|
||||
void *matched;
|
||||
|
||||
/* Check for no-throw areas. */
|
||||
if (data[1] == (_uw) -2)
|
||||
return _URC_FAILURE;
|
||||
|
||||
/* The thrown object immediately folows the ECB. */
|
||||
matched = (void *)(ucbp + 1);
|
||||
if (data[1] != (_uw) -1)
|
||||
{
|
||||
/* Match a catch specification. */
|
||||
rtti = _Unwind_decode_target2 ((_uw) &data[1]);
|
||||
if (!__cxa_type_match (ucbp, (type_info *) rtti,
|
||||
&matched))
|
||||
matched = (void *)0;
|
||||
}
|
||||
|
||||
if (matched)
|
||||
{
|
||||
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 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 mached. 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)
|
||||
{
|
||||
/* Match against teh 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,
|
||||
&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)
|
||||
phase2_call_unexpected_after_unwind = 1;
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 callsite. */
|
||||
_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
|
||||
__aeabi_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
|
||||
__aeabi_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
|
||||
__aeabi_unwind_cpp_pr2 (_Unwind_State state,
|
||||
_Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context)
|
||||
{
|
||||
return __gnu_unwind_pr_common (state, ucbp, context, 2);
|
||||
}
|
271
gcc/config/arm/unwind-arm.h
Normal file
271
gcc/config/arm/unwind-arm.h
Normal file
@ -0,0 +1,271 @@
|
||||
/* Header file for the ARM EABI unwinder
|
||||
Copyright (C) 2003, 2004 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Language-independent unwinder header public defines. This contins both
|
||||
ABI defined objects, and GNU support routines.*/
|
||||
|
||||
#ifndef UNWIND_ARM_H
|
||||
#define UNWIND_ARM_H
|
||||
|
||||
#define __ARM_EABI_UNWINDER__ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* We add a prototype for abort here to avoid creating a dependency on
|
||||
target headers. */
|
||||
extern void abort();
|
||||
|
||||
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_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
|
||||
}
|
||||
_Unwind_State;
|
||||
|
||||
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; /* init reserved1 to 0, then don't touch */
|
||||
_uw reserved2;
|
||||
_uw reserved3;
|
||||
_uw reserved4;
|
||||
_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 */
|
||||
};
|
||||
|
||||
/* Interface functions: */
|
||||
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
|
||||
void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
|
||||
void _Unwind_Complete(_Unwind_Control_Block *ucbp);
|
||||
|
||||
/* 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 */
|
||||
static inline _Unwind_Ptr
|
||||
_Unwind_GetDataRelBase (_Unwind_Context * context __attribute__ ((unused)))
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
static inline _Unwind_Ptr
|
||||
_Unwind_GetTextRelBase (_Unwind_Context * context __attribute__ ((unused)))
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
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_Word tmp;
|
||||
|
||||
tmp = *(_Unwind_Word *) ptr;
|
||||
/* Zero values are always NULL. */
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
#if defined(linux) || defined(__NetBSD__)
|
||||
/* Pc-relative indirect. */
|
||||
tmp += ptr;
|
||||
tmp = *(_Unwind_Word *) tmp;
|
||||
#elif defined(__symbian__)
|
||||
/* Absoute pointer. Nothing more to do. */
|
||||
#else
|
||||
/* Pc-relative pointer. */
|
||||
tmp += ptr;
|
||||
#endif
|
||||
return tmp;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Return the address of the instruction, not the actual IP value. */
|
||||
#define _Unwind_GetIP(context) \
|
||||
(_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 callsite. */
|
||||
#define _Unwind_SetIP(context, val) \
|
||||
_Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
|
||||
|
||||
/* Provided only for 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
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* defined UNWIND_ARM_H */
|
153
libstdc++-v3/libsupc++/eh_arm.cc
Normal file
153
libstdc++-v3/libsupc++/eh_arm.cc
Normal file
@ -0,0 +1,153 @@
|
||||
// -*- C++ -*- ARM specific Exception handling support routines.
|
||||
// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of GCC.
|
||||
//
|
||||
// GCC is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// GCC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING. If not, write to
|
||||
// the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
// Boston, MA 02111-1307, USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
#ifdef __ARM_EABI_UNWINDER__
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
// 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,
|
||||
// update *THROWN_PTR_P.
|
||||
|
||||
extern "C" __cxa_type_match_result
|
||||
__cxa_type_match(_Unwind_Exception* ue_header,
|
||||
const std::type_info* catch_type,
|
||||
bool is_reference __attribute__((__unused__)),
|
||||
void** thrown_ptr_p)
|
||||
{
|
||||
if (!__is_gxx_exception_class(ue_header->exception_class))
|
||||
return ctm_failed;
|
||||
|
||||
__cxa_exception* xh = __get_exception_header_from_ue(ue_header);
|
||||
const std::type_info* throw_type = xh->exceptionType;
|
||||
void* thrown_ptr = *thrown_ptr_p;
|
||||
|
||||
// Pointer types need to adjust the actual pointer, not
|
||||
// the pointer to pointer that is the exception object.
|
||||
// This also has the effect of passing pointer types
|
||||
// "by value" through the __cxa_begin_catch return value.
|
||||
if (throw_type->__is_pointer_p())
|
||||
thrown_ptr = *(void**) thrown_ptr;
|
||||
|
||||
if (catch_type->__do_catch(throw_type, &thrown_ptr, 1))
|
||||
{
|
||||
*thrown_ptr_p = thrown_ptr;
|
||||
|
||||
if (typeid(*catch_type) == typeid (typeid(void*)))
|
||||
{
|
||||
const __pointer_type_info *catch_pointer_type =
|
||||
static_cast<const __pointer_type_info *> (catch_type);
|
||||
const __pointer_type_info *throw_pointer_type =
|
||||
static_cast<const __pointer_type_info *> (throw_type);
|
||||
|
||||
if (typeid (*catch_pointer_type->__pointee) != typeid (void)
|
||||
&& (*catch_pointer_type->__pointee !=
|
||||
*throw_pointer_type->__pointee))
|
||||
return ctm_succeeded_with_ptr_to_base;
|
||||
}
|
||||
|
||||
return ctm_succeeded;
|
||||
}
|
||||
|
||||
return ctm_failed;
|
||||
}
|
||||
|
||||
// ABI defined routine called at the start of a cleanup handler.
|
||||
extern "C" bool
|
||||
__cxa_begin_cleanup(_Unwind_Exception* ue_header)
|
||||
{
|
||||
__cxa_eh_globals *globals = __cxa_get_globals();
|
||||
__cxa_exception *header = __get_exception_header_from_ue(ue_header);
|
||||
|
||||
if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
|
||||
{
|
||||
// TODO: cleanups with foreign exceptions.
|
||||
return false;
|
||||
}
|
||||
header->propagationCount++;
|
||||
// Add it to the chain if this is the first time we've seen this exception.
|
||||
if (header->propagationCount == 1)
|
||||
{
|
||||
header->nextPropagatingException = globals->propagatingExceptions;
|
||||
globals->propagatingExceptions = header;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do the work for __cxa_end_cleanup. Returns the currently propagating
|
||||
// exception object.
|
||||
extern "C" _Unwind_Exception *
|
||||
__gnu_end_cleanup(void)
|
||||
{
|
||||
__cxa_exception *header;
|
||||
__cxa_eh_globals *globals = __cxa_get_globals();
|
||||
|
||||
header = globals->propagatingExceptions;
|
||||
|
||||
// Check something hasn't gone horribly wrong.
|
||||
if (!header)
|
||||
std::terminate();
|
||||
|
||||
header->propagationCount--;
|
||||
if (header->propagationCount == 0)
|
||||
{
|
||||
// Remove exception from chain.
|
||||
globals->propagatingExceptions = header->nextPropagatingException;
|
||||
header->nextPropagatingException = NULL;
|
||||
}
|
||||
return &header->unwindHeader;
|
||||
}
|
||||
|
||||
// Assembly wrapper to call __gnu_end_cleanup without clobbering r1-r3.
|
||||
// Also push r4 to preserve stack alignment.
|
||||
#ifdef __thumb__
|
||||
asm (".global __cxa_end_cleanup\n"
|
||||
" .type __cxa_end_cleanup, \"function\"\n"
|
||||
" .thumb_func\n"
|
||||
"__cxa_end_cleanup:\n"
|
||||
" push\t{r1, r2, r3, r4}\n"
|
||||
" bl\t__gnu_end_cleanup\n"
|
||||
" pop\t{r1, r2, r3, r4}\n"
|
||||
" bl\t_Unwind_Resume @ Never returns\n");
|
||||
#else
|
||||
asm (".global __cxa_end_cleanup\n"
|
||||
" .type __cxa_end_cleanup, \"function\"\n"
|
||||
"__cxa_end_cleanup:\n"
|
||||
" stmfd\tsp!, {r1, r2, r3, r4}\n"
|
||||
" bl\t__gnu_end_cleanup\n"
|
||||
" ldmfd\tsp!, {r1, r2, r3, r4}\n"
|
||||
" bl\t_Unwind_Resume @ Never returns\n");
|
||||
#endif
|
||||
|
||||
#endif
|
162
libstdc++-v3/libsupc++/eh_call.cc
Normal file
162
libstdc++-v3/libsupc++/eh_call.cc
Normal file
@ -0,0 +1,162 @@
|
||||
// -*- C++ -*- Helpers for calling unextected and terminate
|
||||
// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of GCC.
|
||||
//
|
||||
// GCC is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// GCC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING. If not, write to
|
||||
// the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
// Boston, MA 02111-1307, USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include <bits/c++config.h>
|
||||
#include <cstdlib>
|
||||
#include <exception_defines.h>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
#include "unwind-pe.h"
|
||||
|
||||
|
||||
// Helper routine for when the exception handling code needs to call
|
||||
// terminate.
|
||||
|
||||
extern "C" void
|
||||
__cxa_call_terminate(_Unwind_Exception* ue_header)
|
||||
{
|
||||
|
||||
if (ue_header)
|
||||
{
|
||||
// terminate is classed as a catch handler.
|
||||
__cxa_begin_catch(ue_header);
|
||||
|
||||
// Call the terminate handler that was in effect when we threw this
|
||||
// exception. */
|
||||
if (__is_gxx_exception_class(ue_header->exception_class))
|
||||
{
|
||||
__cxa_exception* xh;
|
||||
|
||||
xh = __get_exception_header_from_ue(ue_header);
|
||||
__terminate(xh->terminateHandler);
|
||||
}
|
||||
}
|
||||
/* Call the global routine if we don't have anything better. */
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
|
||||
#ifdef __ARM_EABI_UNWINDER__
|
||||
// The ARM EABI __cxa_call_unexpected has the same semantics as the generic
|
||||
// routine, but the exception specification has a different format.
|
||||
extern "C" void
|
||||
__cxa_call_unexpected(void* exc_obj_in)
|
||||
{
|
||||
_Unwind_Exception* exc_obj
|
||||
= reinterpret_cast<_Unwind_Exception*>(exc_obj_in);
|
||||
|
||||
int rtti_count = 0;
|
||||
_Unwind_Word rtti_stride = 0;
|
||||
_Unwind_Word* rtti_list = NULL;
|
||||
bool foreign_exception;
|
||||
std::unexpected_handler unexpectedHandler = NULL;
|
||||
std::terminate_handler terminateHandler = NULL;
|
||||
__cxa_exception* xh;
|
||||
if (__is_gxx_exception_class(exc_obj->exception_class))
|
||||
{
|
||||
// Save data from the EO, which may be clobbered by _cxa_begin_catch.
|
||||
xh = __get_exception_header_from_ue(exc_obj);
|
||||
unexpectedHandler = xh->unexpectedHandler;
|
||||
terminateHandler = xh->terminateHandler;
|
||||
rtti_count = exc_obj->barrier_cache.bitpattern[1];
|
||||
|
||||
rtti_stride = exc_obj->barrier_cache.bitpattern[3];
|
||||
rtti_list = (_Unwind_Word*) exc_obj->barrier_cache.bitpattern[4];
|
||||
foreign_exception = false;
|
||||
}
|
||||
else
|
||||
foreign_exception = true;
|
||||
|
||||
/* This must be called after extracting data from the EO, but before
|
||||
calling unexpected(). */
|
||||
__cxa_begin_catch(exc_obj);
|
||||
|
||||
// This function is a handler for our exception argument. If we exit
|
||||
// by throwing a different exception, we'll need the original cleaned up.
|
||||
struct end_catch_protect
|
||||
{
|
||||
end_catch_protect() { }
|
||||
~end_catch_protect() { __cxa_end_catch(); }
|
||||
} end_catch_protect_obj;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (foreign_exception)
|
||||
std::unexpected();
|
||||
else
|
||||
__unexpected(unexpectedHandler);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
/* See if the new exception matches the rtti list. */
|
||||
if (foreign_exception)
|
||||
std::terminate();
|
||||
|
||||
// Get the exception thrown from unexpected.
|
||||
|
||||
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||
__cxa_exception* new_xh = globals->caughtExceptions;
|
||||
void* new_ptr = new_xh + 1;
|
||||
const std::type_info* catch_type;
|
||||
int n;
|
||||
bool bad_exception_allowed = false;
|
||||
const std::type_info& bad_exc = typeid(std::bad_exception);
|
||||
|
||||
// Check the new exception against the rtti list
|
||||
for (n = 0; n < rtti_count; n++)
|
||||
{
|
||||
_Unwind_Word offset;
|
||||
|
||||
offset = (_Unwind_Word) &rtti_list[n * (rtti_stride >> 2)];
|
||||
offset = _Unwind_decode_target2(offset);
|
||||
catch_type = (const std::type_info*) (offset);
|
||||
|
||||
if (__cxa_type_match(&new_xh->unwindHeader, catch_type, false,
|
||||
&new_ptr) != ctm_failed)
|
||||
__throw_exception_again;
|
||||
|
||||
if (catch_type->__do_catch(&bad_exc, 0, 1))
|
||||
bad_exception_allowed = true;
|
||||
}
|
||||
|
||||
// If the exception spec allows std::bad_exception, throw that.
|
||||
#ifdef __EXCEPTIONS
|
||||
if (bad_exception_allowed)
|
||||
throw std::bad_exception();
|
||||
#endif
|
||||
|
||||
// Otherwise, die.
|
||||
__terminate(terminateHandler);
|
||||
}
|
||||
}
|
||||
#endif // __ARM_EABI_UNWINDER__
|
Loading…
Reference in New Issue
Block a user