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:
(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.