@@ -105,117 +105,93 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
105105 0x4d4f5a_00_52555354
106106}
107107
108- // We could implement our personality routine in Rust, however exception
109- // info decoding is tedious. More importantly, personality routines have to
110- // handle various platform quirks, which are not fun to maintain. For this
111- // reason, we attempt to reuse personality routine of the C language:
112- // __gcc_personality_v0.
113- //
114- // Since C does not support exception catching, __gcc_personality_v0 simply
115- // always returns _URC_CONTINUE_UNWIND in search phase, and always returns
116- // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
117- //
118- // This is pretty close to Rust's exception handling approach, except that Rust
119- // does have a single "catch-all" handler at the bottom of each thread's stack.
120- // So we have two versions of the personality routine:
121- // - rust_eh_personality, used by all cleanup landing pads, which never catches,
122- // so the behavior of __gcc_personality_v0 is perfectly adequate there, and
123- // - rust_eh_personality_catch, used only by rust_try(), which always catches.
124- //
125- // See also: rustc_trans::trans::intrinsic::trans_gnu_try
126-
127- #[ cfg( all( not( target_arch = "arm" ) ,
108+ // All targets, except 64-bit Windows and ARM (however, iOS goes here as it uses SjLj unwinding).
109+ #[ cfg( all( any( target_os = "ios" , not( target_arch = "arm" ) ) ,
128110 not( all( windows, target_arch = "x86_64" ) ) ) ) ]
129111pub mod eabi {
130112 use unwind as uw;
131- use libc:: c_int;
113+ use libc:: { c_int, uintptr_t} ;
114+ use dwarf:: eh:: { EHContext , EHAction , find_eh_action} ;
132115
133- extern "C" {
134- fn __gcc_personality_v0 ( version : c_int ,
135- actions : uw:: _Unwind_Action ,
136- exception_class : uw:: _Unwind_Exception_Class ,
137- ue_header : * mut uw:: _Unwind_Exception ,
138- context : * mut uw:: _Unwind_Context )
139- -> uw:: _Unwind_Reason_Code ;
140- }
116+ // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
117+ // and TargetLowering::getExceptionSelectorRegister() for each architecture,
118+ // then mapped to DWARF register numbers via register definition tables
119+ // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
120+ // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
141121
142- #[ lang = "eh_personality" ]
143- #[ no_mangle]
144- extern "C" fn rust_eh_personality ( version : c_int ,
145- actions : uw:: _Unwind_Action ,
146- exception_class : uw:: _Unwind_Exception_Class ,
147- ue_header : * mut uw:: _Unwind_Exception ,
148- context : * mut uw:: _Unwind_Context )
149- -> uw:: _Unwind_Reason_Code {
150- unsafe { __gcc_personality_v0 ( version, actions, exception_class, ue_header, context) }
151- }
122+ #[ cfg( target_arch = "x86" ) ]
123+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 2 ) ; // EAX, EDX
152124
153- #[ lang = "eh_personality_catch" ]
154- #[ no_mangle]
155- pub extern "C" fn rust_eh_personality_catch ( version : c_int ,
156- actions : uw:: _Unwind_Action ,
157- exception_class : uw:: _Unwind_Exception_Class ,
158- ue_header : * mut uw:: _Unwind_Exception ,
159- context : * mut uw:: _Unwind_Context )
160- -> uw:: _Unwind_Reason_Code {
125+ #[ cfg( target_arch = "x86_64" ) ]
126+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // RAX, RDX
161127
162- if ( actions as c_int & uw:: _UA_SEARCH_PHASE as c_int ) != 0 {
163- // search phase
164- uw:: _URC_HANDLER_FOUND // catch!
165- } else {
166- // cleanup phase
167- unsafe { __gcc_personality_v0 ( version, actions, exception_class, ue_header, context) }
168- }
169- }
170- }
171-
172- // iOS on armv7 is using SjLj exceptions and therefore requires to use
173- // a specialized personality routine: __gcc_personality_sj0
128+ #[ cfg( target_arch = "arm" ) ]
129+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // R0, R1
174130
175- #[ cfg( all( target_os = "ios" , target_arch = "arm" ) ) ]
176- pub mod eabi {
177- use unwind as uw;
178- use libc:: c_int;
131+ #[ cfg( target_arch = "aarch64" ) ]
132+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // X0, X1
179133
180- extern "C" {
181- fn __gcc_personality_sj0 ( version : c_int ,
182- actions : uw:: _Unwind_Action ,
183- exception_class : uw:: _Unwind_Exception_Class ,
184- ue_header : * mut uw:: _Unwind_Exception ,
185- context : * mut uw:: _Unwind_Context )
186- -> uw:: _Unwind_Reason_Code ;
187- }
134+ // OSX actually has the symbols, but they assert when called.
135+ const HAS_GET_XXX_RELBASE : bool = cfg ! ( not( any( target_os = "ios" , target_os = "macos" ) ) ) ;
188136
189137 #[ lang = "eh_personality" ]
190138 #[ no_mangle]
191- pub extern "C" fn rust_eh_personality ( version : c_int ,
192- actions : uw:: _Unwind_Action ,
193- exception_class : uw:: _Unwind_Exception_Class ,
194- ue_header : * mut uw:: _Unwind_Exception ,
195- context : * mut uw:: _Unwind_Context )
196- -> uw:: _Unwind_Reason_Code {
197- unsafe { __gcc_personality_sj0 ( version, actions, exception_class, ue_header, context) }
139+ #[ allow( unused) ]
140+ unsafe extern "C" fn rust_eh_personality ( version : c_int ,
141+ actions : uw:: _Unwind_Action ,
142+ exception_class : uw:: _Unwind_Exception_Class ,
143+ exception_object : * mut uw:: _Unwind_Exception ,
144+ context : * mut uw:: _Unwind_Context )
145+ -> uw:: _Unwind_Reason_Code {
146+ if version != 1 {
147+ return uw:: _URC_FATAL_PHASE1_ERROR;
148+ }
149+ let lsda = uw:: _Unwind_GetLanguageSpecificData ( context) as * const u8 ;
150+ let mut ip_before_instr: c_int = 0 ;
151+ let ip = uw:: _Unwind_GetIPInfo ( context, & mut ip_before_instr) ;
152+ let eh_context = EHContext {
153+ // The return address points 1 byte past the call instruction,
154+ // which could be in the next IP range in LSDA range table.
155+ ip : if ip_before_instr != 0 { ip } else { ip - 1 } ,
156+ func_start : uw:: _Unwind_GetRegionStart ( context) ,
157+ text_start : if HAS_GET_XXX_RELBASE { uw:: _Unwind_GetTextRelBase ( context) } else { 0 } ,
158+ data_start : if HAS_GET_XXX_RELBASE { uw:: _Unwind_GetDataRelBase ( context) } else { 0 } ,
159+ } ;
160+ let eh_action = find_eh_action ( lsda, & eh_context) ;
161+
162+ if actions as i32 & uw:: _UA_SEARCH_PHASE as i32 != 0 {
163+ match eh_action {
164+ EHAction :: None | EHAction :: Cleanup ( _) => return uw:: _URC_CONTINUE_UNWIND,
165+ EHAction :: Catch ( _) => return uw:: _URC_HANDLER_FOUND,
166+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE1_ERROR,
167+ }
168+ } else {
169+ match eh_action {
170+ EHAction :: None => return uw:: _URC_CONTINUE_UNWIND,
171+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) => {
172+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 0 , exception_object as uintptr_t ) ;
173+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 1 , 0 ) ;
174+ uw:: _Unwind_SetIP ( context, lpad) ;
175+ return uw:: _URC_INSTALL_CONTEXT;
176+ }
177+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE2_ERROR,
178+ }
179+ }
198180 }
199181
182+ #[ cfg( stage0) ]
200183 #[ lang = "eh_personality_catch" ]
201184 #[ no_mangle]
202- pub extern "C" fn rust_eh_personality_catch ( version : c_int ,
203- actions : uw:: _Unwind_Action ,
204- exception_class : uw:: _Unwind_Exception_Class ,
205- ue_header : * mut uw:: _Unwind_Exception ,
206- context : * mut uw:: _Unwind_Context )
207- -> uw:: _Unwind_Reason_Code {
208- if ( actions as c_int & uw:: _UA_SEARCH_PHASE as c_int ) != 0 {
209- // search phase
210- uw:: _URC_HANDLER_FOUND // catch!
211- } else {
212- // cleanup phase
213- unsafe { __gcc_personality_sj0 ( version, actions, exception_class, ue_header, context) }
214- }
185+ pub unsafe extern "C" fn rust_eh_personality_catch ( version : c_int ,
186+ actions : uw:: _Unwind_Action ,
187+ exception_class : uw:: _Unwind_Exception_Class ,
188+ ue_header : * mut uw:: _Unwind_Exception ,
189+ context : * mut uw:: _Unwind_Context )
190+ -> uw:: _Unwind_Reason_Code {
191+ rust_eh_personality ( version, actions, exception_class, ue_header, context)
215192 }
216193}
217194
218-
219195// ARM EHABI uses a slightly different personality routine signature,
220196// but otherwise works the same.
221197#[ cfg( all( target_arch = "arm" , not( target_os = "ios" ) ) ) ]
0 commit comments