3535//!
3636//! Once stack has been unwound down to the handler frame level, unwinding stops
3737//! and the last personality routine transfers control to the catch block.
38+ #![ forbid( unsafe_op_in_unsafe_fn) ]
3839
3940use super :: dwarf:: eh:: { self , EHAction , EHContext } ;
4041use crate :: ffi:: c_int;
@@ -92,7 +93,11 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
9293// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
9394
9495cfg_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+ ) ) ] {
96101 // ARM EHABI personality routine.
97102 // https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
98103 //
@@ -104,90 +109,94 @@ cfg_if::cfg_if! {
104109 exception_object: * mut uw:: _Unwind_Exception,
105110 context: * mut uw:: _Unwind_Context,
106111 ) -> 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 {
115127 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+ } ;
125131
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.
136142
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,
145160 }
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,
168176 }
169- EHAction :: Terminate => return uw:: _URC_FAILURE,
170177 }
171- }
172178
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(
188182 exception_object: * mut uw:: _Unwind_Exception,
189183 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+ }
191200 }
192201 }
193202 } else {
@@ -200,35 +209,37 @@ cfg_if::cfg_if! {
200209 exception_object: * mut uw:: _Unwind_Exception,
201210 context: * mut uw:: _Unwind_Context,
202211 ) -> 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;
215215 }
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,
230242 }
231- EHAction :: Terminate => uw:: _URC_FATAL_PHASE2_ERROR,
232243 }
233244 }
234245 }
@@ -245,13 +256,15 @@ cfg_if::cfg_if! {
245256 contextRecord: * mut uw:: CONTEXT ,
246257 dispatcherContext: * mut uw:: DISPATCHER_CONTEXT ,
247258 ) -> 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+ }
255268 }
256269 } else {
257270 // The personality routine for most of our targets.
@@ -263,32 +276,36 @@ cfg_if::cfg_if! {
263276 exception_object: * mut uw:: _Unwind_Exception,
264277 context: * mut uw:: _Unwind_Context,
265278 ) -> 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+ }
273288 }
274289 }
275290 }
276291 }
277292}
278293
279294unsafe 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+ }
294311}
0 commit comments