Index: libgcc/config/rs6000/linux-unwind.h
===================================================================
--- libgcc/config/rs6000/linux-unwind.h	(revision 176780)
+++ libgcc/config/rs6000/linux-unwind.h	(working copy)
@@ -346,10 +346,28 @@ frob_update_context (struct _Unwind_Cont
 	 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
 }
