@@ -106,117 +106,96 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
106106 0x4d4f5a_00_52555354
107107}
108108
109- // We could implement our personality routine in Rust, however exception
110- // info decoding is tedious. More importantly, personality routines have to
111- // handle various platform quirks, which are not fun to maintain. For this
112- // reason, we attempt to reuse personality routine of the C language:
113- // __gcc_personality_v0.
114- //
115- // Since C does not support exception catching, __gcc_personality_v0 simply
116- // always returns _URC_CONTINUE_UNWIND in search phase, and always returns
117- // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
118- //
119- // This is pretty close to Rust's exception handling approach, except that Rust
120- // does have a single "catch-all" handler at the bottom of each thread's stack.
121- // So we have two versions of the personality routine:
122- // - rust_eh_personality, used by all cleanup landing pads, which never catches,
123- // so the behavior of __gcc_personality_v0 is perfectly adequate there, and
124- // - rust_eh_personality_catch, used only by rust_try(), which always catches.
125- //
126- // See also: rustc_trans::trans::intrinsic::trans_gnu_try
127-
128- #[ cfg( all( not( target_arch = "arm" ) ,
129- not( all( windows, target_arch = "x86_64" ) ) ) ) ]
109+ // All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
110+ // SjLj unwinding). Also, 64-bit Windows implementation lives in seh64_gnu.rs
111+ #[ cfg( all( any( target_os = "ios" , not( target_arch = "arm" ) ) ) ) ]
130112pub mod eabi {
131113 use unwind as uw;
132- use libc:: c_int;
114+ use libc:: { c_int, uintptr_t} ;
115+ use dwarf:: eh:: { EHContext , EHAction , find_eh_action} ;
133116
134- extern "C" {
135- fn __gcc_personality_v0 ( version : c_int ,
136- actions : uw:: _Unwind_Action ,
137- exception_class : uw:: _Unwind_Exception_Class ,
138- ue_header : * mut uw:: _Unwind_Exception ,
139- context : * mut uw:: _Unwind_Context )
140- -> uw:: _Unwind_Reason_Code ;
141- }
117+ // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
118+ // and TargetLowering::getExceptionSelectorRegister() for each architecture,
119+ // then mapped to DWARF register numbers via register definition tables
120+ // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
121+ // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
142122
143- #[ lang = "eh_personality" ]
144- #[ no_mangle]
145- extern "C" fn rust_eh_personality ( version : c_int ,
146- actions : uw:: _Unwind_Action ,
147- exception_class : uw:: _Unwind_Exception_Class ,
148- ue_header : * mut uw:: _Unwind_Exception ,
149- context : * mut uw:: _Unwind_Context )
150- -> uw:: _Unwind_Reason_Code {
151- unsafe { __gcc_personality_v0 ( version, actions, exception_class, ue_header, context) }
152- }
123+ #[ cfg( target_arch = "x86" ) ]
124+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 2 ) ; // EAX, EDX
153125
154- #[ lang = "eh_personality_catch" ]
155- #[ no_mangle]
156- pub extern "C" fn rust_eh_personality_catch ( version : c_int ,
157- actions : uw:: _Unwind_Action ,
158- exception_class : uw:: _Unwind_Exception_Class ,
159- ue_header : * mut uw:: _Unwind_Exception ,
160- context : * mut uw:: _Unwind_Context )
161- -> uw:: _Unwind_Reason_Code {
126+ #[ cfg( target_arch = "x86_64" ) ]
127+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // RAX, RDX
162128
163- if ( actions as c_int & uw:: _UA_SEARCH_PHASE as c_int ) != 0 {
164- // search phase
165- uw:: _URC_HANDLER_FOUND // catch!
166- } else {
167- // cleanup phase
168- unsafe { __gcc_personality_v0 ( version, actions, exception_class, ue_header, context) }
169- }
170- }
171- }
172-
173- // iOS on armv7 is using SjLj exceptions and therefore requires to use
174- // a specialized personality routine: __gcc_personality_sj0
129+ #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
130+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // R0, R1 / X0, X1
175131
176- #[ cfg( all( target_os = "ios" , target_arch = "arm" ) ) ]
177- pub mod eabi {
178- use unwind as uw;
179- use libc:: c_int;
132+ #[ cfg( any( target_arch = "mips" , target_arch = "mipsel" ) ) ]
133+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 4 , 5 ) ; // A0, A1
180134
181- extern "C" {
182- fn __gcc_personality_sj0 ( version : c_int ,
183- actions : uw:: _Unwind_Action ,
184- exception_class : uw:: _Unwind_Exception_Class ,
185- ue_header : * mut uw:: _Unwind_Exception ,
186- context : * mut uw:: _Unwind_Context )
187- -> uw:: _Unwind_Reason_Code ;
188- }
135+ #[ cfg( any( target_arch = "powerpc" , target_arch = "powerpc64" ) ) ]
136+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 3 , 4 ) ; // R3, R4 / X3, X4
189137
138+ // Based on GCC's C and C++ personality routines. For reference, see:
139+ // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
140+ // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
190141 #[ lang = "eh_personality" ]
191142 #[ no_mangle]
192- pub extern "C" fn rust_eh_personality ( version : c_int ,
193- actions : uw:: _Unwind_Action ,
194- exception_class : uw:: _Unwind_Exception_Class ,
195- ue_header : * mut uw:: _Unwind_Exception ,
196- context : * mut uw:: _Unwind_Context )
197- -> uw:: _Unwind_Reason_Code {
198- unsafe { __gcc_personality_sj0 ( version, actions, exception_class, ue_header, context) }
143+ #[ allow( unused) ]
144+ unsafe extern "C" fn rust_eh_personality ( version : c_int ,
145+ actions : uw:: _Unwind_Action ,
146+ exception_class : uw:: _Unwind_Exception_Class ,
147+ exception_object : * mut uw:: _Unwind_Exception ,
148+ context : * mut uw:: _Unwind_Context )
149+ -> uw:: _Unwind_Reason_Code {
150+ if version != 1 {
151+ return uw:: _URC_FATAL_PHASE1_ERROR;
152+ }
153+ let lsda = uw:: _Unwind_GetLanguageSpecificData ( context) as * const u8 ;
154+ let mut ip_before_instr: c_int = 0 ;
155+ let ip = uw:: _Unwind_GetIPInfo ( context, & mut ip_before_instr) ;
156+ let eh_context = EHContext {
157+ // The return address points 1 byte past the call instruction,
158+ // which could be in the next IP range in LSDA range table.
159+ ip : if ip_before_instr != 0 { ip } else { ip - 1 } ,
160+ func_start : uw:: _Unwind_GetRegionStart ( context) ,
161+ get_text_start : & || uw:: _Unwind_GetTextRelBase ( context) ,
162+ get_data_start : & || uw:: _Unwind_GetDataRelBase ( context) ,
163+ } ;
164+ let eh_action = find_eh_action ( lsda, & eh_context) ;
165+
166+ if actions as i32 & uw:: _UA_SEARCH_PHASE as i32 != 0 {
167+ match eh_action {
168+ EHAction :: None | EHAction :: Cleanup ( _) => return uw:: _URC_CONTINUE_UNWIND,
169+ EHAction :: Catch ( _) => return uw:: _URC_HANDLER_FOUND,
170+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE1_ERROR,
171+ }
172+ } else {
173+ match eh_action {
174+ EHAction :: None => return uw:: _URC_CONTINUE_UNWIND,
175+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) => {
176+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 0 , exception_object as uintptr_t ) ;
177+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 1 , 0 ) ;
178+ uw:: _Unwind_SetIP ( context, lpad) ;
179+ return uw:: _URC_INSTALL_CONTEXT;
180+ }
181+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE2_ERROR,
182+ }
183+ }
199184 }
200185
186+ #[ cfg( stage0) ]
201187 #[ lang = "eh_personality_catch" ]
202188 #[ no_mangle]
203- pub extern "C" fn rust_eh_personality_catch ( version : c_int ,
204- actions : uw:: _Unwind_Action ,
205- exception_class : uw:: _Unwind_Exception_Class ,
206- ue_header : * mut uw:: _Unwind_Exception ,
207- context : * mut uw:: _Unwind_Context )
208- -> uw:: _Unwind_Reason_Code {
209- if ( actions as c_int & uw:: _UA_SEARCH_PHASE as c_int ) != 0 {
210- // search phase
211- uw:: _URC_HANDLER_FOUND // catch!
212- } else {
213- // cleanup phase
214- unsafe { __gcc_personality_sj0 ( version, actions, exception_class, ue_header, context) }
215- }
189+ pub unsafe extern "C" fn rust_eh_personality_catch ( version : c_int ,
190+ actions : uw:: _Unwind_Action ,
191+ exception_class : uw:: _Unwind_Exception_Class ,
192+ ue_header : * mut uw:: _Unwind_Exception ,
193+ context : * mut uw:: _Unwind_Context )
194+ -> uw:: _Unwind_Reason_Code {
195+ rust_eh_personality ( version, actions, exception_class, ue_header, context)
216196 }
217197}
218198
219-
220199// ARM EHABI uses a slightly different personality routine signature,
221200// but otherwise works the same.
222201#[ cfg( all( target_arch = "arm" , not( target_os = "ios" ) ) ) ]
0 commit comments