NetBSD Problem Report #44155

From www@NetBSD.org  Fri Nov 26 22:17:58 2010
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by www.NetBSD.org (Postfix) with ESMTP id D179B63BAE5
	for <gnats-bugs@gnats.NetBSD.org>; Fri, 26 Nov 2010 22:17:58 +0000 (UTC)
Message-Id: <20101126221758.6243863B95F@www.NetBSD.org>
Date: Fri, 26 Nov 2010 22:17:58 +0000 (UTC)
From: uwe@NetBSD.org
Reply-To: uwe@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: GCC doesn't implement C++ exceptions for VAX
X-Send-Pr-Version: www-1.0

>Number:         44155
>Category:       port-vax
>Synopsis:       GCC doesn't implement C++ exceptions for VAX
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-vax-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Nov 26 22:20:00 +0000 2010
>Last-Modified:  Fri Nov 26 23:20:02 +0000 2010
>Originator:     Valeriy E. Ushakov
>Release:        NetBSD 5.1
>Organization:
>Environment:
>Description:
GCC has some code for DWARF2 stack unwinding on VAX but it's neither
correct, nor complete, so C++ exceptions currently don't work on VAX
at all.

I've started investigating C++ exceptions in response to
port-vax/43273 and I don't have any more time.  Besides, further work
requires more knowledge of GCC internals that I posses, so I'm filing
this to document my findings so far and leave it at that.

Margins of this web-form are too narrow, so all the details will be in
a follow up mail to this PR.

>How-To-Repeat:

>Fix:

>Release-Note:

>Audit-Trail:

From: "Valeriy E. Ushakov" <uwe@stderr.spb.ru>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: port-vax/44155: GCC doesn't implement C++ exceptions for VAX
Date: Sat, 27 Nov 2010 02:18:19 +0300

 toolchain/43314 needs to get fixed as suggested.

 CFA is defined to be "below the argument count pushed by the CALLS and
 before the start of the saved registers" (see INCOMING_FRAME_SP_OFFSET),
 but vax.h defines FRAME_POINTER_CFA_OFFSET(FNDECL) as 0, which points
 below the frame, so unwinder starts with wrong CFA and ends up with
 garbage or segfault.

 I defined instead ARG_POINTER_CFA_OFFSET(FNDECL) as 0 (only one of
 them have to be defined) to make any progress.  It's not entirely
 correct - that would only be true for CALLS, but not for CALLG, and
 _rtld_bind_start uses CALLG when it cannot eliminate its own
 intermediate frame.  It also triggers an assertion in dwarf2out.c
 compute_frame_pointer_to_cfa_displacement(), so I had to massage that
 too.

 We need to define FRAME_POINTER_CFA_OFFSET(FNDECL) that points to the
 correct location at offset(%fp) where "offset" is the size of the
 frame (saved registers + saved mask + extra word).  I have no idea how
 to do that given the fndecl.

 vax_output_function_prologue() in vax.c generates incorrect offset for
 the CFA when it rebases it w.r.t. frame pointer:

 -      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4));
 +      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 8));

 we need to skip two words, one for saved mask and one for the extra
 "condition handler" slot.

 With the above changes unwinder actually starts working and we fail
 when we try to actually return to the handler.

 The next step is to deal with functions (internal to the unwinder)
 that call __builtin_eh_return.

 For them we need to save not only caller-saved registers (from R6 up),
 but also call-clobbered R2..R5 since they are used for EH_RETURN_DATA_REGNO
 and we need slots for them in the unwind context.

 We also need to provide "eh_return" instruction pattern to generate
 correct code for __builtin_eh_return, since we cannot just do a "RET",
 it will not reset SP to the proper location.  Since I have no clue how
 to write one, I just manually hacked the asm for _Unwind_RaiseException
 to do the following for __builtin_eh_return path.

         ;; set numarg = 0, so that RET doesn't try to pop any extra words
         clrl 60(%fp)

         ;; offset to target SP is currently written to -4(%fp)
         ;; it's a waste of a stack slot, we will use (%fp) later
         ;; when we define STARTING_FRAME_OFFSET to 0
         ;; and EH_RETURN_STACKADJ_RTX to point to (%fp)
         ;;
         ;; our CFA is in %ap if we were called via CALLS
         ;; to be extra safe we should use %fp+64
         ;;
         ;; target SP already have args and numarg slot subtracted!
         addl3 -4(%fp), %ap, %r6

         ;; we need to move 64 bytes of call frame (including numarg we
         ;; zeroed above)
         movc3 $64, (%fp), -64(%r6)

         movab -64(%r6), %fp
         ret

 With all these changes my test C++ program could catch an exception
 thrown in the same module (I didn't even try to address ld.so and
 port-vax/43273).


 Additional observations:

 To correctly restore complete state when an exception is thrown, we
 also need to restore saved PSW bits 15..5 as stored at 4(%fp).  We
 should probably just define an extra DWARF2 column for it and let
 unwinder pick up the right value and stash it into our call frame.


 Defining STARTING_FRAME_OFFSET to -4 to have an extra slot for stack
 adjustment value (EH_RETURN_STACKADJ_RTX) is not necessary, since call
 frame already has a free slot at (%fp) that we can use for that
 purpose.  I didn't want to touch this now to minimize my diffs.  See
 also my comment for addl3 in the eh_return epilogue above.


 My current patch follows.

 Index: dwarf2out.c
 ===================================================================
 RCS file: /cvsroot/src/gnu/dist/gcc4/gcc/dwarf2out.c,v
 retrieving revision 1.1.1.5
 diff -u -r1.1.1.5 dwarf2out.c
 --- dwarf2out.c	2 Feb 2008 22:47:58 -0000	1.1.1.5
 +++ dwarf2out.c	23 Nov 2010 05:42:06 -0000
 @@ -10469,7 +10469,11 @@
        elim = XEXP (elim, 0);
      }
    gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
 -		       : stack_pointer_rtx));
 +		       : stack_pointer_rtx)
 +#if 1 /* XXX: uwe: vax */
 +	      || elim == arg_pointer_rtx
 +#endif
 +);

    frame_pointer_cfa_offset = -offset;
  }
 Index: config/vax/elf.h
 ===================================================================
 RCS file: /cvsroot/src/gnu/dist/gcc4/gcc/config/vax/elf.h,v
 retrieving revision 1.3
 diff -u -r1.3 elf.h
 --- config/vax/elf.h	31 Mar 2007 05:55:11 -0000	1.3
 +++ config/vax/elf.h	23 Nov 2010 05:42:08 -0000
 @@ -107,5 +107,5 @@
      fputs (integer_asm_op (SIZE, FALSE), FILE);		\
      fprintf (FILE, "%%pcrel%d(", SIZE * 8);		\
      assemble_name (FILE, LABEL);			\
 -    fputc (')', FILE);					\
 +    fprintf (FILE, "+%d)", SIZE);			\
    } while (0)
 Index: config/vax/vax.c
 ===================================================================
 RCS file: /cvsroot/src/gnu/dist/gcc4/gcc/config/vax/vax.c,v
 retrieving revision 1.15
 diff -u -r1.15 vax.c
 --- config/vax/vax.c	20 Apr 2007 16:30:32 -0000	1.15
 +++ config/vax/vax.c	23 Nov 2010 05:42:08 -0000
 @@ -115,9 +115,12 @@
    int regno;
    int mask = 0;

 -  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
 -    if (regs_ever_live[regno] && !call_used_regs[regno])
 -      mask |= 1 << regno;
 +  if (current_function_calls_eh_return)
 +    mask = 0x0ffc;
 +  else
 +    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
 +      if (regs_ever_live[regno] && !call_used_regs[regno])
 +	mask |= 1 << regno;

    fprintf (file, "\t.word 0x%x\n", mask);

 @@ -127,13 +130,13 @@
        int offset = 0;

        for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno)
 -	if (regs_ever_live[regno] && !call_used_regs[regno])
 +	if (mask & (1 << regno))
  	  dwarf2out_reg_save (label, regno, offset -= 4);

        dwarf2out_reg_save (label, PC_REGNUM, offset -= 4);
        dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4);
        dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4);
 -      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4));
 +      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 8));
      }

    size -= STARTING_FRAME_OFFSET;
 Index: config/vax/vax.h
 ===================================================================
 RCS file: /cvsroot/src/gnu/dist/gcc4/gcc/config/vax/vax.h,v
 retrieving revision 1.5
 diff -u -r1.5 vax.h
 --- config/vax/vax.h	2 Apr 2007 16:44:17 -0000	1.5
 +++ config/vax/vax.h	23 Nov 2010 05:42:08 -0000
 @@ -181,8 +181,17 @@
     This is computed in `reload', in reload1.c.  */
  #define FRAME_POINTER_REQUIRED 1

 +#if 0
  /* Offset from the frame pointer register value to the top of stack.  */
  #define FRAME_POINTER_CFA_OFFSET(FNDECL) 0
 +#else
 +/* XXX: uwe: This is correct only for CALLS.  But since we only use
 +   CALLS, this is the fastest fix for now.  Ideally we should define
 +   FRAME_POINTER_CFA_OFFSET that actually looks at the fndecl to
 +   figure out the size of the stack frame built above CFA.  */
 +/* Offset from the argument pointer register value to the CFA.  */
 +#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
 +#endif

  /* Base register for access to arguments of the function.  */
  #define ARG_POINTER_REGNUM VAX_AP_REGNUM


 -uwe

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.