LCOV - code coverage report
Current view: top level - src/elf - binary.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 67.0 % 303 203
Test Date: 2025-08-10:00:00:00 Functions: 45.6 % 114 52

            Line data    Source code
       1              : use std::mem::size_of;
       2              : use std::path::Path;
       3              : use std::pin::Pin;
       4              : 
       5              : use num_traits::{cast, Num};
       6              : 
       7              : use lief_ffi as ffi;
       8              : 
       9              : use super::builder::Config;
      10              : use super::dynamic::{self, DynamicEntries, Library};
      11              : use super::hash::{Gnu, Sysv};
      12              : use super::header::Header;
      13              : use super::note::ItNotes;
      14              : use super::parser_config::Config as ParserConfig;
      15              : use super::relocation::{
      16              :     DynamicRelocations, ObjectRelocations, PltGotRelocations, Relocation, Relocations,
      17              : };
      18              : use super::section::{Section, Sections};
      19              : use super::segment::{self, Segments};
      20              : use super::symbol::{DynamicSymbols, ExportedSymbols, ImportedSymbols, SymtabSymbols};
      21              : use super::symbol_versioning::{SymbolVersion, SymbolVersionDefinition, SymbolVersionRequirement};
      22              : use super::{Segment, Symbol};
      23              : use crate::elf::dynamic::DynamicEntry;
      24              : use crate::Error;
      25              : 
      26              : use crate::common::{into_optional, FromFFI};
      27              : use crate::generic;
      28              : use crate::{declare_iterator, to_conv_result, to_result, to_slice};
      29              : 
      30            0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
      31              : pub enum ElfClass {
      32              :     Elf32,
      33              :     Elf64,
      34              :     Unknown,
      35              : }
      36              : 
      37              : impl ElfClass {
      38              :     const ELF_CLASS32: u32 = 1;
      39              :     const ELF_CLASS64: u32 = 2;
      40              : 
      41            0 :     pub fn from_value(value: u32) -> Self {
      42            0 :         match value {
      43            0 :             Self::ELF_CLASS32 => ElfClass::Elf32,
      44            0 :             Self::ELF_CLASS64 => ElfClass::Elf64,
      45            0 :             _ => ElfClass::Unknown,
      46              :         }
      47            0 :     }
      48              : }
      49              : 
      50              : /// This is the main interface to read and write ELF binary attributes.
      51              : ///
      52              : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
      53              : /// functions are exposed
      54              : pub struct Binary {
      55              :     ptr: cxx::UniquePtr<ffi::ELF_Binary>,
      56              : }
      57              : 
      58              : impl std::fmt::Debug for Binary {
      59           96 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      60           96 :         f.debug_struct("Binary")
      61           96 :             .field("header", &self.header())
      62           96 :             .finish()
      63           96 :     }
      64              : }
      65              : 
      66              : impl FromFFI<ffi::ELF_Binary> for Binary {
      67          216 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
      68          216 :         Self { ptr }
      69          216 :     }
      70              : }
      71              : 
      72              : impl Binary {
      73              :     /// Create a [`Binary`] from the given file path
      74           10 :     pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
      75           10 :         let bin = ffi::ELF_Binary::parse(path.as_ref().to_str().unwrap());
      76           10 :         if bin.is_null() {
      77            0 :             return None;
      78           10 :         }
      79           10 :         Some(Binary::from_ffi(bin))
      80           10 :     }
      81              : 
      82              :     /// Parse from a string file path and with a provided configuration
      83            0 :     pub fn parse_with_config<P: AsRef<Path>>(path: P, config: &ParserConfig) -> Option<Self> {
      84            0 :         let ffi_config = config.to_ffi();
      85            0 :         let ffi = ffi::ELF_Binary::parse_with_config(path.as_ref().to_str().unwrap(), &ffi_config);
      86            0 :         if ffi.is_null() {
      87            0 :             return None;
      88            0 :         }
      89            0 :         Some(Binary::from_ffi(ffi))
      90            0 :     }
      91              : 
      92              :     /// Return the main ELF header
      93           96 :     pub fn header(&self) -> Header {
      94           96 :         Header::from_ffi(self.ptr.header())
      95           96 :     }
      96              : 
      97              :     /// Return the size taken by the binary when loaded (virtual size)
      98           96 :     pub fn virtual_size(&self) -> u64 {
      99           96 :         self.ptr.virtual_size()
     100           96 :     }
     101              : 
     102              :     /// Return the path to the ELF interpreter that is used to process the ELF information
     103              :     /// once loaded by the kernel
     104           96 :     pub fn interpreter(&self) -> String {
     105           96 :         self.ptr.interpreter().to_string()
     106           96 :     }
     107              : 
     108              :     /// Return sysv-hash information (if present)
     109           96 :     pub fn sysv_hash(&self) -> Option<Sysv> {
     110           96 :         into_optional(self.ptr.sysv_hash())
     111           96 :     }
     112              : 
     113              :     /// Return GNU Hash info (if present)
     114           96 :     pub fn gnu_hash(&self) -> Option<Gnu> {
     115           96 :         into_optional(self.ptr.gnu_hash())
     116           96 :     }
     117              : 
     118              :     /// Return an iterator over the [`crate::elf::Section`] of the binary
     119           96 :     pub fn sections(&self) -> Sections {
     120           96 :         Sections::new(self.ptr.sections())
     121           96 :     }
     122              : 
     123              :     /// Return an iterator over the [`crate::elf::Segment`] of the binary
     124           96 :     pub fn segments(&self) -> Segments {
     125           96 :         Segments::new(self.ptr.segments())
     126           96 :     }
     127              : 
     128              :     /// Return an iterator over the [`crate::elf::DynamicEntries`] of the binary
     129           96 :     pub fn dynamic_entries(&self) -> DynamicEntries {
     130           96 :         DynamicEntries::new(self.ptr.dynamic_entries())
     131           96 :     }
     132              : 
     133              :     /// Remove **all** dynamic entries with the given tag
     134            0 :     pub fn remove_dynamic_entries_by_tag(&mut self, tag: dynamic::Tag) {
     135            0 :         self.ptr
     136            0 :             .as_mut()
     137            0 :             .unwrap()
     138            0 :             .remove_dynamic_entries_by_tag(tag.into())
     139            0 :     }
     140              : 
     141              :     /// Add the given dynamic entry and return the new entry
     142            0 :     pub fn add_dynamic_entry(&mut self, entry: &dyn dynamic::DynamicEntry) -> dynamic::Entries {
     143            0 :         dynamic::Entries::from_ffi(
     144            0 :             self.ptr
     145            0 :                 .as_mut()
     146            0 :                 .unwrap()
     147            0 :                 .add_dynamic_entry(entry.as_base()),
     148            0 :         )
     149            0 :     }
     150              : 
     151              :     /// Return an iterator over the dynamic [`crate::elf::Symbol`] of the binary
     152           96 :     pub fn dynamic_symbols(&self) -> DynamicSymbols {
     153           96 :         DynamicSymbols::new(self.ptr.dynamic_symbols())
     154           96 :     }
     155              : 
     156              :     /// Return an iterator over the **exported** [`crate::elf::Symbol`] of the binary
     157           96 :     pub fn exported_symbols(&self) -> ExportedSymbols {
     158           96 :         ExportedSymbols::new(self.ptr.exported_symbols())
     159           96 :     }
     160              : 
     161              :     /// Return an iterator over the **imported** [`crate::elf::Symbol`] of the binary
     162           96 :     pub fn imported_symbols(&self) -> ImportedSymbols {
     163           96 :         ImportedSymbols::new(self.ptr.imported_symbols())
     164           96 :     }
     165              : 
     166              :     /// Return an iterator over the symtab-debug [`crate::elf::Symbol`] of the binary
     167           96 :     pub fn symtab_symbols(&self) -> SymtabSymbols {
     168           96 :         SymtabSymbols::new(self.ptr.symtab_symbols())
     169           96 :     }
     170              : 
     171              :     /// Return an iterator over the  [`crate::elf::SymbolVersion`] of the binary
     172          192 :     pub fn symbols_version(&self) -> SymbolsVersion {
     173          192 :         SymbolsVersion::new(self.ptr.symbols_version())
     174          192 :     }
     175              : 
     176              :     /// Return an iterator over the  [`crate::elf::SymbolVersionRequirement`] of the binary
     177           96 :     pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement {
     178           96 :         SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
     179           96 :     }
     180              : 
     181              :     /// Return an iterator over the  [`crate::elf::SymbolVersionDefinition`] of the binary
     182           96 :     pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition {
     183           96 :         SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
     184           96 :     }
     185              : 
     186              :     /// Return an iterator over the  [`crate::elf::Notes`] of the binary
     187           96 :     pub fn notes(&self) -> ItNotes {
     188           96 :         ItNotes::new(self.ptr.notes())
     189           96 :     }
     190              : 
     191              :     /// Return an iterator over the `.plt.got` [`crate::elf::Relocation`] of the binary
     192           96 :     pub fn pltgot_relocations(&self) -> PltGotRelocations {
     193           96 :         PltGotRelocations::new(self.ptr.pltgot_relocations())
     194           96 :     }
     195              : 
     196              :     /// Return an iterator over the regular [`crate::elf::Relocation`] of the binary
     197           96 :     pub fn dynamic_relocations(&self) -> DynamicRelocations {
     198           96 :         DynamicRelocations::new(self.ptr.dynamic_relocations())
     199           96 :     }
     200              : 
     201              :     /// Return an iterator over the object-file (`.o`) [`crate::elf::Relocation`]
     202           96 :     pub fn object_relocations(&self) -> ObjectRelocations {
     203           96 :         ObjectRelocations::new(self.ptr.object_relocations())
     204           96 :     }
     205              : 
     206              :     /// Return an iterator over **all** [`crate::elf::Relocation`] of the binary
     207           96 :     pub fn relocations(&self) -> Relocations {
     208           96 :         Relocations::new(self.ptr.relocations())
     209           96 :     }
     210              : 
     211              :     /// Try to find the ELF section with the given name
     212           96 :     pub fn section_by_name(&self, name: &str) -> Option<Section> {
     213           96 :         into_optional(self.ptr.section_by_name(name))
     214           96 :     }
     215              : 
     216              :     /// Try to find the ELF relocation that takes place at the given address
     217           24 :     pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation> {
     218           24 :         into_optional(self.ptr.relocation_by_addr(address))
     219           24 :     }
     220              : 
     221              :     /// Try to find the `.plt.got` relocation for the given symbol name
     222           24 :     pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation> {
     223           24 :         into_optional(self.ptr.relocation_for_symbol(sym_name))
     224           24 :     }
     225              : 
     226              :     /// Try to find the symbol with the given name in the dynamic `.dynsym` table
     227           12 :     pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
     228           12 :         into_optional(self.ptr.get_dynamic_symbol(sym_name))
     229           12 :     }
     230              : 
     231              :     /// Try to find the symbol with the given name in the debug `.symtab` table
     232           12 :     pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
     233           12 :         into_optional(self.ptr.get_symtab_symbol(sym_name))
     234           12 :     }
     235              : 
     236              :     /// Try to find the library (`DT_NEEDED`) with the given name
     237           24 :     pub fn get_library(&self, name: &str) -> Option<dynamic::Library> {
     238           24 :         into_optional(self.ptr.get_library(name))
     239           24 :     }
     240              : 
     241              :     /// Try to find the section that encompasses the given offset. `skip_nobits` can be used
     242              :     /// to include (or not) the `SHT_NOTBIT` sections
     243           24 :     pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section> {
     244           24 :         into_optional(self.ptr.section_from_offset(offset, skip_nobits))
     245           24 :     }
     246              : 
     247              :     /// Try to find the section that encompasses the given virtual address. `skip_nobits` can be used
     248              :     /// to include (or not) the `SHT_NOTBIT` sections
     249           24 :     pub fn section_from_virtual_address(&self, address: u64, skip_nobits: bool) -> Option<Section> {
     250           24 :         into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
     251           24 :     }
     252              : 
     253              :     /// Try to find the segment that encompasses the given virtual address
     254           24 :     pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment> {
     255           24 :         into_optional(self.ptr.segment_from_virtual_address(address))
     256           24 :     }
     257              : 
     258              :     /// Try to find the segment that encompasses the given offset
     259           24 :     pub fn segment_from_offset(&self, offset: u64) -> Option<Segment> {
     260           24 :         into_optional(self.ptr.segment_from_offset(offset))
     261           24 :     }
     262              : 
     263              :     /// Get a slice of the content at the given address.
     264           12 :     pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
     265           12 :         to_slice!(self.ptr.get_content_from_virtual_address(address, size));
     266           12 :     }
     267              : 
     268              :     /// Convert the given virtual address into an offset
     269           24 :     pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
     270           24 :         to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
     271           24 :     }
     272              : 
     273              :     /// Return the array defined by the given tag (e.g.
     274              :     /// [`dynamic::Tag::INIT_ARRAY`]) with relocations applied (if any)
     275          288 :     pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
     276          288 :         Vec::from(
     277          288 :             self.ptr
     278          288 :                 .get_relocated_dynamic_array(u64::from(tag))
     279          288 :                 .as_slice(),
     280          288 :         )
     281          288 :     }
     282              : 
     283              :     /// True if the current binary is targeting Android
     284            0 :     pub fn is_targeting_android(&self) -> bool {
     285            0 :         self.ptr.is_targeting_android()
     286            0 :     }
     287              : 
     288              :     /// Get the integer value at the given virtual address
     289            4 :     pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
     290            4 :     where
     291            4 :         T: Num + cast::FromPrimitive + cast::ToPrimitive,
     292            4 :     {
     293            4 :         // Can't be in the generic trait because of:
     294            4 :         //   > for a trait to be "object safe" it needs to allow building a vtable to allow the call
     295            4 :         //   > to be resolvable dynamically; for more information visit
     296            4 :         //   > https://doc.rust-lang.org/reference/items/traits.html#object-safety
     297            4 :         if size_of::<T>() == size_of::<u8>() {
     298            1 :             to_conv_result!(
     299            1 :                 ffi::AbstractBinary::get_u8,
     300            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     301            1 :                 |value| {
     302            1 :                     T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
     303            1 :                 },
     304            1 :                 addr
     305              :             );
     306            3 :         }
     307            3 : 
     308            3 :         if size_of::<T>() == size_of::<u16>() {
     309            1 :             to_conv_result!(
     310            1 :                 ffi::AbstractBinary::get_u16,
     311            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     312            1 :                 |value| {
     313            1 :                     T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
     314            1 :                 },
     315            1 :                 addr
     316              :             );
     317            2 :         }
     318            2 : 
     319            2 :         if size_of::<T>() == size_of::<u32>() {
     320            1 :             to_conv_result!(
     321            1 :                 ffi::AbstractBinary::get_u32,
     322            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     323            1 :                 |value| {
     324            1 :                     T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
     325            1 :                 },
     326            1 :                 addr
     327              :             );
     328            1 :         }
     329            1 : 
     330            1 :         if size_of::<T>() == size_of::<u64>() {
     331            1 :             to_conv_result!(
     332            1 :                 ffi::AbstractBinary::get_u64,
     333            1 :                 self.ptr.as_ref().unwrap().as_ref(),
     334            1 :                 |value| {
     335            1 :                     T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
     336            1 :                 },
     337            1 :                 addr
     338              :             );
     339            0 :         }
     340            0 : 
     341            0 :         Err(Error::NotSupported)
     342            4 :     }
     343              : 
     344              :     /// Write back the current ELF binary into the file specified in parameter
     345            1 :     pub fn write<P: AsRef<Path>>(&mut self, output: P) {
     346            1 :         self.ptr.as_mut().unwrap().write(output.as_ref().to_str().unwrap());
     347            1 :     }
     348              : 
     349              :     /// Write back the current ELF binary into the file specified in parameter with the
     350              :     /// configuration provided in the second parameter.
     351            1 :     pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
     352            1 :         self.ptr
     353            1 :             .as_mut()
     354            1 :             .unwrap()
     355            1 :             .write_with_config(output.as_ref().to_str().unwrap(), config.to_ffi());
     356            1 :     }
     357              : 
     358              :     /// Add a library as dependency
     359           12 :     pub fn add_library<'a>(&'a mut self, library: &str) -> Library<'a> {
     360           12 :         Library::from_ffi(self.ptr.as_mut().unwrap().add_library(library))
     361           12 :     }
     362              : 
     363              :     /// Iterator over the functions found in this binary
     364           96 :     pub fn functions(&self) -> generic::Functions {
     365           96 :         generic::Functions::new(self.ptr.functions())
     366           96 :     }
     367              : 
     368              :     /// Try to find the dynamic entry associated with the given tag
     369            0 :     pub fn dynamic_entry_by_tag(&self, tag: dynamic::Tag) -> Option<dynamic::Entries> {
     370            0 :         into_optional(self.ptr.dynamic_entry_by_tag(tag.into()))
     371            0 :     }
     372              : 
     373              :     /// Look for the segment with the given type. If there are multiple segment
     374              :     /// with the same type, it returns the first one.
     375            0 :     pub fn segment_by_type(&self, seg_type: segment::Type) -> Option<Segment> {
     376            0 :         into_optional(self.ptr.segment_by_type(seg_type.into()))
     377            0 :     }
     378              : 
     379              :     /// Remove the given dynamic entry
     380            0 :     pub fn remove_dynamic_entry(&mut self, entry: impl dynamic::DynamicEntry) {
     381            0 :         self.ptr.pin_mut().remove_dynamic_entry(entry.as_base());
     382            0 :     }
     383              : 
     384              :     /// Remove the dynamic entries matching the given predicate.
     385              :     ///
     386              :     /// The function returns the number of entries that have been deleted.
     387            0 :     pub fn remove_dynamic_entry_if<P>(&mut self, predicate: P) -> usize
     388            0 :     where
     389            0 :         P: Fn(&dynamic::Entries) -> bool,
     390            0 :     {
     391            0 :         let entries = self.dynamic_entries()
     392            0 :             .filter(predicate)
     393            0 :             .map(|e| e.as_base().raw_ptr() )
     394            0 :             .collect::<Vec<_>>();
     395            0 : 
     396            0 :         let cnt = entries.len();
     397              : 
     398            0 :         for ffi_entry in entries {
     399            0 :             unsafe {
     400            0 :                 self.ptr.pin_mut().remove_dynamic_entry_from_ptr(ffi_entry);
     401            0 :             }
     402              :         }
     403            0 :         cnt
     404            0 :     }
     405              : 
     406              :     /// Remove the `DT_NEEDED` dependency with the given name
     407            0 :     pub fn remove_library(&mut self, name: &str) {
     408            0 :         self.ptr.pin_mut().remove_library(name.to_string());
     409            0 :     }
     410              : 
     411              :     /// Add the provided segment to the binary. This function returns the
     412              :     /// newly added segment which could define additional attributes like the virtual address.
     413            0 :     pub fn add_segment(&mut self, segment: &Segment) -> Option<Segment> {
     414            0 :         into_optional(
     415            0 :             self.ptr
     416            0 :                 .pin_mut()
     417            0 :                 .add_segment(segment.ptr.as_ref().unwrap()),
     418            0 :         )
     419            0 :     }
     420              : 
     421              :     /// Change the path to the interpreter
     422            0 :     pub fn set_interpreter<P: AsRef<Path>>(&mut self, interpreter: P) {
     423            0 :         self.ptr.pin_mut().set_interpreter(interpreter.as_ref().to_str().unwrap());
     424            0 :     }
     425              : 
     426              :     /// Try to find the SymbolVersionRequirement associated with the given library
     427              :     /// name (e.g. `libc.so.6`)
     428            0 :     pub fn find_version_requirement(&self, libname: &str) -> Option<SymbolVersionRequirement> {
     429            0 :         into_optional(self.ptr.find_version_requirement(libname.to_string()))
     430            0 :     }
     431              : 
     432              :     /// Deletes all required symbol versions linked to the specified library name.
     433              :     /// The function returns true if the operation succeed, false otherwise.
     434              :     ///
     435              :     /// <div class='warning'>
     436              :     /// To maintain consistency, this function also removes versions
     437              :     /// associated with dynamic symbols that are linked to the specified
     438              :     /// library name.
     439              :     /// </div>
     440            0 :     pub fn remove_version_requirement(&mut self, libname: &str) -> bool {
     441            0 :         self.ptr
     442            0 :             .pin_mut()
     443            0 :             .remove_version_requirement(libname.to_string())
     444            0 :     }
     445              : 
     446              :     /// Remove the given segment. If `clear` is set, the original content of the
     447              :     /// segment will be filled with zeros before removal.
     448            0 :     pub fn remove_segment(&mut self, segment: Segment, clear: bool) {
     449            0 :         self.ptr
     450            0 :             .pin_mut()
     451            0 :             .remove_segment(segment.ptr.as_ref().unwrap(), clear)
     452            0 :     }
     453              : 
     454              :     /// Remove all segments associated with the given type.
     455              :     ///
     456              :     /// If `clear` is set, the original content of the segments will be filled
     457              :     /// with zeros before removal.
     458            0 :     pub fn remove_segments_by_type(&mut self, ty: segment::Type, clear: bool) {
     459            0 :         self.ptr.pin_mut().remove_segments_by_type(ty.into(), clear)
     460            0 :     }
     461              : }
     462              : 
     463              : impl generic::Binary for Binary {
     464          480 :     fn as_generic(&self) -> &ffi::AbstractBinary {
     465          480 :         self.ptr.as_ref().unwrap().as_ref()
     466          480 :     }
     467              : 
     468            0 :     fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
     469            0 :         unsafe {
     470            0 :             Pin::new_unchecked({
     471            0 :                 (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractBinary
     472            0 :                     as *mut ffi::AbstractBinary)
     473            0 :                     .as_mut()
     474            0 :                     .unwrap()
     475            0 :             })
     476            0 :         }
     477            0 :     }
     478              : }
     479              : 
     480        18648 : declare_iterator!(
     481        18648 :     SymbolsVersion,
     482        18648 :     SymbolVersion<'a>,
     483        18648 :     ffi::ELF_SymbolVersion,
     484        18648 :     ffi::ELF_Binary,
     485        18648 :     ffi::ELF_Binary_it_symbols_version
     486        18648 : );
     487          180 : declare_iterator!(
     488          180 :     SymbolsVersionRequirement,
     489          180 :     SymbolVersionRequirement<'a>,
     490          180 :     ffi::ELF_SymbolVersionRequirement,
     491          180 :     ffi::ELF_Binary,
     492          180 :     ffi::ELF_Binary_it_symbols_version_requirement
     493          180 : );
     494           36 : declare_iterator!(
     495           36 :     SymbolsVersionDefinition,
     496           36 :     SymbolVersionDefinition<'a>,
     497           36 :     ffi::ELF_SymbolVersionDefinition,
     498           36 :     ffi::ELF_Binary,
     499           36 :     ffi::ELF_Binary_it_symbols_version_definition
     500           36 : );
        

Generated by: LCOV version 2.1-1