Another latent issue exposed on IA-64 (both Linux and VMS) by GCC 4.7: the LC (Loop Counter) register isn't preserved by the unwinder.
The compiler generates unwind info for LC and unwind-ia64.c:uw_install_context restores it if this is deemed necessary. The hitch is that "deemed necessary" means "register saved at some point along the path between thrower and catcher and going through _Unwind_RaiseException". Now if a register isn't saved along this path but clobbered very late, namely in uw_install_context, then nothing restores it before the longjmp. unwind-ia64.c:uw_install_context reads: static void __attribute__((noreturn)) uw_install_context (struct _Unwind_Context *current __attribute__((unused)), struct _Unwind_Context *target) { unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0; long i; /* Copy integer register data from the target context to a temporary buffer. Do this so that we can frob AR.UNAT to get the NaT bits for these registers set properly. */ for (i = 4; i <= 7; ++i) { char nat; void *t = target->ireg[i - 2].loc; if (t) { unw_access_gr (target, i, &ireg_buf[i - 4], &nat, 0); ireg_nat |= (long)nat << (((size_t)&ireg_buf[i - 4] >> 3) & 0x3f); /* Set p6 - p9. */ ireg_pr |= 4L << i; } } and it clobbers LC because of the loop when compiled with GCC 4.7 and above. Bootstrapped/regtested on IA-64/Linux, OK for the mainline? Do we also want it for 4.7.1? 2012-03-21 Eric Botcazou <ebotca...@adacore.com> * config/ia64/unwind-ia64.c (uw_install_context): Manually save LC if it hasn't been previously saved. -- Eric Botcazou
Index: libgcc/config/ia64/unwind-ia64.c =================================================================== --- libgcc/config/ia64/unwind-ia64.c (revision 185395) +++ libgcc/config/ia64/unwind-ia64.c (working copy) @@ -2171,8 +2171,20 @@ uw_install_context (struct _Unwind_Conte struct _Unwind_Context *target) { unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0; + unsigned long saved_lc; long i; + /* ??? LC is a fixed register so the call to __builtin_unwind_init in + uw_init_context doesn't cause it to be saved. In case it isn't in + the user frames either, we need to manually do it here, lest it be + clobbered by the loop just below. */ + if (target->lc_loc == NULL) + { + register unsigned long lc asm ("ar.lc"); + saved_lc = lc; + target->lc_loc = &saved_lc; + } + /* Copy integer register data from the target context to a temporary buffer. Do this so that we can frob AR.UNAT to get the NaT bits for these registers set properly. */