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