@@ -61,6 +61,8 @@ use core::ptr;
61
61
use alloc:: boxed:: Box ;
62
62
63
63
use unwind as uw;
64
+ use libc:: { c_int, uintptr_t} ;
65
+ use dwarf:: eh:: { self , EHContext , EHAction } ;
64
66
65
67
#[ repr( C ) ]
66
68
struct Exception {
@@ -106,139 +108,184 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
106
108
0x4d4f5a_00_52555354
107
109
}
108
110
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" ) ) ) ) ]
112
- pub mod eabi {
113
- use unwind as uw;
114
- use libc:: { c_int, uintptr_t} ;
115
- use dwarf:: eh:: { EHContext , EHAction , find_eh_action} ;
116
111
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.
112
+ // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
113
+ // and TargetLowering::getExceptionSelectorRegister() for each architecture,
114
+ // then mapped to DWARF register numbers via register definition tables
115
+ // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
116
+ // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
122
117
123
- #[ cfg( target_arch = "x86" ) ]
124
- const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 2 ) ; // EAX, EDX
118
+ #[ cfg( target_arch = "x86" ) ]
119
+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 2 ) ; // EAX, EDX
125
120
126
- #[ cfg( target_arch = "x86_64" ) ]
127
- const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // RAX, RDX
121
+ #[ cfg( target_arch = "x86_64" ) ]
122
+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // RAX, RDX
128
123
129
- #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
130
- const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // R0, R1 / X0, X1
124
+ #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
125
+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 0 , 1 ) ; // R0, R1 / X0, X1
131
126
132
- #[ cfg( any( target_arch = "mips" , target_arch = "mipsel" ) ) ]
133
- const UNWIND_DATA_REG : ( i32 , i32 ) = ( 4 , 5 ) ; // A0, A1
127
+ #[ cfg( any( target_arch = "mips" , target_arch = "mipsel" ) ) ]
128
+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 4 , 5 ) ; // A0, A1
134
129
135
- #[ cfg( any( target_arch = "powerpc" , target_arch = "powerpc64" ) ) ]
136
- const UNWIND_DATA_REG : ( i32 , i32 ) = ( 3 , 4 ) ; // R3, R4 / X3, X4
130
+ #[ cfg( any( target_arch = "powerpc" , target_arch = "powerpc64" ) ) ]
131
+ const UNWIND_DATA_REG : ( i32 , i32 ) = ( 3 , 4 ) ; // R3, R4 / X3, X4
137
132
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
141
- #[ lang = "eh_personality" ]
142
- #[ no_mangle]
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) ;
133
+ // The following code is based on GCC's C and C++ personality routines. For reference, see:
134
+ // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
135
+ // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
165
136
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,
137
+ // The personality routine for most of our targets, except ARM, which has a slightly different ABI
138
+ // (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
139
+ // lives in seh64_gnu.rs
140
+ #[ cfg( all( any( target_os = "ios" , not( target_arch = "arm" ) ) ) ) ]
141
+ #[ lang = "eh_personality" ]
142
+ #[ no_mangle]
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 eh_action = find_eh_action ( context) ;
154
+ if actions as i32 & uw:: _UA_SEARCH_PHASE as i32 != 0 {
155
+ match eh_action {
156
+ EHAction :: None | EHAction :: Cleanup ( _) => return uw:: _URC_CONTINUE_UNWIND,
157
+ EHAction :: Catch ( _) => return uw:: _URC_HANDLER_FOUND,
158
+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE1_ERROR,
159
+ }
160
+ } else {
161
+ match eh_action {
162
+ EHAction :: None => return uw:: _URC_CONTINUE_UNWIND,
163
+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) => {
164
+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 0 , exception_object as uintptr_t ) ;
165
+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 1 , 0 ) ;
166
+ uw:: _Unwind_SetIP ( context, lpad) ;
167
+ return uw:: _URC_INSTALL_CONTEXT;
182
168
}
169
+ EHAction :: Terminate => return uw:: _URC_FATAL_PHASE2_ERROR,
183
170
}
184
171
}
185
-
186
- #[ cfg( stage0) ]
187
- #[ lang = "eh_personality_catch" ]
188
- #[ no_mangle]
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)
196
- }
197
172
}
198
173
199
- // ARM EHABI uses a slightly different personality routine signature,
200
- // but otherwise works the same.
174
+ // ARM EHABI personality routine.
175
+ // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
201
176
#[ cfg( all( target_arch = "arm" , not( target_os = "ios" ) ) ) ]
202
- pub mod eabi {
203
- use unwind as uw;
204
- use libc:: c_int;
177
+ #[ lang = "eh_personality" ]
178
+ #[ no_mangle]
179
+ unsafe extern "C" fn rust_eh_personality ( state : uw:: _Unwind_State ,
180
+ exception_object : * mut uw:: _Unwind_Exception ,
181
+ context : * mut uw:: _Unwind_Context )
182
+ -> uw:: _Unwind_Reason_Code {
183
+ let state = state as c_int ;
184
+ let action = state & uw:: _US_ACTION_MASK as c_int ;
185
+ let search_phase = if action == uw:: _US_VIRTUAL_UNWIND_FRAME as c_int {
186
+ // Backtraces on ARM will call the personality routine with
187
+ // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
188
+ // we want to continue unwinding the stack, otherwise all our backtraces
189
+ // would end at __rust_try
190
+ if state & uw:: _US_FORCE_UNWIND as c_int != 0 {
191
+ return continue_unwind ( exception_object, context)
192
+ }
193
+ true
194
+ } else if action == uw:: _US_UNWIND_FRAME_STARTING as c_int {
195
+ false
196
+ } else if action == uw:: _US_UNWIND_FRAME_RESUME as c_int {
197
+ return continue_unwind ( exception_object, context) ;
198
+ } else {
199
+ return uw:: _URC_FAILURE;
200
+ } ;
205
201
206
- extern "C" {
207
- fn __gcc_personality_v0 ( state : uw:: _Unwind_State ,
208
- ue_header : * mut uw:: _Unwind_Exception ,
209
- context : * mut uw:: _Unwind_Context )
210
- -> uw:: _Unwind_Reason_Code ;
211
- }
202
+ // The DWARF unwinder assumes that _Unwind_Context holds things like the function
203
+ // and LSDA pointers, however ARM EHABI places them into the exception object.
204
+ // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
205
+ // take only the context pointer, GCC personality routines stash a pointer to exception_object
206
+ // in the context, using location reserved for ARM's "scratch register" (r12).
207
+ uw:: _Unwind_SetGR ( context, uw:: UNWIND_POINTER_REG , exception_object as uw:: _Unwind_Ptr ) ;
208
+ // ...A more principled approach would be to provide the full definition of ARM's
209
+ // _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
210
+ // bypassing DWARF compatibility functions.
212
211
213
- #[ lang = "eh_personality" ]
214
- #[ no_mangle]
215
- extern "C" fn rust_eh_personality ( state : uw:: _Unwind_State ,
216
- ue_header : * mut uw:: _Unwind_Exception ,
217
- context : * mut uw:: _Unwind_Context )
218
- -> uw:: _Unwind_Reason_Code {
219
- unsafe { __gcc_personality_v0 ( state, ue_header, context) }
212
+ let eh_action = find_eh_action ( context) ;
213
+ if search_phase {
214
+ match eh_action {
215
+ EHAction :: None |
216
+ EHAction :: Cleanup ( _) => return continue_unwind ( exception_object, context) ,
217
+ EHAction :: Catch ( _) => return uw:: _URC_HANDLER_FOUND,
218
+ EHAction :: Terminate => return uw:: _URC_FAILURE,
219
+ }
220
+ } else {
221
+ match eh_action {
222
+ EHAction :: None => return continue_unwind ( exception_object, context) ,
223
+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) => {
224
+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 0 , exception_object as uintptr_t ) ;
225
+ uw:: _Unwind_SetGR ( context, UNWIND_DATA_REG . 1 , 0 ) ;
226
+ uw:: _Unwind_SetIP ( context, lpad) ;
227
+ return uw:: _URC_INSTALL_CONTEXT;
228
+ }
229
+ EHAction :: Terminate => return uw:: _URC_FAILURE,
230
+ }
220
231
}
221
232
222
- #[ lang = "eh_personality_catch" ]
223
- #[ no_mangle]
224
- pub extern "C" fn rust_eh_personality_catch ( state : uw:: _Unwind_State ,
225
- ue_header : * mut uw:: _Unwind_Exception ,
226
- context : * mut uw:: _Unwind_Context )
227
- -> uw:: _Unwind_Reason_Code {
228
- // Backtraces on ARM will call the personality routine with
229
- // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
230
- // we want to continue unwinding the stack, otherwise all our backtraces
231
- // would end at __rust_try.
232
- if ( state as c_int & uw:: _US_ACTION_MASK as c_int ) ==
233
- uw:: _US_VIRTUAL_UNWIND_FRAME as c_int &&
234
- ( state as c_int & uw:: _US_FORCE_UNWIND as c_int ) == 0 {
235
- // search phase
236
- uw:: _URC_HANDLER_FOUND // catch!
233
+ // On ARM EHABI the personality routine is responsible for actually
234
+ // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
235
+ unsafe fn continue_unwind ( exception_object : * mut uw:: _Unwind_Exception ,
236
+ context : * mut uw:: _Unwind_Context )
237
+ -> uw:: _Unwind_Reason_Code {
238
+ if __gnu_unwind_frame ( exception_object, context) == uw:: _URC_NO_REASON {
239
+ uw:: _URC_CONTINUE_UNWIND
237
240
} else {
238
- // cleanup phase
239
- unsafe { __gcc_personality_v0 ( state, ue_header, context) }
241
+ uw:: _URC_FAILURE
240
242
}
241
243
}
244
+ // defined in libgcc
245
+ extern "C" {
246
+ fn __gnu_unwind_frame ( exception_object : * mut uw:: _Unwind_Exception ,
247
+ context : * mut uw:: _Unwind_Context )
248
+ -> uw:: _Unwind_Reason_Code ;
249
+ }
250
+ }
251
+
252
+ unsafe fn find_eh_action ( context : * mut uw:: _Unwind_Context ) -> EHAction {
253
+ let lsda = uw:: _Unwind_GetLanguageSpecificData ( context) as * const u8 ;
254
+ let mut ip_before_instr: c_int = 0 ;
255
+ let ip = uw:: _Unwind_GetIPInfo ( context, & mut ip_before_instr) ;
256
+ let eh_context = EHContext {
257
+ // The return address points 1 byte past the call instruction,
258
+ // which could be in the next IP range in LSDA range table.
259
+ ip : if ip_before_instr != 0 { ip } else { ip - 1 } ,
260
+ func_start : uw:: _Unwind_GetRegionStart ( context) ,
261
+ get_text_start : & || uw:: _Unwind_GetTextRelBase ( context) ,
262
+ get_data_start : & || uw:: _Unwind_GetDataRelBase ( context) ,
263
+ } ;
264
+ eh:: find_eh_action ( lsda, & eh_context)
265
+ }
266
+
267
+ // *** Delete after a new snapshot ***
268
+ #[ cfg( all( stage0, any( target_os = "ios" , not( target_arch = "arm" ) ) ) ) ]
269
+ #[ lang = "eh_personality_catch" ]
270
+ #[ no_mangle]
271
+ pub unsafe extern "C" fn rust_eh_personality_catch ( version : c_int ,
272
+ actions : uw:: _Unwind_Action ,
273
+ exception_class : uw:: _Unwind_Exception_Class ,
274
+ ue_header : * mut uw:: _Unwind_Exception ,
275
+ context : * mut uw:: _Unwind_Context )
276
+ -> uw:: _Unwind_Reason_Code {
277
+ rust_eh_personality ( version, actions, exception_class, ue_header, context)
278
+ }
279
+
280
+ // *** Delete after a new snapshot ***
281
+ #[ cfg( all( stage0, target_arch = "arm" , not( target_os = "ios" ) ) ) ]
282
+ #[ lang = "eh_personality_catch" ]
283
+ #[ no_mangle]
284
+ pub unsafe extern "C" fn rust_eh_personality_catch ( state : uw:: _Unwind_State ,
285
+ ue_header : * mut uw:: _Unwind_Exception ,
286
+ context : * mut uw:: _Unwind_Context )
287
+ -> uw:: _Unwind_Reason_Code {
288
+ rust_eh_personality ( state, ue_header, context)
242
289
}
243
290
244
291
// See docs in the `unwind` module.
0 commit comments