@@ -105,117 +105,93 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
105
105
0x4d4f5a_00_52555354
106
106
}
107
107
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" ) ) ,
128
110
not( all( windows, target_arch = "x86_64" ) ) ) ) ]
129
111
pub mod eabi {
130
112
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} ;
132
115
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.
141
121
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
152
124
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
161
127
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
174
130
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
179
133
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" ) ) ) ;
188
136
189
137
#[ lang = "eh_personality" ]
190
138
#[ 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
+ }
198
180
}
199
181
182
+ #[ cfg( stage0) ]
200
183
#[ lang = "eh_personality_catch" ]
201
184
#[ 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)
215
192
}
216
193
}
217
194
218
-
219
195
// ARM EHABI uses a slightly different personality routine signature,
220
196
// but otherwise works the same.
221
197
#[ cfg( all( target_arch = "arm" , not( target_os = "ios" ) ) ) ]
0 commit comments