xref: /dflybsd-src/contrib/gcc-8.0/libgcc/unwind-dw2.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* DWARF2 exception handling and frame unwind runtime interface routines.
238fd1498Szrj    Copyright (C) 1997-2018 Free Software Foundation, Inc.
338fd1498Szrj 
438fd1498Szrj    This file is part of GCC.
538fd1498Szrj 
638fd1498Szrj    GCC is free software; you can redistribute it and/or modify it
738fd1498Szrj    under the terms of the GNU General Public License as published by
838fd1498Szrj    the Free Software Foundation; either version 3, or (at your option)
938fd1498Szrj    any later version.
1038fd1498Szrj 
1138fd1498Szrj    GCC is distributed in the hope that it will be useful, but WITHOUT
1238fd1498Szrj    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1338fd1498Szrj    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1438fd1498Szrj    License for more details.
1538fd1498Szrj 
1638fd1498Szrj    Under Section 7 of GPL version 3, you are granted additional
1738fd1498Szrj    permissions described in the GCC Runtime Library Exception, version
1838fd1498Szrj    3.1, as published by the Free Software Foundation.
1938fd1498Szrj 
2038fd1498Szrj    You should have received a copy of the GNU General Public License and
2138fd1498Szrj    a copy of the GCC Runtime Library Exception along with this program;
2238fd1498Szrj    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2338fd1498Szrj    <http://www.gnu.org/licenses/>.  */
2438fd1498Szrj 
2538fd1498Szrj #include "tconfig.h"
2638fd1498Szrj #include "tsystem.h"
2738fd1498Szrj #include "coretypes.h"
2838fd1498Szrj #include "tm.h"
2938fd1498Szrj #include "libgcc_tm.h"
3038fd1498Szrj #include "dwarf2.h"
3138fd1498Szrj #include "unwind.h"
3238fd1498Szrj #ifdef __USING_SJLJ_EXCEPTIONS__
3338fd1498Szrj # define NO_SIZE_OF_ENCODED_VALUE
3438fd1498Szrj #endif
3538fd1498Szrj #include "unwind-pe.h"
3638fd1498Szrj #include "unwind-dw2-fde.h"
3738fd1498Szrj #include "gthr.h"
3838fd1498Szrj #include "unwind-dw2.h"
3938fd1498Szrj 
4038fd1498Szrj #ifdef HAVE_SYS_SDT_H
4138fd1498Szrj #include <sys/sdt.h>
4238fd1498Szrj #endif
4338fd1498Szrj 
4438fd1498Szrj #ifndef __USING_SJLJ_EXCEPTIONS__
4538fd1498Szrj 
4638fd1498Szrj #ifndef __LIBGCC_STACK_GROWS_DOWNWARD__
4738fd1498Szrj #define __LIBGCC_STACK_GROWS_DOWNWARD__ 0
4838fd1498Szrj #else
4938fd1498Szrj #undef __LIBGCC_STACK_GROWS_DOWNWARD__
5038fd1498Szrj #define __LIBGCC_STACK_GROWS_DOWNWARD__ 1
5138fd1498Szrj #endif
5238fd1498Szrj 
5338fd1498Szrj /* Dwarf frame registers used for pre gcc 3.0 compiled glibc.  */
5438fd1498Szrj #ifndef PRE_GCC3_DWARF_FRAME_REGISTERS
5538fd1498Szrj #define PRE_GCC3_DWARF_FRAME_REGISTERS __LIBGCC_DWARF_FRAME_REGISTERS__
5638fd1498Szrj #endif
5738fd1498Szrj 
5838fd1498Szrj /* ??? For the public function interfaces, we tend to gcc_assert that the
5938fd1498Szrj    column numbers are in range.  For the dwarf2 unwind info this does happen,
6038fd1498Szrj    although so far in a case that doesn't actually matter.
6138fd1498Szrj 
6238fd1498Szrj    See PR49146, in which a call from x86_64 ms abi to x86_64 unix abi stores
6338fd1498Szrj    the call-saved xmm registers and annotates them.  We havn't bothered
6438fd1498Szrj    providing support for the xmm registers for the x86_64 port primarily
6538fd1498Szrj    because the 64-bit windows targets don't use dwarf2 unwind, using sjlj or
6638fd1498Szrj    SEH instead.  Adding the support for unix targets would generally be a
6738fd1498Szrj    waste.  However, some runtime libraries supplied with ICC do contain such
6838fd1498Szrj    an unorthodox transition, as well as the unwind info to match.  This loss
6938fd1498Szrj    of register restoration doesn't matter in practice, because the exception
7038fd1498Szrj    is caught in the native unix abi, where all of the xmm registers are
7138fd1498Szrj    call clobbered.
7238fd1498Szrj 
7338fd1498Szrj    Ideally, we'd record some bit to notice when we're failing to restore some
7438fd1498Szrj    register recorded in the unwind info, but to do that we need annotation on
7538fd1498Szrj    the unix->ms abi edge, so that we know when the register data may be
7638fd1498Szrj    discarded.  And since this edge is also within the ICC library, we're
7738fd1498Szrj    unlikely to be able to get the new annotation.
7838fd1498Szrj 
7938fd1498Szrj    Barring a magic solution to restore the ms abi defined 128-bit xmm registers
8038fd1498Szrj    (as distictly opposed to the full runtime width) without causing extra
8138fd1498Szrj    overhead for normal unix abis, the best solution seems to be to simply
8238fd1498Szrj    ignore unwind data for unknown columns.  */
8338fd1498Szrj 
8438fd1498Szrj #define UNWIND_COLUMN_IN_RANGE(x) \
8538fd1498Szrj     __builtin_expect((x) <= __LIBGCC_DWARF_FRAME_REGISTERS__, 1)
8638fd1498Szrj 
8738fd1498Szrj #ifdef REG_VALUE_IN_UNWIND_CONTEXT
8838fd1498Szrj typedef _Unwind_Word _Unwind_Context_Reg_Val;
8938fd1498Szrj 
9038fd1498Szrj #ifndef ASSUME_EXTENDED_UNWIND_CONTEXT
9138fd1498Szrj #define ASSUME_EXTENDED_UNWIND_CONTEXT 1
9238fd1498Szrj #endif
9338fd1498Szrj 
9438fd1498Szrj static inline _Unwind_Word
_Unwind_Get_Unwind_Word(_Unwind_Context_Reg_Val val)9538fd1498Szrj _Unwind_Get_Unwind_Word (_Unwind_Context_Reg_Val val)
9638fd1498Szrj {
9738fd1498Szrj   return val;
9838fd1498Szrj }
9938fd1498Szrj 
10038fd1498Szrj static inline _Unwind_Context_Reg_Val
_Unwind_Get_Unwind_Context_Reg_Val(_Unwind_Word val)10138fd1498Szrj _Unwind_Get_Unwind_Context_Reg_Val (_Unwind_Word val)
10238fd1498Szrj {
10338fd1498Szrj   return val;
10438fd1498Szrj }
10538fd1498Szrj #else
10638fd1498Szrj typedef void *_Unwind_Context_Reg_Val;
10738fd1498Szrj 
10838fd1498Szrj static inline _Unwind_Word
_Unwind_Get_Unwind_Word(_Unwind_Context_Reg_Val val)10938fd1498Szrj _Unwind_Get_Unwind_Word (_Unwind_Context_Reg_Val val)
11038fd1498Szrj {
11138fd1498Szrj   return (_Unwind_Word) (_Unwind_Internal_Ptr) val;
11238fd1498Szrj }
11338fd1498Szrj 
11438fd1498Szrj static inline _Unwind_Context_Reg_Val
_Unwind_Get_Unwind_Context_Reg_Val(_Unwind_Word val)11538fd1498Szrj _Unwind_Get_Unwind_Context_Reg_Val (_Unwind_Word val)
11638fd1498Szrj {
11738fd1498Szrj   return (_Unwind_Context_Reg_Val) (_Unwind_Internal_Ptr) val;
11838fd1498Szrj }
11938fd1498Szrj #endif
12038fd1498Szrj 
12138fd1498Szrj #ifndef ASSUME_EXTENDED_UNWIND_CONTEXT
12238fd1498Szrj #define ASSUME_EXTENDED_UNWIND_CONTEXT 0
12338fd1498Szrj #endif
12438fd1498Szrj 
12538fd1498Szrj /* This is the register and unwind state for a particular frame.  This
12638fd1498Szrj    provides the information necessary to unwind up past a frame and return
12738fd1498Szrj    to its caller.  */
12838fd1498Szrj struct _Unwind_Context
12938fd1498Szrj {
13038fd1498Szrj   _Unwind_Context_Reg_Val reg[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
13138fd1498Szrj   void *cfa;
13238fd1498Szrj   void *ra;
13338fd1498Szrj   void *lsda;
13438fd1498Szrj   struct dwarf_eh_bases bases;
13538fd1498Szrj   /* Signal frame context.  */
13638fd1498Szrj #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
13738fd1498Szrj   /* Context which has version/args_size/by_value fields.  */
13838fd1498Szrj #define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
13938fd1498Szrj   /* Bit reserved on AArch64, return address has been signed with A key.  */
14038fd1498Szrj #define RA_A_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)
14138fd1498Szrj   _Unwind_Word flags;
14238fd1498Szrj   /* 0 for now, can be increased when further fields are added to
14338fd1498Szrj      struct _Unwind_Context.  */
14438fd1498Szrj   _Unwind_Word version;
14538fd1498Szrj   _Unwind_Word args_size;
14638fd1498Szrj   char by_value[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
14738fd1498Szrj };
14838fd1498Szrj 
14938fd1498Szrj /* Byte size of every register managed by these routines.  */
15038fd1498Szrj static unsigned char dwarf_reg_size_table[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
15138fd1498Szrj 
15238fd1498Szrj 
15338fd1498Szrj /* Read unaligned data from the instruction buffer.  */
15438fd1498Szrj 
15538fd1498Szrj union unaligned
15638fd1498Szrj {
15738fd1498Szrj   void *p;
15838fd1498Szrj   unsigned u2 __attribute__ ((mode (HI)));
15938fd1498Szrj   unsigned u4 __attribute__ ((mode (SI)));
16038fd1498Szrj   unsigned u8 __attribute__ ((mode (DI)));
16138fd1498Szrj   signed s2 __attribute__ ((mode (HI)));
16238fd1498Szrj   signed s4 __attribute__ ((mode (SI)));
16338fd1498Szrj   signed s8 __attribute__ ((mode (DI)));
16438fd1498Szrj } __attribute__ ((packed));
16538fd1498Szrj 
16638fd1498Szrj static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
16738fd1498Szrj static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
16838fd1498Szrj 					       _Unwind_FrameState *);
16938fd1498Szrj 
17038fd1498Szrj static inline void *
read_pointer(const void * p)17138fd1498Szrj read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
17238fd1498Szrj 
17338fd1498Szrj static inline int
read_1u(const void * p)17438fd1498Szrj read_1u (const void *p) { return *(const unsigned char *) p; }
17538fd1498Szrj 
17638fd1498Szrj static inline int
read_1s(const void * p)17738fd1498Szrj read_1s (const void *p) { return *(const signed char *) p; }
17838fd1498Szrj 
17938fd1498Szrj static inline int
read_2u(const void * p)18038fd1498Szrj read_2u (const void *p) { const union unaligned *up = p; return up->u2; }
18138fd1498Szrj 
18238fd1498Szrj static inline int
read_2s(const void * p)18338fd1498Szrj read_2s (const void *p) { const union unaligned *up = p; return up->s2; }
18438fd1498Szrj 
18538fd1498Szrj static inline unsigned int
read_4u(const void * p)18638fd1498Szrj read_4u (const void *p) { const union unaligned *up = p; return up->u4; }
18738fd1498Szrj 
18838fd1498Szrj static inline int
read_4s(const void * p)18938fd1498Szrj read_4s (const void *p) { const union unaligned *up = p; return up->s4; }
19038fd1498Szrj 
19138fd1498Szrj static inline unsigned long
read_8u(const void * p)19238fd1498Szrj read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
19338fd1498Szrj 
19438fd1498Szrj static inline unsigned long
read_8s(const void * p)19538fd1498Szrj read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
19638fd1498Szrj 
19738fd1498Szrj static inline _Unwind_Word
_Unwind_IsSignalFrame(struct _Unwind_Context * context)19838fd1498Szrj _Unwind_IsSignalFrame (struct _Unwind_Context *context)
19938fd1498Szrj {
20038fd1498Szrj   return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
20138fd1498Szrj }
20238fd1498Szrj 
20338fd1498Szrj static inline void
_Unwind_SetSignalFrame(struct _Unwind_Context * context,int val)20438fd1498Szrj _Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
20538fd1498Szrj {
20638fd1498Szrj   if (val)
20738fd1498Szrj     context->flags |= SIGNAL_FRAME_BIT;
20838fd1498Szrj   else
20938fd1498Szrj     context->flags &= ~SIGNAL_FRAME_BIT;
21038fd1498Szrj }
21138fd1498Szrj 
21238fd1498Szrj static inline _Unwind_Word
_Unwind_IsExtendedContext(struct _Unwind_Context * context)21338fd1498Szrj _Unwind_IsExtendedContext (struct _Unwind_Context *context)
21438fd1498Szrj {
21538fd1498Szrj   return (ASSUME_EXTENDED_UNWIND_CONTEXT
21638fd1498Szrj 	  || (context->flags & EXTENDED_CONTEXT_BIT));
21738fd1498Szrj }
21838fd1498Szrj 
21938fd1498Szrj /* Get the value of register REGNO as saved in CONTEXT.  */
22038fd1498Szrj 
22138fd1498Szrj inline _Unwind_Word
_Unwind_GetGR(struct _Unwind_Context * context,int regno)22238fd1498Szrj _Unwind_GetGR (struct _Unwind_Context *context, int regno)
22338fd1498Szrj {
22438fd1498Szrj   int size, index;
22538fd1498Szrj   _Unwind_Context_Reg_Val val;
22638fd1498Szrj 
22738fd1498Szrj #ifdef DWARF_ZERO_REG
228*58e805e6Szrj   if (regno == DWARF_ZERO_REG)
22938fd1498Szrj     return 0;
23038fd1498Szrj #endif
23138fd1498Szrj 
23238fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (regno);
23338fd1498Szrj   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
23438fd1498Szrj   size = dwarf_reg_size_table[index];
23538fd1498Szrj   val = context->reg[index];
23638fd1498Szrj 
23738fd1498Szrj   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
23838fd1498Szrj     return _Unwind_Get_Unwind_Word (val);
23938fd1498Szrj 
24038fd1498Szrj #ifdef DWARF_LAZY_REGISTER_VALUE
24138fd1498Szrj   {
24238fd1498Szrj     _Unwind_Word value;
24338fd1498Szrj     if (DWARF_LAZY_REGISTER_VALUE (regno, &value))
24438fd1498Szrj       return value;
24538fd1498Szrj   }
24638fd1498Szrj #endif
24738fd1498Szrj 
24838fd1498Szrj   /* This will segfault if the register hasn't been saved.  */
24938fd1498Szrj   if (size == sizeof(_Unwind_Ptr))
25038fd1498Szrj     return * (_Unwind_Ptr *) (_Unwind_Internal_Ptr) val;
25138fd1498Szrj   else
25238fd1498Szrj     {
25338fd1498Szrj       gcc_assert (size == sizeof(_Unwind_Word));
25438fd1498Szrj       return * (_Unwind_Word *) (_Unwind_Internal_Ptr) val;
25538fd1498Szrj     }
25638fd1498Szrj }
25738fd1498Szrj 
25838fd1498Szrj static inline void *
_Unwind_GetPtr(struct _Unwind_Context * context,int index)25938fd1498Szrj _Unwind_GetPtr (struct _Unwind_Context *context, int index)
26038fd1498Szrj {
26138fd1498Szrj   return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index);
26238fd1498Szrj }
26338fd1498Szrj 
26438fd1498Szrj /* Get the value of the CFA as saved in CONTEXT.  */
26538fd1498Szrj 
26638fd1498Szrj _Unwind_Word
_Unwind_GetCFA(struct _Unwind_Context * context)26738fd1498Szrj _Unwind_GetCFA (struct _Unwind_Context *context)
26838fd1498Szrj {
26938fd1498Szrj   return (_Unwind_Ptr) context->cfa;
27038fd1498Szrj }
27138fd1498Szrj 
27238fd1498Szrj /* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
27338fd1498Szrj 
27438fd1498Szrj inline void
_Unwind_SetGR(struct _Unwind_Context * context,int index,_Unwind_Word val)27538fd1498Szrj _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
27638fd1498Szrj {
27738fd1498Szrj   int size;
27838fd1498Szrj   void *ptr;
27938fd1498Szrj 
28038fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (index);
28138fd1498Szrj   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
28238fd1498Szrj   size = dwarf_reg_size_table[index];
28338fd1498Szrj 
28438fd1498Szrj   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
28538fd1498Szrj     {
28638fd1498Szrj       context->reg[index] = _Unwind_Get_Unwind_Context_Reg_Val (val);
28738fd1498Szrj       return;
28838fd1498Szrj     }
28938fd1498Szrj 
29038fd1498Szrj   ptr = (void *) (_Unwind_Internal_Ptr) context->reg[index];
29138fd1498Szrj 
29238fd1498Szrj   if (size == sizeof(_Unwind_Ptr))
29338fd1498Szrj     * (_Unwind_Ptr *) ptr = val;
29438fd1498Szrj   else
29538fd1498Szrj     {
29638fd1498Szrj       gcc_assert (size == sizeof(_Unwind_Word));
29738fd1498Szrj       * (_Unwind_Word *) ptr = val;
29838fd1498Szrj     }
29938fd1498Szrj }
30038fd1498Szrj 
30138fd1498Szrj /* Get the pointer to a register INDEX as saved in CONTEXT.  */
30238fd1498Szrj 
30338fd1498Szrj static inline void *
_Unwind_GetGRPtr(struct _Unwind_Context * context,int index)30438fd1498Szrj _Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
30538fd1498Szrj {
30638fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (index);
30738fd1498Szrj   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
30838fd1498Szrj     return &context->reg[index];
30938fd1498Szrj   return (void *) (_Unwind_Internal_Ptr) context->reg[index];
31038fd1498Szrj }
31138fd1498Szrj 
31238fd1498Szrj /* Set the pointer to a register INDEX as saved in CONTEXT.  */
31338fd1498Szrj 
31438fd1498Szrj static inline void
_Unwind_SetGRPtr(struct _Unwind_Context * context,int index,void * p)31538fd1498Szrj _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
31638fd1498Szrj {
31738fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (index);
31838fd1498Szrj   if (_Unwind_IsExtendedContext (context))
31938fd1498Szrj     context->by_value[index] = 0;
32038fd1498Szrj   context->reg[index] = (_Unwind_Context_Reg_Val) (_Unwind_Internal_Ptr) p;
32138fd1498Szrj }
32238fd1498Szrj 
32338fd1498Szrj /* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
32438fd1498Szrj 
32538fd1498Szrj static inline void
_Unwind_SetGRValue(struct _Unwind_Context * context,int index,_Unwind_Word val)32638fd1498Szrj _Unwind_SetGRValue (struct _Unwind_Context *context, int index,
32738fd1498Szrj 		    _Unwind_Word val)
32838fd1498Szrj {
32938fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (index);
33038fd1498Szrj   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
33138fd1498Szrj   /* Return column size may be smaller than _Unwind_Context_Reg_Val.  */
33238fd1498Szrj   gcc_assert (dwarf_reg_size_table[index] <= sizeof (_Unwind_Context_Reg_Val));
33338fd1498Szrj 
33438fd1498Szrj   context->by_value[index] = 1;
33538fd1498Szrj   context->reg[index] = _Unwind_Get_Unwind_Context_Reg_Val (val);
33638fd1498Szrj }
33738fd1498Szrj 
33838fd1498Szrj /* Return nonzero if register INDEX is stored by value rather than
33938fd1498Szrj    by reference.  */
34038fd1498Szrj 
34138fd1498Szrj static inline int
_Unwind_GRByValue(struct _Unwind_Context * context,int index)34238fd1498Szrj _Unwind_GRByValue (struct _Unwind_Context *context, int index)
34338fd1498Szrj {
34438fd1498Szrj   index = DWARF_REG_TO_UNWIND_COLUMN (index);
34538fd1498Szrj   return context->by_value[index];
34638fd1498Szrj }
34738fd1498Szrj 
34838fd1498Szrj /* Retrieve the return address for CONTEXT.  */
34938fd1498Szrj 
35038fd1498Szrj inline _Unwind_Ptr
_Unwind_GetIP(struct _Unwind_Context * context)35138fd1498Szrj _Unwind_GetIP (struct _Unwind_Context *context)
35238fd1498Szrj {
35338fd1498Szrj   return (_Unwind_Ptr) context->ra;
35438fd1498Szrj }
35538fd1498Szrj 
35638fd1498Szrj /* Retrieve the return address and flag whether that IP is before
35738fd1498Szrj    or after first not yet fully executed instruction.  */
35838fd1498Szrj 
35938fd1498Szrj inline _Unwind_Ptr
_Unwind_GetIPInfo(struct _Unwind_Context * context,int * ip_before_insn)36038fd1498Szrj _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
36138fd1498Szrj {
36238fd1498Szrj   *ip_before_insn = _Unwind_IsSignalFrame (context);
36338fd1498Szrj   return (_Unwind_Ptr) context->ra;
36438fd1498Szrj }
36538fd1498Szrj 
36638fd1498Szrj /* Overwrite the return address for CONTEXT with VAL.  */
36738fd1498Szrj 
36838fd1498Szrj inline void
_Unwind_SetIP(struct _Unwind_Context * context,_Unwind_Ptr val)36938fd1498Szrj _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
37038fd1498Szrj {
37138fd1498Szrj   context->ra = (void *) val;
37238fd1498Szrj }
37338fd1498Szrj 
37438fd1498Szrj void *
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)37538fd1498Szrj _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
37638fd1498Szrj {
37738fd1498Szrj   return context->lsda;
37838fd1498Szrj }
37938fd1498Szrj 
38038fd1498Szrj _Unwind_Ptr
_Unwind_GetRegionStart(struct _Unwind_Context * context)38138fd1498Szrj _Unwind_GetRegionStart (struct _Unwind_Context *context)
38238fd1498Szrj {
38338fd1498Szrj   return (_Unwind_Ptr) context->bases.func;
38438fd1498Szrj }
38538fd1498Szrj 
38638fd1498Szrj void *
_Unwind_FindEnclosingFunction(void * pc)38738fd1498Szrj _Unwind_FindEnclosingFunction (void *pc)
38838fd1498Szrj {
38938fd1498Szrj   struct dwarf_eh_bases bases;
39038fd1498Szrj   const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
39138fd1498Szrj   if (fde)
39238fd1498Szrj     return bases.func;
39338fd1498Szrj   else
39438fd1498Szrj     return NULL;
39538fd1498Szrj }
39638fd1498Szrj 
39738fd1498Szrj #ifndef __ia64__
39838fd1498Szrj _Unwind_Ptr
_Unwind_GetDataRelBase(struct _Unwind_Context * context)39938fd1498Szrj _Unwind_GetDataRelBase (struct _Unwind_Context *context)
40038fd1498Szrj {
40138fd1498Szrj   return (_Unwind_Ptr) context->bases.dbase;
40238fd1498Szrj }
40338fd1498Szrj 
40438fd1498Szrj _Unwind_Ptr
_Unwind_GetTextRelBase(struct _Unwind_Context * context)40538fd1498Szrj _Unwind_GetTextRelBase (struct _Unwind_Context *context)
40638fd1498Szrj {
40738fd1498Szrj   return (_Unwind_Ptr) context->bases.tbase;
40838fd1498Szrj }
40938fd1498Szrj #endif
41038fd1498Szrj 
41138fd1498Szrj #include "md-unwind-support.h"
41238fd1498Szrj 
41338fd1498Szrj /* Extract any interesting information from the CIE for the translation
41438fd1498Szrj    unit F belongs to.  Return a pointer to the byte after the augmentation,
41538fd1498Szrj    or NULL if we encountered an undecipherable augmentation.  */
41638fd1498Szrj 
41738fd1498Szrj static const unsigned char *
extract_cie_info(const struct dwarf_cie * cie,struct _Unwind_Context * context,_Unwind_FrameState * fs)41838fd1498Szrj extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
41938fd1498Szrj 		  _Unwind_FrameState *fs)
42038fd1498Szrj {
42138fd1498Szrj   const unsigned char *aug = cie->augmentation;
42238fd1498Szrj   const unsigned char *p = aug + strlen ((const char *)aug) + 1;
42338fd1498Szrj   const unsigned char *ret = NULL;
42438fd1498Szrj   _uleb128_t utmp;
42538fd1498Szrj   _sleb128_t stmp;
42638fd1498Szrj 
42738fd1498Szrj   /* g++ v2 "eh" has pointer immediately following augmentation string,
42838fd1498Szrj      so it must be handled first.  */
42938fd1498Szrj   if (aug[0] == 'e' && aug[1] == 'h')
43038fd1498Szrj     {
43138fd1498Szrj       fs->eh_ptr = read_pointer (p);
43238fd1498Szrj       p += sizeof (void *);
43338fd1498Szrj       aug += 2;
43438fd1498Szrj     }
43538fd1498Szrj 
43638fd1498Szrj   /* After the augmentation resp. pointer for "eh" augmentation
43738fd1498Szrj      follows for CIE version >= 4 address size byte and
43838fd1498Szrj      segment size byte.  */
43938fd1498Szrj   if (__builtin_expect (cie->version >= 4, 0))
44038fd1498Szrj     {
44138fd1498Szrj       if (p[0] != sizeof (void *) || p[1] != 0)
44238fd1498Szrj 	return NULL;
44338fd1498Szrj       p += 2;
44438fd1498Szrj     }
44538fd1498Szrj   /* Immediately following this are the code and
44638fd1498Szrj      data alignment and return address column.  */
44738fd1498Szrj   p = read_uleb128 (p, &utmp);
44838fd1498Szrj   fs->code_align = (_Unwind_Word)utmp;
44938fd1498Szrj   p = read_sleb128 (p, &stmp);
45038fd1498Szrj   fs->data_align = (_Unwind_Sword)stmp;
45138fd1498Szrj   if (cie->version == 1)
45238fd1498Szrj     fs->retaddr_column = *p++;
45338fd1498Szrj   else
45438fd1498Szrj     {
45538fd1498Szrj       p = read_uleb128 (p, &utmp);
45638fd1498Szrj       fs->retaddr_column = (_Unwind_Word)utmp;
45738fd1498Szrj     }
45838fd1498Szrj   fs->lsda_encoding = DW_EH_PE_omit;
45938fd1498Szrj 
46038fd1498Szrj   /* If the augmentation starts with 'z', then a uleb128 immediately
46138fd1498Szrj      follows containing the length of the augmentation field following
46238fd1498Szrj      the size.  */
46338fd1498Szrj   if (*aug == 'z')
46438fd1498Szrj     {
46538fd1498Szrj       p = read_uleb128 (p, &utmp);
46638fd1498Szrj       ret = p + utmp;
46738fd1498Szrj 
46838fd1498Szrj       fs->saw_z = 1;
46938fd1498Szrj       ++aug;
47038fd1498Szrj     }
47138fd1498Szrj 
47238fd1498Szrj   /* Iterate over recognized augmentation subsequences.  */
47338fd1498Szrj   while (*aug != '\0')
47438fd1498Szrj     {
47538fd1498Szrj       /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
47638fd1498Szrj       if (aug[0] == 'L')
47738fd1498Szrj 	{
47838fd1498Szrj 	  fs->lsda_encoding = *p++;
47938fd1498Szrj 	  aug += 1;
48038fd1498Szrj 	}
48138fd1498Szrj 
48238fd1498Szrj       /* "R" indicates a byte indicating how FDE addresses are encoded.  */
48338fd1498Szrj       else if (aug[0] == 'R')
48438fd1498Szrj 	{
48538fd1498Szrj 	  fs->fde_encoding = *p++;
48638fd1498Szrj 	  aug += 1;
48738fd1498Szrj 	}
48838fd1498Szrj 
48938fd1498Szrj       /* "P" indicates a personality routine in the CIE augmentation.  */
49038fd1498Szrj       else if (aug[0] == 'P')
49138fd1498Szrj 	{
49238fd1498Szrj 	  _Unwind_Ptr personality;
49338fd1498Szrj 
49438fd1498Szrj 	  p = read_encoded_value (context, *p, p + 1, &personality);
49538fd1498Szrj 	  fs->personality = (_Unwind_Personality_Fn) personality;
49638fd1498Szrj 	  aug += 1;
49738fd1498Szrj 	}
49838fd1498Szrj 
49938fd1498Szrj       /* "S" indicates a signal frame.  */
50038fd1498Szrj       else if (aug[0] == 'S')
50138fd1498Szrj 	{
50238fd1498Szrj 	  fs->signal_frame = 1;
50338fd1498Szrj 	  aug += 1;
50438fd1498Szrj 	}
50538fd1498Szrj 
50638fd1498Szrj       /* Otherwise we have an unknown augmentation string.
50738fd1498Szrj 	 Bail unless we saw a 'z' prefix.  */
50838fd1498Szrj       else
50938fd1498Szrj 	return ret;
51038fd1498Szrj     }
51138fd1498Szrj 
51238fd1498Szrj   return ret ? ret : p;
51338fd1498Szrj }
51438fd1498Szrj 
51538fd1498Szrj 
51638fd1498Szrj /* Decode a DW_OP stack program.  Return the top of stack.  Push INITIAL
51738fd1498Szrj    onto the stack to start.  */
51838fd1498Szrj 
51938fd1498Szrj static _Unwind_Word
execute_stack_op(const unsigned char * op_ptr,const unsigned char * op_end,struct _Unwind_Context * context,_Unwind_Word initial)52038fd1498Szrj execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
52138fd1498Szrj 		  struct _Unwind_Context *context, _Unwind_Word initial)
52238fd1498Szrj {
52338fd1498Szrj   _Unwind_Word stack[64];	/* ??? Assume this is enough.  */
52438fd1498Szrj   int stack_elt;
52538fd1498Szrj 
52638fd1498Szrj   stack[0] = initial;
52738fd1498Szrj   stack_elt = 1;
52838fd1498Szrj 
52938fd1498Szrj   while (op_ptr < op_end)
53038fd1498Szrj     {
53138fd1498Szrj       enum dwarf_location_atom op = *op_ptr++;
53238fd1498Szrj       _Unwind_Word result;
53338fd1498Szrj       _uleb128_t reg, utmp;
53438fd1498Szrj       _sleb128_t offset, stmp;
53538fd1498Szrj 
53638fd1498Szrj       switch (op)
53738fd1498Szrj 	{
53838fd1498Szrj 	case DW_OP_lit0:
53938fd1498Szrj 	case DW_OP_lit1:
54038fd1498Szrj 	case DW_OP_lit2:
54138fd1498Szrj 	case DW_OP_lit3:
54238fd1498Szrj 	case DW_OP_lit4:
54338fd1498Szrj 	case DW_OP_lit5:
54438fd1498Szrj 	case DW_OP_lit6:
54538fd1498Szrj 	case DW_OP_lit7:
54638fd1498Szrj 	case DW_OP_lit8:
54738fd1498Szrj 	case DW_OP_lit9:
54838fd1498Szrj 	case DW_OP_lit10:
54938fd1498Szrj 	case DW_OP_lit11:
55038fd1498Szrj 	case DW_OP_lit12:
55138fd1498Szrj 	case DW_OP_lit13:
55238fd1498Szrj 	case DW_OP_lit14:
55338fd1498Szrj 	case DW_OP_lit15:
55438fd1498Szrj 	case DW_OP_lit16:
55538fd1498Szrj 	case DW_OP_lit17:
55638fd1498Szrj 	case DW_OP_lit18:
55738fd1498Szrj 	case DW_OP_lit19:
55838fd1498Szrj 	case DW_OP_lit20:
55938fd1498Szrj 	case DW_OP_lit21:
56038fd1498Szrj 	case DW_OP_lit22:
56138fd1498Szrj 	case DW_OP_lit23:
56238fd1498Szrj 	case DW_OP_lit24:
56338fd1498Szrj 	case DW_OP_lit25:
56438fd1498Szrj 	case DW_OP_lit26:
56538fd1498Szrj 	case DW_OP_lit27:
56638fd1498Szrj 	case DW_OP_lit28:
56738fd1498Szrj 	case DW_OP_lit29:
56838fd1498Szrj 	case DW_OP_lit30:
56938fd1498Szrj 	case DW_OP_lit31:
57038fd1498Szrj 	  result = op - DW_OP_lit0;
57138fd1498Szrj 	  break;
57238fd1498Szrj 
57338fd1498Szrj 	case DW_OP_addr:
57438fd1498Szrj 	  result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr);
57538fd1498Szrj 	  op_ptr += sizeof (void *);
57638fd1498Szrj 	  break;
57738fd1498Szrj 
57838fd1498Szrj 	case DW_OP_GNU_encoded_addr:
57938fd1498Szrj 	  {
58038fd1498Szrj 	    _Unwind_Ptr presult;
58138fd1498Szrj 	    op_ptr = read_encoded_value (context, *op_ptr, op_ptr+1, &presult);
58238fd1498Szrj 	    result = presult;
58338fd1498Szrj 	  }
58438fd1498Szrj 	  break;
58538fd1498Szrj 
58638fd1498Szrj 	case DW_OP_const1u:
58738fd1498Szrj 	  result = read_1u (op_ptr);
58838fd1498Szrj 	  op_ptr += 1;
58938fd1498Szrj 	  break;
59038fd1498Szrj 	case DW_OP_const1s:
59138fd1498Szrj 	  result = read_1s (op_ptr);
59238fd1498Szrj 	  op_ptr += 1;
59338fd1498Szrj 	  break;
59438fd1498Szrj 	case DW_OP_const2u:
59538fd1498Szrj 	  result = read_2u (op_ptr);
59638fd1498Szrj 	  op_ptr += 2;
59738fd1498Szrj 	  break;
59838fd1498Szrj 	case DW_OP_const2s:
59938fd1498Szrj 	  result = read_2s (op_ptr);
60038fd1498Szrj 	  op_ptr += 2;
60138fd1498Szrj 	  break;
60238fd1498Szrj 	case DW_OP_const4u:
60338fd1498Szrj 	  result = read_4u (op_ptr);
60438fd1498Szrj 	  op_ptr += 4;
60538fd1498Szrj 	  break;
60638fd1498Szrj 	case DW_OP_const4s:
60738fd1498Szrj 	  result = read_4s (op_ptr);
60838fd1498Szrj 	  op_ptr += 4;
60938fd1498Szrj 	  break;
61038fd1498Szrj 	case DW_OP_const8u:
61138fd1498Szrj 	  result = read_8u (op_ptr);
61238fd1498Szrj 	  op_ptr += 8;
61338fd1498Szrj 	  break;
61438fd1498Szrj 	case DW_OP_const8s:
61538fd1498Szrj 	  result = read_8s (op_ptr);
61638fd1498Szrj 	  op_ptr += 8;
61738fd1498Szrj 	  break;
61838fd1498Szrj 	case DW_OP_constu:
61938fd1498Szrj 	  op_ptr = read_uleb128 (op_ptr, &utmp);
62038fd1498Szrj 	  result = (_Unwind_Word)utmp;
62138fd1498Szrj 	  break;
62238fd1498Szrj 	case DW_OP_consts:
62338fd1498Szrj 	  op_ptr = read_sleb128 (op_ptr, &stmp);
62438fd1498Szrj 	  result = (_Unwind_Sword)stmp;
62538fd1498Szrj 	  break;
62638fd1498Szrj 
62738fd1498Szrj 	case DW_OP_reg0:
62838fd1498Szrj 	case DW_OP_reg1:
62938fd1498Szrj 	case DW_OP_reg2:
63038fd1498Szrj 	case DW_OP_reg3:
63138fd1498Szrj 	case DW_OP_reg4:
63238fd1498Szrj 	case DW_OP_reg5:
63338fd1498Szrj 	case DW_OP_reg6:
63438fd1498Szrj 	case DW_OP_reg7:
63538fd1498Szrj 	case DW_OP_reg8:
63638fd1498Szrj 	case DW_OP_reg9:
63738fd1498Szrj 	case DW_OP_reg10:
63838fd1498Szrj 	case DW_OP_reg11:
63938fd1498Szrj 	case DW_OP_reg12:
64038fd1498Szrj 	case DW_OP_reg13:
64138fd1498Szrj 	case DW_OP_reg14:
64238fd1498Szrj 	case DW_OP_reg15:
64338fd1498Szrj 	case DW_OP_reg16:
64438fd1498Szrj 	case DW_OP_reg17:
64538fd1498Szrj 	case DW_OP_reg18:
64638fd1498Szrj 	case DW_OP_reg19:
64738fd1498Szrj 	case DW_OP_reg20:
64838fd1498Szrj 	case DW_OP_reg21:
64938fd1498Szrj 	case DW_OP_reg22:
65038fd1498Szrj 	case DW_OP_reg23:
65138fd1498Szrj 	case DW_OP_reg24:
65238fd1498Szrj 	case DW_OP_reg25:
65338fd1498Szrj 	case DW_OP_reg26:
65438fd1498Szrj 	case DW_OP_reg27:
65538fd1498Szrj 	case DW_OP_reg28:
65638fd1498Szrj 	case DW_OP_reg29:
65738fd1498Szrj 	case DW_OP_reg30:
65838fd1498Szrj 	case DW_OP_reg31:
65938fd1498Szrj 	  result = _Unwind_GetGR (context, op - DW_OP_reg0);
66038fd1498Szrj 	  break;
66138fd1498Szrj 	case DW_OP_regx:
66238fd1498Szrj 	  op_ptr = read_uleb128 (op_ptr, &reg);
66338fd1498Szrj 	  result = _Unwind_GetGR (context, reg);
66438fd1498Szrj 	  break;
66538fd1498Szrj 
66638fd1498Szrj 	case DW_OP_breg0:
66738fd1498Szrj 	case DW_OP_breg1:
66838fd1498Szrj 	case DW_OP_breg2:
66938fd1498Szrj 	case DW_OP_breg3:
67038fd1498Szrj 	case DW_OP_breg4:
67138fd1498Szrj 	case DW_OP_breg5:
67238fd1498Szrj 	case DW_OP_breg6:
67338fd1498Szrj 	case DW_OP_breg7:
67438fd1498Szrj 	case DW_OP_breg8:
67538fd1498Szrj 	case DW_OP_breg9:
67638fd1498Szrj 	case DW_OP_breg10:
67738fd1498Szrj 	case DW_OP_breg11:
67838fd1498Szrj 	case DW_OP_breg12:
67938fd1498Szrj 	case DW_OP_breg13:
68038fd1498Szrj 	case DW_OP_breg14:
68138fd1498Szrj 	case DW_OP_breg15:
68238fd1498Szrj 	case DW_OP_breg16:
68338fd1498Szrj 	case DW_OP_breg17:
68438fd1498Szrj 	case DW_OP_breg18:
68538fd1498Szrj 	case DW_OP_breg19:
68638fd1498Szrj 	case DW_OP_breg20:
68738fd1498Szrj 	case DW_OP_breg21:
68838fd1498Szrj 	case DW_OP_breg22:
68938fd1498Szrj 	case DW_OP_breg23:
69038fd1498Szrj 	case DW_OP_breg24:
69138fd1498Szrj 	case DW_OP_breg25:
69238fd1498Szrj 	case DW_OP_breg26:
69338fd1498Szrj 	case DW_OP_breg27:
69438fd1498Szrj 	case DW_OP_breg28:
69538fd1498Szrj 	case DW_OP_breg29:
69638fd1498Szrj 	case DW_OP_breg30:
69738fd1498Szrj 	case DW_OP_breg31:
69838fd1498Szrj 	  op_ptr = read_sleb128 (op_ptr, &offset);
69938fd1498Szrj 	  result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset;
70038fd1498Szrj 	  break;
70138fd1498Szrj 	case DW_OP_bregx:
70238fd1498Szrj 	  op_ptr = read_uleb128 (op_ptr, &reg);
70338fd1498Szrj 	  op_ptr = read_sleb128 (op_ptr, &offset);
70438fd1498Szrj 	  result = _Unwind_GetGR (context, reg) + (_Unwind_Word)offset;
70538fd1498Szrj 	  break;
70638fd1498Szrj 
70738fd1498Szrj 	case DW_OP_dup:
70838fd1498Szrj 	  gcc_assert (stack_elt);
70938fd1498Szrj 	  result = stack[stack_elt - 1];
71038fd1498Szrj 	  break;
71138fd1498Szrj 
71238fd1498Szrj 	case DW_OP_drop:
71338fd1498Szrj 	  gcc_assert (stack_elt);
71438fd1498Szrj 	  stack_elt -= 1;
71538fd1498Szrj 	  goto no_push;
71638fd1498Szrj 
71738fd1498Szrj 	case DW_OP_pick:
71838fd1498Szrj 	  offset = *op_ptr++;
71938fd1498Szrj 	  gcc_assert (offset < stack_elt - 1);
72038fd1498Szrj 	  result = stack[stack_elt - 1 - offset];
72138fd1498Szrj 	  break;
72238fd1498Szrj 
72338fd1498Szrj 	case DW_OP_over:
72438fd1498Szrj 	  gcc_assert (stack_elt >= 2);
72538fd1498Szrj 	  result = stack[stack_elt - 2];
72638fd1498Szrj 	  break;
72738fd1498Szrj 
72838fd1498Szrj 	case DW_OP_swap:
72938fd1498Szrj 	  {
73038fd1498Szrj 	    _Unwind_Word t;
73138fd1498Szrj 	    gcc_assert (stack_elt >= 2);
73238fd1498Szrj 	    t = stack[stack_elt - 1];
73338fd1498Szrj 	    stack[stack_elt - 1] = stack[stack_elt - 2];
73438fd1498Szrj 	    stack[stack_elt - 2] = t;
73538fd1498Szrj 	    goto no_push;
73638fd1498Szrj 	  }
73738fd1498Szrj 
73838fd1498Szrj 	case DW_OP_rot:
73938fd1498Szrj 	  {
74038fd1498Szrj 	    _Unwind_Word t1, t2, t3;
74138fd1498Szrj 
74238fd1498Szrj 	    gcc_assert (stack_elt >= 3);
74338fd1498Szrj 	    t1 = stack[stack_elt - 1];
74438fd1498Szrj 	    t2 = stack[stack_elt - 2];
74538fd1498Szrj 	    t3 = stack[stack_elt - 3];
74638fd1498Szrj 	    stack[stack_elt - 1] = t2;
74738fd1498Szrj 	    stack[stack_elt - 2] = t3;
74838fd1498Szrj 	    stack[stack_elt - 3] = t1;
74938fd1498Szrj 	    goto no_push;
75038fd1498Szrj 	  }
75138fd1498Szrj 
75238fd1498Szrj 	case DW_OP_deref:
75338fd1498Szrj 	case DW_OP_deref_size:
75438fd1498Szrj 	case DW_OP_abs:
75538fd1498Szrj 	case DW_OP_neg:
75638fd1498Szrj 	case DW_OP_not:
75738fd1498Szrj 	case DW_OP_plus_uconst:
75838fd1498Szrj 	  /* Unary operations.  */
75938fd1498Szrj 	  gcc_assert (stack_elt);
76038fd1498Szrj 	  stack_elt -= 1;
76138fd1498Szrj 
76238fd1498Szrj 	  result = stack[stack_elt];
76338fd1498Szrj 
76438fd1498Szrj 	  switch (op)
76538fd1498Szrj 	    {
76638fd1498Szrj 	    case DW_OP_deref:
76738fd1498Szrj 	      {
76838fd1498Szrj 		void *ptr = (void *) (_Unwind_Ptr) result;
76938fd1498Szrj 		result = (_Unwind_Ptr) read_pointer (ptr);
77038fd1498Szrj 	      }
77138fd1498Szrj 	      break;
77238fd1498Szrj 
77338fd1498Szrj 	    case DW_OP_deref_size:
77438fd1498Szrj 	      {
77538fd1498Szrj 		void *ptr = (void *) (_Unwind_Ptr) result;
77638fd1498Szrj 		switch (*op_ptr++)
77738fd1498Szrj 		  {
77838fd1498Szrj 		  case 1:
77938fd1498Szrj 		    result = read_1u (ptr);
78038fd1498Szrj 		    break;
78138fd1498Szrj 		  case 2:
78238fd1498Szrj 		    result = read_2u (ptr);
78338fd1498Szrj 		    break;
78438fd1498Szrj 		  case 4:
78538fd1498Szrj 		    result = read_4u (ptr);
78638fd1498Szrj 		    break;
78738fd1498Szrj 		  case 8:
78838fd1498Szrj 		    result = read_8u (ptr);
78938fd1498Szrj 		    break;
79038fd1498Szrj 		  default:
79138fd1498Szrj 		    gcc_unreachable ();
79238fd1498Szrj 		  }
79338fd1498Szrj 	      }
79438fd1498Szrj 	      break;
79538fd1498Szrj 
79638fd1498Szrj 	    case DW_OP_abs:
79738fd1498Szrj 	      if ((_Unwind_Sword) result < 0)
79838fd1498Szrj 		result = -result;
79938fd1498Szrj 	      break;
80038fd1498Szrj 	    case DW_OP_neg:
80138fd1498Szrj 	      result = -result;
80238fd1498Szrj 	      break;
80338fd1498Szrj 	    case DW_OP_not:
80438fd1498Szrj 	      result = ~result;
80538fd1498Szrj 	      break;
80638fd1498Szrj 	    case DW_OP_plus_uconst:
80738fd1498Szrj 	      op_ptr = read_uleb128 (op_ptr, &utmp);
80838fd1498Szrj 	      result += (_Unwind_Word)utmp;
80938fd1498Szrj 	      break;
81038fd1498Szrj 
81138fd1498Szrj 	    default:
81238fd1498Szrj 	      gcc_unreachable ();
81338fd1498Szrj 	    }
81438fd1498Szrj 	  break;
81538fd1498Szrj 
81638fd1498Szrj 	case DW_OP_and:
81738fd1498Szrj 	case DW_OP_div:
81838fd1498Szrj 	case DW_OP_minus:
81938fd1498Szrj 	case DW_OP_mod:
82038fd1498Szrj 	case DW_OP_mul:
82138fd1498Szrj 	case DW_OP_or:
82238fd1498Szrj 	case DW_OP_plus:
82338fd1498Szrj 	case DW_OP_shl:
82438fd1498Szrj 	case DW_OP_shr:
82538fd1498Szrj 	case DW_OP_shra:
82638fd1498Szrj 	case DW_OP_xor:
82738fd1498Szrj 	case DW_OP_le:
82838fd1498Szrj 	case DW_OP_ge:
82938fd1498Szrj 	case DW_OP_eq:
83038fd1498Szrj 	case DW_OP_lt:
83138fd1498Szrj 	case DW_OP_gt:
83238fd1498Szrj 	case DW_OP_ne:
83338fd1498Szrj 	  {
83438fd1498Szrj 	    /* Binary operations.  */
83538fd1498Szrj 	    _Unwind_Word first, second;
83638fd1498Szrj 	    gcc_assert (stack_elt >= 2);
83738fd1498Szrj 	    stack_elt -= 2;
83838fd1498Szrj 
83938fd1498Szrj 	    second = stack[stack_elt];
84038fd1498Szrj 	    first = stack[stack_elt + 1];
84138fd1498Szrj 
84238fd1498Szrj 	    switch (op)
84338fd1498Szrj 	      {
84438fd1498Szrj 	      case DW_OP_and:
84538fd1498Szrj 		result = second & first;
84638fd1498Szrj 		break;
84738fd1498Szrj 	      case DW_OP_div:
84838fd1498Szrj 		result = (_Unwind_Sword) second / (_Unwind_Sword) first;
84938fd1498Szrj 		break;
85038fd1498Szrj 	      case DW_OP_minus:
85138fd1498Szrj 		result = second - first;
85238fd1498Szrj 		break;
85338fd1498Szrj 	      case DW_OP_mod:
85438fd1498Szrj 		result = second % first;
85538fd1498Szrj 		break;
85638fd1498Szrj 	      case DW_OP_mul:
85738fd1498Szrj 		result = second * first;
85838fd1498Szrj 		break;
85938fd1498Szrj 	      case DW_OP_or:
86038fd1498Szrj 		result = second | first;
86138fd1498Szrj 		break;
86238fd1498Szrj 	      case DW_OP_plus:
86338fd1498Szrj 		result = second + first;
86438fd1498Szrj 		break;
86538fd1498Szrj 	      case DW_OP_shl:
86638fd1498Szrj 		result = second << first;
86738fd1498Szrj 		break;
86838fd1498Szrj 	      case DW_OP_shr:
86938fd1498Szrj 		result = second >> first;
87038fd1498Szrj 		break;
87138fd1498Szrj 	      case DW_OP_shra:
87238fd1498Szrj 		result = (_Unwind_Sword) second >> first;
87338fd1498Szrj 		break;
87438fd1498Szrj 	      case DW_OP_xor:
87538fd1498Szrj 		result = second ^ first;
87638fd1498Szrj 		break;
87738fd1498Szrj 	      case DW_OP_le:
87838fd1498Szrj 		result = (_Unwind_Sword) second <= (_Unwind_Sword) first;
87938fd1498Szrj 		break;
88038fd1498Szrj 	      case DW_OP_ge:
88138fd1498Szrj 		result = (_Unwind_Sword) second >= (_Unwind_Sword) first;
88238fd1498Szrj 		break;
88338fd1498Szrj 	      case DW_OP_eq:
88438fd1498Szrj 		result = (_Unwind_Sword) second == (_Unwind_Sword) first;
88538fd1498Szrj 		break;
88638fd1498Szrj 	      case DW_OP_lt:
88738fd1498Szrj 		result = (_Unwind_Sword) second < (_Unwind_Sword) first;
88838fd1498Szrj 		break;
88938fd1498Szrj 	      case DW_OP_gt:
89038fd1498Szrj 		result = (_Unwind_Sword) second > (_Unwind_Sword) first;
89138fd1498Szrj 		break;
89238fd1498Szrj 	      case DW_OP_ne:
89338fd1498Szrj 		result = (_Unwind_Sword) second != (_Unwind_Sword) first;
89438fd1498Szrj 		break;
89538fd1498Szrj 
89638fd1498Szrj 	      default:
89738fd1498Szrj 		gcc_unreachable ();
89838fd1498Szrj 	      }
89938fd1498Szrj 	  }
90038fd1498Szrj 	  break;
90138fd1498Szrj 
90238fd1498Szrj 	case DW_OP_skip:
90338fd1498Szrj 	  offset = read_2s (op_ptr);
90438fd1498Szrj 	  op_ptr += 2;
90538fd1498Szrj 	  op_ptr += offset;
90638fd1498Szrj 	  goto no_push;
90738fd1498Szrj 
90838fd1498Szrj 	case DW_OP_bra:
90938fd1498Szrj 	  gcc_assert (stack_elt);
91038fd1498Szrj 	  stack_elt -= 1;
91138fd1498Szrj 
91238fd1498Szrj 	  offset = read_2s (op_ptr);
91338fd1498Szrj 	  op_ptr += 2;
91438fd1498Szrj 	  if (stack[stack_elt] != 0)
91538fd1498Szrj 	    op_ptr += offset;
91638fd1498Szrj 	  goto no_push;
91738fd1498Szrj 
91838fd1498Szrj 	case DW_OP_nop:
91938fd1498Szrj 	  goto no_push;
92038fd1498Szrj 
92138fd1498Szrj 	default:
92238fd1498Szrj 	  gcc_unreachable ();
92338fd1498Szrj 	}
92438fd1498Szrj 
92538fd1498Szrj       /* Most things push a result value.  */
92638fd1498Szrj       gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack));
92738fd1498Szrj       stack[stack_elt++] = result;
92838fd1498Szrj     no_push:;
92938fd1498Szrj     }
93038fd1498Szrj 
93138fd1498Szrj   /* We were executing this program to get a value.  It should be
93238fd1498Szrj      at top of stack.  */
93338fd1498Szrj   gcc_assert (stack_elt);
93438fd1498Szrj   stack_elt -= 1;
93538fd1498Szrj   return stack[stack_elt];
93638fd1498Szrj }
93738fd1498Szrj 
93838fd1498Szrj 
93938fd1498Szrj /* Decode DWARF 2 call frame information. Takes pointers the
94038fd1498Szrj    instruction sequence to decode, current register information and
94138fd1498Szrj    CIE info, and the PC range to evaluate.  */
94238fd1498Szrj 
94338fd1498Szrj static void
execute_cfa_program(const unsigned char * insn_ptr,const unsigned char * insn_end,struct _Unwind_Context * context,_Unwind_FrameState * fs)94438fd1498Szrj execute_cfa_program (const unsigned char *insn_ptr,
94538fd1498Szrj 		     const unsigned char *insn_end,
94638fd1498Szrj 		     struct _Unwind_Context *context,
94738fd1498Szrj 		     _Unwind_FrameState *fs)
94838fd1498Szrj {
94938fd1498Szrj   struct frame_state_reg_info *unused_rs = NULL;
95038fd1498Szrj 
95138fd1498Szrj   /* Don't allow remember/restore between CIE and FDE programs.  */
95238fd1498Szrj   fs->regs.prev = NULL;
95338fd1498Szrj 
95438fd1498Szrj   /* The comparison with the return address uses < rather than <= because
95538fd1498Szrj      we are only interested in the effects of code before the call; for a
95638fd1498Szrj      noreturn function, the return address may point to unrelated code with
95738fd1498Szrj      a different stack configuration that we are not interested in.  We
95838fd1498Szrj      assume that the call itself is unwind info-neutral; if not, or if
95938fd1498Szrj      there are delay instructions that adjust the stack, these must be
96038fd1498Szrj      reflected at the point immediately before the call insn.
96138fd1498Szrj      In signal frames, return address is after last completed instruction,
96238fd1498Szrj      so we add 1 to return address to make the comparison <=.  */
96338fd1498Szrj   while (insn_ptr < insn_end
96438fd1498Szrj 	 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
96538fd1498Szrj     {
96638fd1498Szrj       unsigned char insn = *insn_ptr++;
96738fd1498Szrj       _uleb128_t reg, utmp;
96838fd1498Szrj       _sleb128_t offset, stmp;
96938fd1498Szrj 
97038fd1498Szrj       if ((insn & 0xc0) == DW_CFA_advance_loc)
97138fd1498Szrj 	fs->pc += (insn & 0x3f) * fs->code_align;
97238fd1498Szrj       else if ((insn & 0xc0) == DW_CFA_offset)
97338fd1498Szrj 	{
97438fd1498Szrj 	  reg = insn & 0x3f;
97538fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
97638fd1498Szrj 	  offset = (_Unwind_Sword) utmp * fs->data_align;
97738fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
97838fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
97938fd1498Szrj 	    {
98038fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
98138fd1498Szrj 	      fs->regs.reg[reg].loc.offset = offset;
98238fd1498Szrj 	    }
98338fd1498Szrj 	}
98438fd1498Szrj       else if ((insn & 0xc0) == DW_CFA_restore)
98538fd1498Szrj 	{
98638fd1498Szrj 	  reg = insn & 0x3f;
98738fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
98838fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
98938fd1498Szrj 	    fs->regs.reg[reg].how = REG_UNSAVED;
99038fd1498Szrj 	}
99138fd1498Szrj       else switch (insn)
99238fd1498Szrj 	{
99338fd1498Szrj 	case DW_CFA_set_loc:
99438fd1498Szrj 	  {
99538fd1498Szrj 	    _Unwind_Ptr pc;
99638fd1498Szrj 
99738fd1498Szrj 	    insn_ptr = read_encoded_value (context, fs->fde_encoding,
99838fd1498Szrj 					   insn_ptr, &pc);
99938fd1498Szrj 	    fs->pc = (void *) pc;
100038fd1498Szrj 	  }
100138fd1498Szrj 	  break;
100238fd1498Szrj 
100338fd1498Szrj 	case DW_CFA_advance_loc1:
100438fd1498Szrj 	  fs->pc += read_1u (insn_ptr) * fs->code_align;
100538fd1498Szrj 	  insn_ptr += 1;
100638fd1498Szrj 	  break;
100738fd1498Szrj 	case DW_CFA_advance_loc2:
100838fd1498Szrj 	  fs->pc += read_2u (insn_ptr) * fs->code_align;
100938fd1498Szrj 	  insn_ptr += 2;
101038fd1498Szrj 	  break;
101138fd1498Szrj 	case DW_CFA_advance_loc4:
101238fd1498Szrj 	  fs->pc += read_4u (insn_ptr) * fs->code_align;
101338fd1498Szrj 	  insn_ptr += 4;
101438fd1498Szrj 	  break;
101538fd1498Szrj 
101638fd1498Szrj 	case DW_CFA_offset_extended:
101738fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
101838fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
101938fd1498Szrj 	  offset = (_Unwind_Sword) utmp * fs->data_align;
102038fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
102138fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
102238fd1498Szrj 	    {
102338fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
102438fd1498Szrj 	      fs->regs.reg[reg].loc.offset = offset;
102538fd1498Szrj 	    }
102638fd1498Szrj 	  break;
102738fd1498Szrj 
102838fd1498Szrj 	case DW_CFA_restore_extended:
102938fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
103038fd1498Szrj 	  /* FIXME, this is wrong; the CIE might have said that the
103138fd1498Szrj 	     register was saved somewhere.  */
103238fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
103338fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
103438fd1498Szrj 	    fs->regs.reg[reg].how = REG_UNSAVED;
103538fd1498Szrj 	  break;
103638fd1498Szrj 
103738fd1498Szrj 	case DW_CFA_same_value:
103838fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
103938fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
104038fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
104138fd1498Szrj 	    fs->regs.reg[reg].how = REG_UNSAVED;
104238fd1498Szrj 	  break;
104338fd1498Szrj 
104438fd1498Szrj 	case DW_CFA_undefined:
104538fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
104638fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
104738fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
104838fd1498Szrj 	    fs->regs.reg[reg].how = REG_UNDEFINED;
104938fd1498Szrj 	  break;
105038fd1498Szrj 
105138fd1498Szrj 	case DW_CFA_nop:
105238fd1498Szrj 	  break;
105338fd1498Szrj 
105438fd1498Szrj 	case DW_CFA_register:
105538fd1498Szrj 	  {
105638fd1498Szrj 	    _uleb128_t reg2;
105738fd1498Szrj 	    insn_ptr = read_uleb128 (insn_ptr, &reg);
105838fd1498Szrj 	    insn_ptr = read_uleb128 (insn_ptr, &reg2);
105938fd1498Szrj 	    reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
106038fd1498Szrj 	    if (UNWIND_COLUMN_IN_RANGE (reg))
106138fd1498Szrj 	      {
106238fd1498Szrj 	        fs->regs.reg[reg].how = REG_SAVED_REG;
106338fd1498Szrj 	        fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
106438fd1498Szrj 	      }
106538fd1498Szrj 	  }
106638fd1498Szrj 	  break;
106738fd1498Szrj 
106838fd1498Szrj 	case DW_CFA_remember_state:
106938fd1498Szrj 	  {
107038fd1498Szrj 	    struct frame_state_reg_info *new_rs;
107138fd1498Szrj 	    if (unused_rs)
107238fd1498Szrj 	      {
107338fd1498Szrj 		new_rs = unused_rs;
107438fd1498Szrj 		unused_rs = unused_rs->prev;
107538fd1498Szrj 	      }
107638fd1498Szrj 	    else
107738fd1498Szrj 	      new_rs = alloca (sizeof (struct frame_state_reg_info));
107838fd1498Szrj 
107938fd1498Szrj 	    *new_rs = fs->regs;
108038fd1498Szrj 	    fs->regs.prev = new_rs;
108138fd1498Szrj 	  }
108238fd1498Szrj 	  break;
108338fd1498Szrj 
108438fd1498Szrj 	case DW_CFA_restore_state:
108538fd1498Szrj 	  {
108638fd1498Szrj 	    struct frame_state_reg_info *old_rs = fs->regs.prev;
108738fd1498Szrj 	    fs->regs = *old_rs;
108838fd1498Szrj 	    old_rs->prev = unused_rs;
108938fd1498Szrj 	    unused_rs = old_rs;
109038fd1498Szrj 	  }
109138fd1498Szrj 	  break;
109238fd1498Szrj 
109338fd1498Szrj 	case DW_CFA_def_cfa:
109438fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
109538fd1498Szrj 	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
109638fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
109738fd1498Szrj 	  fs->regs.cfa_offset = (_Unwind_Word)utmp;
109838fd1498Szrj 	  fs->regs.cfa_how = CFA_REG_OFFSET;
109938fd1498Szrj 	  break;
110038fd1498Szrj 
110138fd1498Szrj 	case DW_CFA_def_cfa_register:
110238fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
110338fd1498Szrj 	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
110438fd1498Szrj 	  fs->regs.cfa_how = CFA_REG_OFFSET;
110538fd1498Szrj 	  break;
110638fd1498Szrj 
110738fd1498Szrj 	case DW_CFA_def_cfa_offset:
110838fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
110938fd1498Szrj 	  fs->regs.cfa_offset = utmp;
111038fd1498Szrj 	  /* cfa_how deliberately not set.  */
111138fd1498Szrj 	  break;
111238fd1498Szrj 
111338fd1498Szrj 	case DW_CFA_def_cfa_expression:
111438fd1498Szrj 	  fs->regs.cfa_exp = insn_ptr;
111538fd1498Szrj 	  fs->regs.cfa_how = CFA_EXP;
111638fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
111738fd1498Szrj 	  insn_ptr += utmp;
111838fd1498Szrj 	  break;
111938fd1498Szrj 
112038fd1498Szrj 	case DW_CFA_expression:
112138fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
112238fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
112338fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
112438fd1498Szrj 	    {
112538fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_EXP;
112638fd1498Szrj 	      fs->regs.reg[reg].loc.exp = insn_ptr;
112738fd1498Szrj 	    }
112838fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
112938fd1498Szrj 	  insn_ptr += utmp;
113038fd1498Szrj 	  break;
113138fd1498Szrj 
113238fd1498Szrj 	  /* Dwarf3.  */
113338fd1498Szrj 	case DW_CFA_offset_extended_sf:
113438fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
113538fd1498Szrj 	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
113638fd1498Szrj 	  offset = stmp * fs->data_align;
113738fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
113838fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
113938fd1498Szrj 	    {
114038fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
114138fd1498Szrj 	      fs->regs.reg[reg].loc.offset = offset;
114238fd1498Szrj 	    }
114338fd1498Szrj 	  break;
114438fd1498Szrj 
114538fd1498Szrj 	case DW_CFA_def_cfa_sf:
114638fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
114738fd1498Szrj 	  fs->regs.cfa_reg = (_Unwind_Word)utmp;
114838fd1498Szrj 	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
114938fd1498Szrj 	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
115038fd1498Szrj 	  fs->regs.cfa_how = CFA_REG_OFFSET;
115138fd1498Szrj 	  fs->regs.cfa_offset *= fs->data_align;
115238fd1498Szrj 	  break;
115338fd1498Szrj 
115438fd1498Szrj 	case DW_CFA_def_cfa_offset_sf:
115538fd1498Szrj 	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
115638fd1498Szrj 	  fs->regs.cfa_offset = (_Unwind_Sword)stmp;
115738fd1498Szrj 	  fs->regs.cfa_offset *= fs->data_align;
115838fd1498Szrj 	  /* cfa_how deliberately not set.  */
115938fd1498Szrj 	  break;
116038fd1498Szrj 
116138fd1498Szrj 	case DW_CFA_val_offset:
116238fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
116338fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
116438fd1498Szrj 	  offset = (_Unwind_Sword) utmp * fs->data_align;
116538fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
116638fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
116738fd1498Szrj 	    {
116838fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
116938fd1498Szrj 	      fs->regs.reg[reg].loc.offset = offset;
117038fd1498Szrj 	    }
117138fd1498Szrj 	  break;
117238fd1498Szrj 
117338fd1498Szrj 	case DW_CFA_val_offset_sf:
117438fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
117538fd1498Szrj 	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
117638fd1498Szrj 	  offset = stmp * fs->data_align;
117738fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
117838fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
117938fd1498Szrj 	    {
118038fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
118138fd1498Szrj 	      fs->regs.reg[reg].loc.offset = offset;
118238fd1498Szrj 	    }
118338fd1498Szrj 	  break;
118438fd1498Szrj 
118538fd1498Szrj 	case DW_CFA_val_expression:
118638fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
118738fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
118838fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
118938fd1498Szrj 	    {
119038fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_VAL_EXP;
119138fd1498Szrj 	      fs->regs.reg[reg].loc.exp = insn_ptr;
119238fd1498Szrj 	    }
119338fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
119438fd1498Szrj 	  insn_ptr += utmp;
119538fd1498Szrj 	  break;
119638fd1498Szrj 
119738fd1498Szrj 	case DW_CFA_GNU_window_save:
119838fd1498Szrj #if defined (__aarch64__) && !defined (__ILP32__)
119938fd1498Szrj 	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
120038fd1498Szrj 	     return address signing status.  */
120138fd1498Szrj 	  fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
120238fd1498Szrj #else
120338fd1498Szrj 	  /* ??? Hardcoded for SPARC register window configuration.  */
120438fd1498Szrj 	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
120538fd1498Szrj 	    for (reg = 16; reg < 32; ++reg)
120638fd1498Szrj 	      {
120738fd1498Szrj 		fs->regs.reg[reg].how = REG_SAVED_OFFSET;
120838fd1498Szrj 		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
120938fd1498Szrj 	      }
121038fd1498Szrj #endif
121138fd1498Szrj 	  break;
121238fd1498Szrj 
121338fd1498Szrj 	case DW_CFA_GNU_args_size:
121438fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
121538fd1498Szrj 	  context->args_size = (_Unwind_Word)utmp;
121638fd1498Szrj 	  break;
121738fd1498Szrj 
121838fd1498Szrj 	case DW_CFA_GNU_negative_offset_extended:
121938fd1498Szrj 	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
122038fd1498Szrj 	     older PowerPC code.  */
122138fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
122238fd1498Szrj 	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
122338fd1498Szrj 	  offset = (_Unwind_Word) utmp * fs->data_align;
122438fd1498Szrj 	  reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
122538fd1498Szrj 	  if (UNWIND_COLUMN_IN_RANGE (reg))
122638fd1498Szrj 	    {
122738fd1498Szrj 	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
122838fd1498Szrj 	      fs->regs.reg[reg].loc.offset = -offset;
122938fd1498Szrj 	    }
123038fd1498Szrj 	  break;
123138fd1498Szrj 
123238fd1498Szrj 	default:
123338fd1498Szrj 	  gcc_unreachable ();
123438fd1498Szrj 	}
123538fd1498Szrj     }
123638fd1498Szrj }
123738fd1498Szrj 
123838fd1498Szrj /* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
123938fd1498Szrj    its caller and decode it into FS.  This function also sets the
124038fd1498Szrj    args_size and lsda members of CONTEXT, as they are really information
124138fd1498Szrj    about the caller's frame.  */
124238fd1498Szrj 
124338fd1498Szrj static _Unwind_Reason_Code
uw_frame_state_for(struct _Unwind_Context * context,_Unwind_FrameState * fs)124438fd1498Szrj uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
124538fd1498Szrj {
124638fd1498Szrj   const struct dwarf_fde *fde;
124738fd1498Szrj   const struct dwarf_cie *cie;
124838fd1498Szrj   const unsigned char *aug, *insn, *end;
124938fd1498Szrj 
125038fd1498Szrj   memset (fs, 0, sizeof (*fs));
125138fd1498Szrj   context->args_size = 0;
125238fd1498Szrj   context->lsda = 0;
125338fd1498Szrj 
125438fd1498Szrj   if (context->ra == 0)
125538fd1498Szrj     return _URC_END_OF_STACK;
125638fd1498Szrj 
125738fd1498Szrj   fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
125838fd1498Szrj 			  &context->bases);
125938fd1498Szrj   if (fde == NULL)
126038fd1498Szrj     {
126138fd1498Szrj #ifdef MD_FALLBACK_FRAME_STATE_FOR
126238fd1498Szrj       /* Couldn't find frame unwind info for this function.  Try a
126338fd1498Szrj 	 target-specific fallback mechanism.  This will necessarily
126438fd1498Szrj 	 not provide a personality routine or LSDA.  */
126538fd1498Szrj       return MD_FALLBACK_FRAME_STATE_FOR (context, fs);
126638fd1498Szrj #else
126738fd1498Szrj       return _URC_END_OF_STACK;
126838fd1498Szrj #endif
126938fd1498Szrj     }
127038fd1498Szrj 
127138fd1498Szrj   fs->pc = context->bases.func;
127238fd1498Szrj 
127338fd1498Szrj   cie = get_cie (fde);
127438fd1498Szrj   insn = extract_cie_info (cie, context, fs);
127538fd1498Szrj   if (insn == NULL)
127638fd1498Szrj     /* CIE contained unknown augmentation.  */
127738fd1498Szrj     return _URC_FATAL_PHASE1_ERROR;
127838fd1498Szrj 
127938fd1498Szrj   /* First decode all the insns in the CIE.  */
128038fd1498Szrj   end = (const unsigned char *) next_fde ((const struct dwarf_fde *) cie);
128138fd1498Szrj   execute_cfa_program (insn, end, context, fs);
128238fd1498Szrj 
128338fd1498Szrj   /* Locate augmentation for the fde.  */
128438fd1498Szrj   aug = (const unsigned char *) fde + sizeof (*fde);
128538fd1498Szrj   aug += 2 * size_of_encoded_value (fs->fde_encoding);
128638fd1498Szrj   insn = NULL;
128738fd1498Szrj   if (fs->saw_z)
128838fd1498Szrj     {
128938fd1498Szrj       _uleb128_t i;
129038fd1498Szrj       aug = read_uleb128 (aug, &i);
129138fd1498Szrj       insn = aug + i;
129238fd1498Szrj     }
129338fd1498Szrj   if (fs->lsda_encoding != DW_EH_PE_omit)
129438fd1498Szrj     {
129538fd1498Szrj       _Unwind_Ptr lsda;
129638fd1498Szrj 
129738fd1498Szrj       aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
129838fd1498Szrj       context->lsda = (void *) lsda;
129938fd1498Szrj     }
130038fd1498Szrj 
130138fd1498Szrj   /* Then the insns in the FDE up to our target PC.  */
130238fd1498Szrj   if (insn == NULL)
130338fd1498Szrj     insn = aug;
130438fd1498Szrj   end = (const unsigned char *) next_fde (fde);
130538fd1498Szrj   execute_cfa_program (insn, end, context, fs);
130638fd1498Szrj 
130738fd1498Szrj   return _URC_NO_REASON;
130838fd1498Szrj }
130938fd1498Szrj 
131038fd1498Szrj typedef struct frame_state
131138fd1498Szrj {
131238fd1498Szrj   void *cfa;
131338fd1498Szrj   void *eh_ptr;
131438fd1498Szrj   long cfa_offset;
131538fd1498Szrj   long args_size;
131638fd1498Szrj   long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
131738fd1498Szrj   unsigned short cfa_reg;
131838fd1498Szrj   unsigned short retaddr_column;
131938fd1498Szrj   char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
132038fd1498Szrj } frame_state;
132138fd1498Szrj 
132238fd1498Szrj struct frame_state * __frame_state_for (void *, struct frame_state *);
132338fd1498Szrj 
132438fd1498Szrj /* Called from pre-G++ 3.0 __throw to find the registers to restore for
132538fd1498Szrj    a given PC_TARGET.  The caller should allocate a local variable of
132638fd1498Szrj    `struct frame_state' and pass its address to STATE_IN.  */
132738fd1498Szrj 
132838fd1498Szrj struct frame_state *
__frame_state_for(void * pc_target,struct frame_state * state_in)132938fd1498Szrj __frame_state_for (void *pc_target, struct frame_state *state_in)
133038fd1498Szrj {
133138fd1498Szrj   struct _Unwind_Context context;
133238fd1498Szrj   _Unwind_FrameState fs;
133338fd1498Szrj   int reg;
133438fd1498Szrj 
133538fd1498Szrj   memset (&context, 0, sizeof (struct _Unwind_Context));
133638fd1498Szrj   if (!ASSUME_EXTENDED_UNWIND_CONTEXT)
133738fd1498Szrj     context.flags = EXTENDED_CONTEXT_BIT;
133838fd1498Szrj   context.ra = pc_target + 1;
133938fd1498Szrj 
134038fd1498Szrj   if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
134138fd1498Szrj     return 0;
134238fd1498Szrj 
134338fd1498Szrj   /* We have no way to pass a location expression for the CFA to our
134438fd1498Szrj      caller.  It wouldn't understand it anyway.  */
134538fd1498Szrj   if (fs.regs.cfa_how == CFA_EXP)
134638fd1498Szrj     return 0;
134738fd1498Szrj 
134838fd1498Szrj   for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++)
134938fd1498Szrj     {
135038fd1498Szrj       state_in->saved[reg] = fs.regs.reg[reg].how;
135138fd1498Szrj       switch (state_in->saved[reg])
135238fd1498Szrj 	{
135338fd1498Szrj 	case REG_SAVED_REG:
135438fd1498Szrj 	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg;
135538fd1498Szrj 	  break;
135638fd1498Szrj 	case REG_SAVED_OFFSET:
135738fd1498Szrj 	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset;
135838fd1498Szrj 	  break;
135938fd1498Szrj 	default:
136038fd1498Szrj 	  state_in->reg_or_offset[reg] = 0;
136138fd1498Szrj 	  break;
136238fd1498Szrj 	}
136338fd1498Szrj     }
136438fd1498Szrj 
136538fd1498Szrj   state_in->cfa_offset = fs.regs.cfa_offset;
136638fd1498Szrj   state_in->cfa_reg = fs.regs.cfa_reg;
136738fd1498Szrj   state_in->retaddr_column = fs.retaddr_column;
136838fd1498Szrj   state_in->args_size = context.args_size;
136938fd1498Szrj   state_in->eh_ptr = fs.eh_ptr;
137038fd1498Szrj 
137138fd1498Szrj   return state_in;
137238fd1498Szrj }
137338fd1498Szrj 
137438fd1498Szrj typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp;
137538fd1498Szrj 
137638fd1498Szrj static inline void
_Unwind_SetSpColumn(struct _Unwind_Context * context,void * cfa,_Unwind_SpTmp * tmp_sp)137738fd1498Szrj _Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
137838fd1498Szrj 		     _Unwind_SpTmp *tmp_sp)
137938fd1498Szrj {
138038fd1498Szrj   int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
138138fd1498Szrj 
138238fd1498Szrj   if (size == sizeof(_Unwind_Ptr))
138338fd1498Szrj     tmp_sp->ptr = (_Unwind_Ptr) cfa;
138438fd1498Szrj   else
138538fd1498Szrj     {
138638fd1498Szrj       gcc_assert (size == sizeof(_Unwind_Word));
138738fd1498Szrj       tmp_sp->word = (_Unwind_Ptr) cfa;
138838fd1498Szrj     }
138938fd1498Szrj   _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp);
139038fd1498Szrj }
139138fd1498Szrj 
139238fd1498Szrj static void
uw_update_context_1(struct _Unwind_Context * context,_Unwind_FrameState * fs)139338fd1498Szrj uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
139438fd1498Szrj {
139538fd1498Szrj   struct _Unwind_Context orig_context = *context;
139638fd1498Szrj   void *cfa;
139738fd1498Szrj   long i;
139838fd1498Szrj 
139938fd1498Szrj #ifdef __LIBGCC_EH_RETURN_STACKADJ_RTX__
140038fd1498Szrj   /* Special handling here: Many machines do not use a frame pointer,
140138fd1498Szrj      and track the CFA only through offsets from the stack pointer from
140238fd1498Szrj      one frame to the next.  In this case, the stack pointer is never
140338fd1498Szrj      stored, so it has no saved address in the context.  What we do
140438fd1498Szrj      have is the CFA from the previous stack frame.
140538fd1498Szrj 
140638fd1498Szrj      In very special situations (such as unwind info for signal return),
140738fd1498Szrj      there may be location expressions that use the stack pointer as well.
140838fd1498Szrj 
140938fd1498Szrj      Do this conditionally for one frame.  This allows the unwind info
141038fd1498Szrj      for one frame to save a copy of the stack pointer from the previous
141138fd1498Szrj      frame, and be able to use much easier CFA mechanisms to do it.
141238fd1498Szrj      Always zap the saved stack pointer value for the next frame; carrying
141338fd1498Szrj      the value over from one frame to another doesn't make sense.  */
141438fd1498Szrj 
141538fd1498Szrj   _Unwind_SpTmp tmp_sp;
141638fd1498Szrj 
141738fd1498Szrj   if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ()))
141838fd1498Szrj     _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp);
141938fd1498Szrj   _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL);
142038fd1498Szrj #endif
142138fd1498Szrj 
142238fd1498Szrj   /* Compute this frame's CFA.  */
142338fd1498Szrj   switch (fs->regs.cfa_how)
142438fd1498Szrj     {
142538fd1498Szrj     case CFA_REG_OFFSET:
142638fd1498Szrj       cfa = _Unwind_GetPtr (&orig_context, fs->regs.cfa_reg);
142738fd1498Szrj       cfa += fs->regs.cfa_offset;
142838fd1498Szrj       break;
142938fd1498Szrj 
143038fd1498Szrj     case CFA_EXP:
143138fd1498Szrj       {
143238fd1498Szrj 	const unsigned char *exp = fs->regs.cfa_exp;
143338fd1498Szrj 	_uleb128_t len;
143438fd1498Szrj 
143538fd1498Szrj 	exp = read_uleb128 (exp, &len);
143638fd1498Szrj 	cfa = (void *) (_Unwind_Ptr)
143738fd1498Szrj 	  execute_stack_op (exp, exp + len, &orig_context, 0);
143838fd1498Szrj 	break;
143938fd1498Szrj       }
144038fd1498Szrj 
144138fd1498Szrj     default:
144238fd1498Szrj       gcc_unreachable ();
144338fd1498Szrj     }
144438fd1498Szrj   context->cfa = cfa;
144538fd1498Szrj 
144638fd1498Szrj   /* Compute the addresses of all registers saved in this frame.  */
144738fd1498Szrj   for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
144838fd1498Szrj     switch (fs->regs.reg[i].how)
144938fd1498Szrj       {
145038fd1498Szrj       case REG_UNSAVED:
145138fd1498Szrj       case REG_UNDEFINED:
145238fd1498Szrj 	break;
145338fd1498Szrj 
145438fd1498Szrj       case REG_SAVED_OFFSET:
145538fd1498Szrj 	_Unwind_SetGRPtr (context, i,
145638fd1498Szrj 			  (void *) (cfa + fs->regs.reg[i].loc.offset));
145738fd1498Szrj 	break;
145838fd1498Szrj 
145938fd1498Szrj       case REG_SAVED_REG:
146038fd1498Szrj 	if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg))
146138fd1498Szrj 	  _Unwind_SetGRValue (context, i,
146238fd1498Szrj 			      _Unwind_GetGR (&orig_context,
146338fd1498Szrj 					     fs->regs.reg[i].loc.reg));
146438fd1498Szrj 	else
146538fd1498Szrj 	  _Unwind_SetGRPtr (context, i,
146638fd1498Szrj 			    _Unwind_GetGRPtr (&orig_context,
146738fd1498Szrj 					      fs->regs.reg[i].loc.reg));
146838fd1498Szrj 	break;
146938fd1498Szrj 
147038fd1498Szrj       case REG_SAVED_EXP:
147138fd1498Szrj 	{
147238fd1498Szrj 	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
147338fd1498Szrj 	  _uleb128_t len;
147438fd1498Szrj 	  _Unwind_Ptr val;
147538fd1498Szrj 
147638fd1498Szrj 	  exp = read_uleb128 (exp, &len);
147738fd1498Szrj 	  val = execute_stack_op (exp, exp + len, &orig_context,
147838fd1498Szrj 				  (_Unwind_Ptr) cfa);
147938fd1498Szrj 	  _Unwind_SetGRPtr (context, i, (void *) val);
148038fd1498Szrj 	}
148138fd1498Szrj 	break;
148238fd1498Szrj 
148338fd1498Szrj       case REG_SAVED_VAL_OFFSET:
148438fd1498Szrj 	_Unwind_SetGRValue (context, i,
148538fd1498Szrj 			    (_Unwind_Internal_Ptr)
148638fd1498Szrj 			    (cfa + fs->regs.reg[i].loc.offset));
148738fd1498Szrj 	break;
148838fd1498Szrj 
148938fd1498Szrj       case REG_SAVED_VAL_EXP:
149038fd1498Szrj 	{
149138fd1498Szrj 	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
149238fd1498Szrj 	  _uleb128_t len;
149338fd1498Szrj 	  _Unwind_Ptr val;
149438fd1498Szrj 
149538fd1498Szrj 	  exp = read_uleb128 (exp, &len);
149638fd1498Szrj 	  val = execute_stack_op (exp, exp + len, &orig_context,
149738fd1498Szrj 				  (_Unwind_Ptr) cfa);
149838fd1498Szrj 	  _Unwind_SetGRValue (context, i, val);
149938fd1498Szrj 	}
150038fd1498Szrj 	break;
150138fd1498Szrj       }
150238fd1498Szrj 
150338fd1498Szrj   _Unwind_SetSignalFrame (context, fs->signal_frame);
150438fd1498Szrj 
150538fd1498Szrj #ifdef MD_FROB_UPDATE_CONTEXT
150638fd1498Szrj   MD_FROB_UPDATE_CONTEXT (context, fs);
150738fd1498Szrj #endif
150838fd1498Szrj }
150938fd1498Szrj 
151038fd1498Szrj /* CONTEXT describes the unwind state for a frame, and FS describes the FDE
151138fd1498Szrj    of its caller.  Update CONTEXT to refer to the caller as well.  Note
151238fd1498Szrj    that the args_size and lsda members are not updated here, but later in
151338fd1498Szrj    uw_frame_state_for.  */
151438fd1498Szrj 
151538fd1498Szrj static void
uw_update_context(struct _Unwind_Context * context,_Unwind_FrameState * fs)151638fd1498Szrj uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
151738fd1498Szrj {
151838fd1498Szrj   uw_update_context_1 (context, fs);
151938fd1498Szrj 
152038fd1498Szrj   /* In general this unwinder doesn't make any distinction between
152138fd1498Szrj      undefined and same_value rule.  Call-saved registers are assumed
152238fd1498Szrj      to have same_value rule by default and explicit undefined
152338fd1498Szrj      rule is handled like same_value.  The only exception is
152438fd1498Szrj      DW_CFA_undefined on retaddr_column which is supposed to
152538fd1498Szrj      mark outermost frame in DWARF 3.  */
152638fd1498Szrj   if (fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (fs->retaddr_column)].how
152738fd1498Szrj       == REG_UNDEFINED)
152838fd1498Szrj     /* uw_frame_state_for uses context->ra == 0 check to find outermost
152938fd1498Szrj        stack frame.  */
153038fd1498Szrj     context->ra = 0;
153138fd1498Szrj   else
153238fd1498Szrj     {
153338fd1498Szrj       /* Compute the return address now, since the return address column
153438fd1498Szrj 	 can change from frame to frame.  */
153538fd1498Szrj       context->ra = __builtin_extract_return_addr
153638fd1498Szrj 	(_Unwind_GetPtr (context, fs->retaddr_column));
153738fd1498Szrj #ifdef MD_POST_EXTRACT_FRAME_ADDR
153838fd1498Szrj       context->ra = MD_POST_EXTRACT_FRAME_ADDR (context, fs, context->ra);
153938fd1498Szrj #endif
154038fd1498Szrj     }
154138fd1498Szrj }
154238fd1498Szrj 
154338fd1498Szrj static void
uw_advance_context(struct _Unwind_Context * context,_Unwind_FrameState * fs)154438fd1498Szrj uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
154538fd1498Szrj {
154638fd1498Szrj   uw_update_context (context, fs);
154738fd1498Szrj }
154838fd1498Szrj 
154938fd1498Szrj /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
155038fd1498Szrj    level will be the return address and the CFA.  */
155138fd1498Szrj 
155238fd1498Szrj #define uw_init_context(CONTEXT)					   \
155338fd1498Szrj   do									   \
155438fd1498Szrj     {									   \
155538fd1498Szrj       /* Do any necessary initialization to access arbitrary stack frames. \
155638fd1498Szrj 	 On the SPARC, this means flushing the register windows.  */	   \
155738fd1498Szrj       __builtin_unwind_init ();						   \
155838fd1498Szrj       uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),		   \
155938fd1498Szrj 			 __builtin_return_address (0));			   \
156038fd1498Szrj     }									   \
156138fd1498Szrj   while (0)
156238fd1498Szrj 
156338fd1498Szrj static inline void
init_dwarf_reg_size_table(void)156438fd1498Szrj init_dwarf_reg_size_table (void)
156538fd1498Szrj {
156638fd1498Szrj   __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
156738fd1498Szrj }
156838fd1498Szrj 
156938fd1498Szrj static void __attribute__((noinline))
uw_init_context_1(struct _Unwind_Context * context,void * outer_cfa,void * outer_ra)157038fd1498Szrj uw_init_context_1 (struct _Unwind_Context *context,
157138fd1498Szrj 		   void *outer_cfa, void *outer_ra)
157238fd1498Szrj {
157338fd1498Szrj   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
157438fd1498Szrj #ifdef MD_POST_EXTRACT_ROOT_ADDR
157538fd1498Szrj   ra = MD_POST_EXTRACT_ROOT_ADDR (ra);
157638fd1498Szrj #endif
157738fd1498Szrj   _Unwind_FrameState fs;
157838fd1498Szrj   _Unwind_SpTmp sp_slot;
157938fd1498Szrj   _Unwind_Reason_Code code;
158038fd1498Szrj 
158138fd1498Szrj   memset (context, 0, sizeof (struct _Unwind_Context));
158238fd1498Szrj   context->ra = ra;
158338fd1498Szrj   if (!ASSUME_EXTENDED_UNWIND_CONTEXT)
158438fd1498Szrj     context->flags = EXTENDED_CONTEXT_BIT;
158538fd1498Szrj 
158638fd1498Szrj   code = uw_frame_state_for (context, &fs);
158738fd1498Szrj   gcc_assert (code == _URC_NO_REASON);
158838fd1498Szrj 
158938fd1498Szrj #if __GTHREADS
159038fd1498Szrj   {
159138fd1498Szrj     static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
159238fd1498Szrj     if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
159338fd1498Szrj 	&& dwarf_reg_size_table[0] == 0)
159438fd1498Szrj       init_dwarf_reg_size_table ();
159538fd1498Szrj   }
159638fd1498Szrj #else
159738fd1498Szrj   if (dwarf_reg_size_table[0] == 0)
159838fd1498Szrj     init_dwarf_reg_size_table ();
159938fd1498Szrj #endif
160038fd1498Szrj 
160138fd1498Szrj   /* Force the frame state to use the known cfa value.  */
160238fd1498Szrj   _Unwind_SetSpColumn (context, outer_cfa, &sp_slot);
160338fd1498Szrj   fs.regs.cfa_how = CFA_REG_OFFSET;
160438fd1498Szrj   fs.regs.cfa_reg = __builtin_dwarf_sp_column ();
160538fd1498Szrj   fs.regs.cfa_offset = 0;
160638fd1498Szrj 
160738fd1498Szrj   uw_update_context_1 (context, &fs);
160838fd1498Szrj 
160938fd1498Szrj   /* If the return address column was saved in a register in the
161038fd1498Szrj      initialization context, then we can't see it in the given
161138fd1498Szrj      call frame data.  So have the initialization context tell us.  */
161238fd1498Szrj   context->ra = __builtin_extract_return_addr (outer_ra);
161338fd1498Szrj #ifdef MD_POST_EXTRACT_ROOT_ADDR
161438fd1498Szrj   context->ra = MD_POST_EXTRACT_ROOT_ADDR (context->ra);
161538fd1498Szrj #endif
161638fd1498Szrj }
161738fd1498Szrj 
161838fd1498Szrj static void _Unwind_DebugHook (void *, void *)
161938fd1498Szrj   __attribute__ ((__noinline__, __used__, __noclone__));
162038fd1498Szrj 
162138fd1498Szrj /* This function is called during unwinding.  It is intended as a hook
162238fd1498Szrj    for a debugger to intercept exceptions.  CFA is the CFA of the
162338fd1498Szrj    target frame.  HANDLER is the PC to which control will be
162438fd1498Szrj    transferred.  */
162538fd1498Szrj static void
_Unwind_DebugHook(void * cfa,void * handler)162638fd1498Szrj _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
162738fd1498Szrj 		   void *handler __attribute__ ((__unused__)))
162838fd1498Szrj {
162938fd1498Szrj   /* We only want to use stap probes starting with v3.  Earlier
163038fd1498Szrj      versions added too much startup cost.  */
163138fd1498Szrj #if defined (HAVE_SYS_SDT_H) && defined (STAP_PROBE2) && _SDT_NOTE_TYPE >= 3
163238fd1498Szrj   STAP_PROBE2 (libgcc, unwind, cfa, handler);
163338fd1498Szrj #else
163438fd1498Szrj   asm ("");
163538fd1498Szrj #endif
163638fd1498Szrj }
163738fd1498Szrj 
163838fd1498Szrj /* Frob exception handler's address kept in TARGET before installing into
163938fd1498Szrj    CURRENT context.  */
164038fd1498Szrj 
164138fd1498Szrj static inline void *
uw_frob_return_addr(struct _Unwind_Context * current,struct _Unwind_Context * target)164238fd1498Szrj uw_frob_return_addr (struct _Unwind_Context *current
164338fd1498Szrj 		     __attribute__ ((__unused__)),
164438fd1498Szrj 		     struct _Unwind_Context *target)
164538fd1498Szrj {
164638fd1498Szrj   void *ret_addr = __builtin_frob_return_addr (target->ra);
164738fd1498Szrj #ifdef MD_POST_FROB_EH_HANDLER_ADDR
164838fd1498Szrj   ret_addr = MD_POST_FROB_EH_HANDLER_ADDR (current, target, ret_addr);
164938fd1498Szrj #endif
165038fd1498Szrj   return ret_addr;
165138fd1498Szrj }
165238fd1498Szrj 
165338fd1498Szrj /* Install TARGET into CURRENT so that we can return to it.  This is a
165438fd1498Szrj    macro because __builtin_eh_return must be invoked in the context of
165538fd1498Szrj    our caller.  FRAMES is a number of frames to be unwind.
165638fd1498Szrj    _Unwind_Frames_Extra is a macro to do additional work during unwinding
165738fd1498Szrj    if needed, for example shadow stack pointer adjustment for Intel CET
165838fd1498Szrj    technology.  */
165938fd1498Szrj 
166038fd1498Szrj #define uw_install_context(CURRENT, TARGET, FRAMES)			\
166138fd1498Szrj   do									\
166238fd1498Szrj     {									\
166338fd1498Szrj       long offset = uw_install_context_1 ((CURRENT), (TARGET));		\
166438fd1498Szrj       void *handler = uw_frob_return_addr ((CURRENT), (TARGET));	\
166538fd1498Szrj       _Unwind_DebugHook ((TARGET)->cfa, handler);			\
166638fd1498Szrj       _Unwind_Frames_Extra (FRAMES);					\
166738fd1498Szrj       __builtin_eh_return (offset, handler);				\
166838fd1498Szrj     }									\
166938fd1498Szrj   while (0)
167038fd1498Szrj 
167138fd1498Szrj static long
uw_install_context_1(struct _Unwind_Context * current,struct _Unwind_Context * target)167238fd1498Szrj uw_install_context_1 (struct _Unwind_Context *current,
167338fd1498Szrj 		      struct _Unwind_Context *target)
167438fd1498Szrj {
167538fd1498Szrj   long i;
167638fd1498Szrj   _Unwind_SpTmp sp_slot;
167738fd1498Szrj 
167838fd1498Szrj   /* If the target frame does not have a saved stack pointer,
167938fd1498Szrj      then set up the target's CFA.  */
168038fd1498Szrj   if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
168138fd1498Szrj     _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
168238fd1498Szrj 
168338fd1498Szrj   for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__; ++i)
168438fd1498Szrj     {
168538fd1498Szrj       void *c = (void *) (_Unwind_Internal_Ptr) current->reg[i];
168638fd1498Szrj       void *t = (void *) (_Unwind_Internal_Ptr)target->reg[i];
168738fd1498Szrj 
168838fd1498Szrj       gcc_assert (current->by_value[i] == 0);
168938fd1498Szrj       if (target->by_value[i] && c)
169038fd1498Szrj 	{
169138fd1498Szrj 	  _Unwind_Word w;
169238fd1498Szrj 	  _Unwind_Ptr p;
169338fd1498Szrj 	  if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word))
169438fd1498Szrj 	    {
169538fd1498Szrj 	      w = (_Unwind_Internal_Ptr) t;
169638fd1498Szrj 	      memcpy (c, &w, sizeof (_Unwind_Word));
169738fd1498Szrj 	    }
169838fd1498Szrj 	  else
169938fd1498Szrj 	    {
170038fd1498Szrj 	      gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr));
170138fd1498Szrj 	      p = (_Unwind_Internal_Ptr) t;
170238fd1498Szrj 	      memcpy (c, &p, sizeof (_Unwind_Ptr));
170338fd1498Szrj 	    }
170438fd1498Szrj 	}
170538fd1498Szrj       else if (t && c && t != c)
170638fd1498Szrj 	memcpy (c, t, dwarf_reg_size_table[i]);
170738fd1498Szrj     }
170838fd1498Szrj 
170938fd1498Szrj   /* If the current frame doesn't have a saved stack pointer, then we
171038fd1498Szrj      need to rely on EH_RETURN_STACKADJ_RTX to get our target stack
171138fd1498Szrj      pointer value reloaded.  */
171238fd1498Szrj   if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ()))
171338fd1498Szrj     {
171438fd1498Szrj       void *target_cfa;
171538fd1498Szrj 
171638fd1498Szrj       target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ());
171738fd1498Szrj 
171838fd1498Szrj       /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
171938fd1498Szrj       if (__LIBGCC_STACK_GROWS_DOWNWARD__)
172038fd1498Szrj 	return target_cfa - current->cfa + target->args_size;
172138fd1498Szrj       else
172238fd1498Szrj 	return current->cfa - target_cfa - target->args_size;
172338fd1498Szrj     }
172438fd1498Szrj   return 0;
172538fd1498Szrj }
172638fd1498Szrj 
172738fd1498Szrj static inline _Unwind_Ptr
uw_identify_context(struct _Unwind_Context * context)172838fd1498Szrj uw_identify_context (struct _Unwind_Context *context)
172938fd1498Szrj {
173038fd1498Szrj   /* The CFA is not sufficient to disambiguate the context of a function
173138fd1498Szrj      interrupted by a signal before establishing its frame and the context
173238fd1498Szrj      of the signal itself.  */
173338fd1498Szrj   if (__LIBGCC_STACK_GROWS_DOWNWARD__)
173438fd1498Szrj     return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context);
173538fd1498Szrj   else
173638fd1498Szrj     return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context);
173738fd1498Szrj }
173838fd1498Szrj 
173938fd1498Szrj 
174038fd1498Szrj #include "unwind.inc"
174138fd1498Szrj 
174238fd1498Szrj #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
174338fd1498Szrj alias (_Unwind_Backtrace);
174438fd1498Szrj alias (_Unwind_DeleteException);
174538fd1498Szrj alias (_Unwind_FindEnclosingFunction);
174638fd1498Szrj alias (_Unwind_ForcedUnwind);
174738fd1498Szrj alias (_Unwind_GetDataRelBase);
174838fd1498Szrj alias (_Unwind_GetTextRelBase);
174938fd1498Szrj alias (_Unwind_GetCFA);
175038fd1498Szrj alias (_Unwind_GetGR);
175138fd1498Szrj alias (_Unwind_GetIP);
175238fd1498Szrj alias (_Unwind_GetLanguageSpecificData);
175338fd1498Szrj alias (_Unwind_GetRegionStart);
175438fd1498Szrj alias (_Unwind_RaiseException);
175538fd1498Szrj alias (_Unwind_Resume);
175638fd1498Szrj alias (_Unwind_Resume_or_Rethrow);
175738fd1498Szrj alias (_Unwind_SetGR);
175838fd1498Szrj alias (_Unwind_SetIP);
175938fd1498Szrj #endif
176038fd1498Szrj 
176138fd1498Szrj #endif /* !USING_SJLJ_EXCEPTIONS */
1762