use std::mem::size_of;
use std::path::Path;
use std::pin::Pin;
use num_traits::{Num, cast};
use lief_ffi as ffi;
use super::builder::Config;
use super::dynamic::{self, DynamicEntries, Library};
use super::hash::{Gnu, Sysv};
use super::header::Header;
use super::note::ItNotes;
use super::parser_config::Config as ParserConfig;
use super::relocation::{
DynamicRelocations, ObjectRelocations, PltGotRelocations, Relocation, Relocations,
};
use super::section::{Section, Sections};
use super::segment::{self, Segments};
use super::symbol::{DynamicSymbols, ExportedSymbols, ImportedSymbols, SymtabSymbols};
use super::symbol_versioning::{SymbolVersion, SymbolVersionDefinition, SymbolVersionRequirement};
use super::{Segment, Symbol};
use crate::Error;
use crate::elf::dynamic::DynamicEntry;
use crate::common::{AsFFI, FromFFI, into_optional};
use crate::generic;
use crate::{declare_iterator, to_conv_result, to_result, to_slice};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ElfClass {
Elf32,
Elf64,
Unknown,
}
impl ElfClass {
const ELF_CLASS32: u32 = 1;
const ELF_CLASS64: u32 = 2;
pub fn from_value(value: u32) -> Self {
match value {
Self::ELF_CLASS32 => ElfClass::Elf32,
Self::ELF_CLASS64 => ElfClass::Elf64,
_ => ElfClass::Unknown,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum PhdrReloc {
AUTO,
PIE_SHIFT,
BSS_END,
BINARY_END,
SEGMENT_GAP,
UNKNOWN(u32),
}
impl From<u32> for PhdrReloc {
fn from(value: u32) -> Self {
match value {
0 => PhdrReloc::AUTO,
1 => PhdrReloc::PIE_SHIFT,
2 => PhdrReloc::BSS_END,
3 => PhdrReloc::BINARY_END,
4 => PhdrReloc::SEGMENT_GAP,
_ => PhdrReloc::UNKNOWN(value),
}
}
}
impl From<PhdrReloc> for u32 {
fn from(value: PhdrReloc) -> u32 {
match value {
PhdrReloc::AUTO => 0,
PhdrReloc::PIE_SHIFT => 1,
PhdrReloc::BSS_END => 2,
PhdrReloc::BINARY_END => 3,
PhdrReloc::SEGMENT_GAP => 4,
PhdrReloc::UNKNOWN(v) => v,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum SecInsertPos {
AUTO,
POST_SEGMENT,
POST_SECTION,
UNKNOWN(u32),
}
impl From<u32> for SecInsertPos {
fn from(value: u32) -> Self {
match value {
0 => SecInsertPos::AUTO,
1 => SecInsertPos::POST_SEGMENT,
2 => SecInsertPos::POST_SECTION,
_ => SecInsertPos::UNKNOWN(value),
}
}
}
impl From<SecInsertPos> for u32 {
fn from(value: SecInsertPos) -> u32 {
match value {
SecInsertPos::AUTO => 0,
SecInsertPos::POST_SEGMENT => 1,
SecInsertPos::POST_SECTION => 2,
SecInsertPos::UNKNOWN(v) => v,
}
}
}
pub struct Binary {
ptr: cxx::UniquePtr<ffi::ELF_Binary>,
}
impl std::fmt::Debug for Binary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Binary")
.field("header", &self.header())
.finish()
}
}
impl FromFFI<ffi::ELF_Binary> for Binary {
fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
Self { ptr }
}
}
impl Binary {
pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let bin = ffi::ELF_Binary::parse(&__cxx_s);
if bin.is_null() {
return None;
}
Some(Binary::from_ffi(bin))
}
pub fn parse_with_config<P: AsRef<Path>>(path: P, config: &ParserConfig) -> Option<Self> {
let ffi_config = config.to_ffi();
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::ELF_Binary::parse_with_config(&__cxx_s, &ffi_config);
if ffi.is_null() {
return None;
}
Some(Binary::from_ffi(ffi))
}
pub fn parse_from_dump<P: AsRef<Path>>(path: P, addr: u64) -> Option<Self> {
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::ELF_Binary::parse_from_dump(&__cxx_s, addr);
if ffi.is_null() {
return None;
}
Some(Binary::from_ffi(ffi))
}
pub fn parse_from_dump_with_config<P: AsRef<Path>>(
path: P,
addr: u64,
config: &ParserConfig,
) -> Option<Self> {
let ffi_config = config.to_ffi();
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::ELF_Binary::parse_from_dump_with_config(&__cxx_s, addr, &ffi_config);
if ffi.is_null() {
return None;
}
Some(Binary::from_ffi(ffi))
}
pub fn header(&self) -> Header<'_> {
Header::from_ffi(self.ptr.header())
}
pub fn virtual_size(&self) -> u64 {
self.ptr.virtual_size()
}
pub fn interpreter(&self) -> String {
self.ptr.interpreter().to_string()
}
pub fn sysv_hash(&self) -> Option<Sysv<'_>> {
into_optional(self.ptr.sysv_hash())
}
pub fn gnu_hash(&self) -> Option<Gnu<'_>> {
into_optional(self.ptr.gnu_hash())
}
pub fn sections(&self) -> Sections<'_> {
Sections::new(self.ptr.sections())
}
pub fn segments(&self) -> Segments<'_> {
Segments::new(self.ptr.segments())
}
pub fn dynamic_entries(&self) -> DynamicEntries<'_> {
DynamicEntries::new(self.ptr.dynamic_entries())
}
pub fn remove_dynamic_entries_by_tag(&mut self, tag: dynamic::Tag) {
self.ptr
.as_mut()
.unwrap()
.remove_dynamic_entries_by_tag(tag.into())
}
pub fn add_dynamic_entry(&mut self, entry: &dyn dynamic::DynamicEntry) -> dynamic::Entries<'_> {
dynamic::Entries::from_ffi(
self.ptr
.as_mut()
.unwrap()
.add_dynamic_entry(entry.as_base()),
)
}
pub fn dynamic_symbols(&self) -> DynamicSymbols<'_> {
DynamicSymbols::new(self.ptr.dynamic_symbols())
}
pub fn exported_symbols(&self) -> ExportedSymbols<'_> {
ExportedSymbols::new(self.ptr.exported_symbols())
}
pub fn imported_symbols(&self) -> ImportedSymbols<'_> {
ImportedSymbols::new(self.ptr.imported_symbols())
}
pub fn symtab_symbols(&self) -> SymtabSymbols<'_> {
SymtabSymbols::new(self.ptr.symtab_symbols())
}
pub fn symbols_version(&self) -> SymbolsVersion<'_> {
SymbolsVersion::new(self.ptr.symbols_version())
}
pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement<'_> {
SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
}
pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition<'_> {
SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
}
pub fn notes(&self) -> ItNotes<'_> {
ItNotes::new(self.ptr.notes())
}
pub fn pltgot_relocations(&self) -> PltGotRelocations<'_> {
PltGotRelocations::new(self.ptr.pltgot_relocations())
}
pub fn dynamic_relocations(&self) -> DynamicRelocations<'_> {
DynamicRelocations::new(self.ptr.dynamic_relocations())
}
pub fn object_relocations(&self) -> ObjectRelocations<'_> {
ObjectRelocations::new(self.ptr.object_relocations())
}
pub fn relocations(&self) -> Relocations<'_> {
Relocations::new(self.ptr.relocations())
}
pub fn section_by_name(&self, name: &str) -> Option<Section<'_>> {
cxx::let_cxx_string!(__cxx_s = name);
into_optional(self.ptr.section_by_name(&__cxx_s))
}
pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation<'_>> {
into_optional(self.ptr.relocation_by_addr(address))
}
pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation<'_>> {
cxx::let_cxx_string!(__cxx_s = sym_name);
into_optional(self.ptr.relocation_for_symbol(&__cxx_s))
}
pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol<'_>> {
cxx::let_cxx_string!(__cxx_s = sym_name);
into_optional(self.ptr.get_dynamic_symbol(&__cxx_s))
}
pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol<'_>> {
cxx::let_cxx_string!(__cxx_s = sym_name);
into_optional(self.ptr.get_symtab_symbol(&__cxx_s))
}
pub fn get_library(&self, name: &str) -> Option<dynamic::Library<'_>> {
cxx::let_cxx_string!(__cxx_s = name);
into_optional(self.ptr.get_library(&__cxx_s))
}
pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section<'_>> {
into_optional(self.ptr.section_from_offset(offset, skip_nobits))
}
pub fn section_from_virtual_address(
&self,
address: u64,
skip_nobits: bool,
) -> Option<Section<'_>> {
into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
}
pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment<'_>> {
into_optional(self.ptr.segment_from_virtual_address(address))
}
pub fn segment_from_offset(&self, offset: u64) -> Option<Segment<'_>> {
into_optional(self.ptr.segment_from_offset(offset))
}
pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
to_slice!(self.ptr.get_content_from_virtual_address(address, size));
}
pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
}
pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
Vec::from(
self.ptr
.get_relocated_dynamic_array(u64::from(tag))
.as_slice(),
)
}
pub fn is_targeting_android(&self) -> bool {
self.ptr.is_targeting_android()
}
pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
where
T: Num + cast::FromPrimitive + cast::ToPrimitive,
{
if size_of::<T>() == size_of::<u8>() {
to_conv_result!(
ffi::AbstractBinary::get_u8,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u16>() {
to_conv_result!(
ffi::AbstractBinary::get_u16,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u32>() {
to_conv_result!(
ffi::AbstractBinary::get_u32,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u64>() {
to_conv_result!(
ffi::AbstractBinary::get_u64,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
Err(Error::NotSupported)
}
pub fn write<P: AsRef<Path>>(&mut self, output: P) {
cxx::let_cxx_string!(__cxx_s = output.as_ref().to_str().unwrap());
self.ptr.as_mut().unwrap().write(&__cxx_s);
}
pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
cxx::let_cxx_string!(__cxx_out = output.as_ref().to_str().unwrap());
let cfg = config.to_ffi();
self.ptr
.as_mut()
.unwrap()
.write_with_config(&__cxx_out, &cfg);
}
pub fn write_to_bytes(&mut self) -> Vec<u8> {
Vec::from(self.ptr.as_mut().unwrap().write_to_bytes().as_slice())
}
pub fn write_to_bytes_with_config(&mut self, config: Config) -> Vec<u8> {
let cfg = config.to_ffi();
Vec::from(
self.ptr
.as_mut()
.unwrap()
.write_to_bytes_with_config(&cfg)
.as_slice(),
)
}
pub fn add_library<'a>(&'a mut self, library: &str) -> Library<'a> {
cxx::let_cxx_string!(__cxx_s = library);
Library::from_ffi(self.ptr.as_mut().unwrap().add_library(&__cxx_s))
}
pub fn functions(&self) -> generic::Functions<'_> {
generic::Functions::new(self.ptr.functions())
}
pub fn dynamic_entry_by_tag(&self, tag: dynamic::Tag) -> Option<dynamic::Entries<'_>> {
into_optional(self.ptr.dynamic_entry_by_tag(tag.into()))
}
pub fn segment_by_type(&self, seg_type: segment::Type) -> Option<Segment<'_>> {
into_optional(self.ptr.segment_by_type(seg_type.into()))
}
pub fn remove_dynamic_entry(&mut self, entry: impl dynamic::DynamicEntry) {
self.ptr.pin_mut().remove_dynamic_entry(entry.as_base());
}
pub fn remove_dynamic_entry_if<P>(&mut self, predicate: P) -> usize
where
P: Fn(&dynamic::Entries) -> bool,
{
let entries = self
.dynamic_entries()
.filter(predicate)
.map(|e| e.as_base().raw_ptr())
.collect::<Vec<_>>();
let cnt = entries.len();
for ffi_entry in entries {
unsafe {
self.ptr.pin_mut().remove_dynamic_entry_from_ptr(ffi_entry);
}
}
cnt
}
pub fn remove_library(&mut self, name: &str) {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.pin_mut().remove_library(&__cxx_s);
}
pub fn add_segment(&mut self, segment: &Segment) -> Option<Segment<'_>> {
into_optional(
self.ptr
.pin_mut()
.add_segment(segment.ptr.as_ref().unwrap()),
)
}
pub fn set_interpreter<P: AsRef<Path>>(&mut self, interpreter: P) {
cxx::let_cxx_string!(__cxx_s = interpreter.as_ref().to_str().unwrap());
self.ptr.pin_mut().set_interpreter(&__cxx_s);
}
pub fn find_version_requirement(&self, libname: &str) -> Option<SymbolVersionRequirement<'_>> {
cxx::let_cxx_string!(__cxx_s = libname.to_string());
into_optional(self.ptr.find_version_requirement(&__cxx_s))
}
pub fn remove_version_requirement(&mut self, libname: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = libname.to_string());
self.ptr.pin_mut().remove_version_requirement(&__cxx_s)
}
pub fn remove_segment(&mut self, segment: Segment, clear: bool) {
self.ptr
.pin_mut()
.remove_segment(segment.ptr.as_ref().unwrap(), clear)
}
pub fn remove_segments_by_type(&mut self, ty: segment::Type, clear: bool) {
self.ptr.pin_mut().remove_segments_by_type(ty.into(), clear)
}
pub fn symbols(&self) -> AllSymbols<'_> {
AllSymbols::new(self.ptr.symbols())
}
pub fn strings(&self, min_size: u64) -> Vec<String> {
self.ptr
.strings(min_size)
.iter()
.map(|s| s.to_string())
.collect()
}
pub fn last_offset_section(&self) -> u64 {
self.ptr.last_offset_section()
}
pub fn last_offset_segment(&self) -> u64 {
self.ptr.last_offset_segment()
}
pub fn next_virtual_address(&self) -> u64 {
self.ptr.next_virtual_address()
}
pub fn eof_offset(&self) -> u64 {
self.ptr.eof_offset()
}
pub fn dtor_functions(&self) -> generic::Functions<'_> {
generic::Functions::new(self.ptr.dtor_functions())
}
pub fn overlay(&self) -> &[u8] {
to_slice!(self.ptr.get_overlay());
}
pub fn set_overlay(&mut self, data: &[u8]) {
unsafe {
self.ptr
.pin_mut()
.set_overlay(data.as_ptr(), data.len() as u64);
}
}
pub fn has_dynamic_entry_tag(&self, tag: dynamic::Tag) -> bool {
self.ptr.has_dynamic_entry_tag(tag.into())
}
pub fn has_segment_type(&self, ty: segment::Type) -> bool {
self.ptr.has_segment_type(ty.into())
}
pub fn has_note_type(&self, ty: super::note::Type) -> bool {
self.ptr.has_note_type(ty.into())
}
pub fn has_section_type(&self, ty: super::section::Type) -> bool {
self.ptr.has_section_type(ty.into())
}
pub fn note_by_type(&self, ty: super::note::Type) -> Option<super::note::Notes<'_>> {
into_optional(self.ptr.get_note_by_type(ty.into()))
}
pub fn section_by_type(&self, ty: super::section::Type) -> Option<Section<'_>> {
into_optional(self.ptr.get_section_by_type(ty.into()))
}
pub fn has_section(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_section(&__cxx_s)
}
pub fn has_section_with_offset(&self, offset: u64) -> bool {
self.ptr.has_section_with_offset(offset)
}
pub fn has_section_with_va(&self, va: u64) -> bool {
self.ptr.has_section_with_va(va)
}
pub fn has_library(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_library(&__cxx_s)
}
pub fn has_dynamic_symbol(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_dynamic_symbol(&__cxx_s)
}
pub fn has_symtab_symbol(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_symtab_symbol(&__cxx_s)
}
pub fn dynsym_idx(&self, name: &str) -> Option<u64> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
let idx = self.ptr.dynsym_idx(&__cxx_s);
if idx < 0 {
return None;
}
Some(idx as u64)
}
pub fn symtab_idx(&self, name: &str) -> Option<u64> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
let idx = self.ptr.symtab_idx(&__cxx_s);
if idx < 0 {
return None;
}
Some(idx as u64)
}
pub fn patch_pltgot(&mut self, symbol_name: &str, address: u64) {
cxx::let_cxx_string!(__cxx_s = symbol_name.to_string());
self.ptr.pin_mut().patch_pltgot_by_name(&__cxx_s, address);
}
pub fn add_section(
&mut self,
section: &Section,
loaded: bool,
pos: SecInsertPos,
) -> Option<Section<'_>> {
into_optional(
self.ptr
.pin_mut()
.add_section(section.as_ffi(), loaded, pos.into()),
)
}
pub fn add_note(&mut self, note: &super::note::Notes) -> super::note::Notes<'_> {
super::note::Notes::from_ffi(self.ptr.pin_mut().add_note(note.as_ffi()))
}
pub fn add_dynamic_relocation(&mut self, reloc: &Relocation) -> Relocation<'_> {
Relocation::from_ffi(self.ptr.pin_mut().add_dynamic_relocation(reloc.as_ffi()))
}
pub fn add_pltgot_relocation(&mut self, reloc: &Relocation) -> Relocation<'_> {
Relocation::from_ffi(self.ptr.pin_mut().add_pltgot_relocation(reloc.as_ffi()))
}
pub fn add_symtab_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
Symbol::from_ffi(self.ptr.pin_mut().add_symtab_symbol(symbol.as_ffi()))
}
pub fn add_dynamic_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
Symbol::from_ffi(self.ptr.pin_mut().add_dynamic_symbol(symbol.as_ffi()))
}
pub fn add_exported_function(&mut self, address: u64, name: &str) -> Symbol<'_> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
Symbol::from_ffi(self.ptr.pin_mut().add_exported_function(address, &__cxx_s))
}
pub fn export_symbol_by_name(&mut self, symbol_name: &str, value: u64) -> Symbol<'_> {
cxx::let_cxx_string!(__cxx_s = symbol_name.to_string());
Symbol::from_ffi(self.ptr.pin_mut().export_symbol_by_name(&__cxx_s, value))
}
pub fn export_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
Symbol::from_ffi(self.ptr.pin_mut().export_symbol_obj(symbol.as_ffi()))
}
pub fn remove_symtab_symbol(&mut self, name: &str) {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.pin_mut().remove_symtab_symbol_by_name(&__cxx_s);
}
pub fn remove_dynamic_symbol(&mut self, name: &str) {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.pin_mut().remove_dynamic_symbol_by_name(&__cxx_s);
}
pub fn remove_section(&mut self, section: &Section, clear: bool) {
self.ptr.pin_mut().remove_section(section.as_ffi(), clear);
}
pub fn remove_note(&mut self, note: &super::note::Notes) {
self.ptr.pin_mut().remove_note(note.as_ffi());
}
pub fn extend_segment(&mut self, segment: &Segment, size: u64) -> Option<Segment<'_>> {
into_optional(
self.ptr
.pin_mut()
.extend_segment(segment.ptr.as_ref().unwrap(), size),
)
}
pub fn extend_section(&mut self, section: &Section, size: u64) -> Option<Section<'_>> {
into_optional(self.ptr.pin_mut().extend_section(section.as_ffi(), size))
}
pub fn strip(&mut self) {
self.ptr.pin_mut().strip();
}
pub fn section_idx_by_name(&self, name: &str) -> Option<usize> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
let idx = self.ptr.get_section_idx_by_name(&__cxx_s);
if idx < 0 { None } else { Some(idx as usize) }
}
pub fn section_idx(&self, section: &Section) -> Option<usize> {
let idx = self.ptr.get_section_idx_by_section(section.as_ffi());
if idx < 0 { None } else { Some(idx as usize) }
}
pub fn relocate_phdr_table(&mut self, reloc_type: PhdrReloc) -> u64 {
self.ptr.pin_mut().relocate_phdr_table(reloc_type.into())
}
}
impl AsFFI<ffi::ELF_Binary> for Binary {
fn as_ffi(&self) -> &ffi::ELF_Binary {
self.ptr.as_ref().unwrap()
}
fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::ELF_Binary> {
self.ptr.pin_mut()
}
}
impl generic::Binary for Binary {
fn as_generic(&self) -> &ffi::AbstractBinary {
self.ptr.as_ref().unwrap().as_ref()
}
fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
unsafe {
Pin::new_unchecked({
(self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractBinary
as *mut ffi::AbstractBinary)
.as_mut()
.unwrap()
})
}
}
}
declare_iterator!(
SymbolsVersion,
SymbolVersion<'a>,
ffi::ELF_SymbolVersion,
ffi::ELF_Binary,
ffi::ELF_Binary_it_symbols_version
);
declare_iterator!(
SymbolsVersionRequirement,
SymbolVersionRequirement<'a>,
ffi::ELF_SymbolVersionRequirement,
ffi::ELF_Binary,
ffi::ELF_Binary_it_symbols_version_requirement
);
declare_iterator!(
SymbolsVersionDefinition,
SymbolVersionDefinition<'a>,
ffi::ELF_SymbolVersionDefinition,
ffi::ELF_Binary,
ffi::ELF_Binary_it_symbols_version_definition
);
declare_iterator!(
AllSymbols,
Symbol<'a>,
ffi::ELF_Symbol,
ffi::ELF_Binary,
ffi::ELF_Binary_it_symbols
);