LCOV - code coverage report
Current view: top level - src/pe - debug.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 77.8 % 221 172
Test Date: 2024-11-30:00:00:00 Functions: 78.7 % 75 59

            Line data    Source code
       1              : //! Module that wraps the different debug information structure we can find in a PE binary.
       2              : 
       3              : use std::marker::PhantomData;
       4              : 
       5              : use crate::declare_iterator;
       6              : use crate::{common::FromFFI, to_slice};
       7              : use lief_ffi as ffi;
       8              : 
       9          180 : #[derive(Debug)]
      10              : /// This enum exposes the different debug entries that can be
      11              : /// found in the debug DataDirectory.
      12              : pub enum Entries<'a> {
      13              :     CodeView(CodeView<'a>),
      14              :     /// Entry associated with the `IMAGE_DEBUG_TYPE_CODEVIEW`
      15              :     CodeViewPDB(CodeViewPDB<'a>),
      16              :     /// Entry associated with `IMAGE_DEBUG_TYPE_REPRO`
      17              :     Repro(Repro<'a>),
      18              :     /// Entry associated with `IMAGE_DEBUG_TYPE_POGO`
      19              :     Pogo(Pogo<'a>),
      20              :     /// Generic entry for all the other ``IMAGE_DEBUG_xxx`
      21              :     Generic(Generic<'a>),
      22              : }
      23              : 
      24              : #[allow(non_camel_case_types)]
      25          180 : #[derive(Debug, Copy, Clone)]
      26              : pub enum Type {
      27              :     COFF,
      28              :     CODEVIEW,
      29              :     FPO,
      30              :     MISC,
      31              :     EXCEPTION,
      32              :     FIXUP,
      33              :     OMAP_TO_SRC,
      34              :     OMAP_FROM_SRC,
      35              :     BORLAND,
      36              :     RESERVED10,
      37              :     CLSID,
      38              :     VC_FEATURE,
      39              :     POGO,
      40              :     ILTCG,
      41              :     MPX,
      42              :     REPRO,
      43              :     EX_DLLCHARACTERISTICS,
      44              :     UNKNOWN(u32),
      45              : }
      46              : 
      47              : impl From<u32> for Type {
      48          180 :     fn from(value: u32) -> Self {
      49          180 :         match value {
      50            0 :             0x00000001 => Type::COFF,
      51           50 :             0x00000002 => Type::CODEVIEW,
      52            0 :             0x00000003 => Type::FPO,
      53            0 :             0x00000004 => Type::MISC,
      54            0 :             0x00000005 => Type::EXCEPTION,
      55            0 :             0x00000006 => Type::FIXUP,
      56            0 :             0x00000007 => Type::OMAP_TO_SRC,
      57            0 :             0x00000008 => Type::OMAP_FROM_SRC,
      58            0 :             0x00000009 => Type::BORLAND,
      59           10 :             0x0000000a => Type::RESERVED10,
      60            0 :             0x0000000b => Type::CLSID,
      61           30 :             0x0000000c => Type::VC_FEATURE,
      62           50 :             0x0000000d => Type::POGO,
      63           10 :             0x0000000e => Type::ILTCG,
      64            0 :             0x0000000f => Type::MPX,
      65           20 :             0x00000010 => Type::REPRO,
      66           10 :             0x00000014 => Type::EX_DLLCHARACTERISTICS,
      67            0 :             _ => Type::UNKNOWN(value),
      68              :         }
      69          180 :     }
      70              : }
      71              : 
      72              : pub trait DebugEntry {
      73              :     #[doc(hidden)]
      74              :     fn get_base(&self) -> &ffi::PE_Debug;
      75              : 
      76              :     /// Reserved should be 0
      77          180 :     fn characteristics(&self) -> u32 {
      78          180 :         self.get_base().characteristics()
      79          180 :     }
      80              : 
      81              :     /// The time and date when the debug data was created.
      82          180 :     fn timestamp(&self) -> u32 {
      83          180 :         self.get_base().timestamp()
      84          180 :     }
      85              : 
      86              :     /// The major version number of the debug data format.
      87          180 :     fn major_version(&self) -> u16 {
      88          180 :         self.get_base().major_version()
      89          180 :     }
      90              : 
      91              :     /// The minor version number of the debug data format.
      92          180 :     fn minor_version(&self) -> u16 {
      93          180 :         self.get_base().minor_version()
      94          180 :     }
      95              : 
      96              :     /// The format of the debugging information
      97          180 :     fn get_type(&self) -> Type {
      98          180 :         Type::from(self.get_base().get_type())
      99          180 :     }
     100              : 
     101              :     /// Size of the debug data
     102          180 :     fn sizeof_data(&self) -> u32 {
     103          180 :         self.get_base().sizeof_data()
     104          180 :     }
     105              : 
     106              :     /// Address of the debug data relative to the image base
     107          180 :     fn addressof_rawdata(&self) -> u32 {
     108          180 :         self.get_base().addressof_rawdata()
     109          180 :     }
     110              : 
     111              :     /// File offset of the debug data
     112          180 :     fn pointerto_rawdata(&self) -> u32 {
     113          180 :         self.get_base().pointerto_rawdata()
     114          180 :     }
     115              : }
     116              : 
     117              : impl DebugEntry for Entries<'_> {
     118            0 :     fn get_base(&self) -> &ffi::PE_Debug {
     119            0 :         match &self {
     120            0 :             Entries::CodeView(entry) => {
     121            0 :                 entry.get_base()
     122              :             }
     123              : 
     124            0 :             Entries::CodeViewPDB(entry) => {
     125            0 :                 entry.get_base()
     126              :             }
     127              : 
     128            0 :             Entries::Repro(entry) => {
     129            0 :                 entry.get_base()
     130              :             }
     131              : 
     132            0 :             Entries::Pogo(entry) => {
     133            0 :                 entry.get_base()
     134              :             }
     135              : 
     136            0 :             Entries::Generic(entry) => {
     137            0 :                 entry.get_base()
     138              :             }
     139              :         }
     140            0 :     }
     141              : }
     142              : 
     143              : impl std::fmt::Debug for &dyn DebugEntry {
     144          180 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     145          180 :         f.debug_struct("DebugEntry")
     146          180 :             .field("characteristics", &self.characteristics())
     147          180 :             .field("timestamp", &self.timestamp())
     148          180 :             .field("major_version", &self.major_version())
     149          180 :             .field("minor_version", &self.minor_version())
     150          180 :             .field("type", &self.get_type())
     151          180 :             .field("sizeof_data", &self.sizeof_data())
     152          180 :             .field("addressof_rawdata", &self.addressof_rawdata())
     153          180 :             .field("pointerto_rawdata", &self.pointerto_rawdata())
     154          180 :             .finish()
     155          180 :     }
     156              : }
     157              : 
     158              : impl<'a> FromFFI<ffi::PE_Debug> for Entries<'a> {
     159          180 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
     160          180 :         unsafe {
     161          180 :             let debug_ref = ffi_entry.as_ref().unwrap();
     162          180 :             if ffi::PE_Pogo::classof(debug_ref) {
     163           50 :                 let raw = {
     164           50 :                     type From = cxx::UniquePtr<ffi::PE_Debug>;
     165           50 :                     type To = cxx::UniquePtr<ffi::PE_Pogo>;
     166           50 :                     std::mem::transmute::<From, To>(ffi_entry)
     167           50 :                 };
     168           50 :                 Entries::Pogo(Pogo::from_ffi(raw))
     169          130 :             } else if ffi::PE_CodeViewPDB::classof(debug_ref) {
     170           50 :                 let raw = {
     171           50 :                     type From = cxx::UniquePtr<ffi::PE_Debug>;
     172           50 :                     type To = cxx::UniquePtr<ffi::PE_CodeViewPDB>;
     173           50 :                     std::mem::transmute::<From, To>(ffi_entry)
     174           50 :                 };
     175           50 :                 Entries::CodeViewPDB(CodeViewPDB::from_ffi(raw))
     176           80 :             } else if ffi::PE_Repro::classof(debug_ref) {
     177           20 :                 let raw = {
     178           20 :                     type From = cxx::UniquePtr<ffi::PE_Debug>;
     179           20 :                     type To = cxx::UniquePtr<ffi::PE_Repro>;
     180           20 :                     std::mem::transmute::<From, To>(ffi_entry)
     181           20 :                 };
     182           20 :                 Entries::Repro(Repro::from_ffi(raw))
     183           60 :             } else if ffi::PE_CodeView::classof(debug_ref) {
     184            0 :                 let raw = {
     185            0 :                     type From = cxx::UniquePtr<ffi::PE_Debug>;
     186            0 :                     type To = cxx::UniquePtr<ffi::PE_CodeView>;
     187            0 :                     std::mem::transmute::<From, To>(ffi_entry)
     188            0 :                 };
     189            0 :                 Entries::CodeView(CodeView::from_ffi(raw))
     190              :             } else {
     191           60 :                 Entries::Generic(Generic::from_ffi(ffi_entry))
     192              :             }
     193              :         }
     194          180 :     }
     195              : }
     196              : 
     197              : pub struct Generic<'a> {
     198              :     ptr: cxx::UniquePtr<ffi::PE_Debug>,
     199              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     200              : }
     201              : 
     202              : impl<'a> FromFFI<ffi::PE_Debug> for Generic<'a> {
     203           60 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
     204           60 :         Self {
     205           60 :             ptr,
     206           60 :             _owner: PhantomData,
     207           60 :         }
     208           60 :     }
     209              : }
     210              : 
     211              : impl DebugEntry for Generic<'_> {
     212          480 :     fn get_base(&self) -> &ffi::PE_Debug {
     213          480 :         self.ptr.as_ref().unwrap()
     214          480 :     }
     215              : }
     216              : 
     217              : impl std::fmt::Debug for Generic<'_> {
     218           60 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     219           60 :         let base = self as &dyn DebugEntry;
     220           60 :         f.debug_struct("Generic").field("base", &base).finish()
     221           60 :     }
     222              : }
     223              : 
     224              : /// This structure represents a *Profile Guided Optimization* entry from the
     225              : /// debug directory (`IMAGE_DEBUG_TYPE_POGO`).
     226              : pub struct Pogo<'a> {
     227              :     ptr: cxx::UniquePtr<ffi::PE_Pogo>,
     228              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     229              : }
     230              : 
     231              : impl Pogo<'_> {
     232              : 
     233              :     /// An iterator over the different POGO elements: [`PogoEntry`]
     234           50 :     pub fn entries(&self) -> PogoEntries {
     235           50 :         PogoEntries::new(self.ptr.entries())
     236           50 :     }
     237              : }
     238              : 
     239              : impl<'a> FromFFI<ffi::PE_Pogo> for Pogo<'a> {
     240           50 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Pogo>) -> Self {
     241           50 :         Self {
     242           50 :             ptr,
     243           50 :             _owner: PhantomData,
     244           50 :         }
     245           50 :     }
     246              : }
     247              : 
     248              : impl DebugEntry for Pogo<'_> {
     249          400 :     fn get_base(&self) -> &ffi::PE_Debug {
     250          400 :         self.ptr.as_ref().unwrap().as_ref()
     251          400 :     }
     252              : }
     253              : 
     254              : impl std::fmt::Debug for Pogo<'_> {
     255           50 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     256           50 :         let base = self as &dyn DebugEntry;
     257           50 :         f.debug_struct("Pogo").field("base", &base).finish()
     258           50 :     }
     259              : }
     260              : 
     261              : /// Structure which reprents an entry in the [`Pogo`] debug structure
     262              : pub struct PogoEntry<'a> {
     263              :     ptr: cxx::UniquePtr<ffi::PE_PogoEntry>,
     264              :     _owner: PhantomData<&'a ffi::PE_Pogo>,
     265              : }
     266              : 
     267              : impl<'a> FromFFI<ffi::PE_PogoEntry> for PogoEntry<'a> {
     268         2170 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_PogoEntry>) -> Self {
     269         2170 :         Self {
     270         2170 :             ptr,
     271         2170 :             _owner: PhantomData,
     272         2170 :         }
     273         2170 :     }
     274              : }
     275              : 
     276              : impl PogoEntry<'_> {
     277         2170 :     pub fn start_rva(&self) -> u32 {
     278         2170 :         self.ptr.start_rva()
     279         2170 :     }
     280         2170 :     pub fn size(&self) -> u32 {
     281         2170 :         self.ptr.size()
     282         2170 :     }
     283         2170 :     pub fn name(&self) -> String {
     284         2170 :         self.ptr.name().to_string()
     285         2170 :     }
     286              : }
     287              : 
     288              : impl std::fmt::Debug for PogoEntry<'_> {
     289         2170 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     290         2170 :         f.debug_struct("PogoEntry")
     291         2170 :             .field("name", &self.name())
     292         2170 :             .field("size", &self.size())
     293         2170 :             .field("start_rva", &self.start_rva())
     294         2170 :             .finish()
     295         2170 :     }
     296              : }
     297              : 
     298              : /// Structure that represents the (generic) Debug CodeView (`IMAGE_DEBUG_TYPE_CODEVIEW`).
     299              : pub struct CodeView<'a> {
     300              :     ptr: cxx::UniquePtr<ffi::PE_CodeView>,
     301              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     302              : }
     303              : 
     304              : impl<'a> FromFFI<ffi::PE_CodeView> for CodeView<'a> {
     305            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CodeView>) -> Self {
     306            0 :         Self {
     307            0 :             ptr,
     308            0 :             _owner: PhantomData,
     309            0 :         }
     310            0 :     }
     311              : }
     312              : 
     313              : impl DebugEntry for CodeView<'_> {
     314            0 :     fn get_base(&self) -> &ffi::PE_Debug {
     315            0 :         self.ptr.as_ref().unwrap().as_ref()
     316            0 :     }
     317              : }
     318              : 
     319              : impl std::fmt::Debug for CodeView<'_> {
     320            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     321            0 :         f.debug_struct("CodeView").finish()
     322            0 :     }
     323              : }
     324              : 
     325              : /// CodeView PDB specialization
     326              : pub struct CodeViewPDB<'a> {
     327              :     ptr: cxx::UniquePtr<ffi::PE_CodeViewPDB>,
     328              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     329              : }
     330              : 
     331              : impl<'a> FromFFI<ffi::PE_CodeViewPDB> for CodeViewPDB<'a> {
     332           50 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CodeViewPDB>) -> Self {
     333           50 :         Self {
     334           50 :             ptr,
     335           50 :             _owner: PhantomData,
     336           50 :         }
     337           50 :     }
     338              : }
     339              : 
     340              : /// CodeView PDB specialization
     341              : impl CodeViewPDB<'_> {
     342              :     /// Age value to verify. The age does not necessarily correspond to any known
     343              :     /// time value, it is used to determine if a .pdb file is out of sync with a corresponding
     344              :     /// `.exe` file.
     345           50 :     pub fn age(&self) -> u32 {
     346           50 :         self.ptr.age()
     347           50 :     }
     348              : 
     349              :     /// The path to the `.pdb` file
     350           50 :     pub fn filename(&self) -> String {
     351           50 :         self.ptr.filename().to_string()
     352           50 :     }
     353              : 
     354              :     /// The GUID signature to verify against the .pdb file signature.
     355              :     /// This attribute might be used to lookup remote PDB file on a symbol server.
     356            0 :     pub fn guid(&self) -> String {
     357            0 :         self.ptr.guid().to_string()
     358            0 :     }
     359              : 
     360              :     /// The 32-bit signature to verify against the .pdb file signature.
     361            0 :     pub fn signature(&self) -> [u8; 16] {
     362            0 :         let vector: Vec<u8> = self.ptr.signature().iter().map(|&e| e as u8).collect();
     363            0 :         vector.try_into().expect("Wrong size")
     364            0 :     }
     365              : 
     366              : }
     367              : 
     368              : impl DebugEntry for CodeViewPDB<'_> {
     369          400 :     fn get_base(&self) -> &ffi::PE_Debug {
     370          400 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     371          400 :     }
     372              : }
     373              : 
     374              : impl std::fmt::Debug for CodeViewPDB<'_> {
     375           50 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     376           50 :         let base = self as &dyn DebugEntry;
     377           50 :         f.debug_struct("CodeViewPDB")
     378           50 :             .field("base", &base)
     379           50 :             .field("age", &self.age())
     380           50 :             .field("filename", &self.filename())
     381           50 :             .finish()
     382           50 :     }
     383              : }
     384              : 
     385              : /// This structure represents a reproducible build entry from the debug directory
     386              : /// (`IMAGE_DEBUG_TYPE_REPRO`)
     387              : ///
     388              : /// This entry is usually generated with the undocumented `/Brepro` linker flag.
     389              : /// See: <https://nikhilism.com/post/2020/windows-deterministic-builds/>
     390              : pub struct Repro<'a> {
     391              :     ptr: cxx::UniquePtr<ffi::PE_Repro>,
     392              :     _owner: PhantomData<&'a ffi::PE_Binary>,
     393              : }
     394              : 
     395              : impl<'a> FromFFI<ffi::PE_Repro> for Repro<'a> {
     396           20 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Repro>) -> Self {
     397           20 :         Self {
     398           20 :             ptr,
     399           20 :             _owner: PhantomData,
     400           20 :         }
     401           20 :     }
     402              : }
     403              : 
     404              : impl Repro<'_> {
     405              :     /// The hash associated with the reproducible build
     406           20 :     pub fn hash(&self) -> &[u8] {
     407           20 :         to_slice!(self.ptr.hash());
     408           20 :     }
     409              : }
     410              : 
     411              : impl DebugEntry for Repro<'_> {
     412          160 :     fn get_base(&self) -> &ffi::PE_Debug {
     413          160 :         self.ptr.as_ref().unwrap().as_ref()
     414          160 :     }
     415              : }
     416              : 
     417              : impl std::fmt::Debug for Repro<'_> {
     418           20 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     419           20 :         let base = self as &dyn DebugEntry;
     420           20 :         f.debug_struct("Repro").field("base", &base).finish()
     421           20 :     }
     422              : }
     423              : 
     424         2170 : declare_iterator!(
     425         2170 :     PogoEntries,
     426         2170 :     PogoEntry<'a>,
     427         2170 :     ffi::PE_PogoEntry,
     428         2170 :     ffi::PE_Pogo,
     429         2170 :     ffi::PE_Pogo_it_entries
     430         2170 : );
        

Generated by: LCOV version 2.1-1