OSDN Git Service

* unwind-dw2.h (_Unwind_FrameState): Add REG_SAVED_VAL_OFFSET
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 4 Mar 2006 07:07:12 +0000 (07:07 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 4 Mar 2006 07:07:12 +0000 (07:07 +0000)
and REG_SAVED_VAL_EXP constants.
* unwind-dw2.c (struct _Unwind_Context): Add by_value array.
(_Unwind_GetGR, _Unwind_SetGR, _Unwind_GetGRPtr, _Unwind_SetGRPtr):
Handle regs stored by value.
(_Unwind_SetGRValue, _Unwind_GRByValue): New functions.
(execute_cfa_program): Handle DW_CFA_val_offset,
DW_CFA_val_offset_sf and DW_CFA_val_expression.
(uw_update_context_1): Handle REG_SAVED_REG with regs stored by
value specially.  Handle REG_SAVED_VAL_OFFSET and REG_SAVED_VAL_EXP.
(uw_install_context_1): Handle target regs stored by value.

* gcc.target/i386/cleanup-1.c: New test.
* gcc.target/i386/cleanup-2.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111705 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/cleanup-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/cleanup-2.c [new file with mode: 0644]
gcc/unwind-dw2.c
gcc/unwind-dw2.h

index 07edcc3..c3c2ae3 100644 (file)
@@ -1,3 +1,17 @@
+2006-03-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * unwind-dw2.h (_Unwind_FrameState): Add REG_SAVED_VAL_OFFSET
+       and REG_SAVED_VAL_EXP constants.
+       * unwind-dw2.c (struct _Unwind_Context): Add by_value array.
+       (_Unwind_GetGR, _Unwind_SetGR, _Unwind_GetGRPtr, _Unwind_SetGRPtr):
+       Handle regs stored by value.
+       (_Unwind_SetGRValue, _Unwind_GRByValue): New functions.
+       (execute_cfa_program): Handle DW_CFA_val_offset,
+       DW_CFA_val_offset_sf and DW_CFA_val_expression.
+       (uw_update_context_1): Handle REG_SAVED_REG with regs stored by
+       value specially.  Handle REG_SAVED_VAL_OFFSET and REG_SAVED_VAL_EXP.
+       (uw_install_context_1): Handle target regs stored by value.
+
 2006-03-03  Daniel Berlin  <dberlin@dberlin.org>
 
        * tree-sra.c (tree_sra): Return todoflags;
index b74f6d1..9437945 100644 (file)
@@ -1,3 +1,8 @@
+2006-03-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.target/i386/cleanup-1.c: New test.
+       * gcc.target/i386/cleanup-2.c: New test.
+
 2006-03-04  Roger Sayle  <roger@eyesopen.com>
 
        * gfortran.dg/dependency_9.f90: Remove for the time being.
diff --git a/gcc/testsuite/gcc.target/i386/cleanup-1.c b/gcc/testsuite/gcc.target/i386/cleanup-1.c
new file mode 100644 (file)
index 0000000..afc1e0a
--- /dev/null
@@ -0,0 +1,240 @@
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -fasynchronous-unwind-tables -O2" } */
+/* Test complex CFA value expressions.  */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+                  _Unwind_Exception_Class exc_class,
+                  struct _Unwind_Exception *exc_obj,
+                  struct _Unwind_Context *context,
+                  void *stop_parameter)
+{
+  if (actions & _UA_END_OF_STACK)
+    abort ();
+  return _URC_NO_REASON;
+}
+
+static void
+force_unwind ()
+{
+  struct _Unwind_Exception *exc = malloc (sizeof (*exc));
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+  exc->exception_cleanup = 0;
+
+  _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+  abort ();
+}
+
+int count;
+
+static void
+counter (void *p __attribute__((unused)))
+{
+  ++count;
+}
+
+static void
+handler (void *p __attribute__((unused)))
+{
+  if (count != 2)
+    abort ();
+  _exit (0);
+}
+
+static int __attribute__((noinline))
+fn5 (void)
+{
+  char dummy __attribute__((cleanup (counter)));
+  force_unwind ();
+  return 0;
+}
+
+void
+bar (void)
+{
+  char dummy __attribute__((cleanup (counter)));
+  fn5 ();
+}
+
+void __attribute__((noinline))
+foo (int x)
+{
+  char buf[256];
+#ifdef __i386__
+  __asm (
+       "testl  %0, %0\n\t"
+       "jnz    1f\n\t"
+       ".subsection 1\n\t"
+       ".type  _L_mutex_lock_%=, @function\n"
+"_L_mutex_lock_%=:\n"
+"1:\t" "leal   %1, %%ecx\n"
+"2:\t" "call   bar\n"
+"3:\t" "jmp    18f\n"
+"4:\t" ".size _L_mutex_lock_%=, .-_L_mutex_lock_%=\n\t"
+       ".previous\n\t"
+       ".section       .eh_frame,\"a\",@progbits\n"
+"5:\t" ".long  7f-6f   # Length of Common Information Entry\n"
+"6:\t" ".long  0x0     # CIE Identifier Tag\n\t"
+       ".byte  0x1     # CIE Version\n\t"
+       ".ascii \"zR\\0\"       # CIE Augmentation\n\t"
+       ".uleb128 0x1   # CIE Code Alignment Factor\n\t"
+       ".sleb128 -4    # CIE Data Alignment Factor\n\t"
+       ".byte  0x8     # CIE RA Column\n\t"
+       ".uleb128 0x1   # Augmentation size\n\t"
+       ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"
+       ".byte  0xc     # DW_CFA_def_cfa\n\t"
+       ".uleb128 0x4\n\t"
+       ".uleb128 0x0\n\t"
+       ".align 4\n"
+"7:\t" ".long  17f-8f  # FDE Length\n"
+"8:\t" ".long  8b-5b   # FDE CIE offset\n\t"
+       ".long  1b-.    # FDE initial location\n\t"
+       ".long  4b-1b   # FDE address range\n\t"
+       ".uleb128 0x0   # Augmentation size\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x8\n\t"
+       ".uleb128 10f-9f\n"
+"9:\t" ".byte  0x78    # DW_OP_breg8\n\t"
+       ".sleb128 3b-1b\n"
+"10:\t"        ".byte  0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x8\n\t"
+       ".uleb128 12f-11f\n"
+"11:\t"        ".byte  0x78    # DW_OP_breg8\n\t"
+       ".sleb128 3b-2b\n"
+"12:\t"        ".byte  0x40 + (3b-2b-1) # DW_CFA_advance_loc\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x8\n\t"
+       ".uleb128 16f-13f\n"
+"13:\t"        ".byte  0x78    # DW_OP_breg8\n\t"
+       ".sleb128 15f-14f\n\t"
+       ".byte  0x0d    # DW_OP_const4s\n"
+"14:\t"        ".4byte 3b-.\n\t"
+       ".byte  0x1c    # DW_OP_minus\n\t"
+       ".byte  0x0d    # DW_OP_const4s\n"
+"15:\t"        ".4byte 18f-.\n\t"
+       ".byte  0x22    # DW_OP_plus\n"
+"16:\t"        ".align 4\n"
+"17:\t"        ".previous\n"
+"18:"
+       : : "r" (x), "m" (x), "r" (buf)
+       : "memory", "eax", "edx", "ecx");
+#elif defined __x86_64__
+  __asm (
+       "testl  %0, %0\n\t"
+       "jnz    1f\n\t"
+       ".subsection 1\n\t"
+       ".type  _L_mutex_lock_%=, @function\n"
+"_L_mutex_lock_%=:\n"
+"1:\t" "leaq   %1, %%rdi\n"
+"2:\t" "subq   $128, %%rsp\n"
+"3:\t" "call   bar\n"
+"4:\t" "addq   $128, %%rsp\n"
+"5:\t" "jmp    24f\n"
+"6:\t" ".size _L_mutex_lock_%=, .-_L_mutex_lock_%=\n\t"
+       ".previous\n\t"
+       ".section       .eh_frame,\"a\",@progbits\n"
+"7:\t" ".long  9f-8f   # Length of Common Information Entry\n"
+"8:\t" ".long  0x0     # CIE Identifier Tag\n\t"
+       ".byte  0x1     # CIE Version\n\t"
+       ".ascii \"zR\\0\"       # CIE Augmentation\n\t"
+       ".uleb128 0x1   # CIE Code Alignment Factor\n\t"
+       ".sleb128 -8    # CIE Data Alignment Factor\n\t"
+       ".byte  0x10    # CIE RA Column\n\t"
+       ".uleb128 0x1   # Augmentation size\n\t"
+       ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"
+       ".byte  0x12    # DW_CFA_def_cfa_sf\n\t"
+       ".uleb128 0x7\n\t"
+       ".sleb128 16\n\t"
+       ".align 8\n"
+"9:\t" ".long  23f-10f # FDE Length\n"
+"10:\t"        ".long  10b-7b  # FDE CIE offset\n\t"
+       ".long  1b-.    # FDE initial location\n\t"
+       ".long  6b-1b   # FDE address range\n\t"
+       ".uleb128 0x0   # Augmentation size\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 12f-11f\n"
+"11:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 4b-1b\n"
+"12:\t"        ".byte  0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 14f-13f\n"
+"13:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 4b-2b\n"
+"14:\t"        ".byte  0x40 + (3b-2b) # DW_CFA_advance_loc\n\t"
+       ".byte  0x0e    # DW_CFA_def_cfa_offset\n\t"
+       ".uleb128 0\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 16f-15f\n"
+"15:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 4b-3b\n"
+"16:\t"        ".byte  0x40 + (4b-3b-1) # DW_CFA_advance_loc\n\t"
+       ".byte  0x0e    # DW_CFA_def_cfa_offset\n\t"
+       ".uleb128 128\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 20f-17f\n"
+"17:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 19f-18f\n\t"
+       ".byte  0x0d    # DW_OP_const4s\n"
+"18:\t"        ".4byte 4b-.\n\t"
+       ".byte  0x1c    # DW_OP_minus\n\t"
+       ".byte  0x0d    # DW_OP_const4s\n"
+"19:\t"        ".4byte 24f-.\n\t"
+       ".byte  0x22    # DW_OP_plus\n"
+"20:\t"        ".byte  0x40 + (5b-4b+1) # DW_CFA_advance_loc\n\t"
+       ".byte  0x13    # DW_CFA_def_cfa_offset_sf\n\t"
+       ".sleb128 16\n\t"
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 22f-21f\n"
+"21:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 4b-5b\n"
+"22:\t"        ".align 8\n"
+"23:\t"        ".previous\n"
+"24:"
+       : : "r" (x), "m" (x), "r" (buf)
+       : "memory", "rax", "rdx", "rcx", "rsi", "rdi",
+         "r8", "r9", "r10", "r11");
+#else
+# error Unsupported test architecture
+#endif
+}
+
+static int __attribute__((noinline))
+fn2 (void)
+{
+  foo (3);
+  return 0;
+}
+
+static int __attribute__((noinline))
+fn1 (void)
+{
+  fn2 ();
+  return 0;
+}
+
+static void *
+fn0 (void)
+{
+  char dummy __attribute__((cleanup (handler)));
+  fn1 ();
+  return 0;
+}
+
+int
+main (void)
+{
+  fn0 ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cleanup-2.c b/gcc/testsuite/gcc.target/i386/cleanup-2.c
new file mode 100644 (file)
index 0000000..a171077
--- /dev/null
@@ -0,0 +1,205 @@
+/* { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && lp64 } } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -fasynchronous-unwind-tables -O2" } */
+/* Test complex CFA value expressions.  */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+                  _Unwind_Exception_Class exc_class,
+                  struct _Unwind_Exception *exc_obj,
+                  struct _Unwind_Context *context,
+                  void *stop_parameter)
+{
+  if (actions & _UA_END_OF_STACK)
+    abort ();
+  return _URC_NO_REASON;
+}
+
+static void
+force_unwind ()
+{
+  struct _Unwind_Exception *exc = malloc (sizeof (*exc));
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
+  exc->exception_cleanup = 0;
+
+  _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+  abort ();
+}
+
+int count;
+
+static void
+counter (void *p __attribute__((unused)))
+{
+  ++count;
+}
+
+static void
+handler (void *p __attribute__((unused)))
+{
+  if (count != 2)
+    abort ();
+  _exit (0);
+}
+
+static int __attribute__((noinline))
+fn5 (void)
+{
+  char dummy __attribute__((cleanup (counter)));
+  force_unwind ();
+  return 0;
+}
+
+void
+bar (void)
+{
+  char dummy __attribute__((cleanup (counter)));
+  fn5 ();
+}
+
+void __attribute__((noinline))
+foo (int x)
+{
+  char buf[256];
+#ifdef __x86_64__
+  __asm (
+       "testl  %0, %0\n\t"
+       "jnz    1f\n\t"
+       ".subsection 1\n\t"
+       ".type  _L_mutex_lock_%=, @function\n"
+"_L_mutex_lock_%=:\n"
+"1:\t" "leaq   %1, %%rdi\n"
+"2:\t" "subq   $128, %%rsp\n"
+"3:\t" "call   bar\n"
+"4:\t" "addq   $128, %%rsp\n"
+"5:\t" "jmp    21f\n"
+"6:\t" ".size _L_mutex_lock_%=, .-_L_mutex_lock_%=\n\t"
+       ".previous\n\t"
+       ".section       .eh_frame,\"a\",@progbits\n"
+"7:\t" ".long  9f-8f   # Length of Common Information Entry\n"
+"8:\t" ".long  0x0     # CIE Identifier Tag\n\t"
+       ".byte  0x1     # CIE Version\n\t"
+       ".ascii \"zR\\0\"       # CIE Augmentation\n\t"
+       ".uleb128 0x1   # CIE Code Alignment Factor\n\t"
+       ".sleb128 -8    # CIE Data Alignment Factor\n\t"
+       ".byte  0x10    # CIE RA Column\n\t"
+       ".uleb128 0x1   # Augmentation size\n\t"
+       ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"
+       ".byte  0xc     # DW_CFA_def_cfa\n\t"
+       ".uleb128 0x7\n\t"
+       ".uleb128 0x0\n\t"
+       ".align 8\n"
+"9:\t" ".long  20f-10f # FDE Length\n"
+"10:\t"        ".long  10b-7b  # FDE CIE offset\n\t"
+       ".long  1b-.    # FDE initial location\n\t"
+       ".long  6b-1b   # FDE address range\n\t"
+       ".uleb128 0x0   # Augmentation size\n\t"
+       /* This CFA expression computes the address right
+          past the jnz instruction above, from %rip somewhere
+          within the _L_mutex_lock_%= subsection.  */
+       ".byte  0x16    # DW_CFA_val_expression\n\t"
+       ".uleb128 0x10\n\t"
+       ".uleb128 19f-11f\n"
+"11:\t"        ".byte  0x80    # DW_OP_breg16\n\t"
+       ".sleb128 0\n"
+"12:\t"        ".byte  0x12    # DW_OP_dup\n\t"
+       ".byte  0x94    # DW_OP_deref_size\n\t"
+       ".byte  1\n\t"
+       ".byte  0x12    # DW_OP_dup\n\t"
+       ".byte  0x08    # DW_OP_const1u\n\t"
+       ".byte  0x48\n\t"
+       ".byte  0x2e    # DW_OP_ne\n\t"
+       ".byte  0x28    # DW_OP_bra\n\t"
+       ".2byte 16f-13f\n"
+"13:\t"        ".byte  0x13    # DW_OP_drop\n\t"
+       ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 1\n\t"
+       ".byte  0x12    # DW_OP_dup\n\t"
+       ".byte  0x94    # DW_OP_deref_size\n\t"
+       ".byte  1\n\t"
+       ".byte  0x08    # DW_OP_const1u\n\t"
+       ".byte  0x81\n\t"
+       ".byte  0x2e    # DW_OP_ne\n\t"
+       ".byte  0x28    # DW_OP_bra\n\t"
+       ".2byte 15f-14f\n"
+"14:\t"        ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 3b-2b-1\n\t"
+       ".byte  0x2f    # DW_OP_skip\n\t"
+       ".2byte 12b-15f\n"
+"15:\t"        ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 2b-1b-1\n\t"
+       ".byte  0x2f    # DW_OP_skip\n\t"
+       ".2byte 12b-16f\n"
+"16:\t"        ".byte  0x08    # DW_OP_const1u\n\t"
+       ".byte  0xe8\n\t"
+       ".byte  0x2e    # DW_OP_ne\n\t"
+       ".byte  0x28    # DW_OP_bra\n\t"
+       ".2byte 18f-17f\n"
+"17:\t"        ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 4b-3b\n\t"
+       ".byte  0x2f    # DW_OP_skip\n\t"
+       ".2byte 12b-18f\n"
+"18:\t"        ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 1\n\t"
+       ".byte  0x12    # DW_OP_dup\n\t"
+       ".byte  0x94    # DW_OP_deref_size\n\t"
+       ".byte  4\n\t"
+       ".byte  0x08    # DW_OP_const1u\n\t"
+       ".byte  72 - (6b-5b) * 8 # (6b-5b) == 5 ? 32 : 56\n\t"
+       ".byte  0x24    # DW_OP_shl\n\t"
+       ".byte  0x08    # DW_OP_const1u\n\t"
+       ".byte  72 - (6b-5b) * 8 # (6b-5b) == 5 ? 32 : 56\n\t"
+       ".byte  0x26    # DW_OP_shra\n\t"
+       ".byte  0x22    # DW_OP_plus\n\t"
+       ".byte  0x23    # DW_OP_plus_uconst\n\t"
+       ".uleb128 6b-5b-1\n"
+"19:\t"        ".byte  0x40 + (3b-1b) # DW_CFA_advance_loc\n\t"
+       ".byte  0xe     # DW_CFA_def_cfa_offset\n\t"
+       ".uleb128 128\n\t"
+       ".byte  0x40 + (5b-3b) # DW_CFA_advance_loc\n\t"
+       ".byte  0xe     # DW_CFA_def_cfa_offset\n\t"
+       ".uleb128 0\n\t"
+       ".align 8\n"
+"20:\t"        ".previous\n"
+"21:"
+       : : "r" (x), "m" (x), "r" (buf)
+       : "memory", "rax", "rdx", "rcx", "rsi", "rdi",
+         "r8", "r9", "r10", "r11");
+#else
+# error Unsupported test architecture
+#endif
+}
+
+static int __attribute__((noinline))
+fn2 (void)
+{
+  foo (3);
+  return 0;
+}
+
+static int __attribute__((noinline))
+fn1 (void)
+{
+  fn2 ();
+  return 0;
+}
+
+static void *
+fn0 (void)
+{
+  char dummy __attribute__((cleanup (handler)));
+  fn1 ();
+  return 0;
+}
+
+int
+main (void)
+{
+  fn0 ();
+  return 0;
+}
index 8707391..efae54a 100644 (file)
@@ -72,6 +72,7 @@ struct _Unwind_Context
   struct dwarf_eh_bases bases;
   _Unwind_Word args_size;
   char signal_frame;
+  char by_value[DWARF_FRAME_REGISTERS+1];
 };
 
 /* Byte size of every register managed by these routines.  */
@@ -118,7 +119,7 @@ read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
 static inline unsigned long
 read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
 \f
-/* Get the value of register REG as saved in CONTEXT.  */
+/* Get the value of register INDEX as saved in CONTEXT.  */
 
 inline _Unwind_Word
 _Unwind_GetGR (struct _Unwind_Context *context, int index)
@@ -136,6 +137,9 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
   size = dwarf_reg_size_table[index];
   ptr = context->reg[index];
 
+  if (context->by_value[index])
+    return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr;
+
   /* This will segfault if the register hasn't been saved.  */
   if (size == sizeof(_Unwind_Ptr))
     return * (_Unwind_Ptr *) ptr;
@@ -160,7 +164,7 @@ _Unwind_GetCFA (struct _Unwind_Context *context)
   return (_Unwind_Ptr) context->cfa;
 }
 
-/* Overwrite the saved value for register REG in CONTEXT with VAL.  */
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
 
 inline void
 _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
@@ -171,6 +175,13 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
   size = dwarf_reg_size_table[index];
+
+  if (context->by_value[index])
+    {
+      context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
+      return;
+    }
+
   ptr = context->reg[index];
 
   if (size == sizeof(_Unwind_Ptr))
@@ -188,6 +199,8 @@ static inline void *
 _Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
 {
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  if (context->by_value[index])
+    return &context->reg[index];
   return context->reg[index];
 }
 
@@ -197,9 +210,34 @@ static inline void
 _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
 {
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  context->by_value[index] = 0;
   context->reg[index] = p;
 }
 
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
+
+static inline void
+_Unwind_SetGRValue (struct _Unwind_Context *context, int index,
+                   _Unwind_Word val)
+{
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
+  gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr));
+
+  context->by_value[index] = 1;
+  context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
+}
+
+/* Return non-zero if register INDEX is stored by value rather than
+   by reference.  */
+
+static inline int
+_Unwind_GRByValue (struct _Unwind_Context *context, int index)
+{
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  return context->by_value[index];
+}
+
 /* Retrieve the return address for CONTEXT.  */
 
 inline _Unwind_Ptr
@@ -922,7 +960,7 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr += utmp;
          break;
 
-         /* From the dwarf3 draft.  */
+         /* Dwarf3.  */
        case DW_CFA_offset_extended_sf:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_sleb128 (insn_ptr, &stmp);
@@ -945,6 +983,33 @@ execute_cfa_program (const unsigned char *insn_ptr,
          /* cfa_how deliberately not set.  */
          break;
 
+       case DW_CFA_val_offset:
+         insn_ptr = read_uleb128 (insn_ptr, &reg);
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         offset = (_Unwind_Sword) utmp * fs->data_align;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_VAL_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         break;
+
+       case DW_CFA_val_offset_sf:
+         insn_ptr = read_uleb128 (insn_ptr, &reg);
+         insn_ptr = read_sleb128 (insn_ptr, &stmp);
+         offset = stmp * fs->data_align;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_VAL_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         break;
+
+       case DW_CFA_val_expression:
+         insn_ptr = read_uleb128 (insn_ptr, &reg);
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_VAL_EXP;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
+         insn_ptr += utmp;
+         break;
+
        case DW_CFA_GNU_window_save:
          /* ??? Hardcoded for SPARC register window configuration.  */
          for (reg = 16; reg < 32; ++reg)
@@ -1113,7 +1178,7 @@ typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp;
 
 static inline void
 _Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
-                     _Unwind_SpTmp *tmp_sp)
+                    _Unwind_SpTmp *tmp_sp)
 {
   int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
   
@@ -1194,9 +1259,14 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        break;
 
       case REG_SAVED_REG:
-       _Unwind_SetGRPtr
-         (context, i,
-          _Unwind_GetGRPtr (&orig_context, fs->regs.reg[i].loc.reg));
+       if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg))
+         _Unwind_SetGRValue (context, i,
+                             _Unwind_GetGR (&orig_context,
+                                            fs->regs.reg[i].loc.reg));
+       else
+         _Unwind_SetGRPtr (context, i,
+                           _Unwind_GetGRPtr (&orig_context,
+                                             fs->regs.reg[i].loc.reg));
        break;
 
       case REG_SAVED_EXP:
@@ -1211,6 +1281,25 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          _Unwind_SetGRPtr (context, i, (void *) val);
        }
        break;
+
+      case REG_SAVED_VAL_OFFSET:
+       _Unwind_SetGRValue (context, i,
+                           (_Unwind_Internal_Ptr)
+                           (cfa + fs->regs.reg[i].loc.offset));
+       break;
+
+      case REG_SAVED_VAL_EXP:
+       {
+         const unsigned char *exp = fs->regs.reg[i].loc.exp;
+         _Unwind_Word len;
+         _Unwind_Ptr val;
+
+         exp = read_uleb128 (exp, &len);
+         val = execute_stack_op (exp, exp + len, &orig_context,
+                                 (_Unwind_Ptr) cfa);
+         _Unwind_SetGRValue (context, i, val);
+       }
+       break;
       }
 
   context->signal_frame = fs->signal_frame;
@@ -1327,14 +1416,31 @@ uw_install_context_1 (struct _Unwind_Context *current,
   /* If the target frame does not have a saved stack pointer,
      then set up the target's CFA.  */
   if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
-       _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
+    _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
 
   for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
     {
       void *c = current->reg[i];
       void *t = target->reg[i];
 
-      if (t && c && t != c)
+      gcc_assert (current->by_value[i] == 0);
+      if (target->by_value[i] && c)
+       {
+         _Unwind_Word w;
+         _Unwind_Ptr p;
+         if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word))
+           {
+             w = (_Unwind_Internal_Ptr) t;
+             memcpy (c, &w, sizeof (_Unwind_Word));
+           }
+         else
+           {
+             gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr));
+             p = (_Unwind_Internal_Ptr) t;
+             memcpy (c, &p, sizeof (_Unwind_Ptr));
+           }
+       }
+      else if (t && c && t != c)
        memcpy (c, t, dwarf_reg_size_table[i]);
     }
 
index 4851067..34a378b 100644 (file)
@@ -53,7 +53,9 @@ typedef struct
        REG_UNSAVED,
        REG_SAVED_OFFSET,
        REG_SAVED_REG,
-       REG_SAVED_EXP
+       REG_SAVED_EXP,
+       REG_SAVED_VAL_OFFSET,
+       REG_SAVED_VAL_EXP
       } how;
     } reg[DWARF_FRAME_REGISTERS+1];