diff mbox

[IA-64] Work around bug in unwinder

Message ID 201203211803.39173.ebotcazou@adacore.com
State New
Headers show

Commit Message

Eric Botcazou March 21, 2012, 5:03 p.m. UTC
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  <ebotcazou@adacore.com>

	* config/ia64/unwind-ia64.c (uw_install_context): Manually save LC
	if it hasn't been previously saved.

Comments

Richard Henderson March 30, 2012, 4:13 p.m. UTC | #1
On 03/21/2012 01:03 PM, Eric Botcazou wrote:
> 2012-03-21  Eric Botcazou  <ebotcazou@adacore.com>
> 
> 	* config/ia64/unwind-ia64.c (uw_install_context): Manually save LC
> 	if it hasn't been previously saved.

Looks ok, given the other ugliness in this macro.


r~
Eric Botcazou March 31, 2012, 4:28 p.m. UTC | #2
> Looks ok, given the other ugliness in this macro.

Thanks.  There is another pending workaround for IA-64:
  http://gcc.gnu.org/ml/gcc-patches/2012-03/msg00451.html
as well as an implementation of stack checking in the back-end:
  http://gcc.gnu.org/ml/gcc-patches/2012-03/msg00452.html
diff mbox

Patch

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.  */