Hi David, I've been looking into what we need to do to support unwinding from async signal handlers. I've implemented unwind info generation for .glink in the linker, but to keep the ppc64 .glink unwind info simple I've assumed that frob_update_context is still used.
We still have some difficulties related to r2 tracking on ppc64. frob_update_context doesn't quite do the right thing for async unwinding. A typical (no-r11) plt call stub looks like addis r12,2,off@ha std 2,40(1) ld 11,off@l(12) mtctr 11 ld 2,off+8@l(12) bctr or, when the offset from r2 to the function descriptor is small std 2,40(1) ld 11,off(2) mtctr 11 ld 2,off+8(2) bctr Now if we're stopped before the save of r2 we obviously don't want the unwinder to restore r2 from 40(1), but that's exactly what the current unwinder does. Also, there is a one insn window where frob_update_context may do the wrong thing for gcc generated calls via function pointer, which typically looks like ld 0,0(r) std 2,40(1) mtctr 0 ld 2,8(r) bctrl ld 2,40(1) Here, if we are stopped after the "ld 2,8(r)" then r2 needs to be restored from 40(1). The following patch fixes these two issues. Ideally what I'd like to do is have ld and gcc emit accurate r2 tracking unwind info and dispense with hacks like frob_update_context. If ld did emit accurate unwind info for .glink, then the justification for frob_update_context disappears. The difficulty then is backwards compatibility. You'd need a way for the gcc unwinder to handle a mix of old code (that needs frob_update_context) with new code (that doesn't). One way to accomplish this would be to set a dummy reg with initial CIE dwarf instructions, then test this reg in frob_update_context. Bootstrapped and regression tested powerpc64-linux. * 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. 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 } -- Alan Modra Australia Development Lab, IBM