LCOV - code coverage report
Current view: top level - src/elf - binary.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 92.2 % 166 153
Test Date: 2024-10-27:00:00:00 Functions: 67.6 % 71 48

            Line data    Source code
       1              : use std::mem::size_of;
       2              : 
       3              : use num_traits::{Num, cast};
       4              : 
       5              : use lief_ffi as ffi;
       6              : 
       7              : use crate::Error;
       8              : use super::hash::{Sysv, Gnu};
       9              : use super::dynamic::{self, DynamicEntries};
      10              : use super::header::Header;
      11              : use super::section::{Sections, Section};
      12              : use super::segment::Segments;
      13              : use super::symbol::{DynamicSymbols, ExportedSymbols, ImportedSymbols, SymtabSymbols};
      14              : use super::note::ItNotes;
      15              : use super::relocation::{Relocation, PltGotRelocations, DynamicRelocations, ObjectRelocations, Relocations};
      16              : use super::symbol_versioning::{SymbolVersion, SymbolVersionDefinition, SymbolVersionRequirement};
      17              : use super::{Segment, Symbol};
      18              : 
      19              : use crate::generic;
      20              : use crate::{declare_iterator, to_slice, to_result, to_conv_result};
      21              : use crate::common::{into_optional, FromFFI};
      22              : 
      23            0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
      24              : pub enum ElfClass {
      25              :     Elf32,
      26              :     Elf64,
      27              :     Unknown,
      28              : }
      29              : 
      30              : impl ElfClass {
      31              :     const ELF_CLASS32: u32 = 1;
      32              :     const ELF_CLASS64: u32 = 2;
      33              : 
      34            0 :     pub fn from_value(value: u32) -> Self {
      35            0 :         match value {
      36            0 :             Self::ELF_CLASS32 => ElfClass::Elf32,
      37            0 :             Self::ELF_CLASS64 => ElfClass::Elf64,
      38            0 :             _ => ElfClass::Unknown,
      39              :         }
      40            0 :     }
      41              : }
      42              : 
      43              : /// This is the main interface to read and write ELF binary attributes.
      44              : ///
      45              : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
      46              : /// functions are exposed
      47              : pub struct Binary {
      48              :     ptr: cxx::UniquePtr<ffi::ELF_Binary>,
      49              : }
      50              : 
      51              : impl std::fmt::Debug for Binary {
      52           64 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      53           64 :         f.debug_struct("Binary")
      54           64 :             .field("header", &self.header())
      55           64 :             .finish()
      56           64 :     }
      57              : }
      58              : 
      59              : impl FromFFI<ffi::ELF_Binary> for Binary {
      60          128 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
      61          128 :         Self {
      62          128 :             ptr,
      63          128 :         }
      64          128 :     }
      65              : }
      66              : 
      67              : impl Binary {
      68              :     /// Create a [`Binary`] from the given file path
      69           64 :     pub fn parse(path: &str) -> Self {
      70           64 :         let bin = ffi::ELF_Binary::parse(path);
      71           64 :         Binary::from_ffi(bin)
      72           64 :     }
      73              : 
      74              :     /// Return the main ELF header
      75           64 :     pub fn header(&self) -> Header {
      76           64 :         Header::from_ffi(self.ptr.header())
      77           64 :     }
      78              : 
      79              :     /// Return the size taken by the binary when loaded (virtual size)
      80           64 :     pub fn virtual_size(&self) -> u64 {
      81           64 :         self.ptr.virtual_size()
      82           64 :     }
      83              : 
      84              :     /// Return the path to the ELF interpreter that is used to process the ELF information
      85              :     /// once loaded by the kernel
      86           64 :     pub fn interpreter(&self) -> String {
      87           64 :         self.ptr.interpreter().to_string()
      88           64 :     }
      89              : 
      90              :     /// Return sysv-hash information (if present)
      91           64 :     pub fn sysv_hash(&self) -> Option<Sysv> {
      92           64 :         into_optional(self.ptr.sysv_hash())
      93           64 :     }
      94              : 
      95              :     /// Return GNU Hash info (if present)
      96           64 :     pub fn gnu_hash(&self) -> Option<Gnu> {
      97           64 :         into_optional(self.ptr.gnu_hash())
      98           64 :     }
      99              : 
     100              :     /// Return an iterator over the [`crate::elf::Section`] of the binary
     101           64 :     pub fn sections(&self) -> Sections {
     102           64 :         Sections::new(self.ptr.sections())
     103           64 :     }
     104              : 
     105              :     /// Return an iterator over the [`crate::elf::Segment`] of the binary
     106           64 :     pub fn segments(&self) -> Segments {
     107           64 :         Segments::new(self.ptr.segments())
     108           64 :     }
     109              : 
     110              :     /// Return an iterator over the [`crate::elf::DynamicEntries`] of the binary
     111           64 :     pub fn dynamic_entries(&self) -> DynamicEntries {
     112           64 :         DynamicEntries::new(self.ptr.dynamic_entries())
     113           64 :     }
     114              : 
     115              :     /// Return an iterator over the dynamic [`crate::elf::Symbol`] of the binary
     116           64 :     pub fn dynamic_symbols(&self) -> DynamicSymbols {
     117           64 :         DynamicSymbols::new(self.ptr.dynamic_symbols())
     118           64 :     }
     119              : 
     120              :     /// Return an iterator over the **exported** [`crate::elf::Symbol`] of the binary
     121           64 :     pub fn exported_symbols(&self) -> ExportedSymbols {
     122           64 :         ExportedSymbols::new(self.ptr.exported_symbols())
     123           64 :     }
     124              : 
     125              :     /// Return an iterator over the **imported** [`crate::elf::Symbol`] of the binary
     126           64 :     pub fn imported_symbols(&self) -> ImportedSymbols {
     127           64 :         ImportedSymbols::new(self.ptr.imported_symbols())
     128           64 :     }
     129              : 
     130              :     /// Return an iterator over the symtab-debug [`crate::elf::Symbol`] of the binary
     131           64 :     pub fn symtab_symbols(&self) -> SymtabSymbols {
     132           64 :         SymtabSymbols::new(self.ptr.symtab_symbols())
     133           64 :     }
     134              : 
     135              :     /// Return an iterator over the  [`crate::elf::SymbolVersion`] of the binary
     136          128 :     pub fn symbols_version(&self) -> SymbolsVersion {
     137          128 :         SymbolsVersion::new(self.ptr.symbols_version())
     138          128 :     }
     139              : 
     140              :     /// Return an iterator over the  [`crate::elf::SymbolVersionRequirement`] of the binary
     141           64 :     pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement {
     142           64 :         SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
     143           64 :     }
     144              : 
     145              :     /// Return an iterator over the  [`crate::elf::SymbolVersionDefinition`] of the binary
     146           64 :     pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition {
     147           64 :         SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
     148           64 :     }
     149              : 
     150              :     /// Return an iterator over the  [`crate::elf::Notes`] of the binary
     151           64 :     pub fn notes(&self) -> ItNotes {
     152           64 :         ItNotes::new(self.ptr.notes())
     153           64 :     }
     154              : 
     155              :     /// Return an iterator over the `.plt.got` [`crate::elf::Relocation`] of the binary
     156           64 :     pub fn pltgot_relocations(&self) -> PltGotRelocations {
     157           64 :         PltGotRelocations::new(self.ptr.pltgot_relocations())
     158           64 :     }
     159              : 
     160              :     /// Return an iterator over the regular [`crate::elf::Relocation`] of the binary
     161           64 :     pub fn dynamic_relocations(&self) -> DynamicRelocations {
     162           64 :         DynamicRelocations::new(self.ptr.dynamic_relocations())
     163           64 :     }
     164              : 
     165              :     /// Return an iterator over the object-file (`.o`) [`crate::elf::Relocation`]
     166           64 :     pub fn object_relocations(&self) -> ObjectRelocations {
     167           64 :         ObjectRelocations::new(self.ptr.object_relocations())
     168           64 :     }
     169              : 
     170              :     /// Return an iterator over **all** [`crate::elf::Relocation`] of the binary
     171           64 :     pub fn relocations(&self) -> Relocations {
     172           64 :         Relocations::new(self.ptr.relocations())
     173           64 :     }
     174              : 
     175              :     /// Try to find the ELF section with the given name
     176           64 :     pub fn section_by_name(&self, name: &str) -> Option<Section> {
     177           64 :         into_optional(self.ptr.section_by_name(name))
     178           64 :     }
     179              : 
     180              :     /// Try to find the ELF relocation that takes place at the given address
     181           16 :     pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation> {
     182           16 :         into_optional(self.ptr.relocation_by_addr(address))
     183           16 :     }
     184              : 
     185              :     /// Try to find the `.plt.got` relocation for the given symbol name
     186           16 :     pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation> {
     187           16 :         into_optional(self.ptr.relocation_for_symbol(sym_name))
     188           16 :     }
     189              : 
     190              :     /// Try to find the symbol with the given name in the dynamic `.dynsym` table
     191            8 :     pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
     192            8 :         into_optional(self.ptr.get_dynamic_symbol(sym_name))
     193            8 :     }
     194              : 
     195              :     /// Try to find the symbol with the given name in the debug `.symtab` table
     196            8 :     pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
     197            8 :         into_optional(self.ptr.get_symtab_symbol(sym_name))
     198            8 :     }
     199              : 
     200              :     /// Try to find the library (`DT_NEEDED`) with the given name
     201           16 :     pub fn get_library(&self, name: &str) -> Option<dynamic::Library> {
     202           16 :         into_optional(self.ptr.get_library(name))
     203           16 :     }
     204              : 
     205              :     /// Try to find the section that encompasses the given offset. `skip_nobits` can be used
     206              :     /// to include (or not) the `SHT_NOTBIT` sections
     207           16 :     pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section> {
     208           16 :         into_optional(self.ptr.section_from_offset(offset, skip_nobits))
     209           16 :     }
     210              : 
     211              :     /// Try to find the section that encompasses the given virtual address. `skip_nobits` can be used
     212              :     /// to include (or not) the `SHT_NOTBIT` sections
     213           16 :     pub fn section_from_virtual_address(&self, address: u64, skip_nobits: bool) -> Option<Section> {
     214           16 :         into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
     215           16 :     }
     216              : 
     217              :     /// Try to find the segment that encompasses the given virtual address
     218           16 :     pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment> {
     219           16 :         into_optional(self.ptr.segment_from_virtual_address(address))
     220           16 :     }
     221              : 
     222              :     /// Try to find the segment that encompasses the given offset
     223           16 :     pub fn segment_from_offset(&self, offset: u64) -> Option<Segment> {
     224           16 :         into_optional(self.ptr.segment_from_offset(offset))
     225           16 :     }
     226              : 
     227              :     /// Get a slice of the content at the given address.
     228            8 :     pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
     229            8 :         to_slice!(self.ptr.get_content_from_virtual_address(address, size));
     230            8 :     }
     231              : 
     232              :     /// Convert the given virtual address into an offset
     233           16 :     pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
     234           16 :         to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
     235           16 :     }
     236              : 
     237              :     /// Return the array defined by the given tag (e.g.
     238              :     /// [`dynamic::Tag::INIT_ARRAY`]) with relocations applied (if any)
     239          192 :     pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
     240          192 :         Vec::from(self.ptr.get_relocated_dynamic_array(u64::from(tag)).as_slice())
     241          192 :     }
     242              : 
     243              :     /// True if the current binary is targeting Android
     244            0 :     pub fn is_targeting_android(&self) -> bool {
     245            0 :         self.ptr.is_targeting_android()
     246            0 :     }
     247              : 
     248              :     /// Get the integer value at the given virtual address
     249            4 :     pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
     250            4 :         where T: Num + cast::FromPrimitive + cast::ToPrimitive
     251            4 :     {
     252            4 :         // Can't be in the generic trait because of:
     253            4 :         //   > for a trait to be "object safe" it needs to allow building a vtable to allow the call
     254            4 :         //   > to be resolvable dynamically; for more information visit
     255            4 :         //   > https://doc.rust-lang.org/reference/items/traits.html#object-safety
     256            4 :         if size_of::<T>() == size_of::<u8>() {
     257            1 :             to_conv_result!(ffi::AbstractBinary::get_u8,
     258            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     259            1 :                 |value| { T::from_u8(value).expect(format!("Can't cast value: {}", value).as_str()) },
     260            1 :                 addr);
     261            3 :         }
     262            3 : 
     263            3 :         if size_of::<T>() == size_of::<u16>() {
     264            1 :             to_conv_result!(ffi::AbstractBinary::get_u16,
     265            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     266            1 :                 |value| { T::from_u16(value).expect(format!("Can't cast value: {}", value).as_str()) },
     267            1 :                 addr);
     268            2 :         }
     269            2 : 
     270            2 :         if size_of::<T>() == size_of::<u32>() {
     271            1 :             to_conv_result!(ffi::AbstractBinary::get_u32,
     272            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     273            1 :                 |value| { T::from_u32(value).expect(format!("Can't cast value: {}", value).as_str()) },
     274            1 :                 addr);
     275            1 :         }
     276            1 : 
     277            1 :         if size_of::<T>() == size_of::<u64>() {
     278            1 :             to_conv_result!(ffi::AbstractBinary::get_u64,
     279            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     280            1 :                 |value| { T::from_u64(value).expect(format!("Can't cast value: {}", value).as_str()) },
     281            1 :                 addr);
     282            0 :         }
     283            0 : 
     284            0 :         Err(Error::NotSupported)
     285            4 :     }
     286              : }
     287              : 
     288              : impl generic::Binary for Binary {
     289          320 :     fn as_generic(&self) -> &ffi::AbstractBinary {
     290          320 :         self.ptr.as_ref().unwrap().as_ref()
     291          320 :     }
     292              : }
     293              : 
     294              : 
     295        12432 : declare_iterator!(SymbolsVersion, SymbolVersion<'a>, ffi::ELF_SymbolVersion, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version);
     296          120 : declare_iterator!(SymbolsVersionRequirement, SymbolVersionRequirement<'a>, ffi::ELF_SymbolVersionRequirement, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version_requirement);
     297           24 : declare_iterator!(SymbolsVersionDefinition, SymbolVersionDefinition<'a>, ffi::ELF_SymbolVersionDefinition, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version_definition);
        

Generated by: LCOV version 2.1-1