From: Danny S. <dan...@cl...> - 2004-11-23 22:29:15
|
Hi, I've been trying to get DW2 EH exception handling working on windows targets with general success, but have hit a snag. If a C library function that takes a callback arg is compiled using stdcall convention, C++ exception thrown by the callback result in abort. If the C libarary function uses normal (cdelc) calling convention than exceptions thrown by callback are handled. Example: ============================================== /* callback.c library functions */ /* compile this with c */ void caller_c (void (*callback)(void)) { callback(); } void __attribute__((stdcall)) caller_s (void (*callback)(void)) { callback(); } ============================================== /* main.cc */ #include <stdio.h> extern "C" { typedef void (*foo)(void); extern void caller_c (foo); extern void __attribute__ ((__stdcall__)) caller_s (foo); } void callback (void) { printf ("Hello from callback\n"); fflush (stdout); throw 1; } int main () { try { printf ("Testing cdecl\n"); caller_c (callback); } catch (int) { printf ("Caught cdecl\n"); } try { printf ("\nTesting stdcall\n"); caller_s (callback); } catch (int) { printf ("Caught stdcall\n"); } return 0; } ================================================== Compiling with sjlj enabled compiler: gcc -c -o callback.o callback.c g++-sjlj -o main-sjlj.exe main.cc callback.o Both throws are caught. However, if using DW2 EH enabled compiler g++-dw2 -omain-dw2.exe main.cc callback.o I get this: > Testing cdecl > Hello from callback > Caught cdecl > Testing stdcall > Hello from callback > > abnormal program termination. This is significant for windows targets, since the OS win32 api uses stdcall almost exclusively. Before I pull any more hair out trying, does any one have any hints on how to use an MD_FALLBACK_FRAME_STATE_FOR to workaround, or is this a blocker for the use of DW2 EH on windows targets. Danny |
From: Richard H. <rt...@re...> - 2004-11-24 00:33:02
|
On Wed, Nov 24, 2004 at 11:27:11AM +1300, Danny Smith wrote: > Before I pull any more hair out trying, does any one have any hints on > how to use an MD_FALLBACK_FRAME_STATE_FOR to workaround ... That would be wrong. I think the most likely explanation is that there's a bug in the dwarf2 generator for stdcall functions with -fomit-frame-pointer, and the problem should be attacked there. If you've got a call that takes 12 bytes of arguments on the stack and pop them on return, then the unwind info should look like # DW_CFA_GNU_args_size 12 call foo # DW_CFA_def_cfa_offset <previous value - 12> r~ |
From: Danny S. <dan...@cl...> - 2004-11-24 07:52:43
|
Richard Henderson wrote: > On Wed, Nov 24, 2004 at 11:27:11AM +1300, Danny Smith wrote: >> Before I pull any more hair out trying, does any one have any hints >> on how to use an MD_FALLBACK_FRAME_STATE_FOR to workaround ... > > That would be wrong. > > I think the most likely explanation is that there's a bug in the > dwarf2 generator for stdcall functions with -fomit-frame-pointer, > and the problem should be attacked there. > > If you've got a call that takes 12 bytes of arguments on the stack > and pop them on return, then the unwind info should look like > > # DW_CFA_GNU_args_size 12 > call foo > # DW_CFA_def_cfa_offset <previous value - 12> > > Umm, actually I don't think it is stdcall thing at all. When I reran the testcase after doing other things both the cdecl and stdcall functions resulted in uncaught exceptions, I can't explain the success with cdecl in my earlier report, Sorry for the noise. If I compile the callback-using library code with -fexceptions using a DW2 enabled compiler, then both calling conventions work, as expected. So is it a general requirements of DW2 EH that functions that are passed callbacks as args be compiled with -fexceptions, if the callbacks may throw? I don't see how else they could work Danny > r~ |
From: Richard H. <rt...@re...> - 2004-11-24 08:07:34
|
On Wed, Nov 24, 2004 at 08:50:17PM +1300, Danny Smith wrote: > So is it a general requirements of DW2 EH that functions that are passed > callbacks as args be compiled with -fexceptions, if the callbacks may > throw? Yes. Thus glibc compiles e.g. qsort and bsearch with -fexceptions. r~ |
From: Danny S. <dan...@cl...> - 2004-11-24 08:12:30
|
Richard Henderson wrote: > On Wed, Nov 24, 2004 at 11:27:11AM +1300, Danny Smith wrote: >> Before I pull any more hair out trying, does any one have any hints >> on how to use an MD_FALLBACK_FRAME_STATE_FOR to workaround ... > > That would be wrong. > > I think the most likely explanation is that there's a bug in the > dwarf2 generator for stdcall functions with -fomit-frame-pointer, > and the problem should be attacked there. > There does seem to be a problem in the frame-pointer handling see: http://gcc.gnu.org/ml/gcc/2002-11/msg00149.html With this testcase: void __attribute__((stdcall)) test( int a) { a; } void snafu( void) { test( 666); throw 999; } int main( void) { try { snafu( ); return 0; } catch( ...) { return 1; } } I get (today): g++ -fno-omit-frame-pointer PASS (at all optimisation levels). g++ -O{0|1|2} -fomit-frame-pointer -maccumulate-outgoing-args PASS. g++ -O0 -mtune=i686 -mno-accumulate-outgoing-args -fomit-frame-pointer FAIL g++ -O{1,2} -mtune=i686 -mno-accumulate-outgoing-args -fomit-frame-poi nter PASS The optimisation flags that cause failure has changed since the original gcc report. Danny |
From: Richard H. <rt...@re...> - 2004-11-24 18:44:43
|
I reproduced this specific failure on linux, and the following seems to fix the problem. Can you give it a go with whatever more complex test case you have? r~ * dwarf2out.c (dwarf2out_stack_adjust): Add after_p argument. Save args_size adjustments for calls even with cfa as stack pointer. Search calls for stack adjustments after the insn is issued. (dwarf2out_frame_debug): Add after_p argument; pass it on. * dwarf2out.h (dwarf2out_frame_debug): Update to match. * final.c (final_start_function, final_scan_insn): Likewise. Index: dwarf2out.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v retrieving revision 1.559 diff -u -p -r1.559 dwarf2out.c --- dwarf2out.c 24 Nov 2004 14:35:25 -0000 1.559 +++ dwarf2out.c 24 Nov 2004 18:38:47 -0000 @@ -363,7 +363,7 @@ static void initial_return_save (rtx); static HOST_WIDE_INT stack_adjust_offset (rtx); static void output_cfi (dw_cfi_ref, dw_fde_ref, int); static void output_call_frame_info (int); -static void dwarf2out_stack_adjust (rtx); +static void dwarf2out_stack_adjust (rtx, bool); static void flush_queued_reg_saves (void); static bool clobbers_queued_reg_save (rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); @@ -1051,7 +1051,7 @@ stack_adjust_offset (rtx pattern) much extra space it needs to pop off the stack. */ static void -dwarf2out_stack_adjust (rtx insn) +dwarf2out_stack_adjust (rtx insn, bool after_p) { HOST_WIDE_INT offset; const char *label; @@ -1064,26 +1064,31 @@ dwarf2out_stack_adjust (rtx insn) if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn)) return; - if (!flag_asynchronous_unwind_tables && CALL_P (insn)) + /* If only calls can throw, and we have a frame pointer, + save up adjustments until we see the CALL_INSN. */ + if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM) { - /* Extract the size of the args from the CALL rtx itself. */ - insn = PATTERN (insn); - if (GET_CODE (insn) == PARALLEL) - insn = XVECEXP (insn, 0, 0); - if (GET_CODE (insn) == SET) - insn = SET_SRC (insn); - gcc_assert (GET_CODE (insn) == CALL); - - dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); + if (CALL_P (insn) && !after_p) + { + /* Extract the size of the args from the CALL rtx itself. */ + insn = PATTERN (insn); + if (GET_CODE (insn) == PARALLEL) + insn = XVECEXP (insn, 0, 0); + if (GET_CODE (insn) == SET) + insn = SET_SRC (insn); + gcc_assert (GET_CODE (insn) == CALL); + dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); + } return; } - /* If only calls can throw, and we have a frame pointer, - save up adjustments until we see the CALL_INSN. */ - else if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM) - return; - - if (BARRIER_P (insn)) + if (CALL_P (insn) && !after_p) + { + if (!flag_asynchronous_unwind_tables) + dwarf2out_args_size ("", args_size); + return; + } + else if (BARRIER_P (insn)) { /* When we see a BARRIER, we know to reset args_size to 0. Usually the compiler will have already emitted a stack adjustment, but @@ -1124,7 +1129,8 @@ dwarf2out_stack_adjust (rtx insn) label = dwarf2out_cfi_label (); def_cfa_1 (label, &cfa); - dwarf2out_args_size (label, args_size); + if (flag_asynchronous_unwind_tables) + dwarf2out_args_size (label, args_size); } #endif @@ -1772,10 +1778,13 @@ dwarf2out_frame_debug_expr (rtx expr, co /* Record call frame debugging information for INSN, which either sets SP or FP (adjusting how we calculate the frame address) or saves a - register to the stack. If INSN is NULL_RTX, initialize our state. */ + register to the stack. If INSN is NULL_RTX, initialize our state. + + If AFTER_P is false, we're being called before the insn is emitted, + otherwise after. Call instructions get invoked twice. */ void -dwarf2out_frame_debug (rtx insn) +dwarf2out_frame_debug (rtx insn, bool after_p) { const char *label; rtx src; @@ -1812,8 +1821,7 @@ dwarf2out_frame_debug (rtx insn) if (! RTX_FRAME_RELATED_P (insn)) { if (!ACCUMULATE_OUTGOING_ARGS) - dwarf2out_stack_adjust (insn); - + dwarf2out_stack_adjust (insn, after_p); return; } Index: dwarf2out.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/dwarf2out.h,v retrieving revision 1.21 diff -u -p -r1.21 dwarf2out.h --- dwarf2out.h 29 Jun 2003 15:19:13 -0000 1.21 +++ dwarf2out.h 24 Nov 2004 18:38:47 -0000 @@ -20,7 +20,7 @@ Software Foundation, 59 Temple Place - S 02111-1307, USA. */ extern void dwarf2out_decl (tree); -extern void dwarf2out_frame_debug (rtx); +extern void dwarf2out_frame_debug (rtx, bool); extern void debug_dwarf (void); struct die_struct; Index: final.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/final.c,v retrieving revision 1.343 diff -u -p -r1.343 final.c --- final.c 23 Nov 2004 23:10:18 -0000 1.343 +++ final.c 24 Nov 2004 18:38:47 -0000 @@ -1366,7 +1366,7 @@ final_start_function (rtx first ATTRIBUT #if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (NULL_RTX); + dwarf2out_frame_debug (NULL_RTX, false); #endif /* If debugging, assign block numbers to all of the blocks in this @@ -1848,7 +1848,7 @@ final_scan_insn (rtx insn, FILE *file, i case BARRIER: #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + dwarf2out_frame_debug (insn, false); #endif break; @@ -2168,7 +2168,7 @@ final_scan_insn (rtx insn, FILE *file, i #if defined (DWARF2_UNWIND_INFO) if (dwarf2out_do_frame ()) for (i = 1; i < XVECLEN (body, 0); i++) - dwarf2out_frame_debug (XVECEXP (body, 0, i)); + dwarf2out_frame_debug (XVECEXP (body, 0, i), false); #endif /* The first insn in this SEQUENCE might be a JUMP_INSN that will @@ -2460,7 +2460,7 @@ final_scan_insn (rtx insn, FILE *file, i #if defined (DWARF2_UNWIND_INFO) if (CALL_P (insn) && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + dwarf2out_frame_debug (insn, false); #endif /* Find the proper template for this insn. */ @@ -2527,13 +2527,12 @@ final_scan_insn (rtx insn, FILE *file, i the unwind info. We've already done this for delay slots and call instructions. */ #if defined (DWARF2_UNWIND_INFO) - if (NONJUMP_INSN_P (insn) + if (final_sequence == 0 #if !defined (HAVE_prologue) && !ACCUMULATE_OUTGOING_ARGS #endif - && final_sequence == 0 && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); + dwarf2out_frame_debug (insn, true); #endif current_output_insn = debug_insn = 0; |
From: Richard H. <rt...@re...> - 2004-11-24 19:49:23
|
On Wed, Nov 24, 2004 at 01:59:46PM -0500, Andrew Pinski wrote: > Could this be related to PR 17220? I wouldn't think so. My patch *should* only have any affect when stdcall functions are involved. (Well, that's not quite true -- the output may be a bit more compact, since I reduced the number of DW_CFA_GNU_args_size bits emitted, but the same information should be present.) r~ |
From: Ranjit M. <rm...@gm...> - 2004-11-24 06:34:22
|
Richard Henderson wrote: > On Wed, Nov 24, 2004 at 11:27:11AM +1300, Danny Smith wrote: > >>Before I pull any more hair out trying, does any one have any hints on >>how to use an MD_FALLBACK_FRAME_STATE_FOR to workaround ... > > > That would be wrong. > > I think the most likely explanation is that there's a bug in the > dwarf2 generator for stdcall functions with -fomit-frame-pointer, > and the problem should be attacked there. This does seem to ring a bell: http://gcc.gnu.org/ml/gcc/2002-11/msg00149.html I do not have ready access to a DW-2 MinGW build though, so I can't verify if it still is valid. (It does not fail with current mainline on i686-pc-linux-gnu.) Danny, is it possible for you to see if this testcase still fails? Ranjit. -- Ranjit Mathew Email: rmathew AT gmail DOT com Bangalore, INDIA. Web: http://ranjitmathew.tripod.com/ |
From: Aaron W. L. <aar...@aa...> - 2004-11-24 03:21:09
|
Danny Smith wrote: > If a C library function that takes a callback arg is compiled > using stdcall convention, C++ exception thrown by the callback > result in abort. Just to speculate while not asking anyone to implement anything, would there be any value in implementing special behavior when throwing through non-dwarf2 code, such as checking for an SEH handler on the stack, or use the MSVC unwinding routines (which MinGW has access to, I beleive)? Do any Windows system routines have any function local cleanup that they'd need to do registered with SEH, or are they OK with suddenly being zapped out of existance at user code call points? Aaron W. LaFramboise |
From: Christopher F. <cgf...@cy...> - 2004-11-24 05:35:56
|
On Tue, Nov 23, 2004 at 09:22:34PM -0600, Aaron W. LaFramboise wrote: >Do any Windows system routines have any function local cleanup that >they'd need to do registered with SEH, or are they OK with suddenly >being zapped out of existance at user code call points? If cygwin's signal handling code is any indication, Windows system routines will become very unhappy if you just zap the PC away somewhere down (up?) the stack. On Windows 9x you'll eventually cause a system crash, in fact. cgf |
From: Richard H. <rt...@re...> - 2004-11-24 17:32:00
|
On Wed, Nov 24, 2004 at 02:51:35AM -0600, Aaron W. LaFramboise wrote: > Is there a way to have the DW2 unwinder call some particular function, > for eg, if the previous frame was not compiled with -fexceptions, rather > than just crashing? Is this what MD_FALLBACK_FRAME_STATE_FOR is for? Yes, sortof. I don't know if you can make it do what you want, exactly. > Other Windows compilers are able to handle this condition. If you want to be able to handle this, I recommend that you NOT use dwarf2. Handling this condition is not in the dwarf2 design requirements. r~ |
From: Andrew H. <ap...@re...> - 2004-11-24 17:42:30
|
Richard Henderson writes: > On Wed, Nov 24, 2004 at 02:51:35AM -0600, Aaron W. LaFramboise wrote: > > Is there a way to have the DW2 unwinder call some particular function, > > for eg, if the previous frame was not compiled with -fexceptions, rather > > than just crashing? Is this what MD_FALLBACK_FRAME_STATE_FOR is for? > > Yes, sortof. I don't know if you can make it do what you want, exactly. > > > Other Windows compilers are able to handle this condition. > > If you want to be able to handle this, I recommend that you NOT use dwarf2. DWARF2 unwinder data is required by Java for things other than just throwing exceptions. If it's possible to create a MD_FALLBACK_FRAME_STATE_FOR that can unwind through SEH frames -- and I believe it is -- we should do so. Andrew. |