Struct ElfBytes

Source
pub struct ElfBytes<'data, E: EndianParse> {
    pub ehdr: FileHeader<E>,
    /* private fields */
}
Expand description

This type encapsulates the bytes-oriented interface for parsing ELF objects from &[u8].

This parser is no_std and zero-alloc, returning lazy-parsing interfaces wrapped around subslices of the provided ELF bytes &[u8]. The various ELF structures are parsed on-demand into a native Rust representation.

Example usage:

use elf::abi::PT_LOAD;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use elf::segment::ProgramHeader;

let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so");
let file_data = std::fs::read(path).unwrap();

let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).unwrap();

// Get all the common ELF sections (if any). We have a lot of ELF work to do!
let common_sections = file.find_common_data().unwrap();
// ... do some stuff with the symtab, dynsyms etc

// It can also yield iterators on which we can do normal iterator things, like filtering
// for all the segments of a specific type. Parsing is done on each iter.next() call, so
// if you end iteration early, it won't parse the rest of the table.
let first_load_phdr: Option<ProgramHeader> = file.segments().unwrap()
    .iter()
    .find(|phdr|{phdr.p_type == PT_LOAD});
println!("First load segment is at: {}", first_load_phdr.unwrap().p_vaddr);

// Or if you do things like this to get a vec of only the PT_LOAD segments.
let all_load_phdrs: Vec<ProgramHeader> = file.segments().unwrap()
    .iter()
    .filter(|phdr|{phdr.p_type == PT_LOAD})
    .collect();
println!("There are {} PT_LOAD segments", all_load_phdrs.len());

Fields§

§ehdr: FileHeader<E>

Implementations§

Source§

impl<'data, E: EndianParse> ElfBytes<'data, E>

Source

pub fn minimal_parse(data: &'data [u8]) -> Result<Self, ParseError>

Do the minimal parsing work to get an ElfBytes handle from a byte slice containing an ELF object.

This parses the ELF FileHeader, and locates (but does not parse) the Section Header Table and Segment Table.

Source

pub fn segments(&self) -> Option<SegmentTable<'data, E>>

Get this Elf object’s zero-alloc lazy-parsing SegmentTable (if any).

This table parses ProgramHeaders on demand and does not make any internal heap allocations when parsing.

Source

pub fn section_headers(&self) -> Option<SectionHeaderTable<'data, E>>

Get this Elf object’s zero-alloc lazy-parsing SectionHeaderTable (if any).

This table parses SectionHeaders on demand and does not make any internal heap allocations when parsing.

Source

pub fn section_headers_with_strtab( &self, ) -> Result<(Option<SectionHeaderTable<'data, E>>, Option<StringTable<'data>>), ParseError>

Get this ELF object’s SectionHeaderTable alongside its corresponding StringTable.

This is useful if you want to know the string name of sections.

Example usage:

use std::collections::HashMap;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use elf::note::Note;
use elf::note::NoteGnuBuildId;
use elf::section::SectionHeader;

let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so");
let file_data = std::fs::read(path).unwrap();

let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).unwrap();

// Get the section header table alongside its string table
let (shdrs_opt, strtab_opt) = file
    .section_headers_with_strtab()
    .expect("shdrs offsets should be valid");
let (shdrs, strtab) = (
    shdrs_opt.expect("Should have shdrs"),
    strtab_opt.expect("Should have strtab")
);

// Parse the shdrs and collect them into a map keyed on their zero-copied name
let with_names: HashMap<&str, SectionHeader> = shdrs
    .iter()
    .map(|shdr| {
        (
            strtab.get(shdr.sh_name as usize).expect("Failed to get section name"),
            shdr,
        )
    })
    .collect();

// Get the zero-copy parsed type for the the build id note
let build_id_note_shdr: &SectionHeader = with_names
    .get(".note.gnu.build-id")
    .expect("Should have build id note section");
let notes: Vec<_> = file
    .section_data_as_notes(build_id_note_shdr)
    .expect("Should be able to get note section data")
    .collect();
println!("{:?}", notes[0]);
Source

pub fn section_header_by_name( &self, name: &str, ) -> Result<Option<SectionHeader>, ParseError>

Parse section headers until one is found with the given name

Example to get the ELF file’s ABI-tag note

use elf::ElfBytes;
use elf::endian::AnyEndian;
use elf::section::SectionHeader;
use elf::note::Note;
use elf::note::NoteGnuAbiTag;

let path = std::path::PathBuf::from("sample-objects/basic.x86_64");
let file_data = std::fs::read(path).unwrap();
let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).unwrap();

let shdr: SectionHeader = file
    .section_header_by_name(".note.ABI-tag")
    .expect("section table should be parseable")
    .expect("file should have a .note.ABI-tag section");

let notes: Vec<_> = file
    .section_data_as_notes(&shdr)
    .expect("Should be able to get note section data")
    .collect();
assert_eq!(
    notes[0],
    Note::GnuAbiTag(NoteGnuAbiTag {
        os: 0,
        major: 2,
        minor: 6,
        subminor: 32
    }));
Source

pub fn find_common_data(&self) -> Result<CommonElfData<'data, E>, ParseError>

Efficiently locate the set of common sections found in ELF files by doing a single iteration over the SectionHeaders table.

This is useful for those who know they’re going to be accessing multiple common sections, like symbol tables, string tables. Many of these can also be accessed by the more targeted helpers like ElfBytes::symbol_table or ElfBytes::dynamic, though those each do their own internal searches through the shdrs to find the section.

Source

pub fn section_data( &self, shdr: &SectionHeader, ) -> Result<(&'data [u8], Option<CompressionHeader>), ParseError>

Get the section data for a given SectionHeader, alongside an optional compression context.

This library does not do any decompression for the user, but merely returns the raw compressed section data if the section is compressed alongside its ELF compression structure describing the compression algorithm used.

Users who wish to work with compressed sections must pick their compression library of choice and do the decompression themselves. The only two options supported by the ELF spec for section compression are: abi::ELFCOMPRESS_ZLIB and abi::ELFCOMPRESS_ZSTD.

Source

pub fn section_data_as_strtab( &self, shdr: &SectionHeader, ) -> Result<StringTable<'data>, ParseError>

Get the section data for a given SectionHeader, and interpret it as a StringTable

Returns a ParseError if the section is not of type abi::SHT_STRTAB

Source

pub fn section_data_as_rels( &self, shdr: &SectionHeader, ) -> Result<RelIterator<'data, E>, ParseError>

Get the section data for a given SectionHeader, and interpret it as an iterator over no-addend relocations Rel

Returns a ParseError if the section is not of type abi::SHT_REL

Source

pub fn section_data_as_relas( &self, shdr: &SectionHeader, ) -> Result<RelaIterator<'data, E>, ParseError>

Get the section data for a given SectionHeader, and interpret it as an iterator over relocations with addends Rela

Returns a ParseError if the section is not of type abi::SHT_RELA

Source

pub fn section_data_as_notes( &self, shdr: &SectionHeader, ) -> Result<NoteIterator<'data, E>, ParseError>

Get the section data for a given SectionHeader, and interpret it as an iterator over Notes

Returns a ParseError if the section is not of type abi::SHT_NOTE

Source

pub fn segment_data( &self, phdr: &ProgramHeader, ) -> Result<&'data [u8], ParseError>

Get the segment’s file data for a given segment/ProgramHeader.

This is the segment’s data as found in the file.

Source

pub fn segment_data_as_notes( &self, phdr: &ProgramHeader, ) -> Result<NoteIterator<'data, E>, ParseError>

Get the segment’s file data for a given ProgramHeader, and interpret it as an iterator over Notes

Returns a ParseError if the section is not of type abi::PT_NOTE

Source

pub fn dynamic(&self) -> Result<Option<DynamicTable<'data, E>>, ParseError>

Get the .dynamic section or abi::PT_DYNAMIC segment contents.

Source

pub fn symbol_table( &self, ) -> Result<Option<(SymbolTable<'data, E>, StringTable<'data>)>, ParseError>

Get the ELF file’s .symtab and associated strtab (if any)

Source

pub fn dynamic_symbol_table( &self, ) -> Result<Option<(SymbolTable<'data, E>, StringTable<'data>)>, ParseError>

Get the ELF file’s .dynsym and associated strtab (if any)

Source

pub fn symbol_version_table( &self, ) -> Result<Option<SymbolVersionTable<'data, E>>, ParseError>

Locate the section data for the various GNU Symbol Versioning sections (if any) and return them in a SymbolVersionTable that which can interpret them in-place to yield SymbolRequirements and SymbolDefinitions

This is a GNU extension and not all objects use symbol versioning. Returns an empty Option if the object does not use symbol versioning.

Trait Implementations§

Source§

impl<'data, E: Debug + EndianParse> Debug for ElfBytes<'data, E>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'data, E> Freeze for ElfBytes<'data, E>
where E: Freeze,

§

impl<'data, E> RefUnwindSafe for ElfBytes<'data, E>
where E: RefUnwindSafe,

§

impl<'data, E> Send for ElfBytes<'data, E>
where E: Send,

§

impl<'data, E> Sync for ElfBytes<'data, E>
where E: Sync,

§

impl<'data, E> Unpin for ElfBytes<'data, E>
where E: Unpin,

§

impl<'data, E> UnwindSafe for ElfBytes<'data, E>
where E: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.