Line data Source code
1 : //! Module related to the x86_64 exception unwinding support
2 :
3 : use lief_ffi as ffi;
4 :
5 : use std::marker::PhantomData;
6 :
7 : use super::exception::ExceptionInfo;
8 : use crate::common::{into_optional, FromFFI};
9 : use crate::{declare_fwd_iterator, to_opt, to_slice};
10 : use bitflags::bitflags;
11 :
12 : /// This structure represents an entry in the exception table (`.pdata` section)
13 : /// for the x86-64 architecture.
14 : ///
15 : /// Reference: <https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64>
16 : pub struct RuntimeFunction<'a> {
17 : ptr: cxx::UniquePtr<ffi::PE_RuntimeFunctionX64>,
18 : _owner: PhantomData<&'a ffi::PE_Binary>,
19 : }
20 :
21 : impl FromFFI<ffi::PE_RuntimeFunctionX64> for RuntimeFunction<'_> {
22 695500 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_RuntimeFunctionX64>) -> Self {
23 695500 : Self {
24 695500 : ptr,
25 695500 : _owner: PhantomData,
26 695500 : }
27 695500 : }
28 : }
29 :
30 : impl std::fmt::Debug for RuntimeFunction<'_> {
31 695500 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 695500 : let base = self as &dyn ExceptionInfo;
33 695500 : f.debug_struct("RuntimeFunction(x86_64)")
34 695500 : .field("rva_start", &base.rva_start())
35 695500 : .field("rva_end", &self.rva_end())
36 695500 : .field("unwind_rva", &self.unwind_rva())
37 695500 : .field("size", &self.size())
38 695500 : .field("unwind_info", &self.unwind_info())
39 695500 : .finish()
40 695500 : }
41 : }
42 :
43 : impl ExceptionInfo for RuntimeFunction<'_> {
44 695500 : fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
45 695500 : self.ptr.as_ref().unwrap().as_ref()
46 695500 : }
47 : }
48 :
49 : impl RuntimeFunction<'_> {
50 : /// Function end address
51 695500 : pub fn rva_end(&self) -> u32 {
52 695500 : self.ptr.rva_end()
53 695500 : }
54 :
55 : /// Unwind info address
56 695500 : pub fn unwind_rva(&self) -> u32 {
57 695500 : self.ptr.unwind_rva()
58 695500 : }
59 :
60 : /// Size of the function (in bytes)
61 695500 : pub fn size(&self) -> u32 {
62 695500 : self.ptr.size()
63 695500 : }
64 :
65 : /// Detailed unwind information
66 695500 : pub fn unwind_info(&self) -> Option<UnwindInfo<'_>> {
67 695500 : into_optional(self.ptr.unwind_info())
68 695500 : }
69 : }
70 :
71 : #[allow(non_camel_case_types)]
72 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
73 : pub enum UnwindOpcodes {
74 : /// Push a nonvolatile integer register, decrementing RSP by 8.
75 : /// The operation info is the number of the register. Because of the
76 : /// constraints on epilogs, `PUSH_NONVOL` unwind codes must appear first
77 : /// in the prolog and correspondingly, last in the unwind code array.
78 : /// This relative ordering applies to all other unwind codes except
79 : /// [`UnwindOpcodes::PUSH_MACHFRAME`].
80 : PUSH_NONVOL,
81 :
82 : /// Allocate a large-sized area on the stack.
83 : /// There are two forms. If the operation info equals 0,
84 : /// then the size of the allocation divided by 8 is recorded in the next slot,
85 : /// allowing an allocation up to 512K - 8. If the operation info equals 1,
86 : /// then the unscaled size of the allocation is recorded in the next two
87 : /// slots in little-endian format, allowing allocations up to 4GB - 8.
88 : ALLOC_LARGE,
89 :
90 : /// Allocate a small-sized area on the stack. The size of the allocation is
91 : /// the operation info field * 8 + 8, allowing allocations from 8 to 128 bytes.
92 : ALLOC_SMALL,
93 :
94 : /// Establish the frame pointer register by setting the register to some
95 : /// offset of the current RSP. The offset is equal to the Frame Register
96 : /// offset (scaled) field in the UNWIND_INFO * 16, allowing offsets from
97 : /// 0 to 240. The use of an offset permits establishing a frame pointer that
98 : /// points to the middle of the fixed stack allocation, helping code density
99 : /// by allowing more accesses to use short instruction forms. The operation
100 : /// info field is reserved and shouldn't be us
101 : SET_FPREG,
102 :
103 : /// Save a nonvolatile integer register on the stack using a MOV instead of a
104 : /// PUSH. This code is primarily used for shrink-wrapping, where a nonvolatile
105 : /// register is saved to the stack in a position that was previously allocated.
106 : /// The operation info is the number of the register. The scaled-by-8 stack
107 : /// offset is recorded in the next unwind operation code slot, as described
108 : /// in the note above
109 : SAVE_NONVOL,
110 :
111 : /// Save a nonvolatile integer register on the stack with a long offset,
112 : /// using a MOV instead of a PUSH. This code is primarily used for
113 : /// shrink-wrapping, where a nonvolatile register is saved to the stack in a
114 : /// position that was previously allocated. The operation info is the number
115 : /// of the register. The unscaled stack offset is recorded in the next two
116 : /// unwind operation code slots, as described in the note above.
117 : SAVE_NONVOL_FAR,
118 :
119 : /// This entry is only revelant for version 2. It describes the function
120 : /// epilog.
121 : EPILOG,
122 :
123 : /// Reserved
124 : /// Originally SAVE_XMM128_FAR in version 1, but deprecated and removed
125 : SPARE,
126 :
127 : /// Save all 128 bits of a nonvolatile XMM register on the stack.
128 : /// The operation info is the number of the register. The scaled-by-16 stack
129 : /// offset is recorded in the next slot.
130 : SAVE_XMM128,
131 :
132 : /// Save all 128 bits of a nonvolatile XMM register on the stack with a
133 : /// long offset. The operation info is the number of the register.
134 : /// The unscaled stack offset is recorded in the next two slots.
135 : SAVE_XMM128_FAR,
136 :
137 : /// Push a machine frame. This unwind code is used to record the effect of a
138 : /// hardware interrupt or exception.
139 : PUSH_MACHFRAME,
140 :
141 : UNKNOWN(u32),
142 : }
143 :
144 : impl From<u32> for UnwindOpcodes {
145 0 : fn from(value: u32) -> Self {
146 0 : match value {
147 0 : 0x00000000 => UnwindOpcodes::PUSH_NONVOL,
148 0 : 0x00000001 => UnwindOpcodes::ALLOC_LARGE,
149 0 : 0x00000002 => UnwindOpcodes::ALLOC_SMALL,
150 0 : 0x00000003 => UnwindOpcodes::SET_FPREG,
151 0 : 0x00000004 => UnwindOpcodes::SAVE_NONVOL,
152 0 : 0x00000005 => UnwindOpcodes::SAVE_NONVOL_FAR,
153 0 : 0x00000006 => UnwindOpcodes::EPILOG,
154 0 : 0x00000007 => UnwindOpcodes::SPARE,
155 0 : 0x00000008 => UnwindOpcodes::SAVE_XMM128,
156 0 : 0x00000009 => UnwindOpcodes::SAVE_XMM128_FAR,
157 0 : 0x0000000a => UnwindOpcodes::PUSH_MACHFRAME,
158 0 : _ => UnwindOpcodes::UNKNOWN(value),
159 : }
160 0 : }
161 : }
162 : impl From<UnwindOpcodes> for u32 {
163 0 : fn from(value: UnwindOpcodes) -> u32 {
164 0 : match value {
165 0 : UnwindOpcodes::PUSH_NONVOL => 0x00000000,
166 0 : UnwindOpcodes::ALLOC_LARGE => 0x00000001,
167 0 : UnwindOpcodes::ALLOC_SMALL => 0x00000002,
168 0 : UnwindOpcodes::SET_FPREG => 0x00000003,
169 0 : UnwindOpcodes::SAVE_NONVOL => 0x00000004,
170 0 : UnwindOpcodes::SAVE_NONVOL_FAR => 0x00000005,
171 0 : UnwindOpcodes::EPILOG => 0x00000006,
172 0 : UnwindOpcodes::SPARE => 0x00000007,
173 0 : UnwindOpcodes::SAVE_XMM128 => 0x00000008,
174 0 : UnwindOpcodes::SAVE_XMM128_FAR => 0x00000009,
175 0 : UnwindOpcodes::PUSH_MACHFRAME => 0x0000000a,
176 0 : UnwindOpcodes::UNKNOWN(value) => value,
177 : }
178 0 : }
179 : }
180 :
181 : #[allow(non_camel_case_types)]
182 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
183 : pub enum UnwindReg {
184 : RAX,
185 : RCX,
186 : RDX,
187 : RBX,
188 : RSP,
189 : RBP,
190 : RSI,
191 : RDI,
192 : R8,
193 : R9,
194 : R10,
195 : R11,
196 : R12,
197 : R13,
198 : R14,
199 : R15,
200 : UNKNOWN(u32),
201 : }
202 :
203 : impl From<u32> for UnwindReg {
204 0 : fn from(value: u32) -> Self {
205 0 : match value {
206 0 : 0x00000000 => UnwindReg::RAX,
207 0 : 0x00000001 => UnwindReg::RCX,
208 0 : 0x00000002 => UnwindReg::RDX,
209 0 : 0x00000003 => UnwindReg::RBX,
210 0 : 0x00000004 => UnwindReg::RSP,
211 0 : 0x00000005 => UnwindReg::RBP,
212 0 : 0x00000006 => UnwindReg::RSI,
213 0 : 0x00000007 => UnwindReg::RDI,
214 0 : 0x00000008 => UnwindReg::R8,
215 0 : 0x00000009 => UnwindReg::R9,
216 0 : 0x0000000a => UnwindReg::R10,
217 0 : 0x0000000b => UnwindReg::R11,
218 0 : 0x0000000c => UnwindReg::R12,
219 0 : 0x0000000d => UnwindReg::R13,
220 0 : 0x0000000e => UnwindReg::R14,
221 0 : 0x0000000f => UnwindReg::R15,
222 0 : _ => UnwindReg::UNKNOWN(value),
223 : }
224 0 : }
225 : }
226 : impl From<UnwindReg> for u32 {
227 0 : fn from(value: UnwindReg) -> u32 {
228 0 : match value {
229 0 : UnwindReg::RAX => 0x00000000,
230 0 : UnwindReg::RCX => 0x00000001,
231 0 : UnwindReg::RDX => 0x00000002,
232 0 : UnwindReg::RBX => 0x00000003,
233 0 : UnwindReg::RSP => 0x00000004,
234 0 : UnwindReg::RBP => 0x00000005,
235 0 : UnwindReg::RSI => 0x00000006,
236 0 : UnwindReg::RDI => 0x00000007,
237 0 : UnwindReg::R8 => 0x00000008,
238 0 : UnwindReg::R9 => 0x00000009,
239 0 : UnwindReg::R10 => 0x0000000a,
240 0 : UnwindReg::R11 => 0x0000000b,
241 0 : UnwindReg::R12 => 0x0000000c,
242 0 : UnwindReg::R13 => 0x0000000d,
243 0 : UnwindReg::R14 => 0x0000000e,
244 0 : UnwindReg::R15 => 0x0000000f,
245 0 : UnwindReg::UNKNOWN(value) => value,
246 : }
247 0 : }
248 : }
249 :
250 0 : bitflags! {
251 695500 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
252 0 : pub struct UnwindFlags: u8 {
253 0 : /// The function has an exception handler that should be called when looking
254 0 : /// for functions that need to examine exceptions.
255 0 : const EXCEPTION_HANDLER = 0x1;
256 0 :
257 0 : /// The function has a termination handler that should be called when
258 0 : /// unwinding an exception.
259 0 : const TERMINATE_HANDLER = 0x2;
260 0 :
261 0 : /// The chained info payload references a previous `RUNTIME_FUNCTION`
262 0 : const CHAIN_INFO = 0x4;
263 0 : }
264 0 : }
265 :
266 : impl From<u8> for UnwindFlags {
267 695500 : fn from(value: u8) -> Self {
268 695500 : UnwindFlags::from_bits_truncate(value)
269 695500 : }
270 : }
271 :
272 : impl From<UnwindFlags> for u8 {
273 0 : fn from(value: UnwindFlags) -> Self {
274 0 : value.bits()
275 0 : }
276 : }
277 :
278 : impl std::fmt::Display for UnwindFlags {
279 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
280 0 : bitflags::parser::to_writer(self, f)
281 0 : }
282 : }
283 :
284 : /// This structure represents the `UNWIND_INFO` which records the effects
285 : /// a function has on the stack pointer, and where the nonvolatile registers
286 : /// are saved on the stack.
287 : pub struct UnwindInfo<'a> {
288 : ptr: cxx::UniquePtr<ffi::PE_RuntimeFunctionX64_unwind_info_t>,
289 : _owner: PhantomData<&'a ffi::PE_Binary>,
290 : }
291 :
292 : impl FromFFI<ffi::PE_RuntimeFunctionX64_unwind_info_t> for UnwindInfo<'_> {
293 695500 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_RuntimeFunctionX64_unwind_info_t>) -> Self {
294 695500 : Self {
295 695500 : ptr,
296 695500 : _owner: PhantomData,
297 695500 : }
298 695500 : }
299 : }
300 :
301 : impl UnwindInfo<'_> {
302 : /// Version number of the unwind data, currently 1 or 2.
303 695500 : pub fn version(&self) -> u8 {
304 695500 : self.ptr.version()
305 695500 : }
306 :
307 : /// See: [`UnwindFlags`]
308 695500 : pub fn flags(&self) -> UnwindFlags {
309 695500 : UnwindFlags::from(self.ptr.flags())
310 695500 : }
311 :
312 : /// Length of the function prolog in bytes.
313 695500 : pub fn sizeof_prologue(&self) -> u8 {
314 695500 : self.ptr.sizeof_prologue()
315 695500 : }
316 :
317 : /// The number of slots in the unwind codes array. Some unwind codes, for
318 : /// example, [`UnwindOpcodes::SAVE_NONVOL`], require more than one slot in the
319 : /// array
320 695500 : pub fn count_opcodes(&self) -> u8 {
321 695500 : self.ptr.count_opcodes()
322 695500 : }
323 :
324 : /// If nonzero, then the function uses a frame pointer (FP), and this field
325 : /// is the number of the nonvolatile register used as the frame pointer,
326 : /// using the same encoding for the operation info field of [`UnwindOpcodes`]
327 : /// nodes.
328 695500 : pub fn frame_reg(&self) -> u8 {
329 695500 : self.ptr.frame_reg()
330 695500 : }
331 :
332 : /// If the frame register field is nonzero, this field is the scaled offset
333 : /// from RSP that is applied to the FP register when it's established
334 695500 : pub fn frame_reg_offset(&self) -> u8 {
335 695500 : self.ptr.frame_reg_offset()
336 695500 : }
337 :
338 : /// An array of items that explains the effect of the prolog on the
339 : /// nonvolatile registers and RSP
340 0 : pub fn raw_opcodes(&self) -> &[u8] {
341 0 : to_slice!(self.ptr.raw_opcodes());
342 0 : }
343 :
344 : /// Iterator over the unwind code which outputs [`Opcodes`]
345 0 : pub fn opcodes(&self) -> OpcodesIterator<'_> {
346 0 : OpcodesIterator::new(self.ptr.opcodes())
347 0 : }
348 :
349 : /// An image-relative pointer to either the function's language-specific
350 : /// exception or termination handler. This value is set if one of these
351 : /// flags is set: [`UnwindFlags::EXCEPTION_HANDLER`],
352 : /// [`UnwindFlags::TERMINATE_HANDLER`]
353 695500 : pub fn handler(&self) -> Option<u32> {
354 695500 : to_opt!(&ffi::PE_RuntimeFunctionX64_unwind_info_t::handler, &self);
355 695500 : }
356 :
357 : /// If [`UnwindFlags::CHAIN_INFO`] is set, this attributes references the
358 : /// chained runtime function.
359 0 : pub fn chained(&self) -> Option<RuntimeFunction<'_>> {
360 0 : into_optional(self.ptr.chained())
361 0 : }
362 : }
363 :
364 : impl std::fmt::Debug for UnwindInfo<'_> {
365 695500 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366 695500 : f.debug_struct("UnwindInfo")
367 695500 : .field("version", &self.version())
368 695500 : .field("flags", &self.flags())
369 695500 : .field("sizeof_prologue", &self.sizeof_prologue())
370 695500 : .field("count_opcodes", &self.count_opcodes())
371 695500 : .field("frame_reg", &self.frame_reg())
372 695500 : .field("frame_reg_offset", &self.frame_reg_offset())
373 695500 : .field("handler", &self.handler())
374 695500 : .finish()
375 695500 : }
376 : }
377 :
378 : impl std::fmt::Display for UnwindInfo<'_> {
379 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
380 0 : write!(f, "{}", self.ptr.to_string())
381 0 : }
382 : }
383 :
384 : /// Trait shared by all [`Opcodes`]
385 : pub trait Opcode {
386 : #[doc(hidden)]
387 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code;
388 :
389 : /// Offset in the prolog
390 0 : fn position(&self) -> u32 {
391 0 : self.as_generic().position()
392 0 : }
393 :
394 : /// The original opcode
395 0 : fn opcode(&self) -> UnwindOpcodes {
396 0 : UnwindOpcodes::from(self.as_generic().opcode())
397 0 : }
398 : }
399 :
400 : impl std::fmt::Display for &dyn Opcode {
401 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
402 0 : write!(f, "{}", self.as_generic().to_string())
403 0 : }
404 : }
405 :
406 : /// The different `x86_64` unwind opcodes.
407 : pub enum Opcodes<'a> {
408 : /// Represents a stack-allocation operation
409 : Alloc(Alloc<'a>),
410 :
411 : /// Push a nonvolatile integer register
412 : PushNonVol(PushNonVol<'a>),
413 :
414 : /// Push a machine frame
415 : PushMachFrame(PushMachFrame<'a>),
416 :
417 : /// Establish the frame pointer register
418 : SetFPReg(SetFPReg<'a>),
419 :
420 : /// Save a nonvolatile integer register
421 : SaveNonVolatile(SaveNonVolatile<'a>),
422 :
423 : SaveXMM128(SaveXMM128<'a>),
424 :
425 : /// Describes the function's epilog
426 : Epilog(Epilog<'a>),
427 : Spare(Spare<'a>),
428 : }
429 :
430 : impl<'a> FromFFI<ffi::PE_unwind_x64_Code> for Opcodes<'a> {
431 0 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_unwind_x64_Code>) -> Self {
432 0 : unsafe {
433 0 : let code_ref = ffi_entry.as_ref().unwrap();
434 0 : if ffi::PE_unwind_x64_Alloc::classof(code_ref) {
435 0 : let raw = {
436 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
437 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_Alloc>;
438 0 : std::mem::transmute::<From, To>(ffi_entry)
439 0 : };
440 0 : Opcodes::Alloc(Alloc::from_ffi(raw))
441 0 : } else if ffi::PE_unwind_x64_PushNonVol::classof(code_ref) {
442 0 : let raw = {
443 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
444 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_PushNonVol>;
445 0 : std::mem::transmute::<From, To>(ffi_entry)
446 0 : };
447 0 : Opcodes::PushNonVol(PushNonVol::from_ffi(raw))
448 0 : } else if ffi::PE_unwind_x64_PushMachFrame::classof(code_ref) {
449 0 : let raw = {
450 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
451 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_PushMachFrame>;
452 0 : std::mem::transmute::<From, To>(ffi_entry)
453 0 : };
454 0 : Opcodes::PushMachFrame(PushMachFrame::from_ffi(raw))
455 0 : } else if ffi::PE_unwind_x64_SetFPReg::classof(code_ref) {
456 0 : let raw = {
457 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
458 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_SetFPReg>;
459 0 : std::mem::transmute::<From, To>(ffi_entry)
460 0 : };
461 0 : Opcodes::SetFPReg(SetFPReg::from_ffi(raw))
462 0 : } else if ffi::PE_unwind_x64_SaveNonVolatile::classof(code_ref) {
463 0 : let raw = {
464 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
465 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_SaveNonVolatile>;
466 0 : std::mem::transmute::<From, To>(ffi_entry)
467 0 : };
468 0 : Opcodes::SaveNonVolatile(SaveNonVolatile::from_ffi(raw))
469 0 : } else if ffi::PE_unwind_x64_SaveXMM128::classof(code_ref) {
470 0 : let raw = {
471 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
472 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_SaveXMM128>;
473 0 : std::mem::transmute::<From, To>(ffi_entry)
474 0 : };
475 0 : Opcodes::SaveXMM128(SaveXMM128::from_ffi(raw))
476 0 : } else if ffi::PE_unwind_x64_Epilog::classof(code_ref) {
477 0 : let raw = {
478 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
479 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_Epilog>;
480 0 : std::mem::transmute::<From, To>(ffi_entry)
481 0 : };
482 0 : Opcodes::Epilog(Epilog::from_ffi(raw))
483 0 : } else if ffi::PE_unwind_x64_Spare::classof(code_ref) {
484 0 : let raw = {
485 0 : type From = cxx::UniquePtr<ffi::PE_unwind_x64_Code>;
486 0 : type To = cxx::UniquePtr<ffi::PE_unwind_x64_Spare>;
487 0 : std::mem::transmute::<From, To>(ffi_entry)
488 0 : };
489 0 : Opcodes::Spare(Spare::from_ffi(raw))
490 : } else {
491 0 : panic!("Unknown opcode");
492 : }
493 : }
494 0 : }
495 : }
496 :
497 : /// This structure represents a stack-allocation operation
498 : /// ([`UnwindOpcodes::ALLOC_SMALL`] or [`UnwindOpcodes::ALLOC_LARGE`]).
499 : pub struct Alloc<'a> {
500 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Alloc>,
501 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
502 : }
503 :
504 : impl FromFFI<ffi::PE_unwind_x64_Alloc> for Alloc<'_> {
505 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Alloc>) -> Self {
506 0 : Self {
507 0 : ptr,
508 0 : _owner: PhantomData,
509 0 : }
510 0 : }
511 : }
512 :
513 : impl Opcode for Alloc<'_> {
514 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
515 0 : self.ptr.as_ref().unwrap().as_ref()
516 0 : }
517 : }
518 :
519 : impl Alloc<'_> {
520 : /// The size allocated
521 0 : pub fn size(&self) -> u32 {
522 0 : self.ptr.size()
523 0 : }
524 : }
525 :
526 : /// Push a nonvolatile integer register, decrementing RSP by 8
527 : pub struct PushNonVol<'a> {
528 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_PushNonVol>,
529 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
530 : }
531 :
532 : impl FromFFI<ffi::PE_unwind_x64_PushNonVol> for PushNonVol<'_> {
533 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_PushNonVol>) -> Self {
534 0 : Self {
535 0 : ptr,
536 0 : _owner: PhantomData,
537 0 : }
538 0 : }
539 : }
540 :
541 : impl Opcode for PushNonVol<'_> {
542 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
543 0 : self.ptr.as_ref().unwrap().as_ref()
544 0 : }
545 : }
546 :
547 : impl PushNonVol<'_> {
548 : /// The register pushed
549 0 : pub fn reg(&self) -> UnwindReg {
550 0 : UnwindReg::from(self.ptr.reg())
551 0 : }
552 : }
553 :
554 : /// Push a machine frame
555 : pub struct PushMachFrame<'a> {
556 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_PushMachFrame>,
557 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
558 : }
559 :
560 : impl FromFFI<ffi::PE_unwind_x64_PushMachFrame> for PushMachFrame<'_> {
561 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_PushMachFrame>) -> Self {
562 0 : Self {
563 0 : ptr,
564 0 : _owner: PhantomData,
565 0 : }
566 0 : }
567 : }
568 :
569 : impl Opcode for PushMachFrame<'_> {
570 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
571 0 : self.ptr.as_ref().unwrap().as_ref()
572 0 : }
573 : }
574 :
575 : impl PushMachFrame<'_> {
576 : /// The register pushed
577 0 : pub fn value(&self) -> u8 {
578 0 : self.ptr.value()
579 0 : }
580 : }
581 :
582 : /// Establish the frame pointer register by setting the register to some offset
583 : /// of the current RSP
584 : pub struct SetFPReg<'a> {
585 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SetFPReg>,
586 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
587 : }
588 :
589 : impl FromFFI<ffi::PE_unwind_x64_SetFPReg> for SetFPReg<'_> {
590 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SetFPReg>) -> Self {
591 0 : Self {
592 0 : ptr,
593 0 : _owner: PhantomData,
594 0 : }
595 0 : }
596 : }
597 :
598 : impl Opcode for SetFPReg<'_> {
599 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
600 0 : self.ptr.as_ref().unwrap().as_ref()
601 0 : }
602 : }
603 :
604 : impl SetFPReg<'_> {
605 : /// The register pushed
606 0 : pub fn reg(&self) -> UnwindReg {
607 0 : UnwindReg::from(self.ptr.reg())
608 0 : }
609 : }
610 :
611 : /// Save a nonvolatile integer register on the stack using a `MOV` instead of a
612 : /// `PUSH`.
613 : pub struct SaveNonVolatile<'a> {
614 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SaveNonVolatile>,
615 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
616 : }
617 :
618 : impl FromFFI<ffi::PE_unwind_x64_SaveNonVolatile> for SaveNonVolatile<'_> {
619 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SaveNonVolatile>) -> Self {
620 0 : Self {
621 0 : ptr,
622 0 : _owner: PhantomData,
623 0 : }
624 0 : }
625 : }
626 :
627 : impl Opcode for SaveNonVolatile<'_> {
628 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
629 0 : self.ptr.as_ref().unwrap().as_ref()
630 0 : }
631 : }
632 :
633 : impl SaveNonVolatile<'_> {
634 0 : pub fn reg(&self) -> UnwindReg {
635 0 : UnwindReg::from(self.ptr.reg())
636 0 : }
637 :
638 0 : pub fn offset(&self) -> u32 {
639 0 : self.ptr.offset()
640 0 : }
641 : }
642 :
643 : pub struct SaveXMM128<'a> {
644 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SaveXMM128>,
645 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
646 : }
647 :
648 : impl FromFFI<ffi::PE_unwind_x64_SaveXMM128> for SaveXMM128<'_> {
649 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_SaveXMM128>) -> Self {
650 0 : Self {
651 0 : ptr,
652 0 : _owner: PhantomData,
653 0 : }
654 0 : }
655 : }
656 :
657 : impl Opcode for SaveXMM128<'_> {
658 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
659 0 : self.ptr.as_ref().unwrap().as_ref()
660 0 : }
661 : }
662 :
663 : impl SaveXMM128<'_> {
664 0 : pub fn num(&self) -> u8 {
665 0 : self.ptr.num()
666 0 : }
667 :
668 0 : pub fn offset(&self) -> u32 {
669 0 : self.ptr.offset()
670 0 : }
671 : }
672 :
673 : /// Describes the function's epilog
674 : pub struct Epilog<'a> {
675 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Epilog>,
676 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
677 : }
678 :
679 : impl FromFFI<ffi::PE_unwind_x64_Epilog> for Epilog<'_> {
680 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Epilog>) -> Self {
681 0 : Self {
682 0 : ptr,
683 0 : _owner: PhantomData,
684 0 : }
685 0 : }
686 : }
687 :
688 : impl Opcode for Epilog<'_> {
689 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
690 0 : self.ptr.as_ref().unwrap().as_ref()
691 0 : }
692 : }
693 :
694 : impl Epilog<'_> {
695 0 : pub fn flags(&self) -> u8 {
696 0 : self.ptr.flags()
697 0 : }
698 :
699 0 : pub fn size(&self) -> u32 {
700 0 : self.ptr.size()
701 0 : }
702 : }
703 :
704 : pub struct Spare<'a> {
705 : ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Spare>,
706 : _owner: PhantomData<&'a ffi::PE_RuntimeFunctionX64_unwind_info_t>,
707 : }
708 :
709 : impl FromFFI<ffi::PE_unwind_x64_Spare> for Spare<'_> {
710 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_x64_Spare>) -> Self {
711 0 : Self {
712 0 : ptr,
713 0 : _owner: PhantomData,
714 0 : }
715 0 : }
716 : }
717 :
718 : impl Opcode for Spare<'_> {
719 0 : fn as_generic(&self) -> &ffi::PE_unwind_x64_Code {
720 0 : self.ptr.as_ref().unwrap().as_ref()
721 0 : }
722 : }
723 :
724 0 : declare_fwd_iterator!(
725 0 : OpcodesIterator,
726 0 : Opcodes<'a>,
727 0 : ffi::PE_unwind_x64_Code,
728 0 : ffi::PE_RuntimeFunctionX64_unwind_info_t,
729 0 : ffi::PE_RuntimeFunctionX64_unwind_info_t_it_opcodes
730 0 : );
|