35
35
//!
36
36
//! Once stack has been unwound down to the handler frame level, unwinding stops
37
37
//! and the last personality routine transfers control to the catch block.
38
+ #![ forbid( unsafe_op_in_unsafe_fn) ]
38
39
39
40
use super :: dwarf:: eh:: { self , EHAction , EHContext } ;
40
41
use crate :: ffi:: c_int;
@@ -92,7 +93,11 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
92
93
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
93
94
94
95
cfg_if:: cfg_if! {
95
- if #[ cfg( all( not( all( target_vendor = "apple" , not( target_os = "watchos" ) ) ) , target_arch = "arm" , not( target_os = "netbsd" ) ) ) ] {
96
+ if #[ cfg( all(
97
+ target_arch = "arm" ,
98
+ not( all( target_vendor = "apple" , not( target_os = "watchos" ) ) ) ,
99
+ not( target_os = "netbsd" ) ,
100
+ ) ) ] {
96
101
// ARM EHABI personality routine.
97
102
// https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
98
103
//
@@ -104,90 +109,94 @@ cfg_if::cfg_if! {
104
109
exception_object: * mut uw:: _Unwind_Exception,
105
110
context: * mut uw:: _Unwind_Context,
106
111
) -> uw:: _Unwind_Reason_Code {
107
- let state = state as c_int;
108
- let action = state & uw:: _US_ACTION_MASK as c_int;
109
- let search_phase = if action == uw:: _US_VIRTUAL_UNWIND_FRAME as c_int {
110
- // Backtraces on ARM will call the personality routine with
111
- // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
112
- // we want to continue unwinding the stack, otherwise all our backtraces
113
- // would end at __rust_try
114
- if state & uw:: _US_FORCE_UNWIND as c_int != 0 {
112
+ unsafe {
113
+ let state = state as c_int;
114
+ let action = state & uw:: _US_ACTION_MASK as c_int;
115
+ let search_phase = if action == uw:: _US_VIRTUAL_UNWIND_FRAME as c_int {
116
+ // Backtraces on ARM will call the personality routine with
117
+ // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
118
+ // we want to continue unwinding the stack, otherwise all our backtraces
119
+ // would end at __rust_try
120
+ if state & uw:: _US_FORCE_UNWIND as c_int != 0 {
121
+ return continue_unwind( exception_object, context) ;
122
+ }
123
+ true
124
+ } else if action == uw:: _US_UNWIND_FRAME_STARTING as c_int {
125
+ false
126
+ } else if action == uw:: _US_UNWIND_FRAME_RESUME as c_int {
115
127
return continue_unwind( exception_object, context) ;
116
- }
117
- true
118
- } else if action == uw:: _US_UNWIND_FRAME_STARTING as c_int {
119
- false
120
- } else if action == uw:: _US_UNWIND_FRAME_RESUME as c_int {
121
- return continue_unwind( exception_object, context) ;
122
- } else {
123
- return uw:: _URC_FAILURE;
124
- } ;
128
+ } else {
129
+ return uw:: _URC_FAILURE;
130
+ } ;
125
131
126
- // The DWARF unwinder assumes that _Unwind_Context holds things like the function
127
- // and LSDA pointers, however ARM EHABI places them into the exception object.
128
- // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
129
- // take only the context pointer, GCC personality routines stash a pointer to
130
- // exception_object in the context, using location reserved for ARM's
131
- // "scratch register" (r12).
132
- uw:: _Unwind_SetGR( context, uw:: UNWIND_POINTER_REG , exception_object as uw:: _Unwind_Ptr) ;
133
- // ...A more principled approach would be to provide the full definition of ARM's
134
- // _Unwind_Context in our libunwind bindings and fetch the required data from there
135
- // directly, bypassing DWARF compatibility functions.
132
+ // The DWARF unwinder assumes that _Unwind_Context holds things like the function
133
+ // and LSDA pointers, however ARM EHABI places them into the exception object.
134
+ // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
135
+ // take only the context pointer, GCC personality routines stash a pointer to
136
+ // exception_object in the context, using location reserved for ARM's
137
+ // "scratch register" (r12).
138
+ uw:: _Unwind_SetGR( context, uw:: UNWIND_POINTER_REG , exception_object as uw:: _Unwind_Ptr) ;
139
+ // ...A more principled approach would be to provide the full definition of ARM's
140
+ // _Unwind_Context in our libunwind bindings and fetch the required data from there
141
+ // directly, bypassing DWARF compatibility functions.
136
142
137
- let eh_action = match find_eh_action( context) {
138
- Ok ( action) => action,
139
- Err ( _) => return uw:: _URC_FAILURE,
140
- } ;
141
- if search_phase {
142
- match eh_action {
143
- EHAction :: None | EHAction :: Cleanup ( _) => {
144
- return continue_unwind( exception_object, context) ;
143
+ let eh_action = match find_eh_action( context) {
144
+ Ok ( action) => action,
145
+ Err ( _) => return uw:: _URC_FAILURE,
146
+ } ;
147
+ if search_phase {
148
+ match eh_action {
149
+ EHAction :: None | EHAction :: Cleanup ( _) => {
150
+ return continue_unwind( exception_object, context) ;
151
+ }
152
+ EHAction :: Catch ( _) | EHAction :: Filter ( _) => {
153
+ // EHABI requires the personality routine to update the
154
+ // SP value in the barrier cache of the exception object.
155
+ ( * exception_object) . private[ 5 ] =
156
+ uw:: _Unwind_GetGR( context, uw:: UNWIND_SP_REG ) ;
157
+ return uw:: _URC_HANDLER_FOUND;
158
+ }
159
+ EHAction :: Terminate => return uw:: _URC_FAILURE,
145
160
}
146
- EHAction :: Catch ( _) | EHAction :: Filter ( _) => {
147
- // EHABI requires the personality routine to update the
148
- // SP value in the barrier cache of the exception object.
149
- ( * exception_object) . private[ 5 ] =
150
- uw:: _Unwind_GetGR( context, uw:: UNWIND_SP_REG ) ;
151
- return uw:: _URC_HANDLER_FOUND;
152
- }
153
- EHAction :: Terminate => return uw:: _URC_FAILURE,
154
- }
155
- } else {
156
- match eh_action {
157
- EHAction :: None => return continue_unwind( exception_object, context) ,
158
- EHAction :: Filter ( _) if state & uw:: _US_FORCE_UNWIND as c_int != 0 => return continue_unwind( exception_object, context) ,
159
- EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) | EHAction :: Filter ( lpad) => {
160
- uw:: _Unwind_SetGR(
161
- context,
162
- UNWIND_DATA_REG . 0 ,
163
- exception_object as uw:: _Unwind_Ptr,
164
- ) ;
165
- uw:: _Unwind_SetGR( context, UNWIND_DATA_REG . 1 , core:: ptr:: null( ) ) ;
166
- uw:: _Unwind_SetIP( context, lpad) ;
167
- return uw:: _URC_INSTALL_CONTEXT;
161
+ } else {
162
+ match eh_action {
163
+ EHAction :: None => return continue_unwind( exception_object, context) ,
164
+ EHAction :: Filter ( _) if state & uw:: _US_FORCE_UNWIND as c_int != 0 => return continue_unwind( exception_object, context) ,
165
+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) | EHAction :: Filter ( lpad) => {
166
+ uw:: _Unwind_SetGR(
167
+ context,
168
+ UNWIND_DATA_REG . 0 ,
169
+ exception_object as uw:: _Unwind_Ptr,
170
+ ) ;
171
+ uw:: _Unwind_SetGR( context, UNWIND_DATA_REG . 1 , core:: ptr:: null( ) ) ;
172
+ uw:: _Unwind_SetIP( context, lpad) ;
173
+ return uw:: _URC_INSTALL_CONTEXT;
174
+ }
175
+ EHAction :: Terminate => return uw:: _URC_FAILURE,
168
176
}
169
- EHAction :: Terminate => return uw:: _URC_FAILURE,
170
177
}
171
- }
172
178
173
- // On ARM EHABI the personality routine is responsible for actually
174
- // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
175
- unsafe fn continue_unwind(
176
- exception_object: * mut uw:: _Unwind_Exception,
177
- context: * mut uw:: _Unwind_Context,
178
- ) -> uw:: _Unwind_Reason_Code {
179
- if __gnu_unwind_frame( exception_object, context) == uw:: _URC_NO_REASON {
180
- uw:: _URC_CONTINUE_UNWIND
181
- } else {
182
- uw:: _URC_FAILURE
183
- }
184
- }
185
- // defined in libgcc
186
- extern "C" {
187
- fn __gnu_unwind_frame(
179
+ // On ARM EHABI the personality routine is responsible for actually
180
+ // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
181
+ unsafe fn continue_unwind(
188
182
exception_object: * mut uw:: _Unwind_Exception,
189
183
context: * mut uw:: _Unwind_Context,
190
- ) -> uw:: _Unwind_Reason_Code;
184
+ ) -> uw:: _Unwind_Reason_Code {
185
+ unsafe {
186
+ if __gnu_unwind_frame( exception_object, context) == uw:: _URC_NO_REASON {
187
+ uw:: _URC_CONTINUE_UNWIND
188
+ } else {
189
+ uw:: _URC_FAILURE
190
+ }
191
+ }
192
+ }
193
+ // defined in libgcc
194
+ extern "C" {
195
+ fn __gnu_unwind_frame(
196
+ exception_object: * mut uw:: _Unwind_Exception,
197
+ context: * mut uw:: _Unwind_Context,
198
+ ) -> uw:: _Unwind_Reason_Code;
199
+ }
191
200
}
192
201
}
193
202
} else {
@@ -200,35 +209,37 @@ cfg_if::cfg_if! {
200
209
exception_object: * mut uw:: _Unwind_Exception,
201
210
context: * mut uw:: _Unwind_Context,
202
211
) -> uw:: _Unwind_Reason_Code {
203
- if version != 1 {
204
- return uw:: _URC_FATAL_PHASE1_ERROR;
205
- }
206
- let eh_action = match find_eh_action( context) {
207
- Ok ( action) => action,
208
- Err ( _) => return uw:: _URC_FATAL_PHASE1_ERROR,
209
- } ;
210
- if actions as i32 & uw:: _UA_SEARCH_PHASE as i32 != 0 {
211
- match eh_action {
212
- EHAction :: None | EHAction :: Cleanup ( _) => uw:: _URC_CONTINUE_UNWIND,
213
- EHAction :: Catch ( _) | EHAction :: Filter ( _) => uw:: _URC_HANDLER_FOUND,
214
- EHAction :: Terminate => uw:: _URC_FATAL_PHASE1_ERROR,
212
+ unsafe {
213
+ if version != 1 {
214
+ return uw:: _URC_FATAL_PHASE1_ERROR;
215
215
}
216
- } else {
217
- match eh_action {
218
- EHAction :: None => uw:: _URC_CONTINUE_UNWIND,
219
- // Forced unwinding hits a terminate action.
220
- EHAction :: Filter ( _) if actions as i32 & uw:: _UA_FORCE_UNWIND as i32 != 0 => uw:: _URC_CONTINUE_UNWIND,
221
- EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) | EHAction :: Filter ( lpad) => {
222
- uw:: _Unwind_SetGR(
223
- context,
224
- UNWIND_DATA_REG . 0 ,
225
- exception_object. cast( ) ,
226
- ) ;
227
- uw:: _Unwind_SetGR( context, UNWIND_DATA_REG . 1 , core:: ptr:: null( ) ) ;
228
- uw:: _Unwind_SetIP( context, lpad) ;
229
- uw:: _URC_INSTALL_CONTEXT
216
+ let eh_action = match find_eh_action( context) {
217
+ Ok ( action) => action,
218
+ Err ( _) => return uw:: _URC_FATAL_PHASE1_ERROR,
219
+ } ;
220
+ if actions as i32 & uw:: _UA_SEARCH_PHASE as i32 != 0 {
221
+ match eh_action {
222
+ EHAction :: None | EHAction :: Cleanup ( _) => uw:: _URC_CONTINUE_UNWIND,
223
+ EHAction :: Catch ( _) | EHAction :: Filter ( _) => uw:: _URC_HANDLER_FOUND,
224
+ EHAction :: Terminate => uw:: _URC_FATAL_PHASE1_ERROR,
225
+ }
226
+ } else {
227
+ match eh_action {
228
+ EHAction :: None => uw:: _URC_CONTINUE_UNWIND,
229
+ // Forced unwinding hits a terminate action.
230
+ EHAction :: Filter ( _) if actions as i32 & uw:: _UA_FORCE_UNWIND as i32 != 0 => uw:: _URC_CONTINUE_UNWIND,
231
+ EHAction :: Cleanup ( lpad) | EHAction :: Catch ( lpad) | EHAction :: Filter ( lpad) => {
232
+ uw:: _Unwind_SetGR(
233
+ context,
234
+ UNWIND_DATA_REG . 0 ,
235
+ exception_object. cast( ) ,
236
+ ) ;
237
+ uw:: _Unwind_SetGR( context, UNWIND_DATA_REG . 1 , core:: ptr:: null( ) ) ;
238
+ uw:: _Unwind_SetIP( context, lpad) ;
239
+ uw:: _URC_INSTALL_CONTEXT
240
+ }
241
+ EHAction :: Terminate => uw:: _URC_FATAL_PHASE2_ERROR,
230
242
}
231
- EHAction :: Terminate => uw:: _URC_FATAL_PHASE2_ERROR,
232
243
}
233
244
}
234
245
}
@@ -245,13 +256,15 @@ cfg_if::cfg_if! {
245
256
contextRecord: * mut uw:: CONTEXT ,
246
257
dispatcherContext: * mut uw:: DISPATCHER_CONTEXT ,
247
258
) -> uw:: EXCEPTION_DISPOSITION {
248
- uw:: _GCC_specific_handler(
249
- exceptionRecord,
250
- establisherFrame,
251
- contextRecord,
252
- dispatcherContext,
253
- rust_eh_personality_impl,
254
- )
259
+ unsafe {
260
+ uw:: _GCC_specific_handler(
261
+ exceptionRecord,
262
+ establisherFrame,
263
+ contextRecord,
264
+ dispatcherContext,
265
+ rust_eh_personality_impl,
266
+ )
267
+ }
255
268
}
256
269
} else {
257
270
// The personality routine for most of our targets.
@@ -263,32 +276,36 @@ cfg_if::cfg_if! {
263
276
exception_object: * mut uw:: _Unwind_Exception,
264
277
context: * mut uw:: _Unwind_Context,
265
278
) -> uw:: _Unwind_Reason_Code {
266
- rust_eh_personality_impl(
267
- version,
268
- actions,
269
- exception_class,
270
- exception_object,
271
- context,
272
- )
279
+ unsafe {
280
+ rust_eh_personality_impl(
281
+ version,
282
+ actions,
283
+ exception_class,
284
+ exception_object,
285
+ context,
286
+ )
287
+ }
273
288
}
274
289
}
275
290
}
276
291
}
277
292
}
278
293
279
294
unsafe fn find_eh_action ( context : * mut uw:: _Unwind_Context ) -> Result < EHAction , ( ) > {
280
- let lsda = uw:: _Unwind_GetLanguageSpecificData ( context) as * const u8 ;
281
- let mut ip_before_instr: c_int = 0 ;
282
- let ip = uw:: _Unwind_GetIPInfo ( context, & mut ip_before_instr) ;
283
- let eh_context = EHContext {
284
- // The return address points 1 byte past the call instruction,
285
- // which could be in the next IP range in LSDA range table.
286
- //
287
- // `ip = -1` has special meaning, so use wrapping sub to allow for that
288
- ip : if ip_before_instr != 0 { ip } else { ip. wrapping_sub ( 1 ) } ,
289
- func_start : uw:: _Unwind_GetRegionStart ( context) ,
290
- get_text_start : & || uw:: _Unwind_GetTextRelBase ( context) ,
291
- get_data_start : & || uw:: _Unwind_GetDataRelBase ( context) ,
292
- } ;
293
- eh:: find_eh_action ( lsda, & eh_context)
295
+ unsafe {
296
+ let lsda = uw:: _Unwind_GetLanguageSpecificData ( context) as * const u8 ;
297
+ let mut ip_before_instr: c_int = 0 ;
298
+ let ip = uw:: _Unwind_GetIPInfo ( context, & mut ip_before_instr) ;
299
+ let eh_context = EHContext {
300
+ // The return address points 1 byte past the call instruction,
301
+ // which could be in the next IP range in LSDA range table.
302
+ //
303
+ // `ip = -1` has special meaning, so use wrapping sub to allow for that
304
+ ip : if ip_before_instr != 0 { ip } else { ip. wrapping_sub ( 1 ) } ,
305
+ func_start : uw:: _Unwind_GetRegionStart ( context) ,
306
+ get_text_start : & || uw:: _Unwind_GetTextRelBase ( context) ,
307
+ get_data_start : & || uw:: _Unwind_GetDataRelBase ( context) ,
308
+ } ;
309
+ eh:: find_eh_action ( lsda, & eh_context)
310
+ }
294
311
}
0 commit comments