Blame sysdeps/generic/unwind-dw2.c

Packit 6c4009
/* DWARF2 exception handling and frame unwind runtime interface routines.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <dwarf2.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <unwind.h>
Packit 6c4009
#include <unwind-pe.h>
Packit 6c4009
#include <unwind-dw2-fde.h>
Packit 6c4009
#else
Packit 6c4009
#include "tconfig.h"
Packit 6c4009
#include "tsystem.h"
Packit 6c4009
#include "dwarf2.h"
Packit 6c4009
#include "unwind.h"
Packit 6c4009
#include "unwind-pe.h"
Packit 6c4009
#include "unwind-dw2-fde.h"
Packit 6c4009
#include "gthr.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef STACK_GROWS_DOWNWARD
Packit 6c4009
#define STACK_GROWS_DOWNWARD 0
Packit 6c4009
#else
Packit 6c4009
#undef STACK_GROWS_DOWNWARD
Packit 6c4009
#define STACK_GROWS_DOWNWARD 1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* A target can override (perhaps for backward compatibility) how
Packit 6c4009
   many dwarf2 columns are unwound.  */
Packit 6c4009
#ifndef DWARF_FRAME_REGISTERS
Packit 6c4009
#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Dwarf frame registers used for pre gcc 3.0 compiled glibc.  */
Packit 6c4009
#ifndef PRE_GCC3_DWARF_FRAME_REGISTERS
Packit 6c4009
#define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* This is the register and unwind state for a particular frame.  This
Packit 6c4009
   provides the information necessary to unwind up past a frame and return
Packit 6c4009
   to its caller.  */
Packit 6c4009
struct _Unwind_Context
Packit 6c4009
{
Packit 6c4009
  void *reg[DWARF_FRAME_REGISTERS+1];
Packit 6c4009
  void *cfa;
Packit 6c4009
  void *ra;
Packit 6c4009
  void *lsda;
Packit 6c4009
  struct dwarf_eh_bases bases;
Packit 6c4009
  _Unwind_Word args_size;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
/* Byte size of every register managed by these routines.  */
Packit 6c4009
static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009

Packit 6c4009
/* The result of interpreting the frame unwind info for a frame.
Packit 6c4009
   This is all symbolic at this point, as none of the values can
Packit 6c4009
   be resolved until the target pc is located.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* Each register save state can be described in terms of a CFA slot,
Packit 6c4009
     another register, or a location expression.  */
Packit 6c4009
  struct frame_state_reg_info
Packit 6c4009
  {
Packit 6c4009
    struct {
Packit 6c4009
      union {
Packit 6c4009
	_Unwind_Word reg;
Packit 6c4009
	_Unwind_Sword offset;
Packit 6c4009
	const unsigned char *exp;
Packit 6c4009
      } loc;
Packit 6c4009
      enum {
Packit 6c4009
	REG_UNSAVED,
Packit 6c4009
	REG_SAVED_OFFSET,
Packit 6c4009
	REG_SAVED_REG,
Packit 6c4009
	REG_SAVED_EXP,
Packit 6c4009
      } how;
Packit 6c4009
    } reg[DWARF_FRAME_REGISTERS+1];
Packit 6c4009
Packit 6c4009
    /* Used to implement DW_CFA_remember_state.  */
Packit 6c4009
    struct frame_state_reg_info *prev;
Packit 6c4009
  } regs;
Packit 6c4009
Packit 6c4009
  /* The CFA can be described in terms of a reg+offset or a
Packit 6c4009
     location expression.  */
Packit 6c4009
  _Unwind_Sword cfa_offset;
Packit 6c4009
  _Unwind_Word cfa_reg;
Packit 6c4009
  const unsigned char *cfa_exp;
Packit 6c4009
  enum {
Packit 6c4009
    CFA_UNSET,
Packit 6c4009
    CFA_REG_OFFSET,
Packit 6c4009
    CFA_EXP,
Packit 6c4009
  } cfa_how;
Packit 6c4009
Packit 6c4009
  /* The PC described by the current frame state.  */
Packit 6c4009
  void *pc;
Packit 6c4009
Packit 6c4009
  /* The information we care about from the CIE/FDE.  */
Packit 6c4009
  _Unwind_Personality_Fn personality;
Packit 6c4009
  _Unwind_Sword data_align;
Packit 6c4009
  _Unwind_Word code_align;
Packit 6c4009
  unsigned char retaddr_column;
Packit 6c4009
  unsigned char fde_encoding;
Packit 6c4009
  unsigned char lsda_encoding;
Packit 6c4009
  unsigned char saw_z;
Packit 6c4009
  void *eh_ptr;
Packit 6c4009
} _Unwind_FrameState;
Packit 6c4009

Packit 6c4009
/* Read unaligned data from the instruction buffer.  */
Packit 6c4009
Packit 6c4009
union unaligned
Packit 6c4009
{
Packit 6c4009
  void *p;
Packit 6c4009
  unsigned u2 __attribute__ ((mode (HI)));
Packit 6c4009
  unsigned u4 __attribute__ ((mode (SI)));
Packit 6c4009
  unsigned u8 __attribute__ ((mode (DI)));
Packit 6c4009
  signed s2 __attribute__ ((mode (HI)));
Packit 6c4009
  signed s4 __attribute__ ((mode (SI)));
Packit 6c4009
  signed s8 __attribute__ ((mode (DI)));
Packit 6c4009
} __attribute__ ((packed));
Packit 6c4009
Packit 6c4009
static inline void *
Packit 6c4009
read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
read_1u (const void *p) { return *(const unsigned char *) p; }
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
read_1s (const void *p) { return *(const signed char *) p; }
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
read_2u (const void *p) { const union unaligned *up = p; return up->u2; }
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
read_2s (const void *p) { const union unaligned *up = p; return up->s2; }
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
read_4u (const void *p) { const union unaligned *up = p; return up->u4; }
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
read_4s (const void *p) { const union unaligned *up = p; return up->s4; }
Packit 6c4009
Packit 6c4009
static inline unsigned long
Packit 6c4009
read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
Packit 6c4009
Packit 6c4009
static inline unsigned long
Packit 6c4009
read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
Packit 6c4009

Packit 6c4009
/* Get the value of register REG as saved in CONTEXT.  */
Packit 6c4009
Packit 6c4009
inline _Unwind_Word
Packit 6c4009
_Unwind_GetGR (struct _Unwind_Context *context, int index)
Packit 6c4009
{
Packit 6c4009
  /* This will segfault if the register hasn't been saved.  */
Packit 6c4009
  return * (_Unwind_Word *) context->reg[index];
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Get the value of the CFA as saved in CONTEXT.  */
Packit 6c4009
Packit 6c4009
_Unwind_Word
Packit 6c4009
_Unwind_GetCFA (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return (_Unwind_Ptr) context->cfa;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Overwrite the saved value for register REG in CONTEXT with VAL.  */
Packit 6c4009
Packit 6c4009
inline void
Packit 6c4009
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
Packit 6c4009
{
Packit 6c4009
  * (_Unwind_Word *) context->reg[index] = val;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Retrieve the return address for CONTEXT.  */
Packit 6c4009
Packit 6c4009
inline _Unwind_Ptr
Packit 6c4009
_Unwind_GetIP (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return (_Unwind_Ptr) context->ra;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Overwrite the return address for CONTEXT with VAL.  */
Packit 6c4009
Packit 6c4009
inline void
Packit 6c4009
_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
Packit 6c4009
{
Packit 6c4009
  context->ra = (void *) val;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return context->lsda;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
_Unwind_Ptr
Packit 6c4009
_Unwind_GetRegionStart (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return (_Unwind_Ptr) context->bases.func;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_Unwind_FindEnclosingFunction (void *pc)
Packit 6c4009
{
Packit 6c4009
  struct dwarf_eh_bases bases;
Packit 6c4009
  struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
Packit 6c4009
  if (fde)
Packit 6c4009
    return bases.func;
Packit 6c4009
  else
Packit 6c4009
    return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef __ia64__
Packit 6c4009
_Unwind_Ptr
Packit 6c4009
_Unwind_GetDataRelBase (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return (_Unwind_Ptr) context->bases.dbase;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
_Unwind_Ptr
Packit 6c4009
_Unwind_GetTextRelBase (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return (_Unwind_Ptr) context->bases.tbase;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009

Packit 6c4009
/* Extract any interesting information from the CIE for the translation
Packit 6c4009
   unit F belongs to.  Return a pointer to the byte after the augmentation,
Packit 6c4009
   or NULL if we encountered an undecipherable augmentation.  */
Packit 6c4009
Packit 6c4009
static const unsigned char *
Packit 6c4009
extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
Packit 6c4009
		  _Unwind_FrameState *fs)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *aug = cie->augmentation;
Packit 6c4009
  const unsigned char *p = aug + strlen ((const char *) aug) + 1;
Packit 6c4009
  const unsigned char *ret = NULL;
Packit 6c4009
  _Unwind_Word utmp;
Packit 6c4009
Packit 6c4009
  /* g++ v2 "eh" has pointer immediately following augmentation string,
Packit 6c4009
     so it must be handled first.  */
Packit 6c4009
  if (aug[0] == 'e' && aug[1] == 'h')
Packit 6c4009
    {
Packit 6c4009
      fs->eh_ptr = read_pointer (p);
Packit 6c4009
      p += sizeof (void *);
Packit 6c4009
      aug += 2;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Immediately following the augmentation are the code and
Packit 6c4009
     data alignment and return address column.  */
Packit 6c4009
  p = read_uleb128 (p, &fs->code_align);
Packit 6c4009
  p = read_sleb128 (p, &fs->data_align);
Packit 6c4009
  fs->retaddr_column = *p++;
Packit 6c4009
  fs->lsda_encoding = DW_EH_PE_omit;
Packit 6c4009
Packit 6c4009
  /* If the augmentation starts with 'z', then a uleb128 immediately
Packit 6c4009
     follows containing the length of the augmentation field following
Packit 6c4009
     the size.  */
Packit 6c4009
  if (*aug == 'z')
Packit 6c4009
    {
Packit 6c4009
      p = read_uleb128 (p, &utmp);
Packit 6c4009
      ret = p + utmp;
Packit 6c4009
Packit 6c4009
      fs->saw_z = 1;
Packit 6c4009
      ++aug;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Iterate over recognized augmentation subsequences.  */
Packit 6c4009
  while (*aug != '\0')
Packit 6c4009
    {
Packit 6c4009
      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
Packit 6c4009
      if (aug[0] == 'L')
Packit 6c4009
	{
Packit 6c4009
	  fs->lsda_encoding = *p++;
Packit 6c4009
	  aug += 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
Packit 6c4009
      else if (aug[0] == 'R')
Packit 6c4009
	{
Packit 6c4009
	  fs->fde_encoding = *p++;
Packit 6c4009
	  aug += 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* "P" indicates a personality routine in the CIE augmentation.  */
Packit 6c4009
      else if (aug[0] == 'P')
Packit 6c4009
	{
Packit 6c4009
	  _Unwind_Ptr personality;
Packit 6c4009
	  p = read_encoded_value (context, *p, p + 1, &personality);
Packit 6c4009
	  fs->personality = (_Unwind_Personality_Fn) personality;
Packit 6c4009
	  aug += 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Otherwise we have an unknown augmentation string.
Packit 6c4009
	 Bail unless we saw a 'z' prefix.  */
Packit 6c4009
      else
Packit 6c4009
	return ret;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return ret ? ret : p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
/* Decode a DW_OP stack program.  Return the top of stack.  Push INITIAL
Packit 6c4009
   onto the stack to start.  */
Packit 6c4009
Packit 6c4009
static _Unwind_Word
Packit 6c4009
execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
Packit 6c4009
		  struct _Unwind_Context *context, _Unwind_Word initial)
Packit 6c4009
{
Packit 6c4009
  _Unwind_Word stack[64];	/* ??? Assume this is enough.  */
Packit 6c4009
  int stack_elt;
Packit 6c4009
Packit 6c4009
  stack[0] = initial;
Packit 6c4009
  stack_elt = 1;
Packit 6c4009
Packit 6c4009
  while (op_ptr < op_end)
Packit 6c4009
    {
Packit 6c4009
      enum dwarf_location_atom op = *op_ptr++;
Packit 6c4009
      _Unwind_Word result, reg, utmp;
Packit 6c4009
      _Unwind_Sword offset, stmp;
Packit 6c4009
Packit 6c4009
      switch (op)
Packit 6c4009
	{
Packit 6c4009
	case DW_OP_lit0:
Packit 6c4009
	case DW_OP_lit1:
Packit 6c4009
	case DW_OP_lit2:
Packit 6c4009
	case DW_OP_lit3:
Packit 6c4009
	case DW_OP_lit4:
Packit 6c4009
	case DW_OP_lit5:
Packit 6c4009
	case DW_OP_lit6:
Packit 6c4009
	case DW_OP_lit7:
Packit 6c4009
	case DW_OP_lit8:
Packit 6c4009
	case DW_OP_lit9:
Packit 6c4009
	case DW_OP_lit10:
Packit 6c4009
	case DW_OP_lit11:
Packit 6c4009
	case DW_OP_lit12:
Packit 6c4009
	case DW_OP_lit13:
Packit 6c4009
	case DW_OP_lit14:
Packit 6c4009
	case DW_OP_lit15:
Packit 6c4009
	case DW_OP_lit16:
Packit 6c4009
	case DW_OP_lit17:
Packit 6c4009
	case DW_OP_lit18:
Packit 6c4009
	case DW_OP_lit19:
Packit 6c4009
	case DW_OP_lit20:
Packit 6c4009
	case DW_OP_lit21:
Packit 6c4009
	case DW_OP_lit22:
Packit 6c4009
	case DW_OP_lit23:
Packit 6c4009
	case DW_OP_lit24:
Packit 6c4009
	case DW_OP_lit25:
Packit 6c4009
	case DW_OP_lit26:
Packit 6c4009
	case DW_OP_lit27:
Packit 6c4009
	case DW_OP_lit28:
Packit 6c4009
	case DW_OP_lit29:
Packit 6c4009
	case DW_OP_lit30:
Packit 6c4009
	case DW_OP_lit31:
Packit 6c4009
	  result = op - DW_OP_lit0;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_addr:
Packit 6c4009
	  result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr);
Packit 6c4009
	  op_ptr += sizeof (void *);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_const1u:
Packit 6c4009
	  result = read_1u (op_ptr);
Packit 6c4009
	  op_ptr += 1;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const1s:
Packit 6c4009
	  result = read_1s (op_ptr);
Packit 6c4009
	  op_ptr += 1;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const2u:
Packit 6c4009
	  result = read_2u (op_ptr);
Packit 6c4009
	  op_ptr += 2;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const2s:
Packit 6c4009
	  result = read_2s (op_ptr);
Packit 6c4009
	  op_ptr += 2;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const4u:
Packit 6c4009
	  result = read_4u (op_ptr);
Packit 6c4009
	  op_ptr += 4;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const4s:
Packit 6c4009
	  result = read_4s (op_ptr);
Packit 6c4009
	  op_ptr += 4;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const8u:
Packit 6c4009
	  result = read_8u (op_ptr);
Packit 6c4009
	  op_ptr += 8;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_const8s:
Packit 6c4009
	  result = read_8s (op_ptr);
Packit 6c4009
	  op_ptr += 8;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_constu:
Packit 6c4009
	  op_ptr = read_uleb128 (op_ptr, &result);
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_consts:
Packit 6c4009
	  op_ptr = read_sleb128 (op_ptr, &stmp);
Packit 6c4009
	  result = stmp;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_reg0:
Packit 6c4009
	case DW_OP_reg1:
Packit 6c4009
	case DW_OP_reg2:
Packit 6c4009
	case DW_OP_reg3:
Packit 6c4009
	case DW_OP_reg4:
Packit 6c4009
	case DW_OP_reg5:
Packit 6c4009
	case DW_OP_reg6:
Packit 6c4009
	case DW_OP_reg7:
Packit 6c4009
	case DW_OP_reg8:
Packit 6c4009
	case DW_OP_reg9:
Packit 6c4009
	case DW_OP_reg10:
Packit 6c4009
	case DW_OP_reg11:
Packit 6c4009
	case DW_OP_reg12:
Packit 6c4009
	case DW_OP_reg13:
Packit 6c4009
	case DW_OP_reg14:
Packit 6c4009
	case DW_OP_reg15:
Packit 6c4009
	case DW_OP_reg16:
Packit 6c4009
	case DW_OP_reg17:
Packit 6c4009
	case DW_OP_reg18:
Packit 6c4009
	case DW_OP_reg19:
Packit 6c4009
	case DW_OP_reg20:
Packit 6c4009
	case DW_OP_reg21:
Packit 6c4009
	case DW_OP_reg22:
Packit 6c4009
	case DW_OP_reg23:
Packit 6c4009
	case DW_OP_reg24:
Packit 6c4009
	case DW_OP_reg25:
Packit 6c4009
	case DW_OP_reg26:
Packit 6c4009
	case DW_OP_reg27:
Packit 6c4009
	case DW_OP_reg28:
Packit 6c4009
	case DW_OP_reg29:
Packit 6c4009
	case DW_OP_reg30:
Packit 6c4009
	case DW_OP_reg31:
Packit 6c4009
	  result = _Unwind_GetGR (context, op - DW_OP_reg0);
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_regx:
Packit 6c4009
	  op_ptr = read_uleb128 (op_ptr, ®);
Packit 6c4009
	  result = _Unwind_GetGR (context, reg);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_breg0:
Packit 6c4009
	case DW_OP_breg1:
Packit 6c4009
	case DW_OP_breg2:
Packit 6c4009
	case DW_OP_breg3:
Packit 6c4009
	case DW_OP_breg4:
Packit 6c4009
	case DW_OP_breg5:
Packit 6c4009
	case DW_OP_breg6:
Packit 6c4009
	case DW_OP_breg7:
Packit 6c4009
	case DW_OP_breg8:
Packit 6c4009
	case DW_OP_breg9:
Packit 6c4009
	case DW_OP_breg10:
Packit 6c4009
	case DW_OP_breg11:
Packit 6c4009
	case DW_OP_breg12:
Packit 6c4009
	case DW_OP_breg13:
Packit 6c4009
	case DW_OP_breg14:
Packit 6c4009
	case DW_OP_breg15:
Packit 6c4009
	case DW_OP_breg16:
Packit 6c4009
	case DW_OP_breg17:
Packit 6c4009
	case DW_OP_breg18:
Packit 6c4009
	case DW_OP_breg19:
Packit 6c4009
	case DW_OP_breg20:
Packit 6c4009
	case DW_OP_breg21:
Packit 6c4009
	case DW_OP_breg22:
Packit 6c4009
	case DW_OP_breg23:
Packit 6c4009
	case DW_OP_breg24:
Packit 6c4009
	case DW_OP_breg25:
Packit 6c4009
	case DW_OP_breg26:
Packit 6c4009
	case DW_OP_breg27:
Packit 6c4009
	case DW_OP_breg28:
Packit 6c4009
	case DW_OP_breg29:
Packit 6c4009
	case DW_OP_breg30:
Packit 6c4009
	case DW_OP_breg31:
Packit 6c4009
	  op_ptr = read_sleb128 (op_ptr, &offset);
Packit 6c4009
	  result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_OP_bregx:
Packit 6c4009
	  op_ptr = read_uleb128 (op_ptr, ®);
Packit 6c4009
	  op_ptr = read_sleb128 (op_ptr, &offset);
Packit 6c4009
	  result = _Unwind_GetGR (context, reg) + offset;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_dup:
Packit 6c4009
	  if (stack_elt < 1)
Packit 6c4009
	    abort ();
Packit 6c4009
	  result = stack[stack_elt - 1];
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_drop:
Packit 6c4009
	  if (--stack_elt < 0)
Packit 6c4009
	    abort ();
Packit 6c4009
	  goto no_push;
Packit 6c4009
Packit 6c4009
	case DW_OP_pick:
Packit 6c4009
	  offset = *op_ptr++;
Packit 6c4009
	  if (offset >= stack_elt - 1)
Packit 6c4009
	    abort ();
Packit 6c4009
	  result = stack[stack_elt - 1 - offset];
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_over:
Packit 6c4009
	  if (stack_elt < 2)
Packit 6c4009
	    abort ();
Packit 6c4009
	  result = stack[stack_elt - 2];
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_rot:
Packit 6c4009
	  {
Packit 6c4009
	    _Unwind_Word t1, t2, t3;
Packit 6c4009
Packit 6c4009
	    if (stack_elt < 3)
Packit 6c4009
	      abort ();
Packit 6c4009
	    t1 = stack[stack_elt - 1];
Packit 6c4009
	    t2 = stack[stack_elt - 2];
Packit 6c4009
	    t3 = stack[stack_elt - 3];
Packit 6c4009
	    stack[stack_elt - 1] = t2;
Packit 6c4009
	    stack[stack_elt - 2] = t3;
Packit 6c4009
	    stack[stack_elt - 3] = t1;
Packit 6c4009
	    goto no_push;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	case DW_OP_deref:
Packit 6c4009
	case DW_OP_deref_size:
Packit 6c4009
	case DW_OP_abs:
Packit 6c4009
	case DW_OP_neg:
Packit 6c4009
	case DW_OP_not:
Packit 6c4009
	case DW_OP_plus_uconst:
Packit 6c4009
	  /* Unary operations.  */
Packit 6c4009
	  if (--stack_elt < 0)
Packit 6c4009
	    abort ();
Packit 6c4009
	  result = stack[stack_elt];
Packit 6c4009
Packit 6c4009
	  switch (op)
Packit 6c4009
	    {
Packit 6c4009
	    case DW_OP_deref:
Packit 6c4009
	      {
Packit 6c4009
		void *ptr = (void *) (_Unwind_Ptr) result;
Packit 6c4009
		result = (_Unwind_Ptr) read_pointer (ptr);
Packit 6c4009
	      }
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case DW_OP_deref_size:
Packit 6c4009
	      {
Packit 6c4009
		void *ptr = (void *) (_Unwind_Ptr) result;
Packit 6c4009
		switch (*op_ptr++)
Packit 6c4009
		  {
Packit 6c4009
		  case 1:
Packit 6c4009
		    result = read_1u (ptr);
Packit 6c4009
		    break;
Packit 6c4009
		  case 2:
Packit 6c4009
		    result = read_2u (ptr);
Packit 6c4009
		    break;
Packit 6c4009
		  case 4:
Packit 6c4009
		    result = read_4u (ptr);
Packit 6c4009
		    break;
Packit 6c4009
		  case 8:
Packit 6c4009
		    result = read_8u (ptr);
Packit 6c4009
		    break;
Packit 6c4009
		  default:
Packit 6c4009
		    abort ();
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case DW_OP_abs:
Packit 6c4009
	      if ((_Unwind_Sword) result < 0)
Packit 6c4009
		result = -result;
Packit 6c4009
	      break;
Packit 6c4009
	    case DW_OP_neg:
Packit 6c4009
	      result = -result;
Packit 6c4009
	      break;
Packit 6c4009
	    case DW_OP_not:
Packit 6c4009
	      result = ~result;
Packit 6c4009
	      break;
Packit 6c4009
	    case DW_OP_plus_uconst:
Packit 6c4009
	      op_ptr = read_uleb128 (op_ptr, &utmp);
Packit 6c4009
	      result += utmp;
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      abort ();
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_and:
Packit 6c4009
	case DW_OP_div:
Packit 6c4009
	case DW_OP_minus:
Packit 6c4009
	case DW_OP_mod:
Packit 6c4009
	case DW_OP_mul:
Packit 6c4009
	case DW_OP_or:
Packit 6c4009
	case DW_OP_plus:
Packit 6c4009
	case DW_OP_le:
Packit 6c4009
	case DW_OP_ge:
Packit 6c4009
	case DW_OP_eq:
Packit 6c4009
	case DW_OP_lt:
Packit 6c4009
	case DW_OP_gt:
Packit 6c4009
	case DW_OP_ne:
Packit 6c4009
	  {
Packit 6c4009
	    /* Binary operations.  */
Packit 6c4009
	    _Unwind_Word first, second;
Packit 6c4009
	    if ((stack_elt -= 2) < 0)
Packit 6c4009
	      abort ();
Packit 6c4009
	    second = stack[stack_elt];
Packit 6c4009
	    first = stack[stack_elt + 1];
Packit 6c4009
Packit 6c4009
	    switch (op)
Packit 6c4009
	      {
Packit 6c4009
	      case DW_OP_and:
Packit 6c4009
		result = second & first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_div:
Packit 6c4009
		result = (_Unwind_Sword) second / (_Unwind_Sword) first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_minus:
Packit 6c4009
		result = second - first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_mod:
Packit 6c4009
		result = (_Unwind_Sword) second % (_Unwind_Sword) first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_mul:
Packit 6c4009
		result = second * first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_or:
Packit 6c4009
		result = second | first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_plus:
Packit 6c4009
		result = second + first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_shl:
Packit 6c4009
		result = second << first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_shr:
Packit 6c4009
		result = second >> first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_shra:
Packit 6c4009
		result = (_Unwind_Sword) second >> first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_xor:
Packit 6c4009
		result = second ^ first;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_le:
Packit 6c4009
		result = (_Unwind_Sword) first <= (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_ge:
Packit 6c4009
		result = (_Unwind_Sword) first >= (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_eq:
Packit 6c4009
		result = (_Unwind_Sword) first == (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_lt:
Packit 6c4009
		result = (_Unwind_Sword) first < (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_gt:
Packit 6c4009
		result = (_Unwind_Sword) first > (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
	      case DW_OP_ne:
Packit 6c4009
		result = (_Unwind_Sword) first != (_Unwind_Sword) second;
Packit 6c4009
		break;
Packit 6c4009
Packit 6c4009
	      default:
Packit 6c4009
		abort ();
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_OP_skip:
Packit 6c4009
	  offset = read_2s (op_ptr);
Packit 6c4009
	  op_ptr += 2;
Packit 6c4009
	  op_ptr += offset;
Packit 6c4009
	  goto no_push;
Packit 6c4009
Packit 6c4009
	case DW_OP_bra:
Packit 6c4009
	  if (--stack_elt < 0)
Packit 6c4009
	    abort ();
Packit 6c4009
	  offset = read_2s (op_ptr);
Packit 6c4009
	  op_ptr += 2;
Packit 6c4009
	  if (stack[stack_elt] != 0)
Packit 6c4009
	    op_ptr += offset;
Packit 6c4009
	  goto no_push;
Packit 6c4009
Packit 6c4009
	case DW_OP_nop:
Packit 6c4009
	  goto no_push;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  abort ();
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Most things push a result value.  */
Packit 6c4009
      if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack))
Packit 6c4009
	abort ();
Packit 6c4009
      stack[stack_elt++] = result;
Packit 6c4009
    no_push:;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We were executing this program to get a value.  It should be
Packit 6c4009
     at top of stack.  */
Packit 6c4009
  if (--stack_elt < 0)
Packit 6c4009
    abort ();
Packit 6c4009
  return stack[stack_elt];
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Decode DWARF 2 call frame information. Takes pointers the
Packit 6c4009
   instruction sequence to decode, current register information and
Packit 6c4009
   CIE info, and the PC range to evaluate.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
execute_cfa_program (const unsigned char *insn_ptr,
Packit 6c4009
		     const unsigned char *insn_end,
Packit 6c4009
		     struct _Unwind_Context *context,
Packit 6c4009
		     _Unwind_FrameState *fs)
Packit 6c4009
{
Packit 6c4009
  struct frame_state_reg_info *unused_rs = NULL;
Packit 6c4009
Packit 6c4009
  /* Don't allow remember/restore between CIE and FDE programs.  */
Packit 6c4009
  fs->regs.prev = NULL;
Packit 6c4009
Packit 6c4009
  /* The comparison with the return address uses < rather than <= because
Packit 6c4009
     we are only interested in the effects of code before the call; for a
Packit 6c4009
     noreturn function, the return address may point to unrelated code with
Packit 6c4009
     a different stack configuration that we are not interested in.  We
Packit 6c4009
     assume that the call itself is unwind info-neutral; if not, or if
Packit 6c4009
     there are delay instructions that adjust the stack, these must be
Packit 6c4009
     reflected at the point immediately before the call insn.  */
Packit 6c4009
  while (insn_ptr < insn_end && fs->pc < context->ra)
Packit 6c4009
    {
Packit 6c4009
      unsigned char insn = *insn_ptr++;
Packit 6c4009
      _Unwind_Word reg, utmp;
Packit 6c4009
      _Unwind_Sword offset, stmp;
Packit 6c4009
Packit 6c4009
      if ((insn & 0xc0) == DW_CFA_advance_loc)
Packit 6c4009
	fs->pc += (insn & 0x3f) * fs->code_align;
Packit 6c4009
      else if ((insn & 0xc0) == DW_CFA_offset)
Packit 6c4009
	{
Packit 6c4009
	  reg = insn & 0x3f;
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  offset = (_Unwind_Sword) utmp * fs->data_align;
Packit 6c4009
	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
Packit 6c4009
	  fs->regs.reg[reg].loc.offset = offset;
Packit 6c4009
	}
Packit 6c4009
      else if ((insn & 0xc0) == DW_CFA_restore)
Packit 6c4009
	{
Packit 6c4009
	  reg = insn & 0x3f;
Packit 6c4009
	  fs->regs.reg[reg].how = REG_UNSAVED;
Packit 6c4009
	}
Packit 6c4009
      else switch (insn)
Packit 6c4009
	{
Packit 6c4009
	case DW_CFA_set_loc:
Packit 6c4009
	  {
Packit 6c4009
	    _Unwind_Ptr pc;
Packit 6c4009
	    insn_ptr = read_encoded_value (context, fs->fde_encoding,
Packit 6c4009
					   insn_ptr, &pc);
Packit 6c4009
	    fs->pc = (void *) pc;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_advance_loc1:
Packit 6c4009
	  fs->pc += read_1u (insn_ptr) * fs->code_align;
Packit 6c4009
	  insn_ptr += 1;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_CFA_advance_loc2:
Packit 6c4009
	  fs->pc += read_2u (insn_ptr) * fs->code_align;
Packit 6c4009
	  insn_ptr += 2;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_CFA_advance_loc4:
Packit 6c4009
	  fs->pc += read_4u (insn_ptr) * fs->code_align;
Packit 6c4009
	  insn_ptr += 4;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_offset_extended:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  offset = (_Unwind_Sword) utmp * fs->data_align;
Packit 6c4009
	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
Packit 6c4009
	  fs->regs.reg[reg].loc.offset = offset;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_restore_extended:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  fs->regs.reg[reg].how = REG_UNSAVED;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_undefined:
Packit 6c4009
	case DW_CFA_same_value:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_nop:
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_register:
Packit 6c4009
	  {
Packit 6c4009
	    _Unwind_Word reg2;
Packit 6c4009
	    insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	    insn_ptr = read_uleb128 (insn_ptr, ®2;;
Packit 6c4009
	    fs->regs.reg[reg].how = REG_SAVED_REG;
Packit 6c4009
	    fs->regs.reg[reg].loc.reg = reg2;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_remember_state:
Packit 6c4009
	  {
Packit 6c4009
	    struct frame_state_reg_info *new_rs;
Packit 6c4009
	    if (unused_rs)
Packit 6c4009
	      {
Packit 6c4009
		new_rs = unused_rs;
Packit 6c4009
		unused_rs = unused_rs->prev;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      new_rs = __builtin_alloca (sizeof (struct frame_state_reg_info));
Packit 6c4009
Packit 6c4009
	    *new_rs = fs->regs;
Packit 6c4009
	    fs->regs.prev = new_rs;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_restore_state:
Packit 6c4009
	  {
Packit 6c4009
	    struct frame_state_reg_info *old_rs = fs->regs.prev;
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
	    if (old_rs == NULL)
Packit Service d27742
	      __libc_fatal ("Invalid DWARF unwind data.\n");
Packit 6c4009
	    else
Packit 6c4009
#endif
Packit 6c4009
	      {
Packit 6c4009
		fs->regs = *old_rs;
Packit 6c4009
		old_rs->prev = unused_rs;
Packit 6c4009
		unused_rs = old_rs;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  fs->cfa_offset = utmp;
Packit 6c4009
	  fs->cfa_how = CFA_REG_OFFSET;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa_register:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
Packit 6c4009
	  fs->cfa_how = CFA_REG_OFFSET;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa_offset:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  fs->cfa_offset = utmp;
Packit 6c4009
	  /* cfa_how deliberately not set.  */
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa_expression:
Packit 6c4009
	  fs->cfa_exp = insn_ptr;
Packit 6c4009
	  fs->cfa_how = CFA_EXP;
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  insn_ptr += utmp;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_expression:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  fs->regs.reg[reg].how = REG_SAVED_EXP;
Packit 6c4009
	  fs->regs.reg[reg].loc.exp = insn_ptr;
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  insn_ptr += utmp;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	  /* From the 2.1 draft.  */
Packit 6c4009
	case DW_CFA_offset_extended_sf:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  insn_ptr = read_sleb128 (insn_ptr, &stmp);
Packit 6c4009
	  offset = stmp * fs->data_align;
Packit 6c4009
	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
Packit 6c4009
	  fs->regs.reg[reg].loc.offset = offset;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa_sf:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
Packit 6c4009
	  insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
Packit 6c4009
	  fs->cfa_how = CFA_REG_OFFSET;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_def_cfa_offset_sf:
Packit 6c4009
	  insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
Packit 6c4009
	  /* cfa_how deliberately not set.  */
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_GNU_window_save:
Packit 6c4009
	  /* ??? Hardcoded for SPARC register window configuration.
Packit 6c4009
	     At least do not do anything for archs which explicitly
Packit 6c4009
	     define a lower register number.  */
Packit 6c4009
#if DWARF_FRAME_REGISTERS >= 32
Packit 6c4009
	  for (reg = 16; reg < 32; ++reg)
Packit 6c4009
	    {
Packit 6c4009
	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
Packit 6c4009
	      fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_GNU_args_size:
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &context->args_size);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_CFA_GNU_negative_offset_extended:
Packit 6c4009
	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
Packit 6c4009
	     older PowerPC code.  */
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, ®);
Packit 6c4009
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
Packit 6c4009
	  offset = (_Unwind_Word) utmp * fs->data_align;
Packit 6c4009
	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
Packit 6c4009
	  fs->regs.reg[reg].loc.offset = -offset;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  abort ();
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
Packit 6c4009
   its caller and decode it into FS.  This function also sets the
Packit 6c4009
   args_size and lsda members of CONTEXT, as they are really information
Packit 6c4009
   about the caller's frame.  */
Packit 6c4009
Packit 6c4009
static _Unwind_Reason_Code
Packit 6c4009
uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
Packit 6c4009
{
Packit 6c4009
  struct dwarf_fde *fde;
Packit 6c4009
  struct dwarf_cie *cie;
Packit 6c4009
  const unsigned char *aug, *insn, *end;
Packit 6c4009
Packit 6c4009
  memset (fs, 0, sizeof (*fs));
Packit 6c4009
  context->args_size = 0;
Packit 6c4009
  context->lsda = 0;
Packit 6c4009
Packit 6c4009
  fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
Packit 6c4009
  if (fde == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Couldn't find frame unwind info for this function.  Try a
Packit 6c4009
	 target-specific fallback mechanism.  This will necessarily
Packit 6c4009
	 not provide a personality routine or LSDA.  */
Packit 6c4009
#ifdef MD_FALLBACK_FRAME_STATE_FOR
Packit 6c4009
      MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
Packit 6c4009
      return _URC_END_OF_STACK;
Packit 6c4009
    success:
Packit 6c4009
      return _URC_NO_REASON;
Packit 6c4009
#else
Packit 6c4009
      return _URC_END_OF_STACK;
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fs->pc = context->bases.func;
Packit 6c4009
Packit 6c4009
  cie = get_cie (fde);
Packit 6c4009
  insn = extract_cie_info (cie, context, fs);
Packit 6c4009
  if (insn == NULL)
Packit 6c4009
    /* CIE contained unknown augmentation.  */
Packit 6c4009
    return _URC_FATAL_PHASE1_ERROR;
Packit 6c4009
Packit 6c4009
  /* First decode all the insns in the CIE.  */
Packit 6c4009
  end = (unsigned char *) next_fde ((struct dwarf_fde *) cie);
Packit 6c4009
  execute_cfa_program (insn, end, context, fs);
Packit 6c4009
Packit 6c4009
  /* Locate augmentation for the fde.  */
Packit 6c4009
  aug = (unsigned char *) fde + sizeof (*fde);
Packit 6c4009
  aug += 2 * size_of_encoded_value (fs->fde_encoding);
Packit 6c4009
  insn = NULL;
Packit 6c4009
  if (fs->saw_z)
Packit 6c4009
    {
Packit 6c4009
      _Unwind_Word i;
Packit 6c4009
      aug = read_uleb128 (aug, &i);
Packit 6c4009
      insn = aug + i;
Packit 6c4009
    }
Packit 6c4009
  if (fs->lsda_encoding != DW_EH_PE_omit)
Packit 6c4009
    {
Packit 6c4009
      _Unwind_Ptr lsda;
Packit 6c4009
      aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
Packit 6c4009
      context->lsda = (void *) lsda;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Then the insns in the FDE up to our target PC.  */
Packit 6c4009
  if (insn == NULL)
Packit 6c4009
    insn = aug;
Packit 6c4009
  end = (unsigned char *) next_fde (fde);
Packit 6c4009
  execute_cfa_program (insn, end, context, fs);
Packit 6c4009
Packit 6c4009
  return _URC_NO_REASON;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
typedef struct frame_state
Packit 6c4009
{
Packit 6c4009
  void *cfa;
Packit 6c4009
  void *eh_ptr;
Packit 6c4009
  long cfa_offset;
Packit 6c4009
  long args_size;
Packit 6c4009
  long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
Packit 6c4009
  unsigned short cfa_reg;
Packit 6c4009
  unsigned short retaddr_column;
Packit 6c4009
  char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1];
Packit 6c4009
} frame_state;
Packit 6c4009
Packit 6c4009
#ifndef STATIC
Packit 6c4009
# define STATIC
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
STATIC
Packit 6c4009
struct frame_state * __frame_state_for (void *, struct frame_state *);
Packit 6c4009
Packit 6c4009
/* Called from pre-G++ 3.0 __throw to find the registers to restore for
Packit 6c4009
   a given PC_TARGET.  The caller should allocate a local variable of
Packit 6c4009
   `struct frame_state' and pass its address to STATE_IN.  */
Packit 6c4009
Packit 6c4009
STATIC
Packit 6c4009
struct frame_state *
Packit 6c4009
__frame_state_for (void *pc_target, struct frame_state *state_in)
Packit 6c4009
{
Packit 6c4009
  struct _Unwind_Context context;
Packit 6c4009
  _Unwind_FrameState fs;
Packit 6c4009
  int reg;
Packit 6c4009
Packit 6c4009
  memset (&context, 0, sizeof (struct _Unwind_Context));
Packit 6c4009
  context.ra = pc_target + 1;
Packit 6c4009
Packit 6c4009
  if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* We have no way to pass a location expression for the CFA to our
Packit 6c4009
     caller.  It wouldn't understand it anyway.  */
Packit 6c4009
  if (fs.cfa_how == CFA_EXP)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++)
Packit 6c4009
    {
Packit 6c4009
      state_in->saved[reg] = fs.regs.reg[reg].how;
Packit 6c4009
      switch (state_in->saved[reg])
Packit 6c4009
	{
Packit 6c4009
	case REG_SAVED_REG:
Packit 6c4009
	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg;
Packit 6c4009
	  break;
Packit 6c4009
	case REG_SAVED_OFFSET:
Packit 6c4009
	  state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset;
Packit 6c4009
	  break;
Packit 6c4009
	default:
Packit 6c4009
	  state_in->reg_or_offset[reg] = 0;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  state_in->cfa_offset = fs.cfa_offset;
Packit 6c4009
  state_in->cfa_reg = fs.cfa_reg;
Packit 6c4009
  state_in->retaddr_column = fs.retaddr_column;
Packit 6c4009
  state_in->args_size = context.args_size;
Packit 6c4009
  state_in->eh_ptr = fs.eh_ptr;
Packit 6c4009
Packit 6c4009
  return state_in;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
#ifndef _LIBC
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
Packit 6c4009
{
Packit 6c4009
  struct _Unwind_Context orig_context = *context;
Packit 6c4009
  void *cfa;
Packit 6c4009
  long i;
Packit 6c4009
Packit 6c4009
#ifdef EH_RETURN_STACKADJ_RTX
Packit 6c4009
  /* Special handling here: Many machines do not use a frame pointer,
Packit 6c4009
     and track the CFA only through offsets from the stack pointer from
Packit 6c4009
     one frame to the next.  In this case, the stack pointer is never
Packit 6c4009
     stored, so it has no saved address in the context.  What we do
Packit 6c4009
     have is the CFA from the previous stack frame.
Packit 6c4009
Packit 6c4009
     In very special situations (such as unwind info for signal return),
Packit 6c4009
     there may be location expressions that use the stack pointer as well.
Packit 6c4009
Packit 6c4009
     Do this conditionally for one frame.  This allows the unwind info
Packit 6c4009
     for one frame to save a copy of the stack pointer from the previous
Packit 6c4009
     frame, and be able to use much easier CFA mechanisms to do it.
Packit 6c4009
     Always zap the saved stack pointer value for the next frame; carrying
Packit 6c4009
     the value over from one frame to another doesn't make sense.  */
Packit 6c4009
Packit 6c4009
  _Unwind_Word tmp_sp;
Packit 6c4009
Packit 6c4009
  if (!orig_context.reg[__builtin_dwarf_sp_column ()])
Packit 6c4009
    {
Packit 6c4009
      tmp_sp = (_Unwind_Ptr) context->cfa;
Packit 6c4009
      orig_context.reg[__builtin_dwarf_sp_column ()] = &tmp_sp;
Packit 6c4009
    }
Packit 6c4009
  context->reg[__builtin_dwarf_sp_column ()] = NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Compute this frame's CFA.  */
Packit 6c4009
  switch (fs->cfa_how)
Packit 6c4009
    {
Packit 6c4009
    case CFA_REG_OFFSET:
Packit 6c4009
      cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (&orig_context, fs->cfa_reg);
Packit 6c4009
      cfa += fs->cfa_offset;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case CFA_EXP:
Packit 6c4009
      {
Packit 6c4009
	const unsigned char *exp = fs->cfa_exp;
Packit 6c4009
	_Unwind_Word len;
Packit 6c4009
Packit 6c4009
	exp = read_uleb128 (exp, &len;;
Packit 6c4009
	cfa = (void *) (_Unwind_Ptr)
Packit 6c4009
	  execute_stack_op (exp, exp + len, &orig_context, 0);
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
  context->cfa = cfa;
Packit 6c4009
Packit 6c4009
  /* Compute the addresses of all registers saved in this frame.  */
Packit 6c4009
  for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
Packit 6c4009
    switch (fs->regs.reg[i].how)
Packit 6c4009
      {
Packit 6c4009
      case REG_UNSAVED:
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      case REG_SAVED_OFFSET:
Packit 6c4009
	context->reg[i] = cfa + fs->regs.reg[i].loc.offset;
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      case REG_SAVED_REG:
Packit 6c4009
	context->reg[i] = orig_context.reg[fs->regs.reg[i].loc.reg];
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      case REG_SAVED_EXP:
Packit 6c4009
	{
Packit 6c4009
	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
Packit 6c4009
	  _Unwind_Word len;
Packit 6c4009
	  _Unwind_Ptr val;
Packit 6c4009
Packit 6c4009
	  exp = read_uleb128 (exp, &len;;
Packit 6c4009
	  val = execute_stack_op (exp, exp + len, &orig_context,
Packit 6c4009
				  (_Unwind_Ptr) cfa);
Packit 6c4009
	  context->reg[i] = (void *) val;
Packit 6c4009
	}
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
Packit 6c4009
   of its caller.  Update CONTEXT to refer to the caller as well.  Note
Packit 6c4009
   that the args_size and lsda members are not updated here, but later in
Packit 6c4009
   uw_frame_state_for.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
Packit 6c4009
{
Packit 6c4009
  uw_update_context_1 (context, fs);
Packit 6c4009
Packit 6c4009
  /* Compute the return address now, since the return address column
Packit 6c4009
     can change from frame to frame.  */
Packit 6c4009
  context->ra = __builtin_extract_return_addr
Packit 6c4009
    ((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Fill in CONTEXT for top-of-stack.  The only valid registers at this
Packit 6c4009
   level will be the return address and the CFA.  */
Packit 6c4009
Packit 6c4009
#define uw_init_context(CONTEXT)					   \
Packit 6c4009
  do									   \
Packit 6c4009
    {									   \
Packit 6c4009
      /* Do any necessary initialization to access arbitrary stack frames. \
Packit 6c4009
	 On the SPARC, this means flushing the register windows.  */	   \
Packit 6c4009
      __builtin_unwind_init ();						   \
Packit 6c4009
      uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),		   \
Packit 6c4009
			 __builtin_return_address (0));			   \
Packit 6c4009
    }									   \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
uw_init_context_1 (struct _Unwind_Context *context,
Packit 6c4009
		   void *outer_cfa, void *outer_ra)
Packit 6c4009
{
Packit 6c4009
  void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
Packit 6c4009
  _Unwind_FrameState fs;
Packit 6c4009
  _Unwind_Word sp_slot;
Packit 6c4009
Packit 6c4009
  memset (context, 0, sizeof (struct _Unwind_Context));
Packit 6c4009
  context->ra = ra;
Packit 6c4009
Packit 6c4009
  if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  /* Force the frame state to use the known cfa value.  */
Packit 6c4009
  sp_slot = (_Unwind_Ptr) outer_cfa;
Packit 6c4009
  context->reg[__builtin_dwarf_sp_column ()] = &sp_slot;
Packit 6c4009
  fs.cfa_how = CFA_REG_OFFSET;
Packit 6c4009
  fs.cfa_reg = __builtin_dwarf_sp_column ();
Packit 6c4009
  fs.cfa_offset = 0;
Packit 6c4009
Packit 6c4009
  uw_update_context_1 (context, &fs);
Packit 6c4009
Packit 6c4009
  /* If the return address column was saved in a register in the
Packit 6c4009
     initialization context, then we can't see it in the given
Packit 6c4009
     call frame data.  So have the initialization context tell us.  */
Packit 6c4009
  context->ra = __builtin_extract_return_addr (outer_ra);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Install TARGET into CURRENT so that we can return to it.  This is a
Packit 6c4009
   macro because __builtin_eh_return must be invoked in the context of
Packit 6c4009
   our caller.  */
Packit 6c4009
Packit 6c4009
#define uw_install_context(CURRENT, TARGET)				 \
Packit 6c4009
  do									 \
Packit 6c4009
    {									 \
Packit 6c4009
      long offset = uw_install_context_1 ((CURRENT), (TARGET));		 \
Packit 6c4009
      void *handler = __builtin_frob_return_addr ((TARGET)->ra);	 \
Packit 6c4009
      __builtin_eh_return (offset, handler);				 \
Packit 6c4009
    }									 \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
init_dwarf_reg_size_table (void)
Packit 6c4009
{
Packit 6c4009
  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static long
Packit 6c4009
uw_install_context_1 (struct _Unwind_Context *current,
Packit 6c4009
		      struct _Unwind_Context *target)
Packit 6c4009
{
Packit 6c4009
  long i;
Packit 6c4009
Packit 6c4009
#if __GTHREADS
Packit 6c4009
  {
Packit 6c4009
    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
Packit 6c4009
    if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
Packit 6c4009
	|| dwarf_reg_size_table[0] == 0)
Packit 6c4009
      init_dwarf_reg_size_table ();
Packit 6c4009
  }
Packit 6c4009
#else
Packit 6c4009
  if (dwarf_reg_size_table[0] == 0)
Packit 6c4009
    init_dwarf_reg_size_table ();
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
Packit 6c4009
    {
Packit 6c4009
      void *c = current->reg[i];
Packit 6c4009
      void *t = target->reg[i];
Packit 6c4009
      if (t && c && t != c)
Packit 6c4009
	memcpy (c, t, dwarf_reg_size_table[i]);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef EH_RETURN_STACKADJ_RTX
Packit 6c4009
  {
Packit 6c4009
    void *target_cfa;
Packit 6c4009
Packit 6c4009
    /* If the last frame records a saved stack pointer, use it.  */
Packit 6c4009
    if (target->reg[__builtin_dwarf_sp_column ()])
Packit 6c4009
      target_cfa = (void *)(_Unwind_Ptr)
Packit 6c4009
        _Unwind_GetGR (target, __builtin_dwarf_sp_column ());
Packit 6c4009
    else
Packit 6c4009
      target_cfa = target->cfa;
Packit 6c4009
Packit 6c4009
    /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
Packit 6c4009
    if (STACK_GROWS_DOWNWARD)
Packit 6c4009
      return target_cfa - current->cfa + target->args_size;
Packit 6c4009
    else
Packit 6c4009
      return current->cfa - target_cfa - target->args_size;
Packit 6c4009
  }
Packit 6c4009
#else
Packit 6c4009
  return 0;
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline _Unwind_Ptr
Packit 6c4009
uw_identify_context (struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  return _Unwind_GetIP (context);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include "unwind.inc"
Packit 6c4009
Packit 6c4009
#endif /* _LIBC */