LCOV - code coverage report
Current view: top level - src/elf - binary.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 87.1 % 178 155
Test Date: 2024-11-30:00:00:00 Functions: 66.7 % 72 48

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