LCOV - code coverage report
Current view: top level - src/pe - exception_aarch64.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 65.0 % 140 91
Test Date: 2025-02-23:00:00:00 Functions: 63.3 % 30 19

            Line data    Source code
       1              : //! This module contains structures related to the ARM64 exception support in PE files
       2              : 
       3              : use lief_ffi as ffi;
       4              : 
       5              : use std::marker::PhantomData;
       6              : 
       7              : use super::ExceptionInfo;
       8              : 
       9              : use crate::common::FromFFI;
      10              : use crate::{declare_iterator, to_slice};
      11              : 
      12              : /// This enum represents an entry in the exception table (`.pdata` section) for the AArch64
      13              : /// architecture.
      14              : ///
      15              : /// Since the ARM64 unwinding info can be encoded in a *packed* and *unpacked* format, this enums
      16              : /// wraps two entries [`Packed`] and [`Unpacked`].
      17              : ///
      18              : /// Reference: <https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling#arm64-exception-handling-information>
      19       236090 : #[derive(Debug)]
      20              : pub enum RuntimeFunction<'a> {
      21              :     /// A packed exception entry that fits on 30 bits
      22              :     Packed(Packed<'a>),
      23              : 
      24              :     /// An extended exception entry that has variable length data
      25              :     Unpacked(Unpacked<'a>),
      26              : }
      27              : 
      28              : impl<'a> FromFFI<ffi::PE_RuntimeFunctionAArch64> for RuntimeFunction<'a> {
      29       236090 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>) -> Self {
      30       236090 :         unsafe {
      31       236090 :             let obj_ref = ffi_entry.as_ref().unwrap();
      32       236090 :             if ffi::PE_unwind_aarch64_UnpackedFunction::classof(obj_ref) {
      33       133130 :                 let raw = {
      34       133130 :                     type From = cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>;
      35       133130 :                     type To = cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>;
      36       133130 :                     std::mem::transmute::<From, To>(ffi_entry)
      37       133130 :                 };
      38       133130 :                 RuntimeFunction::Unpacked(Unpacked::from_ffi(raw))
      39       102960 :             } else if ffi::PE_unwind_aarch64_PackedFunction::classof(obj_ref) {
      40       102960 :                 let raw = {
      41       102960 :                     type From = cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>;
      42       102960 :                     type To = cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>;
      43       102960 :                     std::mem::transmute::<From, To>(ffi_entry)
      44       102960 :                 };
      45       102960 :                 RuntimeFunction::Packed(Packed::from_ffi(raw))
      46              :             } else {
      47            0 :                 panic!("unsupported format: {}", obj_ref.as_ref().to_string());
      48              :             }
      49              :         }
      50       236090 :     }
      51              : }
      52              : 
      53              : impl ExceptionInfo for RuntimeFunction<'_> {
      54            0 :     fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
      55            0 :         match &self {
      56            0 :             RuntimeFunction::Packed(f) => f.as_generic(),
      57            0 :             RuntimeFunction::Unpacked(f) => f.as_generic(),
      58              :         }
      59            0 :     }
      60              : }
      61              : 
      62              : /// This structure represents a packed AArch64 exception entry.
      63              : ///
      64              : /// An excepted entry can be packed if the unwind data fit in 30 bits
      65              : ///
      66              : /// Reference: <https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#packed-unwind-data>
      67              : pub struct Packed<'a> {
      68              :     ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>,
      69              :     _owner: PhantomData<&'a ffi::PE_Binary>,
      70              : }
      71              : 
      72              : impl<'a> FromFFI<ffi::PE_unwind_aarch64_PackedFunction> for Packed<'a> {
      73       102960 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>) -> Self {
      74       102960 :         Self {
      75       102960 :             ptr,
      76       102960 :             _owner: PhantomData,
      77       102960 :         }
      78       102960 :     }
      79              : }
      80              : 
      81              : impl Packed<'_> {
      82              :     /// Size of the allocated stack
      83       102960 :     pub fn frame_size(&self) -> u8 {
      84       102960 :         self.ptr.frame_size()
      85       102960 :     }
      86              : 
      87              :     /// Number of non-volatile INT registers (x19-x28) saved in the canonical stack location.
      88              :     #[allow(non_snake_case)]
      89       102960 :     pub fn reg_I(&self) -> u8 {
      90       102960 :         self.ptr.reg_I()
      91       102960 :     }
      92              : 
      93              :     /// Number of non-volatile FP registers (d8-d15) saved in the canonical stack location
      94              :     #[allow(non_snake_case)]
      95       102960 :     pub fn reg_F(&self) -> u8 {
      96       102960 :         self.ptr.reg_F()
      97       102960 :     }
      98              : 
      99              :     /// 1-bit flag indicating whether the function homes the integer parameter registers (x0-x7) by
     100              :     /// storing them at the very start of the function.
     101              :     /// (0 = doesn't home registers, 1 = homes registers).
     102              :     #[allow(non_snake_case)]
     103       102960 :     pub fn H(&self) -> u8 {
     104       102960 :         self.ptr.H()
     105       102960 :     }
     106              : 
     107              :     /// Flag indicating whether the function includes extra instructions to set up a frame chain
     108              :     /// and return link.
     109              :     #[allow(non_snake_case)]
     110       102960 :     pub fn CR(&self) -> u8 {
     111       102960 :         self.ptr.CR()
     112       102960 :     }
     113              : }
     114              : 
     115              : impl ExceptionInfo for Packed<'_> {
     116            0 :     fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
     117            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     118            0 :     }
     119              : }
     120              : 
     121              : impl std::fmt::Debug for Packed<'_> {
     122       102960 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     123       102960 :         f.debug_struct("Packed")
     124       102960 :             .field("frame_size", &self.frame_size())
     125       102960 :             .field("RI", &self.reg_I())
     126       102960 :             .field("RF", &self.reg_F())
     127       102960 :             .field("H", &self.H())
     128       102960 :             .field("CR", &self.CR())
     129       102960 :             .finish()
     130       102960 :     }
     131              : }
     132              : 
     133              : /// This class represents an unpacked AArch64 exception entry
     134              : ///
     135              : /// Reference: <https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#xdata-records>
     136              : pub struct Unpacked<'a> {
     137              :     ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>,
     138              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     139              : }
     140              : 
     141              : impl<'a> FromFFI<ffi::PE_unwind_aarch64_UnpackedFunction> for Unpacked<'a> {
     142       133130 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>) -> Self {
     143       133130 :         Self {
     144       133130 :             ptr,
     145       133130 :             _owner: PhantomData,
     146       133130 :         }
     147       133130 :     }
     148              : }
     149              : 
     150              : impl Unpacked<'_> {
     151              :     /// RVA where this unpacked data is located (usually pointing in `.xdata`)
     152       133130 :     pub fn xdata_rva(&self) -> u32 {
     153       133130 :         self.ptr.xdata_rva()
     154       133130 :     }
     155              : 
     156              :     /// Describes the version of the remaining `.xdata`.
     157              :     ///
     158              :     /// Currently (2025-01-04), only version 0 is defined, so values of 1-3 aren't
     159              :     /// permitted.
     160       133130 :     pub fn version(&self) -> u32 {
     161       133130 :         self.ptr.version()
     162       133130 :     }
     163              : 
     164              :     /// 1-bit field that indicates the presence (1) or absence (0) of exception
     165              :     /// data.
     166              :     #[allow(non_snake_case)]
     167       133130 :     pub fn X(&self) -> u8 {
     168       133130 :         self.ptr.X()
     169       133130 :     }
     170              : 
     171              :     /// 1-bit field that indicates that information describing a single epilog is
     172              :     /// packed into the header (1) rather than requiring more scope words later (0).
     173              :     #[allow(non_snake_case)]
     174       133130 :     pub fn E(&self) -> u8 {
     175       133130 :         self.ptr.E()
     176       133130 :     }
     177              : 
     178              :     /// If [`Unpacked::E`] == 0, specifies the count of the total number of epilog scopes.
     179              :     /// Otherwise, return 0
     180       133130 :     pub fn epilog_count(&self) -> u16 {
     181       133130 :         self.ptr.epilog_count()
     182       133130 :     }
     183              : 
     184              :     /// **If E() == 1**, index of the first unwind code that describes the one and
     185              :     /// only epilog.
     186       133130 :     pub fn epilog_offset(&self) -> u16 {
     187       133130 :         self.ptr.epilog_offset()
     188       133130 :     }
     189              : 
     190              :     /// Number of 32-bit words needed to contain all of the unwind codes
     191       133130 :     pub fn code_words(&self) -> u32 {
     192       133130 :         self.ptr.code_words()
     193       133130 :     }
     194              : 
     195              :     /// Exception handler RVA (if any)
     196       133130 :     pub fn exception_handler(&self) -> u32 {
     197       133130 :         self.ptr.exception_handler()
     198       133130 :     }
     199              : 
     200              :     /// Slices that contain the unwind codes.
     201            0 :     pub fn unwind_code(&self) -> &[u8] {
     202            0 :         to_slice!(self.ptr.unwind_code());
     203            0 :     }
     204              : 
     205              :     /// Iterator over the epilog scopes
     206            0 :     pub fn epilog_scopes(&self) -> EpilogScopes {
     207            0 :         EpilogScopes::new(self.ptr.epilog_scopes())
     208            0 :     }
     209              : }
     210              : 
     211              : impl ExceptionInfo for Unpacked<'_> {
     212            0 :     fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
     213            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     214            0 :     }
     215              : }
     216              : 
     217              : impl std::fmt::Debug for Unpacked<'_> {
     218       133130 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     219       133130 :         f.debug_struct("Unpacked")
     220       133130 :             .field("xdata_rva", &self.xdata_rva())
     221       133130 :             .field("version", &self.version())
     222       133130 :             .field("X", &self.X())
     223       133130 :             .field("E", &self.E())
     224       133130 :             .field("epilog_count", &self.epilog_count())
     225       133130 :             .field("epilog_offset", &self.epilog_offset())
     226       133130 :             .field("code_words", &self.code_words())
     227       133130 :             .field("exception_handler", &self.exception_handler())
     228       133130 :             .finish()
     229       133130 :     }
     230              : }
     231              : 
     232              : /// This strucure describes an epilog scope.
     233              : pub struct EpilogScope<'a> {
     234              :     ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t>,
     235              :     _owner: PhantomData<&'a ffi::PE_unwind_aarch64_UnpackedFunction>,
     236              : }
     237              : 
     238              : impl<'a> FromFFI<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t> for EpilogScope<'a> {
     239            0 :     fn from_ffi(
     240            0 :         ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t>,
     241            0 :     ) -> Self {
     242            0 :         Self {
     243            0 :             ptr,
     244            0 :             _owner: PhantomData,
     245            0 :         }
     246            0 :     }
     247              : }
     248              : 
     249              : impl EpilogScope<'_> {
     250              :     /// Offset of the epilog relatives to the start of the function
     251            0 :     pub fn start_offset(&self) -> u32 {
     252            0 :         self.ptr.start_offset()
     253            0 :     }
     254              : 
     255              :     /// Byte index of the first unwind code that describes this epilog
     256            0 :     pub fn start_index(&self) -> u16 {
     257            0 :         self.ptr.start_index()
     258            0 :     }
     259              : 
     260              :     /// Reserved for future expansion. Should be 0.
     261            0 :     pub fn reserved(&self) -> u8 {
     262            0 :         self.ptr.reserved()
     263            0 :     }
     264              : }
     265              : 
     266              : impl std::fmt::Debug for EpilogScope<'_> {
     267            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     268            0 :         f.debug_struct("EpilogScope")
     269            0 :             .field("start_offset", &self.start_offset())
     270            0 :             .field("start_index", &self.start_index())
     271            0 :             .field("reserved", &self.reserved())
     272            0 :             .finish()
     273            0 :     }
     274              : }
     275              : 
     276            0 : declare_iterator!(
     277            0 :     EpilogScopes,
     278            0 :     EpilogScope<'a>,
     279            0 :     ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t,
     280            0 :     ffi::PE_unwind_aarch64_UnpackedFunction,
     281            0 :     ffi::PE_unwind_aarch64_UnpackedFunction_it_const_epilog_scopes
     282            0 : );
        

Generated by: LCOV version 2.1-1