unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
authorJakub Jelinek <jakub@redhat.com>
Wed, 16 Jul 2003 11:52:55 +0000 (13:52 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 16 Jul 2003 11:52:55 +0000 (13:52 +0200)
* unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
(uw_update_context_1): Use it.
* config/rs6000/rs6000.c (insn_after_throw): Remove.
(rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location
in parent frame if _Unwind_* called directly instead of through
.plt.
(rs6000_emit_eh_toc_restore): Remove.
(rs6000_emit_prologue): Update stack pointer before doing any saving
if current_function_calls_eh_return.  Generate unwind info for $r2.
(rs6000_emit_epilogue): Restore stack pointer after doing all
restoring if current_function_calls_eh_return.  Restore $r2.
* config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove.
* config/rs6000/rs6000.md (eh_return): Remove call to
rs6000_emit_eh_toc_restore.
* config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define.
* config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define.

* gcc.dg/cleanup-8.c: New test.
* gcc.dg/cleanup-9.c: New test.

From-SVN: r69450

gcc/ChangeLog
gcc/config/rs6000/aix.h
gcc/config/rs6000/linux64.h
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cleanup-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-9.c [new file with mode: 0644]
gcc/unwind-dw2.c

index 0e76adbcc02e6b22277dc483fa5534c65e99814a..027a53f74060ce1f47fb59be081b00f52330c093 100644 (file)
@@ -1,3 +1,22 @@
+2003-07-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
+       (uw_update_context_1): Use it.
+       * config/rs6000/rs6000.c (insn_after_throw): Remove.
+       (rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location
+       in parent frame if _Unwind_* called directly instead of through
+       .plt.
+       (rs6000_emit_eh_toc_restore): Remove.
+       (rs6000_emit_prologue): Update stack pointer before doing any saving
+       if current_function_calls_eh_return.  Generate unwind info for $r2.
+       (rs6000_emit_epilogue): Restore stack pointer after doing all
+       restoring if current_function_calls_eh_return.  Restore $r2.
+       * config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove.
+       * config/rs6000/rs6000.md (eh_return): Remove call to
+       rs6000_emit_eh_toc_restore.
+       * config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define.
+       * config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define.
+
 2003-07-15  Jakub Jelinek  <jakub@redhat.com>
 
        * expr.c (emit_block_move): Don't move anything if size is const 0.
index d40221513aa39a53ebde123badad8bea934c91ee..ec6a350f157a24744a8f3fc91a910625fd500f55 100644 (file)
    So we have to squirrel it away with this.  */
 #define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
 
+/* If the current unwind info (FS) does not contain explicit info
+   saving R2, then we have to do a minor amount of code reading to
+   figure out if it was saved.  The big problem here is that the
+   code that does the save/restore is generated by the linker, so
+   we have no good way to determine at compile time what to do.  */
+
+#ifdef __powerpc64__
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS)                                        \
+  do {                                                                 \
+    if ((FS)->regs.reg[2].how == REG_UNSAVED)                          \
+      {                                                                        \
+       unsigned int *insn                                              \
+         = (unsigned int *)                                            \
+           _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM);                \
+       if (*insn == 0xE8410028)                                        \
+         _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40);                 \
+      }                                                                        \
+  } while (0)
+#else
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS)                                        \
+  do {                                                                 \
+    if ((FS)->regs.reg[2].how == REG_UNSAVED)                          \
+      {                                                                        \
+       unsigned int *insn                                              \
+         = (unsigned int *)                                            \
+           _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM);                \
+       if (*insn == 0x80410014)                                        \
+         _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20);                 \
+      }                                                                        \
+  } while (0)
+#endif
+
 #define PROFILE_HOOK(LABEL)   output_profile_hook (LABEL)
 
 /* Print subsidiary information on the compiler version in use.  */
index 4ef7382cee8af56c45dca5f48ab236910a4d687a..5d7c74df266cd4f83c81f181d019e88b8a24b82c 100644 (file)
@@ -553,6 +553,24 @@ enum { SIGNAL_FRAMESIZE = 64 };
 
 #ifdef __powerpc64__
 
+/* If the current unwind info (FS) does not contain explicit info
+   saving R2, then we have to do a minor amount of code reading to
+   figure out if it was saved.  The big problem here is that the
+   code that does the save/restore is generated by the linker, so
+   we have no good way to determine at compile time what to do.  */
+
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS)                                        \
+  do {                                                                 \
+    if ((FS)->regs.reg[2].how == REG_UNSAVED)                          \
+      {                                                                        \
+       unsigned int *insn                                              \
+         = (unsigned int *)                                            \
+           _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM);                \
+       if (*insn == 0xE8410028)                                        \
+         _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40);                 \
+      }                                                                        \
+  } while (0)
+
 #define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)              \
   do {                                                                 \
     unsigned char *pc_ = (CONTEXT)->ra;                                        \
index fc7e9cb96d84db4fd58fd3acb21b985184e34d88..bbdaa6ac6f069193cc16e1c47b3b80215a303648 100644 (file)
@@ -126,7 +126,6 @@ extern int mfcr_operation PARAMS ((rtx, enum machine_mode));
 extern int mtcrf_operation PARAMS ((rtx, enum machine_mode));
 extern int lmw_operation PARAMS ((rtx, enum machine_mode));
 extern struct rtx_def *create_TOC_reference PARAMS ((rtx));
-extern void rs6000_emit_eh_toc_restore PARAMS ((rtx));
 extern void rs6000_split_altivec_in_gprs (rtx *);
 extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
 extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
index fa296d5db94ad87bff69ed6c3db122c49e197fcb..8f268974aa5d178a6e7453f603089db4cf99c02d 100644 (file)
@@ -10800,132 +10800,40 @@ create_TOC_reference (symbol)
                 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
 }
 
-/* __throw will restore its own return address to be the same as the
-   return address of the function that the throw is being made to.
-   This is unfortunate, because we want to check the original
-   return address to see if we need to restore the TOC.
-   So we have to squirrel it away here.  
-   This is used only in compiling __throw and __rethrow. 
+/* If _Unwind_* has been called from within the same module,
+   toc register is not guaranteed to be saved to 40(1) on function
+   entry.  Save it there in that case.  */
 
-   Most of this code should be removed by CSE.  */
-static rtx insn_after_throw;
-
-/* This does the saving...  */
 void
 rs6000_aix_emit_builtin_unwind_init ()
 {
   rtx mem;
   rtx stack_top = gen_reg_rtx (Pmode);
   rtx opcode_addr = gen_reg_rtx (Pmode);
-
-  insn_after_throw = gen_reg_rtx (SImode);
+  rtx opcode = gen_reg_rtx (SImode);
+  rtx tocompare = gen_reg_rtx (SImode);
+  rtx no_toc_save_needed = gen_label_rtx ();
 
   mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
   emit_move_insn (stack_top, mem);
 
-  mem = gen_rtx_MEM (Pmode, 
-                    gen_rtx_PLUS (Pmode, stack_top, 
+  mem = gen_rtx_MEM (Pmode,
+                    gen_rtx_PLUS (Pmode, stack_top,
                                   GEN_INT (2 * GET_MODE_SIZE (Pmode))));
   emit_move_insn (opcode_addr, mem);
-  emit_move_insn (insn_after_throw, gen_rtx_MEM (SImode, opcode_addr));
-}
-
-/* Emit insns to _restore_ the TOC register, at runtime (specifically
-   in _eh.o).  Only used on AIX.
-
-   The idea is that on AIX, function calls look like this:
-       bl  somefunction-trampoline
-       lwz r2,20(sp)
-
-   and later,
-       somefunction-trampoline:
-       stw r2,20(sp)
-        ... load function address in the count register ...
-       bctr
-   or like this, if the linker determines that this is not a cross-module call
-   and so the TOC need not be restored:
-       bl  somefunction
-       nop
-   or like this, if the compiler could determine that this is not a
-   cross-module call:
-       bl  somefunction
-   now, the tricky bit here is that register 2 is saved and restored
-   by the _linker_, so we can't readily generate debugging information
-   for it.  So we need to go back up the call chain looking at the
-   insns at return addresses to see which calls saved the TOC register
-   and so see where it gets restored from.
-
-   Oh, and all this gets done in RTL inside the eh_epilogue pattern,
-   just before the actual epilogue.
-
-   On the bright side, this incurs no space or time overhead unless an
-   exception is thrown, except for the extra code in libgcc.a.  
-
-   The parameter STACKSIZE is a register containing (at runtime)
-   the amount to be popped off the stack in addition to the stack frame
-   of this routine (which will be __throw or __rethrow, and so is
-   guaranteed to have a stack frame).  */
-
-void
-rs6000_emit_eh_toc_restore (stacksize)
-     rtx stacksize;
-{
-  rtx top_of_stack;
-  rtx bottom_of_stack = gen_reg_rtx (Pmode);
-  rtx tocompare = gen_reg_rtx (SImode);
-  rtx opcode = gen_reg_rtx (SImode);
-  rtx opcode_addr = gen_reg_rtx (Pmode);
-  rtx mem;
-  rtx loop_start = gen_label_rtx ();
-  rtx no_toc_restore_needed = gen_label_rtx ();
-  rtx loop_exit = gen_label_rtx ();
-  
-  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
-  set_mem_alias_set (mem, rs6000_sr_alias_set);
-  emit_move_insn (bottom_of_stack, mem);
-
-  top_of_stack = expand_binop (Pmode, add_optab, 
-                              bottom_of_stack, stacksize,
-                              NULL_RTX, 1, OPTAB_WIDEN);
-
-  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014 
+  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
+  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
                                           : 0xE8410028, SImode));
 
-  if (insn_after_throw == NULL_RTX)
-    abort ();
-  emit_move_insn (opcode, insn_after_throw);
-  
-  emit_note (NOTE_INSN_LOOP_BEG);
-  emit_label (loop_start);
-  
-  do_compare_rtx_and_jump (opcode, tocompare, NE, 1,
+  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
                           SImode, NULL_RTX, NULL_RTX,
-                          no_toc_restore_needed);
-  
-  mem = gen_rtx_MEM (Pmode, 
-                    gen_rtx_PLUS (Pmode, bottom_of_stack, 
-                                  GEN_INT (5 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (gen_rtx_REG (Pmode, 2), mem);
-
-  emit_label (no_toc_restore_needed);
-  do_compare_rtx_and_jump (top_of_stack, bottom_of_stack, EQ, 1,
-                          Pmode, NULL_RTX, NULL_RTX,
-                          loop_exit);
-
-  mem = gen_rtx_MEM (Pmode, bottom_of_stack);
-  set_mem_alias_set (mem, rs6000_sr_alias_set);
-  emit_move_insn (bottom_of_stack, mem);
-  
-  mem = gen_rtx_MEM (Pmode, 
-                    gen_rtx_PLUS (Pmode, bottom_of_stack, 
-                                  GEN_INT (2 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (opcode_addr, mem);
-  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
+                          no_toc_save_needed);
 
-  emit_note (NOTE_INSN_LOOP_CONT);
-  emit_jump (loop_start);
-  emit_note (NOTE_INSN_LOOP_END);
-  emit_label (loop_exit);
+  mem = gen_rtx_MEM (Pmode,
+                    gen_rtx_PLUS (Pmode, stack_top,
+                                  GEN_INT (5 * GET_MODE_SIZE (Pmode))));
+  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
+  emit_label (no_toc_save_needed);
 }
 \f
 /* This ties together stack memory (MEM with an alias set of
@@ -11347,7 +11255,8 @@ rs6000_emit_prologue ()
                        || FP_SAVE_INLINE (info->first_fp_reg_save));
 
   /* For V.4, update stack before we do any saving and set back pointer.  */
-  if (info->push_p && DEFAULT_ABI == ABI_V4)
+  if (info->push_p
+      && (DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
     {
       if (info->total_size < 32767)
        sp_offset = info->total_size;
@@ -11575,6 +11484,23 @@ rs6000_emit_prologue ()
     {
       unsigned int i, regno;
 
+      /* In AIX ABI we need to pretend we save r2 here.  */
+      if (TARGET_AIX)
+       {
+         rtx addr, reg, mem;
+
+         reg = gen_rtx_REG (reg_mode, 2);
+         addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                              GEN_INT (sp_offset + 5 * reg_size));
+         mem = gen_rtx_MEM (reg_mode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         insn = emit_move_insn (mem, reg);
+         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
+                               NULL_RTX, NULL_RTX);
+         PATTERN (insn) = gen_blockage ();
+       }
+
       for (i = 0; ; ++i)
        {
          regno = EH_RETURN_DATA_REGNO (i);
@@ -11633,7 +11559,8 @@ rs6000_emit_prologue ()
 
   /* Update stack and set back pointer unless this is V.4, 
      for which it was done previously.  */
-  if (info->push_p && DEFAULT_ABI != ABI_V4)
+  if (info->push_p
+      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
     rs6000_emit_allocate_stack (info->total_size, FALSE);
 
   /* Set frame pointer, if needed.  */
@@ -11812,7 +11739,8 @@ rs6000_emit_epilogue (sibcall)
     }
   else if (info->push_p)
     {
-      if (DEFAULT_ABI == ABI_V4)
+      if (DEFAULT_ABI == ABI_V4
+         || current_function_calls_eh_return)
        sp_offset = info->total_size;
       else
        {
@@ -11897,6 +11825,17 @@ rs6000_emit_epilogue (sibcall)
     {
       unsigned int i, regno;
 
+      if (TARGET_AIX)
+       {
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (sp_offset + 5 * reg_size));
+         rtx mem = gen_rtx_MEM (reg_mode, addr);
+
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
+       }
+
       for (i = 0; ; ++i)
        {
          rtx mem;
@@ -12048,7 +11987,8 @@ rs6000_emit_epilogue (sibcall)
      (which may not have any obvious dependency on the stack).  This
      doesn't hurt performance, because there is no scheduling that can
      be done after this point.  */
-  if (DEFAULT_ABI == ABI_V4)
+  if (DEFAULT_ABI == ABI_V4
+      || current_function_calls_eh_return)
     {
       if (frame_reg_rtx != sp_reg_rtx)
          rs6000_emit_stack_tie ();
index bf778e2e22c7a64607ec567700c7118816aea8a6..f39e849628ac4be83ef87caebae617e5c92482ff 100644 (file)
   ""
   "
 {
-  if (TARGET_AIX)
-    rs6000_emit_eh_toc_restore (EH_RETURN_STACKADJ_RTX);
   if (TARGET_32BIT)
     emit_insn (gen_eh_set_lr_si (operands[0]));
   else
index e6f3233c9ff18857651dc1096f8a21d7ef4ffa66..ab2deeb4fe64e71fd491e274c9c7c609d707cc7b 100644 (file)
@@ -1,3 +1,8 @@
+2003-07-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.dg/cleanup-8.c: New test.
+       * gcc.dg/cleanup-9.c: New test.
+
 2003-07-16  Danny Smith  <dannysmith@users.sourceforge.net>
 
        * g++.dg/ext/dll-MI1.h: New file.
diff --git a/gcc/testsuite/gcc.dg/cleanup-8.c b/gcc/testsuite/gcc.dg/cleanup-8.c
new file mode 100644 (file)
index 0000000..91e387c
--- /dev/null
@@ -0,0 +1,97 @@
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
+/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
+/* Verify that cleanups work with exception handling through signal
+   frames.  */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.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));
+  exc->exception_class = 0;
+  exc->exception_cleanup = 0;
+                   
+#ifndef __USING_SJLJ_EXCEPTIONS__
+  _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+  _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+                   
+  abort ();
+}
+
+int count;
+char *null;
+
+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 ()
+{
+  char dummy __attribute__((cleanup (counter)));
+  force_unwind ();
+  return 0;
+}
+
+static void fn4 (int sig)
+{
+  char dummy __attribute__((cleanup (counter)));
+  fn5 ();
+  null = NULL;
+}
+
+static void fn3 ()
+{
+  abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+  *null = 0;
+  fn3 ();
+  return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+  signal (SIGSEGV, fn4);
+  fn2 ();
+  return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+  char dummy __attribute__((cleanup (handler)));
+  fn1 ();
+  null = 0;
+  return 0;
+}
+
+int main()
+{ 
+  fn0 ();
+  abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-9.c b/gcc/testsuite/gcc.dg/cleanup-9.c
new file mode 100644 (file)
index 0000000..0c17f25
--- /dev/null
@@ -0,0 +1,101 @@
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
+/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
+/* Verify that cleanups work with exception handling through realtime
+   signal frames.  */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.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));
+  exc->exception_class = 0;
+  exc->exception_cleanup = 0;
+                   
+#ifndef __USING_SJLJ_EXCEPTIONS__
+  _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+  _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+                   
+  abort ();
+}
+
+int count;
+char *null;
+
+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 ()
+{
+  char dummy __attribute__((cleanup (counter)));
+  force_unwind ();
+  return 0;
+}
+
+static void fn4 (int sig, siginfo_t *info, void *ctx)
+{
+  char dummy __attribute__((cleanup (counter)));
+  fn5 ();
+  null = NULL;
+}
+
+static void fn3 ()
+{
+  abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+  *null = 0;
+  fn3 ();
+  return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+  struct sigaction s;
+  sigemptyset (&s.sa_mask);
+  s.sa_sigaction = fn4;
+  s.sa_flags = SA_ONESHOT | SA_SIGINFO;
+  sigaction (SIGSEGV, &s, NULL);
+  fn2 ();
+  return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+  char dummy __attribute__((cleanup (handler)));
+  fn1 ();
+  null = 0;
+  return 0;
+}
+
+int main()
+{ 
+  fn0 ();
+  abort ();
+}
index eadd88bba5ac3fc3f5e4e3766c4f0ba6d61f23aa..3e58be6cb693b594339d87a0ee9c4e3c5f3d93a2 100644 (file)
 #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
 #endif
 
+/* A target can do some update context frobbing.  */
+#ifndef MD_FROB_UPDATE_CONTEXT
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) do { } while (0)
+#endif
+
 /* This is the register and unwind state for a particular frame.  This
    provides the information necessary to unwind up past a frame and return
    to its caller.  */
@@ -1203,6 +1208,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        }
        break;
       }
+
+  MD_FROB_UPDATE_CONTEXT (context, fs);
 }
 
 /* CONTEXT describes the unwind state for a frame, and FS describes the FDE