@@ -106,117 +106,96 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
106
106
0x4d4f5a_00_52555354
107
107
}
108
108
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" ) ) ) ) ]
130
112
pub mod eabi {
131
113
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} ;
133
116
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.
142
122
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
153
125
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
162
128
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
175
131
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
180
134
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
189
137
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
190
141
#[ lang = "eh_personality" ]
191
142
#[ 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
+ }
199
184
}
200
185
186
+ #[ cfg( stage0) ]
201
187
#[ lang = "eh_personality_catch" ]
202
188
#[ 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)
216
196
}
217
197
}
218
198
219
-
220
199
// ARM EHABI uses a slightly different personality routine signature,
221
200
// but otherwise works the same.
222
201
#[ cfg( all( target_arch = "arm" , not( target_os = "ios" ) ) ) ]
0 commit comments