From 8ad0b5306ddfc738d6e450528ee9beb281212ea0 Mon Sep 17 00:00:00 2001 From: gingold Date: Thu, 19 Jul 2012 07:29:24 +0000 Subject: [PATCH] libstdc++-v3/ * libsupc++/eh_personality.cc (__gxx_personality_seh0): New function. Adjust for SEH. * config/abi/pre/gnu.ver: Add __gxx_personality_seh0. libobjc/ * exception.c (__gnu_objc_personality_seh0): New function. libjava/ * libgcj.ver: Add __gcj_personality_seh0. * exception.cc (__gcj_personality_seh0): New function. Adjust for SEH. libgcc/ * unwind-seh.c: New file. * unwind-generic.h: Include windows.h for SEH. (_Unwind_Exception): Use 6 private fields for SEH. (_GCC_specific_handler): Declare. * unwind-c.c (__gcc_personality_seh0): New function. Adjust for SEH. * config/i386/libgcc-cygming.ver: New file. * config/i386/t-seh-eh: New file. * config.host (x86_64-*-mingw*): Default to seh. gcc/ * opts.c (finish_options): Handle UI_SEH. * expr.c (build_personality_function): Handle UI_SEH. * dwarf2out.c (dwarf2out_begin_prologue): Handle UI_SEH. * coretypes.h (unwind_info_type): Add UI_SEH. * config/i386/winnt.c (i386_pe_seh_emit_except_personality): New function. (i386_pe_seh_init_sections): Likewise. * config/i386/cygming.h (TARGET_ASM_EMIT_EXCEPT_PERSONALITY): Define. (TARGET_ASM_INIT_SECTIONS): Define. * common/config/i386/i386-common.c (TARGET_EXCEPT_UNWIND_INFO): Define. (i386_except_unwind_info): New function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@189644 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 15 + gcc/common/config/i386/i386-common.c | 24 ++ gcc/config/i386/cygming.h | 4 + gcc/config/i386/i386-protos.h | 2 + gcc/config/i386/winnt.c | 42 +++ gcc/coretypes.h | 3 +- gcc/dwarf2out.c | 2 +- gcc/expr.c | 3 + gcc/opts.c | 6 +- libgcc/ChangeLog | 13 + libgcc/config.host | 2 +- libgcc/config/i386/libgcc-cygming.ver | 22 ++ libgcc/config/i386/t-seh-eh | 6 + libgcc/config/i386/t-slibgcc-cygming | 2 +- libgcc/unwind-c.c | 15 + libgcc/unwind-generic.h | 17 ++ libgcc/unwind-seh.c | 483 +++++++++++++++++++++++++++++++ libjava/ChangeLog | 7 + libjava/exception.cc | 20 +- libjava/libgcj.ver | 1 + libobjc/ChangeLog | 7 +- libobjc/exception.c | 15 + libstdc++-v3/ChangeLog | 7 + libstdc++-v3/config/abi/pre/gnu.ver | 1 + libstdc++-v3/libsupc++/eh_personality.cc | 20 +- 25 files changed, 729 insertions(+), 10 deletions(-) create mode 100644 libgcc/config/i386/libgcc-cygming.ver create mode 100644 libgcc/config/i386/t-seh-eh create mode 100644 libgcc/unwind-seh.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d4bd184..174d62f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2012-07-19 Tristan Gingold + Richard Henderson + + * opts.c (finish_options): Handle UI_SEH. + * expr.c (build_personality_function): Handle UI_SEH. + * dwarf2out.c (dwarf2out_begin_prologue): Handle UI_SEH. + * coretypes.h (unwind_info_type): Add UI_SEH. + * config/i386/winnt.c (i386_pe_seh_emit_except_personality): + New function. + (i386_pe_seh_init_sections): Likewise. + * config/i386/cygming.h (TARGET_ASM_EMIT_EXCEPT_PERSONALITY): Define. + (TARGET_ASM_INIT_SECTIONS): Define. + * common/config/i386/i386-common.c (TARGET_EXCEPT_UNWIND_INFO): Define. + (i386_except_unwind_info): New function. + 2012-07-18 Maciej W. Rozycki Chao-ying Fu diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c index 70b7eb7..1fe04a6 100644 --- a/gcc/common/config/i386/i386-common.c +++ b/gcc/common/config/i386/i386-common.c @@ -667,6 +667,30 @@ ix86_supports_split_stack (bool report ATTRIBUTE_UNUSED, return ret; } +/* Implement TARGET_EXCEPT_UNWIND_INFO. */ + +static enum unwind_info_type +i386_except_unwind_info (struct gcc_options *opts) +{ + /* Honor the --enable-sjlj-exceptions configure switch. */ +#ifdef CONFIG_SJLJ_EXCEPTIONS + if (CONFIG_SJLJ_EXCEPTIONS) + return UI_SJLJ; +#endif + + /* On windows 64, prefer SEH exceptions over anything else. */ + if (TARGET_64BIT && DEFAULT_ABI == MS_ABI && opts->x_flag_unwind_tables) + return UI_SEH; + + if (DWARF2_UNWIND_INFO) + return UI_DWARF2; + + return UI_SJLJ; +} + +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO i386_except_unwind_info + #undef TARGET_DEFAULT_TARGET_FLAGS #define TARGET_DEFAULT_TARGET_FLAGS \ (TARGET_DEFAULT \ diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index b5f89c4..8455a67 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -48,6 +48,10 @@ along with GCC; see the file COPYING3. If not see #define TARGET_ASM_UNWIND_EMIT_BEFORE_INSN false #undef TARGET_ASM_FUNCTION_END_PROLOGUE #define TARGET_ASM_FUNCTION_END_PROLOGUE i386_pe_seh_end_prologue +#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY +#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY i386_pe_seh_emit_except_personality +#undef TARGET_ASM_INIT_SECTIONS +#define TARGET_ASM_INIT_SECTIONS i386_pe_seh_init_sections #define SUBTARGET_ASM_UNWIND_INIT i386_pe_seh_init #undef DEFAULT_ABI diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index fe733b0..49e6bbd 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -258,6 +258,8 @@ extern tree i386_pe_mangle_assembler_name (const char *); extern void i386_pe_seh_init (FILE *); extern void i386_pe_seh_end_prologue (FILE *); extern void i386_pe_seh_unwind_emit (FILE *, rtx); +extern void i386_pe_seh_emit_except_personality (rtx); +extern void i386_pe_seh_init_sections (void); /* In winnt-cxx.c and winnt-stubs.c */ extern void i386_pe_adjust_class_at_definition (tree); diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index 5b71ccb..17ee137 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -1143,6 +1143,48 @@ i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn) found: seh_frame_related_expr (asm_out_file, seh, pat); } + +void +i386_pe_seh_emit_except_personality (rtx personality) +{ + int flags = 0; + + if (!TARGET_SEH) + return; + + fputs ("\t.seh_handler\t", asm_out_file); + output_addr_const (asm_out_file, personality); + +#if 0 + /* ??? The current implementation of _GCC_specific_handler requires + both except and unwind handling, regardless of which sorts the + user-level function requires. */ + eh_region r; + FOR_ALL_EH_REGION(r) + { + if (r->type == ERT_CLEANUP) + flags |= 1; + else + flags |= 2; + } +#else + flags = 3; +#endif + + if (flags & 1) + fputs (", @unwind", asm_out_file); + if (flags & 2) + fputs (", @except", asm_out_file); + fputc ('\n', asm_out_file); +} + +void +i386_pe_seh_init_sections (void) +{ + if (TARGET_SEH) + exception_section = get_unnamed_section (0, output_section_asm_op, + "\t.seh_handlerdata"); +} void i386_pe_start_function (FILE *f, const char *name, tree decl) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 7e5c048..02578f6 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -116,7 +116,8 @@ enum unwind_info_type UI_NONE, UI_SJLJ, UI_DWARF2, - UI_TARGET + UI_TARGET, + UI_SEH }; /* Callgraph node profile representation. */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index d4b6831..dd48d1d 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -976,7 +976,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, call-site information. We must emit this label if it might be used. */ if (!do_frame && (!flag_exceptions - || targetm_common.except_unwind_info (&global_options) != UI_TARGET)) + || targetm_common.except_unwind_info (&global_options) == UI_SJLJ)) return; fnsec = function_section (current_function_decl); diff --git a/gcc/expr.c b/gcc/expr.c index 3ba5743..5aec53e 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11011,6 +11011,9 @@ build_personality_function (const char *lang) case UI_TARGET: unwind_and_version = "_v0"; break; + case UI_SEH: + unwind_and_version = "_seh0"; + break; default: gcc_unreachable (); } diff --git a/gcc/opts.c b/gcc/opts.c index 6224c6a..d928784 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -717,7 +717,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, if (opts->x_flag_exceptions && opts->x_flag_reorder_blocks_and_partition - && (ui_except == UI_SJLJ || ui_except == UI_TARGET)) + && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)) { inform (loc, "-freorder-blocks-and-partition does not work " @@ -732,7 +732,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, if (opts->x_flag_unwind_tables && !targetm_common.unwind_tables_default && opts->x_flag_reorder_blocks_and_partition - && (ui_except == UI_SJLJ || ui_except == UI_TARGET)) + && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)) { inform (loc, "-freorder-blocks-and-partition does not support " @@ -749,7 +749,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, && (!targetm_common.have_named_sections || (opts->x_flag_unwind_tables && targetm_common.unwind_tables_default - && (ui_except == UI_SJLJ || ui_except == UI_TARGET)))) + && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)))) { inform (loc, "-freorder-blocks-and-partition does not work " diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index f7acfcb..2424cab 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,16 @@ +2012-07-19 Tristan Gingold + Richard Henderson + + * unwind-seh.c: New file. + * unwind-generic.h: Include windows.h for SEH. + (_Unwind_Exception): Use 6 private fields for SEH. + (_GCC_specific_handler): Declare. + * unwind-c.c (__gcc_personality_seh0): New function. + Adjust for SEH. + * config/i386/libgcc-cygming.ver: New file. + * config/i386/t-seh-eh: New file. + * config.host (x86_64-*-mingw*): Default to seh. + 2012-07-14 Steven Bosscher * config/t-darwin (crt3.0): Remove work-around for fixed PR26840. diff --git a/libgcc/config.host b/libgcc/config.host index d8ad48c..2615d87 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -618,7 +618,7 @@ x86_64-*-mingw*) if test x$enable_sjlj_exceptions = xyes; then tmake_eh_file="i386/t-sjlj-eh" else - tmake_eh_file="i386/t-dw2-eh" + tmake_eh_file="i386/t-seh-eh" fi # Shared libgcc DLL install dir depends on cross/native build. if test x${build} = x${host} ; then diff --git a/libgcc/config/i386/libgcc-cygming.ver b/libgcc/config/i386/libgcc-cygming.ver new file mode 100644 index 0000000..8966cfb --- /dev/null +++ b/libgcc/config/i386/libgcc-cygming.ver @@ -0,0 +1,22 @@ +# Copyright (C) 2012 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +GCC_4.8 { + _GCC_specific_handler + __gcc_personality_seh0 +} diff --git a/libgcc/config/i386/t-seh-eh b/libgcc/config/i386/t-seh-eh new file mode 100644 index 0000000..066ca54b --- /dev/null +++ b/libgcc/config/i386/t-seh-eh @@ -0,0 +1,6 @@ + +# We are using SEH EH. +EH_MODEL = seh + +# Use SEH exception handling. +LIB2ADDEH = $(srcdir)/unwind-seh.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/i386/t-slibgcc-cygming b/libgcc/config/i386/t-slibgcc-cygming index 3bee8b9..6236c78 100644 --- a/libgcc/config/i386/t-slibgcc-cygming +++ b/libgcc/config/i386/t-slibgcc-cygming @@ -55,4 +55,4 @@ SHLIB_MKMAP = $(srcdir)/mkmap-flat.awk # We'd like to use SHLIB_SONAME here too, but shlib_base_name # does not get substituted before mkmap-flat.awk is run. SHLIB_MKMAP_OPTS = -v pe_dll=libgcc_s_$(EH_MODEL)-$(SHLIB_SOVERSION)$(SHLIB_EXT) -SHLIB_MAPFILES = libgcc-std.ver +SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-cygming.ver diff --git a/libgcc/unwind-c.c b/libgcc/unwind-c.c index bd4941d..eb50ad8 100644 --- a/libgcc/unwind-c.c +++ b/libgcc/unwind-c.c @@ -93,6 +93,8 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, #ifdef __USING_SJLJ_EXCEPTIONS__ #define PERSONALITY_FUNCTION __gcc_personality_sj0 #define __builtin_eh_return_data_regno(x) x +#elif defined(__SEH__) +#define PERSONALITY_FUNCTION __gcc_personality_imp #else #define PERSONALITY_FUNCTION __gcc_personality_v0 #endif @@ -107,6 +109,9 @@ PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception * ue_header, struct _Unwind_Context * context) #else +#ifdef __SEH__ +static +#endif _Unwind_Reason_Code PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, struct _Unwind_Context *); @@ -227,3 +232,13 @@ PERSONALITY_FUNCTION (int version, _Unwind_SetIP (context, landing_pad); return _URC_INSTALL_CONTEXT; } + +#ifdef __SEH__ +EXCEPTION_DISPOSITION +__gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) +{ + return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, + ms_disp, __gcc_personality_imp); +} +#endif /* SEH */ diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h index 4ff9017..c9c993b 100644 --- a/libgcc/unwind-generic.h +++ b/libgcc/unwind-generic.h @@ -28,6 +28,11 @@ #ifndef _UNWIND_H #define _UNWIND_H +#ifdef __SEH__ +/* Only for _GCC_specific_handler. */ +#include +#endif + #ifndef HIDE_EXPORTS #pragma GCC visibility push(default) #endif @@ -86,8 +91,13 @@ struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; + +#if !defined (__USING_SJLJ_EXCEPTIONS__) && defined (__SEH__) + _Unwind_Word private_[6]; +#else _Unwind_Word private_1; _Unwind_Word private_2; +#endif /* @@@ The IA-64 ABI says that this structure must be double-word aligned. Taking that literally does not make much sense generically. Instead we @@ -265,6 +275,13 @@ extern void * _Unwind_FindEnclosingFunction (void *pc); # error "What type shall we use for _sleb128_t?" #endif +#ifdef __SEH__ +/* Handles the mapping from SEH to GCC interfaces. */ +EXCEPTION_DISPOSITION _GCC_specific_handler (PEXCEPTION_RECORD, void *, + PCONTEXT, PDISPATCHER_CONTEXT, + _Unwind_Personality_Fn); +#endif + #ifdef __cplusplus } #endif diff --git a/libgcc/unwind-seh.c b/libgcc/unwind-seh.c new file mode 100644 index 0000000..24e4280 --- /dev/null +++ b/libgcc/unwind-seh.c @@ -0,0 +1,483 @@ +/* Structured Exception Handling (SEH) runtime interface routines. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "unwind.h" + +#ifdef __SEH__ + +/* At the moment everything is written for x64, but in theory this could + also be used for i386, arm, mips and other extant embedded Windows. */ +#ifndef __x86_64__ +#error "Unsupported architecture." +#endif + +/* Define GCC's exception codes. See + http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx + In particular, MS defines bits: + [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success) + [29] = 1 (user-defined) + [28] = 0 (reserved) + We define bits: + [24:27] = type + [0:23] = magic + We set "magic" to "GCC", which is similar to MVC++ which uses "msc" + as the low 3 bytes of its user-defined codes for C++ exceptions. + + We define the ExceptionInformation entries as follows: + [0] = _Unwind_Exception pointer + [1] = target frame + [2] = target ip + [3] = target rdx +*/ + +#define STATUS_USER_DEFINED (1U << 29) + +#define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') +#define GCC_EXCEPTION(TYPE) \ + (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC) + +#define STATUS_GCC_THROW GCC_EXCEPTION (0) +#define STATUS_GCC_UNWIND GCC_EXCEPTION (1) +#define STATUS_GCC_FORCED GCC_EXCEPTION (2) + + +struct _Unwind_Context +{ + _Unwind_Word cfa; + _Unwind_Word ra; + _Unwind_Word reg[2]; + PDISPATCHER_CONTEXT disp; +}; + +/* Get the value of register INDEX as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *c, int index) +{ + if (index < 0 || index > 2) + abort (); + return c->reg[index]; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +void +_Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val) +{ + if (index < 0 || index > 2) + abort (); + c->reg[index] = val; +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *c) +{ + return c->cfa; +} + +/* Retrieve the return address for CONTEXT. */ + +_Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *c) +{ + return c->ra; +} + +/* Retrieve the return address and flag whether that IP is before + or after first not yet fully executed instruction. */ + +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn) +{ + /* ??? Is there a concept of a signal context properly? There's + obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might + have arranged for that not to matter, really. */ + *ip_before_insn = 0; + return c->ra; +} + +/* Overwrite the return address for CONTEXT with VAL. */ + +void +_Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val) +{ + c->ra = val; +} + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *c) +{ + return c->disp->HandlerData; +} + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *c) +{ + return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + PRUNTIME_FUNCTION entry; + ULONG64 ImageBase; + + entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL); + + return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL); +} + +_Unwind_Ptr +_Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED) +{ + return 0; +} + +_Unwind_Ptr +_Unwind_GetTextRelBase (struct _Unwind_Context *c) +{ + return c->disp->ImageBase; +} + + +/* The two-phase unwind process that GCC uses is ordered differently + from the two-phase unwind process that SEH uses. The mechansism + that GCC uses is to have the filter return _URC_HANDER_FOUND; the + mechanism that SEH uses is for the filter function call back into + the unwinder. + + An Ideal port to SEH would have GCC emit handler functions that + can be called, given a pointer to the "EstablisherFrame" (i.e. + the frame pointer base of the user-level function) can manipulate + the user-level variables within the user-level function's stack + frame. Once done manipulating the variables, it would return + a ExceptionContinueSearch, and the unwind process would continue. + + GCC has always done things a bit differently. We continue to + transfer control back into the user-level function which, once + done manipulating the user-level variables, re-throws the exception. */ + +/* The "real" language-specific personality handler forwards to here + where we handle the MS SEH state and transforms it into the GCC + unwind state as per GCC's , at which point we defer to + the regular language-specfic exception handler, which is passed in. */ + +EXCEPTION_DISPOSITION +_GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp, + _Unwind_Personality_Fn gcc_per) +{ + DWORD ms_flags = ms_exc->ExceptionFlags; + DWORD ms_code = ms_exc->ExceptionCode; + + struct _Unwind_Exception *gcc_exc + = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0]; + struct _Unwind_Context gcc_context; + _Unwind_Action gcc_action; + _Unwind_Reason_Code gcc_reason; + + if (ms_flags & EXCEPTION_TARGET_UNWIND) + { + /* This frame is known to be the target frame. We've already + "installed" the target_ip and RAX value via the arguments + to RtlUnwindEx. All that's left is to set the RDX value + and "continue" to have the context installed. */ + ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; + return ExceptionContinueSearch; + } + + if (ms_code == STATUS_GCC_UNWIND) + { + /* This is a colliding exception that we threw so that we could + cancel the already in-flight exception and stop in a frame + that wanted to perform some unwind action. The only relevant + test is that we're the target frame. */ + if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame) + { + RtlUnwindEx (this_frame, ms_exc->ExceptionInformation[2], + ms_exc, gcc_exc, ms_orig_context, + ms_disp->HistoryTable); + abort (); + } + return ExceptionContinueSearch; + } + + gcc_context.cfa = ms_disp->ContextRecord->Rsp; + gcc_context.ra = ms_disp->ControlPc; + gcc_context.reg[0] = 0xdeadbeef; /* These are write-only. */ + gcc_context.reg[1] = 0xdeadbeef; + gcc_context.disp = ms_disp; + + if (ms_code == STATUS_GCC_FORCED) + { + _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0]; + void *stop_argument = (void *) gcc_exc->private_[4]; + + gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; + + stop (1, gcc_action, gcc_exc->exception_class, gcc_exc, + &gcc_context, stop_argument); + + goto phase2; + } + + /* ??? TODO: handling non-gcc user-defined exceptions as foreign. */ + if (ms_code != STATUS_GCC_THROW) + return ExceptionContinueSearch; + + if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + /* This is Phase 2. */ + /* We know this isn't the target frame because we've already tested + EXCEPTION_TARGET_UNWIND. The remaining possibility is that the + gcc personality has unwind code to run. */ + + gcc_action = _UA_CLEANUP_PHASE; + phase2: + gcc_reason = gcc_per (1, gcc_action, gcc_exc->exception_class, + gcc_exc, &gcc_context); + + if (gcc_reason == _URC_CONTINUE_UNWIND) + return ExceptionContinueSearch; + + if (gcc_reason == _URC_INSTALL_CONTEXT) + { + /* Scratch space for the bits for the unwind catch. */ + ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; + ms_exc->ExceptionInformation[2] = gcc_context.ra; + ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; + + /* Cancel the current exception by raising another. */ + RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE, + 4, ms_exc->ExceptionInformation); + + /* Is RaiseException declared noreturn? */ + } + + /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */ + } + else + { + /* This is Phase 1. */ + gcc_reason = gcc_per (1, _UA_SEARCH_PHASE, gcc_exc->exception_class, + gcc_exc, &gcc_context); + + if (gcc_reason == _URC_CONTINUE_UNWIND) + return ExceptionContinueSearch; + + if (gcc_reason == _URC_HANDLER_FOUND) + { + /* We really need some of the information that GCC's personality + routines compute during phase 2 right now, like the target IP. + Go ahead and ask for it now, and cache it. */ + gcc_reason = gcc_per (1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME, + gcc_exc->exception_class, gcc_exc, + &gcc_context); + if (gcc_reason != _URC_INSTALL_CONTEXT) + abort (); + + gcc_exc->private_[1] = (_Unwind_Ptr) this_frame; + gcc_exc->private_[2] = gcc_context.ra; + gcc_exc->private_[3] = gcc_context.reg[1]; + + ms_exc->NumberParameters = 4; + ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; + ms_exc->ExceptionInformation[2] = gcc_context.ra; + ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; + + /* Begin phase 2. Perform the unwinding. */ + RtlUnwindEx (this_frame, gcc_context.ra, ms_exc, gcc_exc, + ms_orig_context, ms_disp->HistoryTable); + } + + /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR. */ + } + abort (); +} + +/* Raise an exception, passing along the given exception object. */ + +_Unwind_Reason_Code +_Unwind_RaiseException (struct _Unwind_Exception *exc) +{ + memset (exc->private_, 0, sizeof (exc->private_)); + + /* The ExceptionInformation array will have only 1 element, EXC. */ + RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc); + + /* The exception handler installed in crt0 will continue any GCC + exception that reaches there (and isn't marked non-continuable). + Returning allows the C++ runtime to call std::terminate. */ + return _URC_END_OF_STACK; +} + +/* Resume propagation of an existing exception. This is used after + e.g. executing cleanup code, and not to implement rethrowing. */ + +void +_Unwind_Resume (struct _Unwind_Exception *gcc_exc) +{ + UNWIND_HISTORY_TABLE ms_history; + EXCEPTION_RECORD ms_exc; + CONTEXT ms_context; + + memset (&ms_exc, 0, sizeof(ms_exc)); + memset (&ms_history, 0, sizeof(ms_history)); + + /* ??? Not 100% perfect, since we aren't passing on the *original* + exception context, but should be good enough. */ + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ms_exc.NumberParameters = 4; + ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc; + ms_exc.ExceptionInformation[1] = gcc_exc->private_[1]; + ms_exc.ExceptionInformation[2] = gcc_exc->private_[2]; + ms_exc.ExceptionInformation[3] = gcc_exc->private_[3]; + + ms_context.ContextFlags = CONTEXT_ALL; + RtlCaptureContext (&ms_context); + + RtlUnwindEx ((void *) gcc_exc->private_[1], gcc_exc->private_[2], + &ms_exc, gcc_exc, &ms_context, &ms_history); + + /* Is RtlUnwindEx declared noreturn? */ + abort (); +} + +static _Unwind_Reason_Code +_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc) +{ + _Unwind_Stop_Fn stop; + void * stop_argument; + + RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc); + + /* If we get here, we got to top-of-stack. */ + /* ??? We no longer have a context pointer to pass in. */ + + stop = (_Unwind_Stop_Fn) exc->private_[0]; + stop_argument = (void *) exc->private_[4]; + stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK, + exc->exception_class, exc, NULL, stop_argument); + + return _UA_END_OF_STACK; +} + +_Unwind_Reason_Code +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) +{ + if (exc->private_[0] == 0) + _Unwind_RaiseException (exc); + else + _Unwind_ForcedUnwind_Phase2 (exc); + abort (); +} + +/* Raise an exception for forced unwinding. */ + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument) +{ + /* ??? This is a hack that only works with _GCC_specific_handler. + There's no way to invoke STOP within frames that use a different + exception handler. This is essentially just good enough to run + the code within the gcc testsuite. */ + + memset (exc->private_, 0, sizeof (exc->private_)); + exc->private_[0] = (_Unwind_Ptr) stop; + exc->private_[4] = (_Unwind_Ptr) stop_argument; + + return _Unwind_ForcedUnwind_Phase2 (exc); +} + +/* A convenience function that calls the exception_cleanup field. */ + +void +_Unwind_DeleteException (struct _Unwind_Exception *exc) +{ + if (exc->exception_cleanup) + (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); +} + +/* Perform stack backtrace through unwind data. */ + +_Unwind_Reason_Code +_Unwind_Backtrace(_Unwind_Trace_Fn trace ATTRIBUTE_UNUSED, + void *trace_argument ATTRIBUTE_UNUSED) +{ +#if 0 + UNWIND_HISTORY_TABLE ms_history; + CONTEXT ms_context; + struct _Unwind_Context gcc_context; + + memset (&ms_history, 0, sizeof(ms_history)); + memset (&gcc_context, 0, sizeof(gcc_context)); + + ms_context.ContextFlags = CONTEXT_ALL; + RtlCaptureContext (&ms_context); + + gcc_context.disp.ContextRecord = &ms_context; + gcc_context.disp.HistoryTable = &ms_history; + + while (1) + { + gcc_context.disp.ControlPc = ms_context.Rip; + gcc_context.disp.FunctionEntry + = RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp.ImageBase, + &ms_history); + + if (gcc_context.disp.FunctionEntry) + { + gcc_context.disp.LanguageHandler + = RtlVirtualUnwind (0, gcc_context.disp.ImageBase, ms_context.Rip, + gcc_context.disp.FunctionEntry, &ms_context, + &gcc_context.disp.HandlerData, + &gcc_context.disp.EstablisherFrame, NULL); + } + else + { + ms_context.Rip = *(ULONG_PTR *)ms_context.Rsp; + ms_context.Rsp += 8; + } + + /* Call trace function. */ + if (trace (&gcc_context, trace_argument) != _URC_NO_REASON) + return _URC_FATAL_PHASE1_ERROR; + + /* ??? Check for invalid stack pointer. */ + if (ms_context.Rip == 0) + return _URC_END_OF_STACK; + } +#else + return _URC_END_OF_STACK; +#endif +} +#endif /* __SEH__ */ diff --git a/libjava/ChangeLog b/libjava/ChangeLog index e9b3a0f..6b59802 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,10 @@ +2012-07-19 Tristan Gingold + Richard Henderson + + * libgcj.ver: Add __gcj_personality_seh0. + * exception.cc (__gcj_personality_seh0): New function. + Adjust for SEH. + 2012-07-18 H.J. Lu PR libjava/53973 diff --git a/libjava/exception.cc b/libjava/exception.cc index 56f25ad..cc5ab7c 100644 --- a/libjava/exception.cc +++ b/libjava/exception.cc @@ -197,6 +197,8 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) #ifdef SJLJ_EXCEPTIONS #define PERSONALITY_FUNCTION __gcj_personality_sj0 #define __builtin_eh_return_data_regno(x) x +#elif defined (__SEH__) +#define PERSONALITY_FUNCTION __gcj_personality_imp #else #define PERSONALITY_FUNCTION __gcj_personality_v0 #endif @@ -220,7 +222,12 @@ PERSONALITY_FUNCTION (_Unwind_State state, #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND -extern "C" _Unwind_Reason_Code +#ifdef __SEH__ +static +#else +extern "C" +#endif +_Unwind_Reason_Code PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, @@ -484,3 +491,14 @@ PERSONALITY_FUNCTION (int version, #endif return _URC_INSTALL_CONTEXT; } + +#ifdef __SEH__ +extern "C" +EXCEPTION_DISPOSITION +__gcj_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) +{ + return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, + ms_disp, __gcj_personality_imp); +} +#endif /* SEH */ diff --git a/libjava/libgcj.ver b/libjava/libgcj.ver index 4e90d9d..142c6fb 100644 --- a/libjava/libgcj.ver +++ b/libjava/libgcj.ver @@ -7,6 +7,7 @@ _Jv_*; __gcj_personality_v0; __gcj_personality_sj0; + __gcj_personality_seh0; _Z*; local: *; diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index 3946e65..fe1d395 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,8 @@ +2012-07-19 Tristan Gingold + Richard Henderson + + * exception.c (__gnu_objc_personality_seh0): New function. + 2012-05-16 H.J. Lu * configure: Regenerated. @@ -38,7 +43,7 @@ fields other than the first two upon loading a class. 2011-10-09 Nicola Pero - + * class.c (objc_lookup_class): Added back for compatibility with clang which seems to emit calls to it. diff --git a/libobjc/exception.c b/libobjc/exception.c index 04308ce..1f802a8 100644 --- a/libobjc/exception.c +++ b/libobjc/exception.c @@ -202,6 +202,8 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) #ifdef SJLJ_EXCEPTIONS #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0 #define __builtin_eh_return_data_regno(x) x +#elif defined(__SEH__) +#define PERSONALITY_FUNCTION __gnu_objc_personality_imp #else #define PERSONALITY_FUNCTION __gnu_objc_personality_v0 #endif @@ -225,6 +227,9 @@ PERSONALITY_FUNCTION (_Unwind_State state, #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND +#ifdef __SEH__ +static +#endif _Unwind_Reason_Code PERSONALITY_FUNCTION (int version, _Unwind_Action actions, @@ -519,3 +524,13 @@ objc_exception_throw (id exception) abort (); } +#ifdef __SEH__ +EXCEPTION_DISPOSITION +__gnu_objc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, + PDISPATCHER_CONTEXT ms_disp) +{ + return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, + ms_disp, __gnu_objc_personality_imp); +} +#endif /* SEH */ diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f9dd6c7..1a6f19f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,10 @@ +2012-07-19 Tristan Gingold + Richard Henderson + + * libsupc++/eh_personality.cc (__gxx_personality_seh0): New function. + Adjust for SEH. + * config/abi/pre/gnu.ver: Add __gxx_personality_seh0. + 2012-07-18 Paolo Carlini PR c++/51213 diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index b99a812..cd0be4e 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1357,6 +1357,7 @@ CXXABI_1.3 { __cxa_vec_new3; __gxx_personality_v0; __gxx_personality_sj0; + __gxx_personality_seh0; __dynamic_cast; # *_type_info classes, ctor and dtor diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index 729d688..72f596e 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -332,11 +332,18 @@ namespace __cxxabiv1 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS #define PERSONALITY_FUNCTION __gxx_personality_sj0 #define __builtin_eh_return_data_regno(x) x +#elif defined(__SEH__) +#define PERSONALITY_FUNCTION __gxx_personality_imp #else #define PERSONALITY_FUNCTION __gxx_personality_v0 #endif -extern "C" _Unwind_Reason_Code +#ifdef __SEH__ +static +#else +extern "C" +#endif +_Unwind_Reason_Code #ifdef __ARM_EABI_UNWINDER__ PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception* ue_header, @@ -778,4 +785,15 @@ __cxa_call_unexpected (void *exc_obj_in) } #endif +#ifdef __SEH__ +extern "C" +EXCEPTION_DISPOSITION +__gxx_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, + PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) +{ + return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, + ms_disp, __gxx_personality_imp); +} +#endif /* SEH */ + } // namespace __cxxabiv1 -- 2.7.4