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: 2026-04-12:00:00:00 Functions: 25.7 % 74 19

            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 : );
        

Generated by: LCOV version 2.1-1