aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2011-07-28 17:14:24 +0930
committerAlan Modra <amodra@gcc.gnu.org>2011-07-28 17:14:24 +0930
commit2374a88acff100721223f7b944488e64279f0fb2 (patch)
tree38124867cdec12320e0c7fdd18da3c2229ed2f1c
parentd8fa1b739feb67b0b93f93d37b0384b403e74662 (diff)
downloadgcc-2374a88acff100721223f7b944488e64279f0fb2.zip
gcc-2374a88acff100721223f7b944488e64279f0fb2.tar.gz
gcc-2374a88acff100721223f7b944488e64279f0fb2.tar.bz2
linux-unwind.h (frob_update_context <__powerpc64__>): Leave r2 REG_UNSAVED if stopped on the instruction that saves r2 in a plt call stub.
* 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
-rw-r--r--libgcc/ChangeLog6
-rw-r--r--libgcc/config/rs6000/linux-unwind.h26
2 files changed, 28 insertions, 4 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 8fab793..49b087d 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -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.
diff --git a/libgcc/config/rs6000/linux-unwind.h b/libgcc/config/rs6000/linux-unwind.h
index a16df97..27e5f82 100644
--- a/libgcc/config/rs6000/linux-unwind.h
+++ b/libgcc/config/rs6000/linux-unwind.h
@@ -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
}