2007-11-13 22:41:50 +00:00
|
|
|
|
/* DWARF2 exception handling and frame unwinding for Xtensa.
|
2013-02-04 19:06:20 +00:00
|
|
|
|
Copyright (C) 1997-2013 Free Software Foundation, Inc.
|
2007-11-13 22:41:50 +00:00
|
|
|
|
|
|
|
|
|
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
|
2009-04-09 17:00:19 +02:00
|
|
|
|
the Free Software Foundation; either version 3, or (at your option)
|
2007-11-13 22:41:50 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2009-04-09 17:00:19 +02:00
|
|
|
|
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/>. */
|
2007-11-13 22:41:50 +00:00
|
|
|
|
|
|
|
|
|
#include "tconfig.h"
|
|
|
|
|
#include "tsystem.h"
|
|
|
|
|
#include "coretypes.h"
|
|
|
|
|
#include "tm.h"
|
Move libgcc_tm_file to toplevel libgcc
gcc:
* configure.ac (libgcc_tm_file_list, libgcc_tm_include_list):
Remove.
* configure: Regenerate.
* Makefile.in (libgcc_tm_file_list, libgcc_tm_include_list): Remove.
(TM_H): Remove libgcc_tm.h, $(libgcc_tm_file_list).
(libgcc_tm.h, cs-libgcc_tm.h): Remove.
(clean): Remove libgcc_tm.h
* mkconfig.sh: Don't include libgcc_tm.h in tm.h.
* config.gcc (libgcc_tm_file): Remove.
(arm*-*-linux*): Remove libgcc_tm_file for arm*-*-linux-*eabi.
(arm*-*-uclinux*): Remove libgcc_tm_file for arm*-*-uclinux*eabi.
(arm*-*-eabi*, arm*-*-symbianelf*): Remove libgcc_tm_file.
(avr-*-rtems*): Likewise.
(avr-*-*): Likewise.
(frv-*-elf): Likewise.
(frv-*-*linux*): Likewise.
(h8300-*-rtems*): Likewise.
(h8300-*-elf*): Likewise.
(i[34567]86-*-darwin*): Likewise.
(x86_64-*-darwin*): Likewise.
(rx-*-elf*): Likewise.
(tic6x-*-elf): Likewise.
(tic6x-*-uclinux): Likewise.
(i[34567]86-*-linux*, x86_64-*-linux*): Likewise.
libgcc:
* configure.ac (tm_file_): New variable.
Determine from tm_file.
(tm_file, tm_defines): Substitute.
* configure: Regenerate.
* mkheader.sh: New file.
* Makefile.in (clean): Remove libgcc_tm.h.
($(objects)): Depend on libgcc_tm.h.
(libgcc_tm_defines, libgcc_tm_file): New variables.
(libgcc_tm.h, libgcc_tm.stamp): New targets.
($(libgcc-objects), $(libgcc-s-objects), $(libgcc-eh-objects))
($(libgcov-objects), $(libunwind-objects), $(libunwind-s-objects))
($(extra-parts)): Depend on libgcc_tm.h.
* config.host (tm_defines, tm_file): New variable.
(arm*-*-linux*): Set tm_file for arm*-*-linux-*eabi.
(arm*-*-uclinux*): Set tm_file for arm*-*-uclinux*eabi.
(arm*-*-eabi*, arm*-*-symbianelf*): Set tm_file.
(avr-*-rtems*): Likewise.
(avr-*-*): Likewise.
(frv-*-elf): Likewise.
(frv-*-*linux*): Likewise.
(h8300-*-rtems*): Likewise.
(h8300-*-elf*): Likewise.
(i[34567]86-*-darwin*): Likewise.
(x86_64-*-darwin*): Likewise.
(rx-*-elf): Likewise.
(tic6x-*-uclinux): Likewise.
(tic6x-*-elf): Likewise.
(i[34567]86-*-linux*, x86_64-*-linux*): Likewise.
* config/alpha/gthr-posix.c: Include libgcc_tm.h.
* config/i386/cygming-crtbegin.c: Likewise.
* config/i386/cygming-crtend.c: Likewise.
* config/ia64/fde-vms.c: Likewise.
* config/ia64/unwind-ia64.c: Likewise.
* config/libbid/bid_gcc_intrinsics.h: Likewise.
* config/rs6000/darwin-fallback.c: Likewise.
* config/stormy16/lib2funcs.c: Likewise.
* config/xtensa/unwind-dw2-xtensa.c: Likewise.
* crtstuff.c: Likewise.
* dfp-bit.h: Likewise.
* emutls.c: Likewise.
* fixed-bit.c: Likewise.
* fp-bit.c: Likewise.
* generic-morestack-thread.c: Likewise.
* generic-morestack.c: Likewise.
* libgcc2.c: Likewise.
* libgcov.c: Likewise.
* unwind-dw2-fde-dip.c: Likewise.
* unwind-dw2-fde.c: Likewise.
* unwind-dw2.c: Likewise.
* unwind-sjlj.c: Likewise.
Co-Authored-By: Paolo Bonzini <bonzini@gnu.org>
From-SVN: r180775
2011-11-02 15:26:35 +00:00
|
|
|
|
#include "libgcc_tm.h"
|
2009-07-09 19:41:25 +00:00
|
|
|
|
#include "dwarf2.h"
|
2007-11-13 22:41:50 +00:00
|
|
|
|
#include "unwind.h"
|
|
|
|
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
|
|
|
|
# define NO_SIZE_OF_ENCODED_VALUE
|
|
|
|
|
#endif
|
|
|
|
|
#include "unwind-pe.h"
|
|
|
|
|
#include "unwind-dw2-fde.h"
|
|
|
|
|
#include "unwind-dw2-xtensa.h"
|
|
|
|
|
|
|
|
|
|
#ifndef __USING_SJLJ_EXCEPTIONS__
|
|
|
|
|
|
|
|
|
|
/* The standard CIE and FDE structures work fine for Xtensa but the
|
|
|
|
|
variable-size register window save areas are not a good fit for the rest
|
|
|
|
|
of the standard DWARF unwinding mechanism. Nor is that mechanism
|
|
|
|
|
necessary, since the register save areas are always in fixed locations
|
|
|
|
|
in each stack frame. This file is a stripped down and customized version
|
|
|
|
|
of the standard DWARF unwinding code. It needs to be customized to have
|
|
|
|
|
builtin logic for finding the save areas and also to track the stack
|
|
|
|
|
pointer value (besides the CFA) while unwinding since the primary save
|
|
|
|
|
area is located below the stack pointer. It is stripped down to reduce
|
|
|
|
|
code size and ease the maintenance burden of tracking changes in the
|
|
|
|
|
standard version of the code. */
|
|
|
|
|
|
|
|
|
|
#ifndef DWARF_REG_TO_UNWIND_COLUMN
|
|
|
|
|
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF
|
|
|
|
|
|
|
|
|
|
/* This is the register and unwind state for a particular frame. This
|
|
|
|
|
provides the information necessary to unwind up past a frame and return
|
|
|
|
|
to its caller. */
|
|
|
|
|
struct _Unwind_Context
|
|
|
|
|
{
|
|
|
|
|
/* Track register window save areas of 4 registers each, instead of
|
|
|
|
|
keeping separate addresses for the individual registers. */
|
|
|
|
|
_Unwind_Word *reg[4];
|
|
|
|
|
|
|
|
|
|
void *cfa;
|
|
|
|
|
void *sp;
|
|
|
|
|
void *ra;
|
|
|
|
|
|
|
|
|
|
/* Cache the 2 high bits to replace the window size in return addresses. */
|
|
|
|
|
_Unwind_Word ra_high_bits;
|
|
|
|
|
|
|
|
|
|
void *lsda;
|
|
|
|
|
struct dwarf_eh_bases bases;
|
|
|
|
|
/* Signal frame context. */
|
|
|
|
|
#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
|
|
|
|
|
_Unwind_Word flags;
|
|
|
|
|
/* 0 for now, can be increased when further fields are added to
|
|
|
|
|
struct _Unwind_Context. */
|
|
|
|
|
_Unwind_Word version;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read unaligned data from the instruction buffer. */
|
|
|
|
|
|
|
|
|
|
union unaligned
|
|
|
|
|
{
|
|
|
|
|
void *p;
|
|
|
|
|
} __attribute__ ((packed));
|
|
|
|
|
|
|
|
|
|
static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
|
|
|
|
|
static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
|
|
|
|
|
_Unwind_FrameState *);
|
|
|
|
|
|
|
|
|
|
static inline void *
|
|
|
|
|
read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
|
|
|
|
|
|
|
|
|
|
static inline _Unwind_Word
|
|
|
|
|
_Unwind_IsSignalFrame (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
|
|
|
|
|
{
|
|
|
|
|
if (val)
|
|
|
|
|
context->flags |= SIGNAL_FRAME_BIT;
|
|
|
|
|
else
|
|
|
|
|
context->flags &= ~SIGNAL_FRAME_BIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the value of register INDEX as saved in CONTEXT. */
|
|
|
|
|
|
|
|
|
|
inline _Unwind_Word
|
|
|
|
|
_Unwind_GetGR (struct _Unwind_Context *context, int index)
|
|
|
|
|
{
|
|
|
|
|
_Unwind_Word *ptr;
|
|
|
|
|
|
|
|
|
|
index = DWARF_REG_TO_UNWIND_COLUMN (index);
|
|
|
|
|
ptr = context->reg[index >> 2] + (index & 3);
|
|
|
|
|
|
|
|
|
|
return *ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the value of the CFA as saved in CONTEXT. */
|
|
|
|
|
|
|
|
|
|
_Unwind_Word
|
|
|
|
|
_Unwind_GetCFA (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (_Unwind_Ptr) context->cfa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
|
|
|
|
|
{
|
|
|
|
|
_Unwind_Word *ptr;
|
|
|
|
|
|
|
|
|
|
index = DWARF_REG_TO_UNWIND_COLUMN (index);
|
|
|
|
|
ptr = context->reg[index >> 2] + (index & 3);
|
|
|
|
|
|
|
|
|
|
*ptr = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve the return address for CONTEXT. */
|
|
|
|
|
|
|
|
|
|
inline _Unwind_Ptr
|
|
|
|
|
_Unwind_GetIP (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (_Unwind_Ptr) context->ra;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve the return address and flag whether that IP is before
|
|
|
|
|
or after first not yet fully executed instruction. */
|
|
|
|
|
|
|
|
|
|
inline _Unwind_Ptr
|
|
|
|
|
_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
|
|
|
|
|
{
|
|
|
|
|
*ip_before_insn = _Unwind_IsSignalFrame (context);
|
|
|
|
|
return (_Unwind_Ptr) context->ra;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Overwrite the return address for CONTEXT with VAL. */
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
|
|
|
|
|
{
|
|
|
|
|
context->ra = (void *) val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return context->lsda;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_Unwind_Ptr
|
|
|
|
|
_Unwind_GetRegionStart (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (_Unwind_Ptr) context->bases.func;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
_Unwind_FindEnclosingFunction (void *pc)
|
|
|
|
|
{
|
|
|
|
|
struct dwarf_eh_bases bases;
|
|
|
|
|
const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
|
|
|
|
|
if (fde)
|
|
|
|
|
return bases.func;
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_Unwind_Ptr
|
|
|
|
|
_Unwind_GetDataRelBase (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (_Unwind_Ptr) context->bases.dbase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_Unwind_Ptr
|
|
|
|
|
_Unwind_GetTextRelBase (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return (_Unwind_Ptr) context->bases.tbase;
|
|
|
|
|
}
|
|
|
|
|
|
linux.h (MD_UNWIND_SUPPORT): Remove.
gcc:
* config/alpha/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/alpha/osf5.h (MD_UNWIND_SUPPORT): Remove.
* config/alpha/vms.h (MD_UNWIND_SUPPORT): Remove.
* config/bfin/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/bfin/uclinux.h (MD_UNWIND_SUPPORT): Remove.
* config/i386/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/i386/linux64.h (MD_UNWIND_SUPPORT): Remove.
* config/i386/sol2.h (MD_UNWIND_SUPPORT): Remove.
* config/i386/mingw32.h (MD_UNWIND_SUPPORT): Remove.
* config/ia64/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/ia64/vms.h (MD_UNWIND_SUPPORT): Remove.
* config/m68k/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/mips/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/pa/pa-hpux.h (MD_UNWIND_SUPPORT): Remove.
* config/pa/pa32-linux.h (MD_UNWIND_SUPPORT): Remove.
* config/rs6000/darwin.h (MD_UNWIND_SUPPORT): Remove.
* config/rs6000/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/rs6000/linux64.h (MD_UNWIND_SUPPORT): Remove.
* config/s390/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/s390/tpf.h (MD_UNWIND_SUPPORT): Remove.
* config/sh/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/sparc/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/sparc/linux64.h (MD_UNWIND_SUPPORT): Remove.
* config/sparc/sol2.h (MD_UNWIND_SUPPORT): Remove.
* config/xtensa/linux.h (MD_UNWIND_SUPPORT): Remove.
* config/alpha/linux-unwind.h: Move to ../libgcc/config/alpha.
* config/alpha/osf5-unwind.h: Move to ../libgcc/config/alpha.
* config/alpha/vms-unwind.h: Move to ../libgcc/config/alpha.
* config/bfin/linux-unwind.h: Move to ../libgcc/config/bfin.
* config/i386/linux-unwind.h: Move to ../libgcc/config/i386.
* config/i386/sol2-unwind.h: Move to ../libgcc/config/i386.
* config/i386/w32-unwind.h: Move to ../libgcc/config/i386.
* config/ia64/linux-unwind.h: Move to ../libgcc/config/ia64.
* config/ia64/vms-unwind.h: Move to ../libgcc/config/ia64.
* config/m68k/linux-unwind.h: Move to ../libgcc/config/m68k.
* config/mips/linux-unwind.h: Move to ../libgcc/config/mips.
* config/pa/hpux-unwind.h: Move to ../libgcc/config/pa.
* config/pa/linux-unwind.h: Move to ../libgcc/config/pa.
* config/rs6000/darwin-unwind.h: Move to ../libgcc/config/rs6000.
* config/rs6000/linux-unwind.h: Move to ../libgcc/config/rs6000.
* config/s390/linux-unwind.h: Move to ../libgcc/config/s390.
* config/s390/tpf-unwind.h: Move to ../libgcc/config/s390.
* config/sh/linux-unwind.h: Move to ../libgcc/config/sh.
* config/sparc/linux-unwind.h: Move to ../libgcc/config/sparc.
* config/sparc/sol2-unwind.h: Move to ../libgcc/config/sparc.
* config/xtensa/linux-unwind.h: Move to ../libgcc/config/xtensa.
* config/darwin9.h (DARWIN_LIBSYSTEM_HAS_UNWIND): Remove.
* system.h (MD_UNWIND_SUPPORT): Poison.
* doc/tm.texi.in (Exception Handling, MD_UNWIND_SUPPORT): Remove.
* doc/tm.texi: Regenerate.
* unwind-dw2.c: Include md-unwind-support.h instead of
MD_UNWIND_SUPPORT.
* config/ia64/unwind-ia64.c: Likewise.
* config/xtensa/unwind-dw2-xtensa.c: Likewise.
libgcc:
* config/alpha/linux-unwind.h: Move from ../gcc/config/alpha.
* config/alpha/osf5-unwind.h: Move from ../gcc/config/alpha.
* config/alpha/vms-unwind.h: Move from ../gcc/config/alpha.
* config/bfin/linux-unwind.h: Move from ../gcc/config/bfin.
* config/i386/linux-unwind.h: Move from ../gcc/config/i386.
* config/i386/sol2-unwind.h: Move from ../gcc/config/i386.
* config/i386/w32-unwind.h: Move from ../gcc/config/i386.
Wrap in !__MINGW64__.
* config/ia64/linux-unwind.h: Move from ../gcc/config/ia64.
* config/ia64/vms-unwind.h: Move from ../gcc/config/ia64.
* config/m68k/linux-unwind.h: Move from ../gcc/config/m68k.
* config/mips/linux-unwind.h: Move from ../gcc/config/mips.
* config/pa/hpux-unwind.h: Move from ../gcc/config/pa.
* config/pa/linux-unwind.h: Move from ../gcc/config/pa.
* config/rs6000/darwin-unwind.h: Move from ../gcc/config/rs6000.
Wrap in !__LP64__.
* config/rs6000/linux-unwind.h: Move from ../gcc/config/rs6000.
* config/s390/linux-unwind.h: Move from ../gcc/config/s390.
* config/s390/tpf-unwind.h: Move from ../gcc/config/s390.
* config/sh/linux-unwind.h: Move from ../gcc/config/sh.
* config/sparc/linux-unwind.h: Move from ../gcc/config/sparc.
* config/sparc/sol2-unwind.h: Move from ../gcc/config/sparc.
* config/xtensa/linux-unwind.h: Move from ../gcc/config/xtensa.
* config/no-unwind.h: New file.
* config.host (md_unwind_header): Document.
Define.
(alpha*-*-linux*, alpha*-dec-osf5.1*, alpha64-dec-*vms*,
alpha*-dec-*vms*, bfin*-uclinux*, bfin*-linux-uclibc*,
hppa*-*-linux*, hppa[12]*-*-hpux10*, hppa*64*-*-hpux11*,
hppa[12]*-*-hpux11*): Set md_unwind_header.
(i[34567]86-*-linux*): Handle i[34567]86-*-kopensolaris*-gnu.
Set md_unwind_header.
(x86_64-*-linux*, i[34567]86-*-solaris2*): Set md_unwind_header.
(i[34567]86-*-cygwin*): Split from i[34567]86-*-mingw*.
(i[34567]86-*-mingw*, ia64*-*-linux*, ia64-hp-*vms*,
m68k-*-uclinux*, m68k-*-linux*, mips64*-*-linux*, mips*-*-linux*,
powerpc-*-darwin*, powerpc-*-linux*, s390-*-linux*,
s390x-*-linux*, s390x-ibm-tpf*, sh*-*-linux*, sparc-*-linux*,
sparc*-*-solaris2*, sparc64-*-linux*, xtensa*-*-linux*): Set
md_unwind_header.
* configure.ac: Link md-unwind-support.h to $md_unwind_header.
* configure: Regenerate.
From-SVN: r174613
2011-06-03 18:30:39 +00:00
|
|
|
|
#include "md-unwind-support.h"
|
2007-11-13 22:41:50 +00:00
|
|
|
|
|
|
|
|
|
/* Extract any interesting information from the CIE for the translation
|
|
|
|
|
unit F belongs to. Return a pointer to the byte after the augmentation,
|
|
|
|
|
or NULL if we encountered an undecipherable augmentation. */
|
|
|
|
|
|
|
|
|
|
static const unsigned char *
|
|
|
|
|
extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
|
|
|
|
|
_Unwind_FrameState *fs)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *aug = cie->augmentation;
|
|
|
|
|
const unsigned char *p = aug + strlen ((const char *)aug) + 1;
|
|
|
|
|
const unsigned char *ret = NULL;
|
|
|
|
|
_uleb128_t utmp;
|
|
|
|
|
_sleb128_t stmp;
|
|
|
|
|
|
|
|
|
|
/* g++ v2 "eh" has pointer immediately following augmentation string,
|
|
|
|
|
so it must be handled first. */
|
|
|
|
|
if (aug[0] == 'e' && aug[1] == 'h')
|
|
|
|
|
{
|
|
|
|
|
fs->eh_ptr = read_pointer (p);
|
|
|
|
|
p += sizeof (void *);
|
|
|
|
|
aug += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Immediately following the augmentation are the code and
|
|
|
|
|
data alignment and return address column. */
|
|
|
|
|
p = read_uleb128 (p, &utmp);
|
|
|
|
|
p = read_sleb128 (p, &stmp);
|
|
|
|
|
if (cie->version == 1)
|
|
|
|
|
fs->retaddr_column = *p++;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p = read_uleb128 (p, &utmp);
|
|
|
|
|
fs->retaddr_column = (_Unwind_Word)utmp;
|
|
|
|
|
}
|
|
|
|
|
fs->lsda_encoding = DW_EH_PE_omit;
|
|
|
|
|
|
|
|
|
|
/* If the augmentation starts with 'z', then a uleb128 immediately
|
|
|
|
|
follows containing the length of the augmentation field following
|
|
|
|
|
the size. */
|
|
|
|
|
if (*aug == 'z')
|
|
|
|
|
{
|
|
|
|
|
p = read_uleb128 (p, &utmp);
|
|
|
|
|
ret = p + utmp;
|
|
|
|
|
|
|
|
|
|
fs->saw_z = 1;
|
|
|
|
|
++aug;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Iterate over recognized augmentation subsequences. */
|
|
|
|
|
while (*aug != '\0')
|
|
|
|
|
{
|
|
|
|
|
/* "L" indicates a byte showing how the LSDA pointer is encoded. */
|
|
|
|
|
if (aug[0] == 'L')
|
|
|
|
|
{
|
|
|
|
|
fs->lsda_encoding = *p++;
|
|
|
|
|
aug += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* "R" indicates a byte indicating how FDE addresses are encoded. */
|
|
|
|
|
else if (aug[0] == 'R')
|
|
|
|
|
{
|
|
|
|
|
fs->fde_encoding = *p++;
|
|
|
|
|
aug += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* "P" indicates a personality routine in the CIE augmentation. */
|
|
|
|
|
else if (aug[0] == 'P')
|
|
|
|
|
{
|
|
|
|
|
_Unwind_Ptr personality;
|
|
|
|
|
|
|
|
|
|
p = read_encoded_value (context, *p, p + 1, &personality);
|
|
|
|
|
fs->personality = (_Unwind_Personality_Fn) personality;
|
|
|
|
|
aug += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* "S" indicates a signal frame. */
|
|
|
|
|
else if (aug[0] == 'S')
|
|
|
|
|
{
|
|
|
|
|
fs->signal_frame = 1;
|
|
|
|
|
aug += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Otherwise we have an unknown augmentation string.
|
|
|
|
|
Bail unless we saw a 'z' prefix. */
|
|
|
|
|
else
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret ? ret : p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
|
|
|
|
|
its caller and decode it into FS. This function also sets the
|
|
|
|
|
lsda member of CONTEXT, as it is really information
|
|
|
|
|
about the caller's frame. */
|
|
|
|
|
|
|
|
|
|
static _Unwind_Reason_Code
|
|
|
|
|
uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
|
|
|
|
{
|
|
|
|
|
const struct dwarf_fde *fde;
|
|
|
|
|
const struct dwarf_cie *cie;
|
|
|
|
|
const unsigned char *aug;
|
|
|
|
|
int window_size;
|
|
|
|
|
_Unwind_Word *ra_ptr;
|
|
|
|
|
|
|
|
|
|
memset (fs, 0, sizeof (*fs));
|
|
|
|
|
context->lsda = 0;
|
|
|
|
|
|
|
|
|
|
fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
|
|
|
|
|
&context->bases);
|
|
|
|
|
if (fde == NULL)
|
|
|
|
|
{
|
|
|
|
|
#ifdef MD_FALLBACK_FRAME_STATE_FOR
|
|
|
|
|
_Unwind_Reason_Code reason;
|
|
|
|
|
/* Couldn't find frame unwind info for this function. Try a
|
|
|
|
|
target-specific fallback mechanism. This will necessarily
|
|
|
|
|
not provide a personality routine or LSDA. */
|
|
|
|
|
reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs);
|
|
|
|
|
if (reason != _URC_END_OF_STACK)
|
|
|
|
|
return reason;
|
2008-01-18 01:37:53 +00:00
|
|
|
|
#endif
|
2007-11-13 22:41:50 +00:00
|
|
|
|
/* The frame was not recognized and handled by the fallback function,
|
|
|
|
|
but it is not really the end of the stack. Fall through here and
|
|
|
|
|
unwind it anyway. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cie = get_cie (fde);
|
|
|
|
|
if (extract_cie_info (cie, context, fs) == NULL)
|
|
|
|
|
/* CIE contained unknown augmentation. */
|
|
|
|
|
return _URC_FATAL_PHASE1_ERROR;
|
|
|
|
|
|
|
|
|
|
/* Locate augmentation for the fde. */
|
|
|
|
|
aug = (const unsigned char *) fde + sizeof (*fde);
|
|
|
|
|
aug += 2 * size_of_encoded_value (fs->fde_encoding);
|
|
|
|
|
if (fs->saw_z)
|
|
|
|
|
{
|
|
|
|
|
_uleb128_t i;
|
|
|
|
|
aug = read_uleb128 (aug, &i);
|
|
|
|
|
}
|
|
|
|
|
if (fs->lsda_encoding != DW_EH_PE_omit)
|
|
|
|
|
{
|
|
|
|
|
_Unwind_Ptr lsda;
|
|
|
|
|
|
|
|
|
|
aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
|
|
|
|
|
context->lsda = (void *) lsda;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-18 01:37:53 +00:00
|
|
|
|
/* Check for the end of the stack. This needs to be checked after
|
|
|
|
|
the MD_FALLBACK_FRAME_STATE_FOR check for signal frames because
|
|
|
|
|
the contents of context->reg[0] are undefined at a signal frame,
|
|
|
|
|
and register a0 may appear to be zero. (The return address in
|
|
|
|
|
context->ra comes from register a4 or a8). */
|
|
|
|
|
ra_ptr = context->reg[0];
|
|
|
|
|
if (ra_ptr && *ra_ptr == 0)
|
|
|
|
|
return _URC_END_OF_STACK;
|
|
|
|
|
|
2007-11-13 22:41:50 +00:00
|
|
|
|
/* Find the window size from the high bits of the return address. */
|
|
|
|
|
if (ra_ptr)
|
|
|
|
|
window_size = (*ra_ptr >> 30) * 4;
|
|
|
|
|
else
|
|
|
|
|
window_size = 8;
|
|
|
|
|
|
|
|
|
|
fs->retaddr_column = window_size;
|
|
|
|
|
|
|
|
|
|
return _URC_NO_REASON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
|
|
|
|
{
|
|
|
|
|
struct _Unwind_Context orig_context = *context;
|
|
|
|
|
_Unwind_Word *sp, *cfa, *next_cfa;
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-01-18 01:37:53 +00:00
|
|
|
|
if (fs->signal_regs)
|
2007-11-13 22:41:50 +00:00
|
|
|
|
{
|
|
|
|
|
cfa = (_Unwind_Word *) fs->signal_regs[1];
|
|
|
|
|
next_cfa = (_Unwind_Word *) cfa[-3];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
context->reg[i] = fs->signal_regs + (i << 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int window_size = fs->retaddr_column >> 2;
|
|
|
|
|
|
|
|
|
|
sp = (_Unwind_Word *) orig_context.sp;
|
|
|
|
|
cfa = (_Unwind_Word *) orig_context.cfa;
|
|
|
|
|
next_cfa = (_Unwind_Word *) cfa[-3];
|
|
|
|
|
|
|
|
|
|
/* Registers a0-a3 are in the save area below sp. */
|
|
|
|
|
context->reg[0] = sp - 4;
|
|
|
|
|
|
|
|
|
|
/* Find the extra save area below next_cfa. */
|
|
|
|
|
for (i = 1; i < window_size; i++)
|
|
|
|
|
context->reg[i] = next_cfa - 4 * (1 + window_size - i);
|
|
|
|
|
|
|
|
|
|
/* Remaining registers rotate from previous save areas. */
|
|
|
|
|
for (i = window_size; i < 4; i++)
|
|
|
|
|
context->reg[i] = orig_context.reg[i - window_size];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context->sp = cfa;
|
|
|
|
|
context->cfa = next_cfa;
|
|
|
|
|
|
|
|
|
|
_Unwind_SetSignalFrame (context, fs->signal_frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
|
|
|
|
|
of its caller. Update CONTEXT to refer to the caller as well. Note
|
|
|
|
|
that the lsda member is not updated here, but later in
|
|
|
|
|
uw_frame_state_for. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
|
|
|
|
{
|
|
|
|
|
uw_update_context_1 (context, fs);
|
|
|
|
|
|
|
|
|
|
/* Compute the return address now, since the return address column
|
|
|
|
|
can change from frame to frame. */
|
2008-01-18 01:37:53 +00:00
|
|
|
|
if (fs->signal_ra != 0)
|
|
|
|
|
context->ra = (void *) fs->signal_ra;
|
|
|
|
|
else
|
|
|
|
|
context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column)
|
|
|
|
|
& XTENSA_RA_FIELD_MASK) | context->ra_high_bits);
|
2007-11-13 22:41:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
|
|
|
|
{
|
|
|
|
|
uw_update_context (context, fs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fill in CONTEXT for top-of-stack. The only valid registers at this
|
|
|
|
|
level will be the return address and the CFA. */
|
|
|
|
|
|
|
|
|
|
#define uw_init_context(CONTEXT) \
|
|
|
|
|
do \
|
|
|
|
|
{ \
|
|
|
|
|
__builtin_unwind_init (); \
|
|
|
|
|
uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \
|
|
|
|
|
__builtin_return_address (0)); \
|
|
|
|
|
} \
|
|
|
|
|
while (0)
|
|
|
|
|
|
2009-09-07 15:41:52 +00:00
|
|
|
|
static void __attribute__((noinline))
|
2007-11-13 22:41:50 +00:00
|
|
|
|
uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa,
|
|
|
|
|
void *outer_ra)
|
|
|
|
|
{
|
|
|
|
|
void *ra = __builtin_return_address (0);
|
|
|
|
|
void *cfa = __builtin_dwarf_cfa ();
|
|
|
|
|
_Unwind_FrameState fs;
|
|
|
|
|
|
|
|
|
|
memset (context, 0, sizeof (struct _Unwind_Context));
|
|
|
|
|
context->ra = ra;
|
|
|
|
|
|
|
|
|
|
memset (&fs, 0, sizeof (fs));
|
|
|
|
|
fs.retaddr_column = 8;
|
|
|
|
|
context->sp = cfa;
|
|
|
|
|
context->cfa = outer_cfa;
|
|
|
|
|
context->ra_high_bits =
|
|
|
|
|
((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK;
|
|
|
|
|
uw_update_context_1 (context, &fs);
|
|
|
|
|
|
|
|
|
|
context->ra = outer_ra;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Install TARGET into CURRENT so that we can return to it. This is a
|
|
|
|
|
macro because __builtin_eh_return must be invoked in the context of
|
|
|
|
|
our caller. */
|
|
|
|
|
|
|
|
|
|
#define uw_install_context(CURRENT, TARGET) \
|
|
|
|
|
do \
|
|
|
|
|
{ \
|
|
|
|
|
long offset = uw_install_context_1 ((CURRENT), (TARGET)); \
|
|
|
|
|
void *handler = __builtin_frob_return_addr ((TARGET)->ra); \
|
|
|
|
|
__builtin_eh_return (offset, handler); \
|
|
|
|
|
} \
|
|
|
|
|
while (0)
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
uw_install_context_1 (struct _Unwind_Context *current,
|
|
|
|
|
struct _Unwind_Context *target)
|
|
|
|
|
{
|
|
|
|
|
long i;
|
|
|
|
|
|
|
|
|
|
/* The eh_return insn assumes a window size of 8, so don't bother copying
|
|
|
|
|
the save areas for registers a8-a15 since they won't be reloaded. */
|
|
|
|
|
for (i = 0; i < 2; ++i)
|
|
|
|
|
{
|
|
|
|
|
void *c = current->reg[i];
|
|
|
|
|
void *t = target->reg[i];
|
|
|
|
|
|
|
|
|
|
if (t && c && t != c)
|
|
|
|
|
memcpy (c, t, 4 * sizeof (_Unwind_Word));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline _Unwind_Ptr
|
|
|
|
|
uw_identify_context (struct _Unwind_Context *context)
|
|
|
|
|
{
|
|
|
|
|
return _Unwind_GetCFA (context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "unwind.inc"
|
|
|
|
|
|
|
|
|
|
#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
|
|
|
|
|
alias (_Unwind_Backtrace);
|
|
|
|
|
alias (_Unwind_DeleteException);
|
|
|
|
|
alias (_Unwind_FindEnclosingFunction);
|
|
|
|
|
alias (_Unwind_ForcedUnwind);
|
|
|
|
|
alias (_Unwind_GetDataRelBase);
|
|
|
|
|
alias (_Unwind_GetTextRelBase);
|
|
|
|
|
alias (_Unwind_GetCFA);
|
|
|
|
|
alias (_Unwind_GetGR);
|
|
|
|
|
alias (_Unwind_GetIP);
|
|
|
|
|
alias (_Unwind_GetLanguageSpecificData);
|
|
|
|
|
alias (_Unwind_GetRegionStart);
|
|
|
|
|
alias (_Unwind_RaiseException);
|
|
|
|
|
alias (_Unwind_Resume);
|
|
|
|
|
alias (_Unwind_Resume_or_Rethrow);
|
|
|
|
|
alias (_Unwind_SetGR);
|
|
|
|
|
alias (_Unwind_SetIP);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif /* !USING_SJLJ_EXCEPTIONS */
|