OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / unwind-dw2.c
index 6eb163d..e013ce6 100644 (file)
@@ -1,27 +1,28 @@
 /* DWARF2 exception handling and frame unwind runtime interface routines.
    Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include "tconfig.h"
 #include "tsystem.h"
 #include "dwarf2.h"
 #include "unwind.h"
+#include "unwind-pe.h"
 #include "unwind-dw2-fde.h"
 #include "gthr.h"
 
@@ -67,9 +68,9 @@ typedef struct
   {
     struct {
       union {
-       unsigned int reg;
+       _Unwind_Word reg;
        _Unwind_Sword offset;
-       unsigned char *exp;
+       const unsigned char *exp;
       } loc;
       enum {
        REG_UNSAVED,
@@ -87,7 +88,7 @@ typedef struct
      location expression.  */
   _Unwind_Sword cfa_offset;
   _Unwind_Word cfa_reg;
-  unsigned char *cfa_exp;
+  const unsigned char *cfa_exp;
   enum {
     CFA_UNSET,
     CFA_REG_OFFSET,
@@ -99,60 +100,15 @@ typedef struct
 
   /* The information we care about from the CIE/FDE.  */
   _Unwind_Personality_Fn personality;
-  signed int data_align;
-  unsigned int code_align;
+  _Unwind_Sword data_align;
+  _Unwind_Word code_align;
   unsigned char retaddr_column;
-  unsigned char addr_encoding;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
   unsigned char saw_z;
-  unsigned char saw_lsda;
+  void *eh_ptr;
 } _Unwind_FrameState;
 \f
-/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
-   by R, and return the new value of BUF.  */
-
-static unsigned char *
-read_uleb128 (unsigned char *buf, _Unwind_Word *r)
-{
-  unsigned shift = 0;
-  _Unwind_Word result = 0;
-
-  while (1)
-    {
-      unsigned char byte = *buf++;
-      result |= (byte & 0x7f) << shift;
-      if ((byte & 0x80) == 0)
-       break;
-      shift += 7;
-    }
-  *r = result;
-  return buf;
-}
-
-/* Decode the signed LEB128 constant at BUF into the variable pointed to
-   by R, and return the new value of BUF.  */
-
-static unsigned char *
-read_sleb128 (unsigned char *buf, _Unwind_Sword *r)
-{
-  unsigned shift = 0;
-  _Unwind_Sword result = 0;
-  unsigned char byte;
-
-  while (1)
-    {
-      byte = *buf++;
-      result |= (byte & 0x7f) << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-       break;
-    }
-  if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
-    result |= - (1 << shift);
-
-  *r = result;
-  return buf;
-}
-
 /* Read unaligned data from the instruction buffer.  */
 
 union unaligned
@@ -167,107 +123,31 @@ union unaligned
 } __attribute__ ((packed));
 
 static inline void *
-read_pointer (void *p) { union unaligned *up = p; return up->p; }
+read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
 
 static inline int
-read_1u (void *p) { return *(unsigned char *)p; }
+read_1u (const void *p) { return *(const unsigned char *)p; }
 
 static inline int
-read_1s (void *p) { return *(signed char *)p; }
+read_1s (const void *p) { return *(const signed char *)p; }
 
 static inline int
-read_2u (void *p) { union unaligned *up = p; return up->u2; }
+read_2u (const void *p) { const union unaligned *up = p; return up->u2; }
 
 static inline int
-read_2s (void *p) { union unaligned *up = p; return up->s2; }
+read_2s (const void *p) { const union unaligned *up = p; return up->s2; }
 
 static inline unsigned int
-read_4u (void *p) { union unaligned *up = p; return up->u4; }
+read_4u (const void *p) { const union unaligned *up = p; return up->u4; }
 
 static inline int
-read_4s (void *p) { union unaligned *up = p; return up->s4; }
+read_4s (const void *p) { const union unaligned *up = p; return up->s4; }
 
 static inline unsigned long
-read_8u (void *p) { union unaligned *up = p; return up->u8; }
+read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
 
 static inline unsigned long
-read_8s (void *p) { union unaligned *up = p; return up->s8; }
-
-static unsigned char *
-read_encoded_pointer (unsigned char *p, unsigned char encoding,
-                     struct dwarf_eh_bases *bases, void **pptr)
-{
-  signed long val;
-  unsigned char *ret;
-  
-  switch (encoding & 0x0f)
-    {
-    case DW_EH_PE_absptr:
-      val = (_Unwind_Ptr) read_pointer (p);
-      ret = p + sizeof (void *);
-      break;
-
-    case DW_EH_PE_uleb128:
-      ret = read_uleb128 (p, &val);
-      break;
-    case DW_EH_PE_sleb128:
-      ret = read_sleb128 (p, &val);
-      break;
-
-    case DW_EH_PE_udata2:
-      val = read_2u (p);
-      ret = p + 2;
-      break;
-    case DW_EH_PE_udata4:
-      val = read_4u (p);
-      ret = p + 4;
-      break;
-    case DW_EH_PE_udata8:
-      val = read_8u (p);
-      ret = p + 8;
-      break;
-
-    case DW_EH_PE_sdata2:
-      val = read_2s (p);
-      ret = p + 2;
-      break;
-    case DW_EH_PE_sdata4:
-      val = read_4s (p);
-      ret = p + 4;
-      break;
-    case DW_EH_PE_sdata8:
-      val = read_8s (p);
-      ret = p + 8;
-      break;
-
-    default:
-      abort ();
-    }
-
-  if (val != 0)
-    switch (encoding & 0xf0)
-      {
-      case DW_EH_PE_absptr:
-       break;
-      case DW_EH_PE_pcrel:
-       val += (_Unwind_Ptr) p;
-       break;
-      case DW_EH_PE_textrel:
-       val += (_Unwind_Ptr) bases->tbase;
-       break;
-      case DW_EH_PE_datarel:
-       val += (_Unwind_Ptr) bases->dbase;
-       break;
-      case DW_EH_PE_funcrel:
-       val += (_Unwind_Ptr) bases->func;
-       break;
-      default:
-       abort ();
-      }
-
-  *pptr = (void *) (_Unwind_Ptr) val;
-  return ret;
-}
+read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
 \f
 /* Get the value of register REG as saved in CONTEXT.  */
 
@@ -332,32 +212,38 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context)
    unit F belongs to.  Return a pointer to the byte after the augmentation,
    or NULL if we encountered an undecipherable augmentation.  */
 
-static unsigned char *
+static const unsigned char *
 extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
                  _Unwind_FrameState *fs)
 {
-  unsigned char *aug = cie->augmentation;
-  unsigned char *p = aug + strlen (aug) + 1;
-  unsigned char *ret = NULL;
-  _Unwind_Word code_align;
-  _Unwind_Sword data_align;
+  const unsigned char *aug = cie->augmentation;
+  const unsigned char *p = aug + strlen (aug) + 1;
+  const unsigned char *ret = NULL;
+  _Unwind_Word utmp;
+
+  /* g++ v2 "eh" has pointer immediately following augmentation string,
+     so it must be handled first.  */
+  if (aug[0] == 'e' && aug[1] == 'h')
+    {
+      fs->eh_ptr = read_pointer (p);
+      p += sizeof (void *);
+      aug += 2;
+    }
 
   /* Immediately following the augmentation are the code and
      data alignment and return address column.  */
-  p = read_uleb128 (p, &code_align);
-  p = read_sleb128 (p, &data_align);
-  fs->code_align = code_align;
-  fs->data_align = data_align;
+  p = read_uleb128 (p, &fs->code_align);
+  p = read_sleb128 (p, &fs->data_align);
   fs->retaddr_column = *p++;
+  fs->lsda_encoding = DW_EH_PE_omit;
 
   /* If the augmentation starts with 'z', then a uleb128 immediately
      follows containing the length of the augmentation field following
      the size.  */
   if (*aug == 'z')
     {
-      _Unwind_Word i;
-      p = read_uleb128 (p, &i);
-      ret = p + i;
+      p = read_uleb128 (p, &utmp);
+      ret = p + utmp;
 
       fs->saw_z = 1;
       ++aug;
@@ -366,27 +252,25 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
   /* Iterate over recognized augmentation subsequences.  */
   while (*aug != '\0')
     {
-      /* "eh" was used by g++ v2; recognize and skip.  */
-      if (aug[0] == 'e' && aug[1] == 'h')
+      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
+      if (aug[0] == 'L')
        {
-         p += sizeof (void *);
-         aug += 2;
+         fs->lsda_encoding = *p++;
+         aug += 1;
        }
 
-      /* "R" indicates a byte indicating how addresses are encoded.  */
+      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
       else if (aug[0] == 'R')
        {
-         fs->addr_encoding = *p++;
+         fs->fde_encoding = *p++;
          aug += 1;
        }
 
-      /* "P" indicates a personality routine in the CIE augmentation
-        and an lsda pointer in the FDE augmentation.  */
+      /* "P" indicates a personality routine in the CIE augmentation.  */
       else if (aug[0] == 'P')
        {
-         p = read_encoded_pointer (p, fs->addr_encoding, &context->bases,
-                                   (void **) &fs->personality);
-         fs->saw_lsda = 1;
+         p = read_encoded_value (context, *p, p + 1,
+                                 (_Unwind_Ptr *) &fs->personality);
          aug += 1;
        }
 
@@ -404,10 +288,10 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
    onto the stack to start.  */
 
 static _Unwind_Word
-execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
+execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
                  struct _Unwind_Context *context, _Unwind_Word initial)
 {
-  _Unwind_Word stack[64];      /* ??? Assume this is enough. */
+  _Unwind_Word stack[64];      /* ??? Assume this is enough.  */
   int stack_elt;
 
   stack[0] = initial;
@@ -416,8 +300,8 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
   while (op_ptr < op_end)
     {
       enum dwarf_location_atom op = *op_ptr++;
-      _Unwind_Word result, reg;
-      _Unwind_Sword offset;
+      _Unwind_Word result, reg, utmp;
+      _Unwind_Sword offset, stmp;
 
       switch (op)
        {
@@ -497,8 +381,8 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
          op_ptr = read_uleb128 (op_ptr, &result);
          break;
        case DW_OP_consts:
-         op_ptr = read_sleb128 (op_ptr, &offset);
-         result = offset;
+         op_ptr = read_sleb128 (op_ptr, &stmp);
+         result = stmp;
          break;
 
        case DW_OP_reg0:
@@ -674,9 +558,12 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
              result = ~result;
              break;
            case DW_OP_plus_uconst:
-             op_ptr = read_uleb128 (op_ptr, &reg);
-             result += reg;
+             op_ptr = read_uleb128 (op_ptr, &utmp);
+             result += utmp;
              break;
+
+           default:
+             abort ();
            }
          break;
 
@@ -754,6 +641,9 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
            case DW_OP_ne:
              result = (_Unwind_Sword)first != (_Unwind_Sword)second;
              break;
+
+           default:
+             abort ();
            }
          }
          break;
@@ -800,8 +690,10 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
    CIE info, and the PC range to evaluate.  */
 
 static void
-execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
-                    struct _Unwind_Context *context, _Unwind_FrameState *fs)
+execute_cfa_program (const unsigned char *insn_ptr,
+                    const unsigned char *insn_end,
+                    struct _Unwind_Context *context,
+                    _Unwind_FrameState *fs)
 {
   struct frame_state_reg_info *unused_rs = NULL;
 
@@ -811,16 +703,16 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
   while (insn_ptr < insn_end && fs->pc < context->ra)
     {
       unsigned char insn = *insn_ptr++;
-      _Unwind_Word reg, uoffset;
-      _Unwind_Sword offset;
+      _Unwind_Word reg, utmp;
+      _Unwind_Sword offset, stmp;
 
       if (insn & DW_CFA_advance_loc)
        fs->pc += (insn & 0x3f) * fs->code_align;
       else if (insn & DW_CFA_offset)
        {
          reg = insn & 0x3f;
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
-         offset = (_Unwind_Sword)uoffset * fs->data_align;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         offset = (_Unwind_Sword)utmp * fs->data_align;
          fs->regs.reg[reg].how = REG_SAVED_OFFSET;
          fs->regs.reg[reg].loc.offset = offset;
        }
@@ -832,27 +724,27 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
       else switch (insn)
        {
        case DW_CFA_set_loc:
-         insn_ptr = read_encoded_pointer (insn_ptr, fs->addr_encoding,
-                                          &context->bases, &fs->pc);
+         insn_ptr = read_encoded_value (context, fs->fde_encoding,
+                                        insn_ptr, (_Unwind_Ptr *) &fs->pc);
          break;
 
        case DW_CFA_advance_loc1:
-         fs->pc += read_1u (insn_ptr);
+         fs->pc += read_1u (insn_ptr) * fs->code_align;
          insn_ptr += 1;
          break;
        case DW_CFA_advance_loc2:
-         fs->pc += read_2u (insn_ptr);
+         fs->pc += read_2u (insn_ptr) * fs->code_align;
          insn_ptr += 2;
          break;
        case DW_CFA_advance_loc4:
-         fs->pc += read_4u (insn_ptr);
+         fs->pc += read_4u (insn_ptr) * fs->code_align;
          insn_ptr += 4;
          break;
 
        case DW_CFA_offset_extended:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
-         offset = (_Unwind_Sword)uoffset * fs->data_align;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         offset = (_Unwind_Sword)utmp * fs->data_align;
          fs->regs.reg[reg].how = REG_SAVED_OFFSET;
          fs->regs.reg[reg].loc.offset = offset;
          break;
@@ -886,7 +778,7 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
                unused_rs = unused_rs->prev;
              }
            else
-             new_rs = alloca (sizeof (struct frame_state_reg_info));
+             new_rs = __builtin_alloca (sizeof (struct frame_state_reg_info));
 
            *new_rs = fs->regs;
            fs->regs.prev = new_rs;
@@ -904,8 +796,8 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
 
        case DW_CFA_def_cfa:
          insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
-         fs->cfa_offset = uoffset;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         fs->cfa_offset = utmp;
          fs->cfa_how = CFA_REG_OFFSET;
          break;
 
@@ -915,31 +807,31 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
          break;
 
        case DW_CFA_def_cfa_offset:
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
-         fs->cfa_offset = uoffset;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         fs->cfa_offset = utmp;
          /* cfa_how deliberately not set.  */
          break;
 
        case DW_CFA_def_cfa_expression:
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
          fs->cfa_exp = insn_ptr;
          fs->cfa_how = CFA_EXP;
-         insn_ptr += uoffset;
+         insn_ptr += utmp;
          break;
 
        case DW_CFA_expression:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
          fs->regs.reg[reg].how = REG_SAVED_EXP;
          fs->regs.reg[reg].loc.exp = insn_ptr;
-         insn_ptr += uoffset;
+         insn_ptr += utmp;
          break;
 
          /* From the 2.1 draft.  */
        case DW_CFA_offset_extended_sf:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         insn_ptr = read_sleb128 (insn_ptr, &offset);
-         offset *= fs->data_align;
+         insn_ptr = read_sleb128 (insn_ptr, &stmp);
+         offset = stmp * fs->data_align;
          fs->regs.reg[reg].how = REG_SAVED_OFFSET;
          fs->regs.reg[reg].loc.offset = offset;
          break;
@@ -951,7 +843,7 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
          break;
 
        case DW_CFA_def_cfa_offset_sf:
-         insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_offset);
+         insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
          /* cfa_how deliberately not set.  */
          break;
 
@@ -972,8 +864,8 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
          /* Obsoleted by DW_CFA_offset_extended_sf, but used by
             older PowerPC code.  */
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         insn_ptr = read_uleb128 (insn_ptr, &uoffset);
-         offset = (_Unwind_Sword)uoffset * fs->data_align;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         offset = (_Unwind_Word)utmp * fs->data_align;
          fs->regs.reg[reg].how = REG_SAVED_OFFSET;
          fs->regs.reg[reg].loc.offset = -offset;
          break;
@@ -989,7 +881,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
   struct dwarf_fde *fde;
   struct dwarf_cie *cie;
-  unsigned char *aug, *insn, *end;
+  const unsigned char *aug, *insn, *end;
 
   memset (fs, 0, sizeof (*fs));
   context->args_size = 0;
@@ -1000,7 +892,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     {
       /* Couldn't find frame unwind info for this function.  Try a
         target-specific fallback mechanism.  This will necessarily
-        not profide a personality routine or LSDA.  */
+        not provide a personality routine or LSDA.  */
 #ifdef MD_FALLBACK_FRAME_STATE_FOR
       MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
       return _URC_END_OF_STACK;
@@ -1011,8 +903,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 #endif
     }
 
-  context->bases.func = fde->pc_begin;
-  fs->pc = fde->pc_begin;
+  fs->pc = context->bases.func;
 
   cie = get_cie (fde);
   insn = extract_cie_info (cie, context, fs);
@@ -1026,6 +917,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 
   /* Locate augmentation for the fde.  */
   aug = (unsigned char *)fde + sizeof (*fde);
+  aug += 2 * size_of_encoded_value (fs->fde_encoding);
   insn = NULL;
   if (fs->saw_z)
     {
@@ -1033,9 +925,9 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
       aug = read_uleb128 (aug, &i);
       insn = aug + i;
     }
-  if (fs->saw_lsda)
-    aug = read_encoded_pointer (aug, fs->addr_encoding,
-                               &context->bases, &context->lsda);
+  if (fs->lsda_encoding != DW_EH_PE_omit)
+    aug = read_encoded_value (context, fs->lsda_encoding, aug,
+                             (_Unwind_Ptr *) &context->lsda);
 
   /* Then the insns in the FDE up to our target PC.  */
   if (insn == NULL)
@@ -1045,8 +937,69 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 
   return _URC_NO_REASON;
 }
+\f
+typedef struct frame_state
+{
+  void *cfa;
+  void *eh_ptr;
+  long cfa_offset;
+  long args_size;
+  long reg_or_offset[DWARF_FRAME_REGISTERS+1];
+  unsigned short cfa_reg;
+  unsigned short retaddr_column;
+  char saved[DWARF_FRAME_REGISTERS+1];
+} frame_state;
+
+struct frame_state * __frame_state_for (void *, struct frame_state *);
+
+/* Called from pre-G++ 3.0 __throw to find the registers to restore for
+   a given PC_TARGET.  The caller should allocate a local variable of
+   `struct frame_state' and pass its address to STATE_IN.  */
+
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+{
+  struct _Unwind_Context context;
+  _Unwind_FrameState fs;
+  int reg;
+
+  memset (&context, 0, sizeof (struct _Unwind_Context));
+  context.ra = pc_target + 1;
+
+  if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
+    return 0;
+
+  /* We have no way to pass a location expression for the CFA to our
+     caller.  It wouldn't understand it anyway.  */
+  if (fs.cfa_how == CFA_EXP)
+    return 0;
+
+  for (reg = 0; reg < DWARF_FRAME_REGISTERS + 1; reg++)
+    {
+      state_in->saved[reg] = fs.regs.reg[reg].how;
+      switch (state_in->saved[reg])
+       {
+       case REG_SAVED_REG:
+         state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg;
+         break;
+       case REG_SAVED_OFFSET:
+         state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset;
+         break;
+       default:
+         state_in->reg_or_offset[reg] = 0;
+         break;
+       }
+    }
 
+  state_in->cfa_offset = fs.cfa_offset;
+  state_in->cfa_reg = fs.cfa_reg;
+  state_in->retaddr_column = fs.retaddr_column;
+  state_in->args_size = context.args_size;
+  state_in->eh_ptr = fs.eh_ptr;
 
+  return state_in;
+}
+\f
 static void
 uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
@@ -1076,7 +1029,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
         CFA calculation is so complicated as to require a stack program
         that this will not be a problem.  */
       {
-       unsigned char *exp = fs->cfa_exp;
+       const unsigned char *exp = fs->cfa_exp;
        _Unwind_Word len;
 
        exp = read_uleb128 (exp, &len);
@@ -1104,7 +1057,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        break;
       case REG_SAVED_EXP:
        {
-         unsigned char *exp = fs->regs.reg[i].loc.exp;
+         const unsigned char *exp = fs->regs.reg[i].loc.exp;
          _Unwind_Word len;
          _Unwind_Ptr val;