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

`// 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

`}

`