linux-unwind.h (frob_update_context <__powerpc64__>): Leave r2 REG_UNSAVED if stopped...
authorAlan Modra <amodra@gmail.com>
Thu, 28 Jul 2011 07:44:24 +0000 (17:14 +0930)
committerAlan Modra <amodra@gcc.gnu.org>
Thu, 28 Jul 2011 07:44:24 +0000 (17:14 +0930)
* config/rs6000/linux-unwind.h (frob_update_context <__powerpc64__>):
Leave r2 REG_UNSAVED if stopped on the instruction that saves r2
in a plt call stub.  Do restore r2 if stopped on bctrl.

From-SVN: r176861

libgcc/ChangeLog
libgcc/config/rs6000/linux-unwind.h

index 8fab793254faffd57ddf5e13fcddbb5d86f40390..49b087d3579f67628d992afa9e563d0c4338ad0a 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-28  Alan Modra  <amodra@gmail.com>
+
+       * config/rs6000/linux-unwind.h (frob_update_context <__powerpc64__>):
+       Leave r2 REG_UNSAVED if stopped on the instruction that saves r2
+       in a plt call stub.  Do restore r2 if stopped on bctrl.
+
 2011-07-18  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config.host (i[3456x]86-*-netware*): Remove.
index a16df97e97ea2934f01e486204f7348730b1467b..27e5f82c7e30f165ae8178da722fef9212478b96 100644 (file)
@@ -346,10 +346,28 @@ frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATT
         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.  */
-      unsigned int *insn
-       = (unsigned int *) _Unwind_GetGR (context, R_LR);
-      if (insn && *insn == 0xE8410028)
-       _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+      if (pc[0] == 0xF8410028
+         || ((pc[0] & 0xFFFF0000) == 0x3D820000
+             && pc[1] == 0xF8410028))
+       {
+         /* We are in a plt call stub or r2 adjusting long branch stub,
+            before r2 has been saved.  Keep REG_UNSAVED.  */
+       }
+      else if (pc[0] == 0x4E800421
+              && pc[1] == 0xE8410028)
+       {
+         /* We are at the bctrl instruction in a call via function
+            pointer.  gcc always emits the load of the new r2 just
+            before the bctrl.  */
+         _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+       }
+      else
+       {
+         unsigned int *insn
+           = (unsigned int *) _Unwind_GetGR (context, R_LR);
+         if (insn && *insn == 0xE8410028)
+           _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+       }
     }
 #endif
 }