diff options
author | Alan Modra <amodra@gmail.com> | 2011-07-28 17:14:24 +0930 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2011-07-28 17:14:24 +0930 |
commit | 2374a88acff100721223f7b944488e64279f0fb2 (patch) | |
tree | 38124867cdec12320e0c7fdd18da3c2229ed2f1c | |
parent | d8fa1b739feb67b0b93f93d37b0384b403e74662 (diff) | |
download | gcc-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/ChangeLog | 6 | ||||
-rw-r--r-- | libgcc/config/rs6000/linux-unwind.h | 26 |
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 } |