LCOV - code coverage report
Current view: top level - src/pe - exception_x64.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 20.5 % 356 73
Test Date: 2025-02-23:00:00:00 Functions: 24.7 % 73 18

            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              : 
        

Generated by: LCOV version 2.1-1