std: unsafe-wrap gcc::rust_eh_personality and impl · patricklam/verify-rust-std@d252b6b (original) (raw)
`@@ -35,6 +35,7 @@
`
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
`
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
`}
`