190075Sobrien/* DWARF2 exception handling and frame unwind runtime interface routines.
2169689Skan   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
390075Sobrien   Free Software Foundation, Inc.
490075Sobrien
590075Sobrien   This file is part of GCC.
690075Sobrien
790075Sobrien   GCC is free software; you can redistribute it and/or modify it
890075Sobrien   under the terms of the GNU General Public License as published by
990075Sobrien   the Free Software Foundation; either version 2, or (at your option)
1090075Sobrien   any later version.
1190075Sobrien
12132718Skan   In addition to the permissions in the GNU General Public License, the
13132718Skan   Free Software Foundation gives you unlimited permission to link the
14132718Skan   compiled version of this file into combinations with other programs,
15132718Skan   and to distribute those combinations without any restriction coming
16132718Skan   from the use of this file.  (The General Public License restrictions
17132718Skan   do apply in other respects; for example, they cover modification of
18132718Skan   the file, and distribution when not linked into a combined
19132718Skan   executable.)
20132718Skan
2190075Sobrien   GCC is distributed in the hope that it will be useful, but WITHOUT
2290075Sobrien   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2390075Sobrien   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
2490075Sobrien   License for more details.
2590075Sobrien
2690075Sobrien   You should have received a copy of the GNU General Public License
2790075Sobrien   along with GCC; see the file COPYING.  If not, write to the Free
28169689Skan   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29169689Skan   02110-1301, USA.  */
3090075Sobrien
3190075Sobrien#include "tconfig.h"
3290075Sobrien#include "tsystem.h"
33132718Skan#include "coretypes.h"
34132718Skan#include "tm.h"
3590075Sobrien#include "dwarf2.h"
3690075Sobrien#include "unwind.h"
37132718Skan#ifdef __USING_SJLJ_EXCEPTIONS__
38132718Skan# define NO_SIZE_OF_ENCODED_VALUE
39132718Skan#endif
4090075Sobrien#include "unwind-pe.h"
4190075Sobrien#include "unwind-dw2-fde.h"
4290075Sobrien#include "gthr.h"
43169689Skan#include "unwind-dw2.h"
4490075Sobrien
4590075Sobrien#ifndef __USING_SJLJ_EXCEPTIONS__
4690075Sobrien
4790075Sobrien#ifndef STACK_GROWS_DOWNWARD
4890075Sobrien#define STACK_GROWS_DOWNWARD 0
4990075Sobrien#else
5090075Sobrien#undef STACK_GROWS_DOWNWARD
5190075Sobrien#define STACK_GROWS_DOWNWARD 1
5290075Sobrien#endif
5390075Sobrien
5490075Sobrien/* Dwarf frame registers used for pre gcc 3.0 compiled glibc.  */
5590075Sobrien#ifndef PRE_GCC3_DWARF_FRAME_REGISTERS
5690075Sobrien#define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
5790075Sobrien#endif
5890075Sobrien
59132718Skan#ifndef DWARF_REG_TO_UNWIND_COLUMN
60132718Skan#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
61132718Skan#endif
62132718Skan
63117395Skan/* This is the register and unwind state for a particular frame.  This
64117395Skan   provides the information necessary to unwind up past a frame and return
65117395Skan   to its caller.  */
6690075Sobrienstruct _Unwind_Context
6790075Sobrien{
6890075Sobrien  void *reg[DWARF_FRAME_REGISTERS+1];
6990075Sobrien  void *cfa;
7090075Sobrien  void *ra;
7190075Sobrien  void *lsda;
7290075Sobrien  struct dwarf_eh_bases bases;
73169689Skan  /* Signal frame context.  */
74169689Skan#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
75169689Skan  /* Context which has version/args_size/by_value fields.  */
76169689Skan#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
77169689Skan  _Unwind_Word flags;
78169689Skan  /* 0 for now, can be increased when further fields are added to
79169689Skan     struct _Unwind_Context.  */
80169689Skan  _Unwind_Word version;
8190075Sobrien  _Unwind_Word args_size;
82169689Skan  char by_value[DWARF_FRAME_REGISTERS+1];
8390075Sobrien};
8490075Sobrien
8590075Sobrien/* Byte size of every register managed by these routines.  */
86122180Skanstatic unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
8790075Sobrien
8890075Sobrien
8990075Sobrien/* Read unaligned data from the instruction buffer.  */
9090075Sobrien
9190075Sobrienunion unaligned
9290075Sobrien{
9390075Sobrien  void *p;
9490075Sobrien  unsigned u2 __attribute__ ((mode (HI)));
9590075Sobrien  unsigned u4 __attribute__ ((mode (SI)));
9690075Sobrien  unsigned u8 __attribute__ ((mode (DI)));
9790075Sobrien  signed s2 __attribute__ ((mode (HI)));
9890075Sobrien  signed s4 __attribute__ ((mode (SI)));
9990075Sobrien  signed s8 __attribute__ ((mode (DI)));
10090075Sobrien} __attribute__ ((packed));
10190075Sobrien
102169689Skanstatic void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
103169689Skanstatic _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
104169689Skan					       _Unwind_FrameState *);
105169689Skan
10690075Sobrienstatic inline void *
10790075Sobrienread_pointer (const void *p) { const union unaligned *up = p; return up->p; }
10890075Sobrien
10990075Sobrienstatic inline int
11090075Sobrienread_1u (const void *p) { return *(const unsigned char *) p; }
11190075Sobrien
11290075Sobrienstatic inline int
11390075Sobrienread_1s (const void *p) { return *(const signed char *) p; }
11490075Sobrien
11590075Sobrienstatic inline int
11690075Sobrienread_2u (const void *p) { const union unaligned *up = p; return up->u2; }
11790075Sobrien
11890075Sobrienstatic inline int
11990075Sobrienread_2s (const void *p) { const union unaligned *up = p; return up->s2; }
12090075Sobrien
12190075Sobrienstatic inline unsigned int
12290075Sobrienread_4u (const void *p) { const union unaligned *up = p; return up->u4; }
12390075Sobrien
12490075Sobrienstatic inline int
12590075Sobrienread_4s (const void *p) { const union unaligned *up = p; return up->s4; }
12690075Sobrien
12790075Sobrienstatic inline unsigned long
12890075Sobrienread_8u (const void *p) { const union unaligned *up = p; return up->u8; }
12990075Sobrien
13090075Sobrienstatic inline unsigned long
13190075Sobrienread_8s (const void *p) { const union unaligned *up = p; return up->s8; }
13290075Sobrien
133169689Skanstatic inline _Unwind_Word
134169689Skan_Unwind_IsSignalFrame (struct _Unwind_Context *context)
135169689Skan{
136169689Skan  return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
137169689Skan}
13890075Sobrien
139169689Skanstatic inline void
140169689Skan_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
141169689Skan{
142169689Skan  if (val)
143169689Skan    context->flags |= SIGNAL_FRAME_BIT;
144169689Skan  else
145169689Skan    context->flags &= ~SIGNAL_FRAME_BIT;
146169689Skan}
147169689Skan
148169689Skanstatic inline _Unwind_Word
149169689Skan_Unwind_IsExtendedContext (struct _Unwind_Context *context)
150169689Skan{
151169689Skan  return context->flags & EXTENDED_CONTEXT_BIT;
152169689Skan}
153169689Skan
154169689Skan/* Get the value of register INDEX as saved in CONTEXT.  */
155169689Skan
15690075Sobrieninline _Unwind_Word
15790075Sobrien_Unwind_GetGR (struct _Unwind_Context *context, int index)
15890075Sobrien{
159132718Skan  int size;
160132718Skan  void *ptr;
161132718Skan
162146895Skan#ifdef DWARF_ZERO_REG
163146895Skan  if (index == DWARF_ZERO_REG)
164146895Skan    return 0;
165146895Skan#endif
166146895Skan
167132718Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
168169689Skan  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
169132718Skan  size = dwarf_reg_size_table[index];
170132718Skan  ptr = context->reg[index];
171132718Skan
172169689Skan  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
173169689Skan    return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr;
174169689Skan
17590075Sobrien  /* This will segfault if the register hasn't been saved.  */
176132718Skan  if (size == sizeof(_Unwind_Ptr))
177132718Skan    return * (_Unwind_Ptr *) ptr;
178169689Skan  else
179169689Skan    {
180169689Skan      gcc_assert (size == sizeof(_Unwind_Word));
181169689Skan      return * (_Unwind_Word *) ptr;
182169689Skan    }
18390075Sobrien}
18490075Sobrien
185132718Skanstatic inline void *
186132718Skan_Unwind_GetPtr (struct _Unwind_Context *context, int index)
187132718Skan{
188132718Skan  return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index);
189132718Skan}
190132718Skan
191117395Skan/* Get the value of the CFA as saved in CONTEXT.  */
192117395Skan
193117395Skan_Unwind_Word
194117395Skan_Unwind_GetCFA (struct _Unwind_Context *context)
195117395Skan{
196132718Skan  return (_Unwind_Ptr) context->cfa;
197117395Skan}
198117395Skan
199169689Skan/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
20090075Sobrien
20190075Sobrieninline void
20290075Sobrien_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
20390075Sobrien{
204132718Skan  int size;
205132718Skan  void *ptr;
206132718Skan
207132718Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
208169689Skan  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
209132718Skan  size = dwarf_reg_size_table[index];
210169689Skan
211169689Skan  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
212169689Skan    {
213169689Skan      context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
214169689Skan      return;
215169689Skan    }
216169689Skan
217132718Skan  ptr = context->reg[index];
218132718Skan
219132718Skan  if (size == sizeof(_Unwind_Ptr))
220132718Skan    * (_Unwind_Ptr *) ptr = val;
221132718Skan  else
222169689Skan    {
223169689Skan      gcc_assert (size == sizeof(_Unwind_Word));
224169689Skan      * (_Unwind_Word *) ptr = val;
225169689Skan    }
22690075Sobrien}
22790075Sobrien
228132718Skan/* Get the pointer to a register INDEX as saved in CONTEXT.  */
229132718Skan
230132718Skanstatic inline void *
231132718Skan_Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
232132718Skan{
233132718Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
234169689Skan  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
235169689Skan    return &context->reg[index];
236132718Skan  return context->reg[index];
237132718Skan}
238132718Skan
239132718Skan/* Set the pointer to a register INDEX as saved in CONTEXT.  */
240132718Skan
241132718Skanstatic inline void
242132718Skan_Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
243132718Skan{
244132718Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
245169689Skan  if (_Unwind_IsExtendedContext (context))
246169689Skan    context->by_value[index] = 0;
247132718Skan  context->reg[index] = p;
248132718Skan}
249132718Skan
250169689Skan/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
251169689Skan
252169689Skanstatic inline void
253169689Skan_Unwind_SetGRValue (struct _Unwind_Context *context, int index,
254169689Skan		    _Unwind_Word val)
255169689Skan{
256169689Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
257169689Skan  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
258169689Skan  gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr));
259169689Skan
260169689Skan  context->by_value[index] = 1;
261169689Skan  context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
262169689Skan}
263169689Skan
264169689Skan/* Return nonzero if register INDEX is stored by value rather than
265169689Skan   by reference.  */
266169689Skan
267169689Skanstatic inline int
268169689Skan_Unwind_GRByValue (struct _Unwind_Context *context, int index)
269169689Skan{
270169689Skan  index = DWARF_REG_TO_UNWIND_COLUMN (index);
271169689Skan  return context->by_value[index];
272169689Skan}
273169689Skan
27490075Sobrien/* Retrieve the return address for CONTEXT.  */
27590075Sobrien
27690075Sobrieninline _Unwind_Ptr
27790075Sobrien_Unwind_GetIP (struct _Unwind_Context *context)
27890075Sobrien{
27990075Sobrien  return (_Unwind_Ptr) context->ra;
28090075Sobrien}
28190075Sobrien
282169689Skan/* Retrieve the return address and flag whether that IP is before
283169689Skan   or after first not yet fully executed instruction.  */
284169689Skan
285169689Skaninline _Unwind_Ptr
286169689Skan_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
287169689Skan{
288169689Skan  *ip_before_insn = _Unwind_IsSignalFrame (context);
289169689Skan  return (_Unwind_Ptr) context->ra;
290169689Skan}
291169689Skan
29290075Sobrien/* Overwrite the return address for CONTEXT with VAL.  */
29390075Sobrien
29490075Sobrieninline void
29590075Sobrien_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
29690075Sobrien{
29790075Sobrien  context->ra = (void *) val;
29890075Sobrien}
29990075Sobrien
30090075Sobrienvoid *
30190075Sobrien_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
30290075Sobrien{
30390075Sobrien  return context->lsda;
30490075Sobrien}
30590075Sobrien
30690075Sobrien_Unwind_Ptr
30790075Sobrien_Unwind_GetRegionStart (struct _Unwind_Context *context)
30890075Sobrien{
30990075Sobrien  return (_Unwind_Ptr) context->bases.func;
31090075Sobrien}
31190075Sobrien
312117395Skanvoid *
313117395Skan_Unwind_FindEnclosingFunction (void *pc)
314117395Skan{
315117395Skan  struct dwarf_eh_bases bases;
316132718Skan  const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
317117395Skan  if (fde)
318117395Skan    return bases.func;
319117395Skan  else
320117395Skan    return NULL;
321117395Skan}
322117395Skan
32390075Sobrien#ifndef __ia64__
32490075Sobrien_Unwind_Ptr
32590075Sobrien_Unwind_GetDataRelBase (struct _Unwind_Context *context)
32690075Sobrien{
32790075Sobrien  return (_Unwind_Ptr) context->bases.dbase;
32890075Sobrien}
32990075Sobrien
33090075Sobrien_Unwind_Ptr
33190075Sobrien_Unwind_GetTextRelBase (struct _Unwind_Context *context)
33290075Sobrien{
33390075Sobrien  return (_Unwind_Ptr) context->bases.tbase;
33490075Sobrien}
33590075Sobrien#endif
336169689Skan
337169689Skan#ifdef MD_UNWIND_SUPPORT
338169689Skan#include MD_UNWIND_SUPPORT
339169689Skan#endif
34090075Sobrien
34190075Sobrien/* Extract any interesting information from the CIE for the translation
34290075Sobrien   unit F belongs to.  Return a pointer to the byte after the augmentation,
34390075Sobrien   or NULL if we encountered an undecipherable augmentation.  */
34490075Sobrien
34590075Sobrienstatic const unsigned char *
346132718Skanextract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
34790075Sobrien		  _Unwind_FrameState *fs)
34890075Sobrien{
34990075Sobrien  const unsigned char *aug = cie->augmentation;
350169689Skan  const unsigned char *p = aug + strlen ((const char *)aug) + 1;
35190075Sobrien  const unsigned char *ret = NULL;
35290075Sobrien  _Unwind_Word utmp;
35390075Sobrien
35490075Sobrien  /* g++ v2 "eh" has pointer immediately following augmentation string,
35590075Sobrien     so it must be handled first.  */
35690075Sobrien  if (aug[0] == 'e' && aug[1] == 'h')
35790075Sobrien    {
35890075Sobrien      fs->eh_ptr = read_pointer (p);
35990075Sobrien      p += sizeof (void *);
36090075Sobrien      aug += 2;
36190075Sobrien    }
36290075Sobrien
36390075Sobrien  /* Immediately following the augmentation are the code and
36490075Sobrien     data alignment and return address column.  */
36590075Sobrien  p = read_uleb128 (p, &fs->code_align);
36690075Sobrien  p = read_sleb128 (p, &fs->data_align);
367169689Skan  if (cie->version == 1)
368169689Skan    fs->retaddr_column = *p++;
369169689Skan  else
370169689Skan    p = read_uleb128 (p, &fs->retaddr_column);
37190075Sobrien  fs->lsda_encoding = DW_EH_PE_omit;
37290075Sobrien
37390075Sobrien  /* If the augmentation starts with 'z', then a uleb128 immediately
37490075Sobrien     follows containing the length of the augmentation field following
37590075Sobrien     the size.  */
37690075Sobrien  if (*aug == 'z')
37790075Sobrien    {
37890075Sobrien      p = read_uleb128 (p, &utmp);
37990075Sobrien      ret = p + utmp;
38090075Sobrien
38190075Sobrien      fs->saw_z = 1;
38290075Sobrien      ++aug;
38390075Sobrien    }
38490075Sobrien
38590075Sobrien  /* Iterate over recognized augmentation subsequences.  */
38690075Sobrien  while (*aug != '\0')
38790075Sobrien    {
38890075Sobrien      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
38990075Sobrien      if (aug[0] == 'L')
39090075Sobrien	{
39190075Sobrien	  fs->lsda_encoding = *p++;
39290075Sobrien	  aug += 1;
39390075Sobrien	}
39490075Sobrien
39590075Sobrien      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
39690075Sobrien      else if (aug[0] == 'R')
39790075Sobrien	{
39890075Sobrien	  fs->fde_encoding = *p++;
39990075Sobrien	  aug += 1;
40090075Sobrien	}
40190075Sobrien
40290075Sobrien      /* "P" indicates a personality routine in the CIE augmentation.  */
40390075Sobrien      else if (aug[0] == 'P')
40490075Sobrien	{
405169689Skan	  _Unwind_Ptr personality;
406169689Skan
407169689Skan	  p = read_encoded_value (context, *p, p + 1, &personality);
408169689Skan	  fs->personality = (_Unwind_Personality_Fn) personality;
40990075Sobrien	  aug += 1;
41090075Sobrien	}
41190075Sobrien
412169689Skan      /* "S" indicates a signal frame.  */
413169689Skan      else if (aug[0] == 'S')
414169689Skan	{
415169689Skan	  fs->signal_frame = 1;
416169689Skan	  aug += 1;
417169689Skan	}
418169689Skan
41990075Sobrien      /* Otherwise we have an unknown augmentation string.
42090075Sobrien	 Bail unless we saw a 'z' prefix.  */
42190075Sobrien      else
42290075Sobrien	return ret;
42390075Sobrien    }
42490075Sobrien
42590075Sobrien  return ret ? ret : p;
42690075Sobrien}
42790075Sobrien
42890075Sobrien
42990075Sobrien/* Decode a DW_OP stack program.  Return the top of stack.  Push INITIAL
43090075Sobrien   onto the stack to start.  */
43190075Sobrien
43290075Sobrienstatic _Unwind_Word
43390075Sobrienexecute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
43490075Sobrien		  struct _Unwind_Context *context, _Unwind_Word initial)
43590075Sobrien{
43690075Sobrien  _Unwind_Word stack[64];	/* ??? Assume this is enough.  */
43790075Sobrien  int stack_elt;
43890075Sobrien
43990075Sobrien  stack[0] = initial;
44090075Sobrien  stack_elt = 1;
44190075Sobrien
44290075Sobrien  while (op_ptr < op_end)
44390075Sobrien    {
44490075Sobrien      enum dwarf_location_atom op = *op_ptr++;
44590075Sobrien      _Unwind_Word result, reg, utmp;
44690075Sobrien      _Unwind_Sword offset, stmp;
44790075Sobrien
44890075Sobrien      switch (op)
44990075Sobrien	{
45090075Sobrien	case DW_OP_lit0:
45190075Sobrien	case DW_OP_lit1:
45290075Sobrien	case DW_OP_lit2:
45390075Sobrien	case DW_OP_lit3:
45490075Sobrien	case DW_OP_lit4:
45590075Sobrien	case DW_OP_lit5:
45690075Sobrien	case DW_OP_lit6:
45790075Sobrien	case DW_OP_lit7:
45890075Sobrien	case DW_OP_lit8:
45990075Sobrien	case DW_OP_lit9:
46090075Sobrien	case DW_OP_lit10:
46190075Sobrien	case DW_OP_lit11:
46290075Sobrien	case DW_OP_lit12:
46390075Sobrien	case DW_OP_lit13:
46490075Sobrien	case DW_OP_lit14:
46590075Sobrien	case DW_OP_lit15:
46690075Sobrien	case DW_OP_lit16:
46790075Sobrien	case DW_OP_lit17:
46890075Sobrien	case DW_OP_lit18:
46990075Sobrien	case DW_OP_lit19:
47090075Sobrien	case DW_OP_lit20:
47190075Sobrien	case DW_OP_lit21:
47290075Sobrien	case DW_OP_lit22:
47390075Sobrien	case DW_OP_lit23:
47490075Sobrien	case DW_OP_lit24:
47590075Sobrien	case DW_OP_lit25:
47690075Sobrien	case DW_OP_lit26:
47790075Sobrien	case DW_OP_lit27:
47890075Sobrien	case DW_OP_lit28:
47990075Sobrien	case DW_OP_lit29:
48090075Sobrien	case DW_OP_lit30:
48190075Sobrien	case DW_OP_lit31:
48290075Sobrien	  result = op - DW_OP_lit0;
48390075Sobrien	  break;
48490075Sobrien
48590075Sobrien	case DW_OP_addr:
48690075Sobrien	  result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr);
48790075Sobrien	  op_ptr += sizeof (void *);
48890075Sobrien	  break;
48990075Sobrien
49090075Sobrien	case DW_OP_const1u:
49190075Sobrien	  result = read_1u (op_ptr);
49290075Sobrien	  op_ptr += 1;
49390075Sobrien	  break;
49490075Sobrien	case DW_OP_const1s:
49590075Sobrien	  result = read_1s (op_ptr);
49690075Sobrien	  op_ptr += 1;
49790075Sobrien	  break;
49890075Sobrien	case DW_OP_const2u:
49990075Sobrien	  result = read_2u (op_ptr);
50090075Sobrien	  op_ptr += 2;
50190075Sobrien	  break;
50290075Sobrien	case DW_OP_const2s:
50390075Sobrien	  result = read_2s (op_ptr);
50490075Sobrien	  op_ptr += 2;
50590075Sobrien	  break;
50690075Sobrien	case DW_OP_const4u:
50790075Sobrien	  result = read_4u (op_ptr);
50890075Sobrien	  op_ptr += 4;
50990075Sobrien	  break;
51090075Sobrien	case DW_OP_const4s:
51190075Sobrien	  result = read_4s (op_ptr);
51290075Sobrien	  op_ptr += 4;
51390075Sobrien	  break;
51490075Sobrien	case DW_OP_const8u:
51590075Sobrien	  result = read_8u (op_ptr);
51690075Sobrien	  op_ptr += 8;
51790075Sobrien	  break;
51890075Sobrien	case DW_OP_const8s:
51990075Sobrien	  result = read_8s (op_ptr);
52090075Sobrien	  op_ptr += 8;
52190075Sobrien	  break;
52290075Sobrien	case DW_OP_constu:
52390075Sobrien	  op_ptr = read_uleb128 (op_ptr, &result);
52490075Sobrien	  break;
52590075Sobrien	case DW_OP_consts:
52690075Sobrien	  op_ptr = read_sleb128 (op_ptr, &stmp);
52790075Sobrien	  result = stmp;
52890075Sobrien	  break;
52990075Sobrien
53090075Sobrien	case DW_OP_reg0:
53190075Sobrien	case DW_OP_reg1:
53290075Sobrien	case DW_OP_reg2:
53390075Sobrien	case DW_OP_reg3:
53490075Sobrien	case DW_OP_reg4:
53590075Sobrien	case DW_OP_reg5:
53690075Sobrien	case DW_OP_reg6:
53790075Sobrien	case DW_OP_reg7:
53890075Sobrien	case DW_OP_reg8:
53990075Sobrien	case DW_OP_reg9:
54090075Sobrien	case DW_OP_reg10:
54190075Sobrien	case DW_OP_reg11:
54290075Sobrien	case DW_OP_reg12:
54390075Sobrien	case DW_OP_reg13:
54490075Sobrien	case DW_OP_reg14:
54590075Sobrien	case DW_OP_reg15:
54690075Sobrien	case DW_OP_reg16:
54790075Sobrien	case DW_OP_reg17:
54890075Sobrien	case DW_OP_reg18:
54990075Sobrien	case DW_OP_reg19:
55090075Sobrien	case DW_OP_reg20:
55190075Sobrien	case DW_OP_reg21:
55290075Sobrien	case DW_OP_reg22:
55390075Sobrien	case DW_OP_reg23:
55490075Sobrien	case DW_OP_reg24:
55590075Sobrien	case DW_OP_reg25:
55690075Sobrien	case DW_OP_reg26:
55790075Sobrien	case DW_OP_reg27:
55890075Sobrien	case DW_OP_reg28:
55990075Sobrien	case DW_OP_reg29:
56090075Sobrien	case DW_OP_reg30:
56190075Sobrien	case DW_OP_reg31:
56290075Sobrien	  result = _Unwind_GetGR (context, op - DW_OP_reg0);
56390075Sobrien	  break;
56490075Sobrien	case DW_OP_regx:
56590075Sobrien	  op_ptr = read_uleb128 (op_ptr, &reg);
56690075Sobrien	  result = _Unwind_GetGR (context, reg);
56790075Sobrien	  break;
56890075Sobrien
56990075Sobrien	case DW_OP_breg0:
57090075Sobrien	case DW_OP_breg1:
57190075Sobrien	case DW_OP_breg2:
57290075Sobrien	case DW_OP_breg3:
57390075Sobrien	case DW_OP_breg4:
57490075Sobrien	case DW_OP_breg5:
57590075Sobrien	case DW_OP_breg6:
57690075Sobrien	case DW_OP_breg7:
57790075Sobrien	case DW_OP_breg8:
57890075Sobrien	case DW_OP_breg9:
57990075Sobrien	case DW_OP_breg10:
58090075Sobrien	case DW_OP_breg11:
58190075Sobrien	case DW_OP_breg12:
58290075Sobrien	case DW_OP_breg13:
58390075Sobrien	case DW_OP_breg14:
58490075Sobrien	case DW_OP_breg15:
58590075Sobrien	case DW_OP_breg16:
58690075Sobrien	case DW_OP_breg17:
58790075Sobrien	case DW_OP_breg18:
58890075Sobrien	case DW_OP_breg19:
58990075Sobrien	case DW_OP_breg20:
59090075Sobrien	case DW_OP_breg21:
59190075Sobrien	case DW_OP_breg22:
59290075Sobrien	case DW_OP_breg23:
59390075Sobrien	case DW_OP_breg24:
59490075Sobrien	case DW_OP_breg25:
59590075Sobrien	case DW_OP_breg26:
59690075Sobrien	case DW_OP_breg27:
59790075Sobrien	case DW_OP_breg28:
59890075Sobrien	case DW_OP_breg29:
59990075Sobrien	case DW_OP_breg30:
60090075Sobrien	case DW_OP_breg31:
60190075Sobrien	  op_ptr = read_sleb128 (op_ptr, &offset);
60290075Sobrien	  result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset;
60390075Sobrien	  break;
60490075Sobrien	case DW_OP_bregx:
60590075Sobrien	  op_ptr = read_uleb128 (op_ptr, &reg);
60690075Sobrien	  op_ptr = read_sleb128 (op_ptr, &offset);
60790075Sobrien	  result = _Unwind_GetGR (context, reg) + offset;
60890075Sobrien	  break;
60990075Sobrien
61090075Sobrien	case DW_OP_dup:
611169689Skan	  gcc_assert (stack_elt);
61290075Sobrien	  result = stack[stack_elt - 1];
61390075Sobrien	  break;
61490075Sobrien
61590075Sobrien	case DW_OP_drop:
616169689Skan	  gcc_assert (stack_elt);
617169689Skan	  stack_elt -= 1;
61890075Sobrien	  goto no_push;
61990075Sobrien
62090075Sobrien	case DW_OP_pick:
62190075Sobrien	  offset = *op_ptr++;
622169689Skan	  gcc_assert (offset < stack_elt - 1);
62390075Sobrien	  result = stack[stack_elt - 1 - offset];
62490075Sobrien	  break;
62590075Sobrien
62690075Sobrien	case DW_OP_over:
627169689Skan	  gcc_assert (stack_elt >= 2);
62890075Sobrien	  result = stack[stack_elt - 2];
62990075Sobrien	  break;
63090075Sobrien
631169689Skan	case DW_OP_swap:
632169689Skan	  {
633169689Skan	    _Unwind_Word t;
634169689Skan	    gcc_assert (stack_elt >= 2);
635169689Skan	    t = stack[stack_elt - 1];
636169689Skan	    stack[stack_elt - 1] = stack[stack_elt - 2];
637169689Skan	    stack[stack_elt - 2] = t;
638169689Skan	    goto no_push;
639169689Skan	  }
640169689Skan
64190075Sobrien	case DW_OP_rot:
64290075Sobrien	  {
64390075Sobrien	    _Unwind_Word t1, t2, t3;
64490075Sobrien
645169689Skan	    gcc_assert (stack_elt >= 3);
64690075Sobrien	    t1 = stack[stack_elt - 1];
64790075Sobrien	    t2 = stack[stack_elt - 2];
64890075Sobrien	    t3 = stack[stack_elt - 3];
64990075Sobrien	    stack[stack_elt - 1] = t2;
65090075Sobrien	    stack[stack_elt - 2] = t3;
65190075Sobrien	    stack[stack_elt - 3] = t1;
65290075Sobrien	    goto no_push;
65390075Sobrien	  }
65490075Sobrien
65590075Sobrien	case DW_OP_deref:
65690075Sobrien	case DW_OP_deref_size:
65790075Sobrien	case DW_OP_abs:
65890075Sobrien	case DW_OP_neg:
65990075Sobrien	case DW_OP_not:
66090075Sobrien	case DW_OP_plus_uconst:
66190075Sobrien	  /* Unary operations.  */
662169689Skan	  gcc_assert (stack_elt);
663169689Skan	  stack_elt -= 1;
664169689Skan
66590075Sobrien	  result = stack[stack_elt];
66690075Sobrien
66790075Sobrien	  switch (op)
66890075Sobrien	    {
66990075Sobrien	    case DW_OP_deref:
67090075Sobrien	      {
67190075Sobrien		void *ptr = (void *) (_Unwind_Ptr) result;
67290075Sobrien		result = (_Unwind_Ptr) read_pointer (ptr);
67390075Sobrien	      }
67490075Sobrien	      break;
67590075Sobrien
67690075Sobrien	    case DW_OP_deref_size:
67790075Sobrien	      {
67890075Sobrien		void *ptr = (void *) (_Unwind_Ptr) result;
67990075Sobrien		switch (*op_ptr++)
68090075Sobrien		  {
68190075Sobrien		  case 1:
68290075Sobrien		    result = read_1u (ptr);
68390075Sobrien		    break;
68490075Sobrien		  case 2:
68590075Sobrien		    result = read_2u (ptr);
68690075Sobrien		    break;
68790075Sobrien		  case 4:
68890075Sobrien		    result = read_4u (ptr);
68990075Sobrien		    break;
69090075Sobrien		  case 8:
69190075Sobrien		    result = read_8u (ptr);
69290075Sobrien		    break;
69390075Sobrien		  default:
694169689Skan		    gcc_unreachable ();
69590075Sobrien		  }
69690075Sobrien	      }
69790075Sobrien	      break;
69890075Sobrien
69990075Sobrien	    case DW_OP_abs:
70090075Sobrien	      if ((_Unwind_Sword) result < 0)
70190075Sobrien		result = -result;
70290075Sobrien	      break;
70390075Sobrien	    case DW_OP_neg:
70490075Sobrien	      result = -result;
70590075Sobrien	      break;
70690075Sobrien	    case DW_OP_not:
70790075Sobrien	      result = ~result;
70890075Sobrien	      break;
70990075Sobrien	    case DW_OP_plus_uconst:
71090075Sobrien	      op_ptr = read_uleb128 (op_ptr, &utmp);
71190075Sobrien	      result += utmp;
71290075Sobrien	      break;
71390075Sobrien
71490075Sobrien	    default:
715169689Skan	      gcc_unreachable ();
71690075Sobrien	    }
71790075Sobrien	  break;
71890075Sobrien
71990075Sobrien	case DW_OP_and:
72090075Sobrien	case DW_OP_div:
72190075Sobrien	case DW_OP_minus:
72290075Sobrien	case DW_OP_mod:
72390075Sobrien	case DW_OP_mul:
72490075Sobrien	case DW_OP_or:
72590075Sobrien	case DW_OP_plus:
726146895Skan	case DW_OP_shl:
727146895Skan	case DW_OP_shr:
728146895Skan	case DW_OP_shra:
729146895Skan	case DW_OP_xor:
73090075Sobrien	case DW_OP_le:
73190075Sobrien	case DW_OP_ge:
73290075Sobrien	case DW_OP_eq:
73390075Sobrien	case DW_OP_lt:
73490075Sobrien	case DW_OP_gt:
73590075Sobrien	case DW_OP_ne:
73690075Sobrien	  {
73790075Sobrien	    /* Binary operations.  */
73890075Sobrien	    _Unwind_Word first, second;
739169689Skan	    gcc_assert (stack_elt >= 2);
740169689Skan	    stack_elt -= 2;
741169689Skan
742117395Skan	    second = stack[stack_elt];
743117395Skan	    first = stack[stack_elt + 1];
74490075Sobrien
745117395Skan	    switch (op)
746117395Skan	      {
747117395Skan	      case DW_OP_and:
748117395Skan		result = second & first;
749117395Skan		break;
750117395Skan	      case DW_OP_div:
751117395Skan		result = (_Unwind_Sword) second / (_Unwind_Sword) first;
752117395Skan		break;
753117395Skan	      case DW_OP_minus:
754117395Skan		result = second - first;
755117395Skan		break;
756117395Skan	      case DW_OP_mod:
757117395Skan		result = (_Unwind_Sword) second % (_Unwind_Sword) first;
758117395Skan		break;
759117395Skan	      case DW_OP_mul:
760117395Skan		result = second * first;
761117395Skan		break;
762117395Skan	      case DW_OP_or:
763117395Skan		result = second | first;
764117395Skan		break;
765117395Skan	      case DW_OP_plus:
766117395Skan		result = second + first;
767117395Skan		break;
768117395Skan	      case DW_OP_shl:
769117395Skan		result = second << first;
770117395Skan		break;
771117395Skan	      case DW_OP_shr:
772117395Skan		result = second >> first;
773117395Skan		break;
774117395Skan	      case DW_OP_shra:
775117395Skan		result = (_Unwind_Sword) second >> first;
776117395Skan		break;
777117395Skan	      case DW_OP_xor:
778117395Skan		result = second ^ first;
779117395Skan		break;
780117395Skan	      case DW_OP_le:
781117395Skan		result = (_Unwind_Sword) first <= (_Unwind_Sword) second;
782117395Skan		break;
783117395Skan	      case DW_OP_ge:
784117395Skan		result = (_Unwind_Sword) first >= (_Unwind_Sword) second;
785117395Skan		break;
786117395Skan	      case DW_OP_eq:
787117395Skan		result = (_Unwind_Sword) first == (_Unwind_Sword) second;
788117395Skan		break;
789117395Skan	      case DW_OP_lt:
790117395Skan		result = (_Unwind_Sword) first < (_Unwind_Sword) second;
791117395Skan		break;
792117395Skan	      case DW_OP_gt:
793117395Skan		result = (_Unwind_Sword) first > (_Unwind_Sword) second;
794117395Skan		break;
795117395Skan	      case DW_OP_ne:
796117395Skan		result = (_Unwind_Sword) first != (_Unwind_Sword) second;
797117395Skan		break;
79890075Sobrien
799117395Skan	      default:
800169689Skan		gcc_unreachable ();
801117395Skan	      }
80290075Sobrien	  }
80390075Sobrien	  break;
80490075Sobrien
80590075Sobrien	case DW_OP_skip:
80690075Sobrien	  offset = read_2s (op_ptr);
80790075Sobrien	  op_ptr += 2;
80890075Sobrien	  op_ptr += offset;
80990075Sobrien	  goto no_push;
81090075Sobrien
81190075Sobrien	case DW_OP_bra:
812169689Skan	  gcc_assert (stack_elt);
813169689Skan	  stack_elt -= 1;
814169689Skan
81590075Sobrien	  offset = read_2s (op_ptr);
81690075Sobrien	  op_ptr += 2;
81790075Sobrien	  if (stack[stack_elt] != 0)
81890075Sobrien	    op_ptr += offset;
81990075Sobrien	  goto no_push;
82090075Sobrien
82190075Sobrien	case DW_OP_nop:
82290075Sobrien	  goto no_push;
82390075Sobrien
82490075Sobrien	default:
825169689Skan	  gcc_unreachable ();
82690075Sobrien	}
82790075Sobrien
82890075Sobrien      /* Most things push a result value.  */
829169689Skan      gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack));
830117395Skan      stack[stack_elt++] = result;
83190075Sobrien    no_push:;
83290075Sobrien    }
83390075Sobrien
83490075Sobrien  /* We were executing this program to get a value.  It should be
83590075Sobrien     at top of stack.  */
836169689Skan  gcc_assert (stack_elt);
837169689Skan  stack_elt -= 1;
83890075Sobrien  return stack[stack_elt];
83990075Sobrien}
84090075Sobrien
84190075Sobrien
84290075Sobrien/* Decode DWARF 2 call frame information. Takes pointers the
84390075Sobrien   instruction sequence to decode, current register information and
84490075Sobrien   CIE info, and the PC range to evaluate.  */
84590075Sobrien
84690075Sobrienstatic void
84790075Sobrienexecute_cfa_program (const unsigned char *insn_ptr,
84890075Sobrien		     const unsigned char *insn_end,
84990075Sobrien		     struct _Unwind_Context *context,
85090075Sobrien		     _Unwind_FrameState *fs)
85190075Sobrien{
85290075Sobrien  struct frame_state_reg_info *unused_rs = NULL;
85390075Sobrien
85490075Sobrien  /* Don't allow remember/restore between CIE and FDE programs.  */
85590075Sobrien  fs->regs.prev = NULL;
85690075Sobrien
85790075Sobrien  /* The comparison with the return address uses < rather than <= because
85890075Sobrien     we are only interested in the effects of code before the call; for a
85990075Sobrien     noreturn function, the return address may point to unrelated code with
86090075Sobrien     a different stack configuration that we are not interested in.  We
86190075Sobrien     assume that the call itself is unwind info-neutral; if not, or if
86290075Sobrien     there are delay instructions that adjust the stack, these must be
863169689Skan     reflected at the point immediately before the call insn.
864169689Skan     In signal frames, return address is after last completed instruction,
865169689Skan     so we add 1 to return address to make the comparison <=.  */
866169689Skan  while (insn_ptr < insn_end
867169689Skan	 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
86890075Sobrien    {
86990075Sobrien      unsigned char insn = *insn_ptr++;
87090075Sobrien      _Unwind_Word reg, utmp;
87190075Sobrien      _Unwind_Sword offset, stmp;
87290075Sobrien
87390075Sobrien      if ((insn & 0xc0) == DW_CFA_advance_loc)
87490075Sobrien	fs->pc += (insn & 0x3f) * fs->code_align;
87590075Sobrien      else if ((insn & 0xc0) == DW_CFA_offset)
87690075Sobrien	{
87790075Sobrien	  reg = insn & 0x3f;
87890075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
87990075Sobrien	  offset = (_Unwind_Sword) utmp * fs->data_align;
880132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
881132718Skan	    = REG_SAVED_OFFSET;
882132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
88390075Sobrien	}
88490075Sobrien      else if ((insn & 0xc0) == DW_CFA_restore)
88590075Sobrien	{
88690075Sobrien	  reg = insn & 0x3f;
887132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED;
88890075Sobrien	}
88990075Sobrien      else switch (insn)
89090075Sobrien	{
89190075Sobrien	case DW_CFA_set_loc:
892169689Skan	  {
893169689Skan	    _Unwind_Ptr pc;
894169689Skan
895169689Skan	    insn_ptr = read_encoded_value (context, fs->fde_encoding,
896169689Skan					   insn_ptr, &pc);
897169689Skan	    fs->pc = (void *) pc;
898169689Skan	  }
89990075Sobrien	  break;
90090075Sobrien
90190075Sobrien	case DW_CFA_advance_loc1:
90290075Sobrien	  fs->pc += read_1u (insn_ptr) * fs->code_align;
90390075Sobrien	  insn_ptr += 1;
90490075Sobrien	  break;
90590075Sobrien	case DW_CFA_advance_loc2:
90690075Sobrien	  fs->pc += read_2u (insn_ptr) * fs->code_align;
90790075Sobrien	  insn_ptr += 2;
90890075Sobrien	  break;
90990075Sobrien	case DW_CFA_advance_loc4:
91090075Sobrien	  fs->pc += read_4u (insn_ptr) * fs->code_align;
91190075Sobrien	  insn_ptr += 4;
91290075Sobrien	  break;
91390075Sobrien
91490075Sobrien	case DW_CFA_offset_extended:
91590075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &reg);
91690075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
91790075Sobrien	  offset = (_Unwind_Sword) utmp * fs->data_align;
918132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
919132718Skan	    = REG_SAVED_OFFSET;
920132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
92190075Sobrien	  break;
92290075Sobrien
92390075Sobrien	case DW_CFA_restore_extended:
92490075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &reg);
925169689Skan	  /* FIXME, this is wrong; the CIE might have said that the
926169689Skan	     register was saved somewhere.  */
927132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
92890075Sobrien	  break;
92990075Sobrien
93090075Sobrien	case DW_CFA_undefined:
93190075Sobrien	case DW_CFA_same_value:
932110611Skan	  insn_ptr = read_uleb128 (insn_ptr, &reg);
933169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
934110611Skan	  break;
935110611Skan
93690075Sobrien	case DW_CFA_nop:
93790075Sobrien	  break;
93890075Sobrien
93990075Sobrien	case DW_CFA_register:
94090075Sobrien	  {
94190075Sobrien	    _Unwind_Word reg2;
94290075Sobrien	    insn_ptr = read_uleb128 (insn_ptr, &reg);
94390075Sobrien	    insn_ptr = read_uleb128 (insn_ptr, &reg2);
944132718Skan	    fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG;
945132718Skan	    fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg = reg2;
94690075Sobrien	  }
94790075Sobrien	  break;
948117395Skan
94990075Sobrien	case DW_CFA_remember_state:
95090075Sobrien	  {
95190075Sobrien	    struct frame_state_reg_info *new_rs;
95290075Sobrien	    if (unused_rs)
95390075Sobrien	      {
95490075Sobrien		new_rs = unused_rs;
95590075Sobrien		unused_rs = unused_rs->prev;
95690075Sobrien	      }
95790075Sobrien	    else
958169689Skan	      new_rs = alloca (sizeof (struct frame_state_reg_info));
95990075Sobrien
96090075Sobrien	    *new_rs = fs->regs;
96190075Sobrien	    fs->regs.prev = new_rs;
96290075Sobrien	  }
96390075Sobrien	  break;
96490075Sobrien
96590075Sobrien	case DW_CFA_restore_state:
96690075Sobrien	  {
96790075Sobrien	    struct frame_state_reg_info *old_rs = fs->regs.prev;
96890075Sobrien	    fs->regs = *old_rs;
96990075Sobrien	    old_rs->prev = unused_rs;
97090075Sobrien	    unused_rs = old_rs;
97190075Sobrien	  }
97290075Sobrien	  break;
97390075Sobrien
97490075Sobrien	case DW_CFA_def_cfa:
97590075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
97690075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
97790075Sobrien	  fs->cfa_offset = utmp;
97890075Sobrien	  fs->cfa_how = CFA_REG_OFFSET;
97990075Sobrien	  break;
98090075Sobrien
98190075Sobrien	case DW_CFA_def_cfa_register:
98290075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
98390075Sobrien	  fs->cfa_how = CFA_REG_OFFSET;
98490075Sobrien	  break;
98590075Sobrien
98690075Sobrien	case DW_CFA_def_cfa_offset:
98790075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
98890075Sobrien	  fs->cfa_offset = utmp;
98990075Sobrien	  /* cfa_how deliberately not set.  */
99090075Sobrien	  break;
99190075Sobrien
99290075Sobrien	case DW_CFA_def_cfa_expression:
99390075Sobrien	  fs->cfa_exp = insn_ptr;
99490075Sobrien	  fs->cfa_how = CFA_EXP;
995117395Skan	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
99690075Sobrien	  insn_ptr += utmp;
99790075Sobrien	  break;
99890075Sobrien
99990075Sobrien	case DW_CFA_expression:
100090075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &reg);
1001132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP;
1002132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
1003117395Skan	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
100490075Sobrien	  insn_ptr += utmp;
100590075Sobrien	  break;
100690075Sobrien
1007169689Skan	  /* Dwarf3.  */
100890075Sobrien	case DW_CFA_offset_extended_sf:
100990075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &reg);
101090075Sobrien	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
101190075Sobrien	  offset = stmp * fs->data_align;
1012132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
1013132718Skan	    = REG_SAVED_OFFSET;
1014132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
101590075Sobrien	  break;
1016117395Skan
101790075Sobrien	case DW_CFA_def_cfa_sf:
101890075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
101990075Sobrien	  insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
102090075Sobrien	  fs->cfa_how = CFA_REG_OFFSET;
1021169689Skan	  fs->cfa_offset *= fs->data_align;
102290075Sobrien	  break;
102390075Sobrien
102490075Sobrien	case DW_CFA_def_cfa_offset_sf:
102590075Sobrien	  insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
1026169689Skan	  fs->cfa_offset *= fs->data_align;
102790075Sobrien	  /* cfa_how deliberately not set.  */
102890075Sobrien	  break;
102990075Sobrien
1030169689Skan	case DW_CFA_val_offset:
1031169689Skan	  insn_ptr = read_uleb128 (insn_ptr, &reg);
1032169689Skan	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
1033169689Skan	  offset = (_Unwind_Sword) utmp * fs->data_align;
1034169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
1035169689Skan	    = REG_SAVED_VAL_OFFSET;
1036169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
1037169689Skan	  break;
1038169689Skan
1039169689Skan	case DW_CFA_val_offset_sf:
1040169689Skan	  insn_ptr = read_uleb128 (insn_ptr, &reg);
1041169689Skan	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
1042169689Skan	  offset = stmp * fs->data_align;
1043169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
1044169689Skan	    = REG_SAVED_VAL_OFFSET;
1045169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
1046169689Skan	  break;
1047169689Skan
1048169689Skan	case DW_CFA_val_expression:
1049169689Skan	  insn_ptr = read_uleb128 (insn_ptr, &reg);
1050169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
1051169689Skan	    = REG_SAVED_VAL_EXP;
1052169689Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
1053169689Skan	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
1054169689Skan	  insn_ptr += utmp;
1055169689Skan	  break;
1056169689Skan
105790075Sobrien	case DW_CFA_GNU_window_save:
105890075Sobrien	  /* ??? Hardcoded for SPARC register window configuration.  */
105990075Sobrien	  for (reg = 16; reg < 32; ++reg)
106090075Sobrien	    {
106190075Sobrien	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
106290075Sobrien	      fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
106390075Sobrien	    }
106490075Sobrien	  break;
106590075Sobrien
106690075Sobrien	case DW_CFA_GNU_args_size:
106790075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &context->args_size);
106890075Sobrien	  break;
106990075Sobrien
107090075Sobrien	case DW_CFA_GNU_negative_offset_extended:
107190075Sobrien	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
107290075Sobrien	     older PowerPC code.  */
107390075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &reg);
107490075Sobrien	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
107590075Sobrien	  offset = (_Unwind_Word) utmp * fs->data_align;
1076132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
1077132718Skan	    = REG_SAVED_OFFSET;
1078132718Skan	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset;
107990075Sobrien	  break;
108090075Sobrien
108190075Sobrien	default:
1082169689Skan	  gcc_unreachable ();
108390075Sobrien	}
108490075Sobrien    }
108590075Sobrien}
108690075Sobrien
1087117395Skan/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
1088117395Skan   its caller and decode it into FS.  This function also sets the
1089117395Skan   args_size and lsda members of CONTEXT, as they are really information
1090117395Skan   about the caller's frame.  */
1091117395Skan
109290075Sobrienstatic _Unwind_Reason_Code
109390075Sobrienuw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
109490075Sobrien{
1095132718Skan  const struct dwarf_fde *fde;
1096132718Skan  const struct dwarf_cie *cie;
109790075Sobrien  const unsigned char *aug, *insn, *end;
109890075Sobrien
109990075Sobrien  memset (fs, 0, sizeof (*fs));
110090075Sobrien  context->args_size = 0;
110190075Sobrien  context->lsda = 0;
110290075Sobrien
1103122180Skan  if (context->ra == 0)
1104122180Skan    return _URC_END_OF_STACK;
1105122180Skan
1106169689Skan  fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
1107169689Skan			  &context->bases);
110890075Sobrien  if (fde == NULL)
110990075Sobrien    {
1110169689Skan#ifdef MD_FALLBACK_FRAME_STATE_FOR
111190075Sobrien      /* Couldn't find frame unwind info for this function.  Try a
111290075Sobrien	 target-specific fallback mechanism.  This will necessarily
111390075Sobrien	 not provide a personality routine or LSDA.  */
1114169689Skan      return MD_FALLBACK_FRAME_STATE_FOR (context, fs);
111590075Sobrien#else
111690075Sobrien      return _URC_END_OF_STACK;
111790075Sobrien#endif
111890075Sobrien    }
111990075Sobrien
112090075Sobrien  fs->pc = context->bases.func;
112190075Sobrien
112290075Sobrien  cie = get_cie (fde);
112390075Sobrien  insn = extract_cie_info (cie, context, fs);
112490075Sobrien  if (insn == NULL)
112590075Sobrien    /* CIE contained unknown augmentation.  */
112690075Sobrien    return _URC_FATAL_PHASE1_ERROR;
112790075Sobrien
112890075Sobrien  /* First decode all the insns in the CIE.  */
112990075Sobrien  end = (unsigned char *) next_fde ((struct dwarf_fde *) cie);
113090075Sobrien  execute_cfa_program (insn, end, context, fs);
113190075Sobrien
113290075Sobrien  /* Locate augmentation for the fde.  */
113390075Sobrien  aug = (unsigned char *) fde + sizeof (*fde);
113490075Sobrien  aug += 2 * size_of_encoded_value (fs->fde_encoding);
113590075Sobrien  insn = NULL;
113690075Sobrien  if (fs->saw_z)
113790075Sobrien    {
113890075Sobrien      _Unwind_Word i;
113990075Sobrien      aug = read_uleb128 (aug, &i);
114090075Sobrien      insn = aug + i;
114190075Sobrien    }
114290075Sobrien  if (fs->lsda_encoding != DW_EH_PE_omit)
1143169689Skan    {
1144169689Skan      _Unwind_Ptr lsda;
1145169689Skan
1146169689Skan      aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
1147169689Skan      context->lsda = (void *) lsda;
1148169689Skan    }
114990075Sobrien
115090075Sobrien  /* Then the insns in the FDE up to our target PC.  */
115190075Sobrien  if (insn == NULL)
115290075Sobrien    insn = aug;
115390075Sobrien  end = (unsigned char *) next_fde (fde);
115490075Sobrien  execute_cfa_program (insn, end, context, fs);
115590075Sobrien
115690075Sobrien  return _URC_NO_REASON;
115790075Sobrien}
115890075Sobrien
115990075Sobrientypedef struct frame_state
116090075Sobrien{
116190075Sobrien  void *cfa;
116290075Sobrien  void *eh_ptr;
116390075Sobrien  long cfa_offset;
116490075Sobrien  long args_size;
116590075Sobrien  long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
116690075Sobrien  unsigned short cfa_reg;
116790075Sobrien  unsigned short retaddr_column;
116890075Sobrien  char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
116990075Sobrien} frame_state;
117090075Sobrien
117190075Sobrienstruct frame_state * __frame_state_for (void *, struct frame_state *);
117290075Sobrien
117390075Sobrien/* Called from pre-G++ 3.0 __throw to find the registers to restore for
117490075Sobrien   a given PC_TARGET.  The caller should allocate a local variable of
117590075Sobrien   `struct frame_state' and pass its address to STATE_IN.  */
117690075Sobrien
117790075Sobrienstruct frame_state *
117890075Sobrien__frame_state_for (void *pc_target, struct frame_state *state_in)
117990075Sobrien{
118090075Sobrien  struct _Unwind_Context context;
118190075Sobrien  _Unwind_FrameState fs;
118290075Sobrien  int reg;
118390075Sobrien
118490075Sobrien  memset (&context, 0, sizeof (struct _Unwind_Context));
1185169689Skan  context.flags = EXTENDED_CONTEXT_BIT;
118690075Sobrien  context.ra = pc_target + 1;
118790075Sobrien
118890075Sobrien  if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
118990075Sobrien    return 0;
119090075Sobrien
119190075Sobrien  /* We have no way to pass a location expression for the CFA to our
119290075Sobrien     caller.  It wouldn't understand it anyway.  */
119390075Sobrien  if (fs.cfa_how == CFA_EXP)
119490075Sobrien    return 0;
119590075Sobrien
119690075Sobrien  for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++)
119790075Sobrien    {
119890075Sobrien      state_in->saved[reg] = fs.regs.reg[reg].how;
119990075Sobrien      switch (state_in->saved[reg])
120090075Sobrien	{
120190075Sobrien	case REG_SAVED_REG:
120290075Sobrien	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg;
120390075Sobrien	  break;
120490075Sobrien	case REG_SAVED_OFFSET:
120590075Sobrien	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset;
120690075Sobrien	  break;
120790075Sobrien	default:
120890075Sobrien	  state_in->reg_or_offset[reg] = 0;
120990075Sobrien	  break;
121090075Sobrien	}
121190075Sobrien    }
121290075Sobrien
121390075Sobrien  state_in->cfa_offset = fs.cfa_offset;
121490075Sobrien  state_in->cfa_reg = fs.cfa_reg;
121590075Sobrien  state_in->retaddr_column = fs.retaddr_column;
121690075Sobrien  state_in->args_size = context.args_size;
121790075Sobrien  state_in->eh_ptr = fs.eh_ptr;
121890075Sobrien
121990075Sobrien  return state_in;
122090075Sobrien}
122190075Sobrien
1222132718Skantypedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp;
1223132718Skan
1224132718Skanstatic inline void
1225132718Skan_Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
1226169689Skan		     _Unwind_SpTmp *tmp_sp)
1227132718Skan{
1228132718Skan  int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
1229132718Skan
1230132718Skan  if (size == sizeof(_Unwind_Ptr))
1231132718Skan    tmp_sp->ptr = (_Unwind_Ptr) cfa;
1232132718Skan  else
1233169689Skan    {
1234169689Skan      gcc_assert (size == sizeof(_Unwind_Word));
1235169689Skan      tmp_sp->word = (_Unwind_Ptr) cfa;
1236169689Skan    }
1237132718Skan  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp);
1238132718Skan}
1239132718Skan
124090075Sobrienstatic void
124190075Sobrienuw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
124290075Sobrien{
124390075Sobrien  struct _Unwind_Context orig_context = *context;
124490075Sobrien  void *cfa;
124590075Sobrien  long i;
124690075Sobrien
1247117395Skan#ifdef EH_RETURN_STACKADJ_RTX
1248117395Skan  /* Special handling here: Many machines do not use a frame pointer,
1249117395Skan     and track the CFA only through offsets from the stack pointer from
1250117395Skan     one frame to the next.  In this case, the stack pointer is never
1251117395Skan     stored, so it has no saved address in the context.  What we do
1252117395Skan     have is the CFA from the previous stack frame.
1253117395Skan
1254117395Skan     In very special situations (such as unwind info for signal return),
1255117395Skan     there may be location expressions that use the stack pointer as well.
1256117395Skan
1257117395Skan     Do this conditionally for one frame.  This allows the unwind info
1258117395Skan     for one frame to save a copy of the stack pointer from the previous
1259117395Skan     frame, and be able to use much easier CFA mechanisms to do it.
1260117395Skan     Always zap the saved stack pointer value for the next frame; carrying
1261117395Skan     the value over from one frame to another doesn't make sense.  */
1262117395Skan
1263132718Skan  _Unwind_SpTmp tmp_sp;
1264117395Skan
1265132718Skan  if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ()))
1266132718Skan    _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp);
1267132718Skan  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL);
1268117395Skan#endif
1269117395Skan
127090075Sobrien  /* Compute this frame's CFA.  */
127190075Sobrien  switch (fs->cfa_how)
127290075Sobrien    {
127390075Sobrien    case CFA_REG_OFFSET:
1274132718Skan      cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg);
127590075Sobrien      cfa += fs->cfa_offset;
127690075Sobrien      break;
127790075Sobrien
127890075Sobrien    case CFA_EXP:
127990075Sobrien      {
128090075Sobrien	const unsigned char *exp = fs->cfa_exp;
128190075Sobrien	_Unwind_Word len;
128290075Sobrien
128390075Sobrien	exp = read_uleb128 (exp, &len);
128490075Sobrien	cfa = (void *) (_Unwind_Ptr)
1285117395Skan	  execute_stack_op (exp, exp + len, &orig_context, 0);
128690075Sobrien	break;
128790075Sobrien      }
128890075Sobrien
128990075Sobrien    default:
1290169689Skan      gcc_unreachable ();
129190075Sobrien    }
129290075Sobrien  context->cfa = cfa;
129390075Sobrien
129490075Sobrien  /* Compute the addresses of all registers saved in this frame.  */
129590075Sobrien  for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
129690075Sobrien    switch (fs->regs.reg[i].how)
129790075Sobrien      {
129890075Sobrien      case REG_UNSAVED:
129990075Sobrien	break;
1300117395Skan
130190075Sobrien      case REG_SAVED_OFFSET:
1302132718Skan	_Unwind_SetGRPtr (context, i,
1303132718Skan			  (void *) (cfa + fs->regs.reg[i].loc.offset));
130490075Sobrien	break;
1305117395Skan
130690075Sobrien      case REG_SAVED_REG:
1307169689Skan	if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg))
1308169689Skan	  _Unwind_SetGRValue (context, i,
1309169689Skan			      _Unwind_GetGR (&orig_context,
1310169689Skan					     fs->regs.reg[i].loc.reg));
1311169689Skan	else
1312169689Skan	  _Unwind_SetGRPtr (context, i,
1313169689Skan			    _Unwind_GetGRPtr (&orig_context,
1314169689Skan					      fs->regs.reg[i].loc.reg));
131590075Sobrien	break;
1316117395Skan
131790075Sobrien      case REG_SAVED_EXP:
131890075Sobrien	{
131990075Sobrien	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
132090075Sobrien	  _Unwind_Word len;
132190075Sobrien	  _Unwind_Ptr val;
132290075Sobrien
132390075Sobrien	  exp = read_uleb128 (exp, &len);
132490075Sobrien	  val = execute_stack_op (exp, exp + len, &orig_context,
132590075Sobrien				  (_Unwind_Ptr) cfa);
1326132718Skan	  _Unwind_SetGRPtr (context, i, (void *) val);
132790075Sobrien	}
132890075Sobrien	break;
1329169689Skan
1330169689Skan      case REG_SAVED_VAL_OFFSET:
1331169689Skan	_Unwind_SetGRValue (context, i,
1332169689Skan			    (_Unwind_Internal_Ptr)
1333169689Skan			    (cfa + fs->regs.reg[i].loc.offset));
1334169689Skan	break;
1335169689Skan
1336169689Skan      case REG_SAVED_VAL_EXP:
1337169689Skan	{
1338169689Skan	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
1339169689Skan	  _Unwind_Word len;
1340169689Skan	  _Unwind_Ptr val;
1341169689Skan
1342169689Skan	  exp = read_uleb128 (exp, &len);
1343169689Skan	  val = execute_stack_op (exp, exp + len, &orig_context,
1344169689Skan				  (_Unwind_Ptr) cfa);
1345169689Skan	  _Unwind_SetGRValue (context, i, val);
1346169689Skan	}
1347169689Skan	break;
134890075Sobrien      }
1349132718Skan
1350169689Skan  _Unwind_SetSignalFrame (context, fs->signal_frame);
1351169689Skan
1352169689Skan#ifdef MD_FROB_UPDATE_CONTEXT
1353132718Skan  MD_FROB_UPDATE_CONTEXT (context, fs);
1354169689Skan#endif
135590075Sobrien}
135690075Sobrien
1357117395Skan/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
1358117395Skan   of its caller.  Update CONTEXT to refer to the caller as well.  Note
1359117395Skan   that the args_size and lsda members are not updated here, but later in
1360117395Skan   uw_frame_state_for.  */
1361117395Skan
136290075Sobrienstatic void
136390075Sobrienuw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
136490075Sobrien{
136590075Sobrien  uw_update_context_1 (context, fs);
136690075Sobrien
136790075Sobrien  /* Compute the return address now, since the return address column
136890075Sobrien     can change from frame to frame.  */
136990075Sobrien  context->ra = __builtin_extract_return_addr
1370132718Skan    (_Unwind_GetPtr (context, fs->retaddr_column));
137190075Sobrien}
1372169689Skan
1373169689Skanstatic void
1374169689Skanuw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
1375169689Skan{
1376169689Skan  uw_update_context (context, fs);
1377169689Skan}
137890075Sobrien
137990075Sobrien/* Fill in CONTEXT for top-of-stack.  The only valid registers at this
138090075Sobrien   level will be the return address and the CFA.  */
1381117395Skan
138290075Sobrien#define uw_init_context(CONTEXT)					   \
138390075Sobrien  do									   \
138490075Sobrien    {									   \
138590075Sobrien      /* Do any necessary initialization to access arbitrary stack frames. \
138690075Sobrien	 On the SPARC, this means flushing the register windows.  */	   \
138790075Sobrien      __builtin_unwind_init ();						   \
138890075Sobrien      uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),		   \
138990075Sobrien			 __builtin_return_address (0));			   \
139090075Sobrien    }									   \
139190075Sobrien  while (0)
139290075Sobrien
1393132718Skanstatic inline void
1394132718Skaninit_dwarf_reg_size_table (void)
1395132718Skan{
1396132718Skan  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
1397132718Skan}
1398132718Skan
139990075Sobrienstatic void
140090075Sobrienuw_init_context_1 (struct _Unwind_Context *context,
140190075Sobrien		   void *outer_cfa, void *outer_ra)
140290075Sobrien{
140390075Sobrien  void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
140490075Sobrien  _Unwind_FrameState fs;
1405132718Skan  _Unwind_SpTmp sp_slot;
1406169689Skan  _Unwind_Reason_Code code;
140790075Sobrien
140890075Sobrien  memset (context, 0, sizeof (struct _Unwind_Context));
140990075Sobrien  context->ra = ra;
1410169689Skan  context->flags = EXTENDED_CONTEXT_BIT;
141190075Sobrien
1412169689Skan  code = uw_frame_state_for (context, &fs);
1413169689Skan  gcc_assert (code == _URC_NO_REASON);
141490075Sobrien
1415132718Skan#if __GTHREADS
1416132718Skan  {
1417132718Skan    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
1418132718Skan    if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
1419132718Skan	|| dwarf_reg_size_table[0] == 0)
1420132718Skan      init_dwarf_reg_size_table ();
1421132718Skan  }
1422132718Skan#else
1423132718Skan  if (dwarf_reg_size_table[0] == 0)
1424132718Skan    init_dwarf_reg_size_table ();
1425132718Skan#endif
1426132718Skan
142790075Sobrien  /* Force the frame state to use the known cfa value.  */
1428132718Skan  _Unwind_SetSpColumn (context, outer_cfa, &sp_slot);
142990075Sobrien  fs.cfa_how = CFA_REG_OFFSET;
1430117395Skan  fs.cfa_reg = __builtin_dwarf_sp_column ();
143190075Sobrien  fs.cfa_offset = 0;
143290075Sobrien
143390075Sobrien  uw_update_context_1 (context, &fs);
143490075Sobrien
143590075Sobrien  /* If the return address column was saved in a register in the
143690075Sobrien     initialization context, then we can't see it in the given
143790075Sobrien     call frame data.  So have the initialization context tell us.  */
143890075Sobrien  context->ra = __builtin_extract_return_addr (outer_ra);
143990075Sobrien}
144090075Sobrien
144190075Sobrien
144290075Sobrien/* Install TARGET into CURRENT so that we can return to it.  This is a
144390075Sobrien   macro because __builtin_eh_return must be invoked in the context of
144490075Sobrien   our caller.  */
144590075Sobrien
144690075Sobrien#define uw_install_context(CURRENT, TARGET)				 \
144790075Sobrien  do									 \
144890075Sobrien    {									 \
144990075Sobrien      long offset = uw_install_context_1 ((CURRENT), (TARGET));		 \
145090075Sobrien      void *handler = __builtin_frob_return_addr ((TARGET)->ra);	 \
145190075Sobrien      __builtin_eh_return (offset, handler);				 \
145290075Sobrien    }									 \
145390075Sobrien  while (0)
145490075Sobrien
145590075Sobrienstatic long
145690075Sobrienuw_install_context_1 (struct _Unwind_Context *current,
145790075Sobrien		      struct _Unwind_Context *target)
145890075Sobrien{
145990075Sobrien  long i;
1460169689Skan  _Unwind_SpTmp sp_slot;
146190075Sobrien
1462169689Skan  /* If the target frame does not have a saved stack pointer,
1463169689Skan     then set up the target's CFA.  */
1464169689Skan  if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
1465169689Skan    _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
1466169689Skan
146790075Sobrien  for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
146890075Sobrien    {
146990075Sobrien      void *c = current->reg[i];
147090075Sobrien      void *t = target->reg[i];
1471132718Skan
1472169689Skan      gcc_assert (current->by_value[i] == 0);
1473169689Skan      if (target->by_value[i] && c)
1474169689Skan	{
1475169689Skan	  _Unwind_Word w;
1476169689Skan	  _Unwind_Ptr p;
1477169689Skan	  if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word))
1478169689Skan	    {
1479169689Skan	      w = (_Unwind_Internal_Ptr) t;
1480169689Skan	      memcpy (c, &w, sizeof (_Unwind_Word));
1481169689Skan	    }
1482169689Skan	  else
1483169689Skan	    {
1484169689Skan	      gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr));
1485169689Skan	      p = (_Unwind_Internal_Ptr) t;
1486169689Skan	      memcpy (c, &p, sizeof (_Unwind_Ptr));
1487169689Skan	    }
1488169689Skan	}
1489169689Skan      else if (t && c && t != c)
149090075Sobrien	memcpy (c, t, dwarf_reg_size_table[i]);
149190075Sobrien    }
149290075Sobrien
1493169689Skan  /* If the current frame doesn't have a saved stack pointer, then we
1494169689Skan     need to rely on EH_RETURN_STACKADJ_RTX to get our target stack
1495169689Skan     pointer value reloaded.  */
1496169689Skan  if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ()))
1497169689Skan    {
1498169689Skan      void *target_cfa;
1499117395Skan
1500132718Skan      target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ());
1501117395Skan
1502169689Skan      /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
1503169689Skan      if (STACK_GROWS_DOWNWARD)
1504169689Skan	return target_cfa - current->cfa + target->args_size;
1505169689Skan      else
1506169689Skan	return current->cfa - target_cfa - target->args_size;
1507169689Skan    }
1508117395Skan  return 0;
150990075Sobrien}
151090075Sobrien
151190075Sobrienstatic inline _Unwind_Ptr
151290075Sobrienuw_identify_context (struct _Unwind_Context *context)
151390075Sobrien{
151490075Sobrien  return _Unwind_GetIP (context);
151590075Sobrien}
151690075Sobrien
151790075Sobrien
151890075Sobrien#include "unwind.inc"
151990075Sobrien
1520146895Skan#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
1521146895Skanalias (_Unwind_Backtrace);
1522146895Skanalias (_Unwind_DeleteException);
1523146895Skanalias (_Unwind_FindEnclosingFunction);
1524146895Skanalias (_Unwind_ForcedUnwind);
1525146895Skanalias (_Unwind_GetDataRelBase);
1526146895Skanalias (_Unwind_GetTextRelBase);
1527146895Skanalias (_Unwind_GetCFA);
1528146895Skanalias (_Unwind_GetGR);
1529146895Skanalias (_Unwind_GetIP);
1530146895Skanalias (_Unwind_GetLanguageSpecificData);
1531146895Skanalias (_Unwind_GetRegionStart);
1532146895Skanalias (_Unwind_RaiseException);
1533146895Skanalias (_Unwind_Resume);
1534146895Skanalias (_Unwind_Resume_or_Rethrow);
1535146895Skanalias (_Unwind_SetGR);
1536146895Skanalias (_Unwind_SetIP);
1537146895Skan#endif
1538146895Skan
153990075Sobrien#endif /* !USING_SJLJ_EXCEPTIONS */
1540