Add no-std ElfStream support
This commit is contained in:
parent
b7067d3307
commit
1436aab797
@ -16,10 +16,12 @@ edition = "2021"
|
||||
name = "elf"
|
||||
|
||||
[dependencies]
|
||||
hashbrown = { version = "0.14.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["std", "to_str"]
|
||||
std = []
|
||||
to_str = []
|
||||
no_std_stream = ["hashbrown"]
|
||||
# Enable for nightly feature(error_in_core) to impl core::error::Error on ParseError
|
||||
nightly = []
|
||||
|
@ -1,6 +1,9 @@
|
||||
use core::ops::Range;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
use crate::abi;
|
||||
use crate::compression::CompressionHeader;
|
||||
@ -10,6 +13,7 @@ use crate::file::{parse_ident, Class};
|
||||
use crate::gnu_symver::{
|
||||
SymbolVersionTable, VerDefIterator, VerNeedIterator, VersionIndex, VersionIndexTable,
|
||||
};
|
||||
use crate::io_traits::{Read, Seek, SeekFrom};
|
||||
use crate::note::NoteIterator;
|
||||
use crate::parse::{ParseAt, ParseError};
|
||||
use crate::relocation::{RelIterator, RelaIterator};
|
||||
@ -24,7 +28,7 @@ use crate::file::FileHeader;
|
||||
/// This type encapsulates the stream-oriented interface for parsing ELF objects from
|
||||
/// a `Read + Seek`.
|
||||
#[derive(Debug)]
|
||||
pub struct ElfStream<E: EndianParse, S: std::io::Read + std::io::Seek> {
|
||||
pub struct ElfStream<E: EndianParse, S: Read + Seek> {
|
||||
pub ehdr: FileHeader<E>,
|
||||
shdrs: Vec<SectionHeader>,
|
||||
phdrs: Vec<ProgramHeader>,
|
||||
@ -113,7 +117,7 @@ fn parse_program_headers<E: EndianParse, S: Read + Seek>(
|
||||
Ok(phdrs_vec)
|
||||
}
|
||||
|
||||
impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
|
||||
impl<E: EndianParse, S: Read + Seek> ElfStream<E, S> {
|
||||
/// Do a minimal amount of parsing work to open an [ElfStream] handle from a Read+Seek containing an ELF object.
|
||||
///
|
||||
/// This parses the ELF [FileHeader], [SectionHeader] table, and [ProgramHeader] (segments) table.
|
||||
|
141
src/io_traits.rs
Normal file
141
src/io_traits.rs
Normal file
@ -0,0 +1,141 @@
|
||||
#[cfg(feature = "std")]
|
||||
pub type StreamError = std::io::Error;
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub struct StreamError {
|
||||
pub message: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SeekFrom {
|
||||
Start(u64),
|
||||
End(i64),
|
||||
Current(i64),
|
||||
}
|
||||
|
||||
pub trait Read {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, StreamError>;
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), StreamError>;
|
||||
}
|
||||
|
||||
pub trait Seek {
|
||||
fn seek(&mut self, pos: SeekFrom) -> Result<u64, StreamError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: std::io::Read> Read for R {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, StreamError> {
|
||||
std::io::Read::read(self, buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), StreamError> {
|
||||
std::io::Read::read_exact(self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<S: std::io::Seek> Seek for S {
|
||||
#[inline]
|
||||
fn seek(&mut self, pos: SeekFrom) -> Result<u64, StreamError> {
|
||||
std::io::Seek::seek(self, pos.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<SeekFrom> for std::io::SeekFrom {
|
||||
fn from(value: SeekFrom) -> Self {
|
||||
match value {
|
||||
SeekFrom::Current(v) => Self::Current(v),
|
||||
SeekFrom::Start(v) => Self::Start(v),
|
||||
SeekFrom::End(v) => Self::End(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl From<StreamError> for crate::ParseError {
|
||||
fn from(e: StreamError) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod no_std_stream_tests {
|
||||
use crate::{abi, endian::AnyEndian, ElfStream};
|
||||
|
||||
use super::{Read, Seek, SeekFrom, StreamError};
|
||||
|
||||
pub struct NoStdStream {
|
||||
pos: usize,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl NoStdStream {
|
||||
pub fn read_from_path<P: AsRef<std::path::Path>>(path: P) -> Result<Self, std::io::Error> {
|
||||
let data = std::fs::read(path)?;
|
||||
Ok(Self { pos: 0, data })
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for NoStdStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Result<usize, StreamError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), StreamError> {
|
||||
if self.pos + buf.len() > self.data.len() {
|
||||
unimplemented!();
|
||||
}
|
||||
buf.copy_from_slice(&self.data[self.pos..self.pos + buf.len()]);
|
||||
self.pos += buf.len();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for NoStdStream {
|
||||
fn seek(&mut self, pos: SeekFrom) -> Result<u64, StreamError> {
|
||||
match pos {
|
||||
SeekFrom::End(offset) => {
|
||||
if offset == 0 {
|
||||
self.pos = self.data.len();
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
SeekFrom::Start(offset) => {
|
||||
if offset > self.data.len() as u64 {
|
||||
unimplemented!()
|
||||
} else {
|
||||
self.pos = offset as usize;
|
||||
}
|
||||
}
|
||||
SeekFrom::Current(_offset) => {
|
||||
unimplemented!();
|
||||
}
|
||||
};
|
||||
|
||||
Ok(self.pos as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_std_stream() {
|
||||
let stream = NoStdStream::read_from_path("sample-objects/basic.x86_64").unwrap();
|
||||
let mut file = ElfStream::<AnyEndian, _>::open_stream(stream).expect("Open test1");
|
||||
|
||||
let (shdrs, strtab) = file
|
||||
.section_headers_with_strtab()
|
||||
.expect("Failed to get shdrs");
|
||||
let (shdrs, strtab) = (shdrs, strtab.unwrap());
|
||||
|
||||
let shdr_4 = &shdrs[4];
|
||||
let name = strtab
|
||||
.get(shdr_4.sh_name as usize)
|
||||
.expect("Failed to get section name");
|
||||
|
||||
assert_eq!(name, ".gnu.hash");
|
||||
assert_eq!(shdr_4.sh_type, abi::SHT_GNU_HASH);
|
||||
}
|
||||
}
|
@ -144,6 +144,8 @@ pub mod segment;
|
||||
pub mod string_table;
|
||||
pub mod symbol;
|
||||
|
||||
pub mod io_traits;
|
||||
|
||||
#[cfg(feature = "to_str")]
|
||||
pub mod to_str;
|
||||
|
||||
@ -154,9 +156,9 @@ mod elf_bytes;
|
||||
pub use elf_bytes::CommonElfData;
|
||||
pub use elf_bytes::ElfBytes;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "no_std_stream"))]
|
||||
mod elf_stream;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "no_std_stream"))]
|
||||
pub use elf_stream::ElfStream;
|
||||
|
||||
pub use parse::ParseError;
|
||||
|
@ -53,6 +53,7 @@ pub enum ParseError {
|
||||
/// to represent in the native machine's usize type for in-memory processing.
|
||||
/// This could be the case when processessing large 64-bit files on a 32-bit machine.
|
||||
TryFromIntError(core::num::TryFromIntError),
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Returned when parsing an ELF structure out of an io stream encountered
|
||||
/// an io error.
|
||||
|
Loading…
x
Reference in New Issue
Block a user