Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pod: add slice_from_all_bytes{_mut} #672

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions src/pod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ type Result<T> = result::Result<T, ()>;
/// - have no padding
pub unsafe trait Pod: Copy + 'static {}

/// Cast a byte slice to a `Pod` type.
/// Cast the head of a byte slice to a `Pod` type.
///
/// Returns the type and the tail of the slice.
/// Returns the type and the tail of the byte slice.
///
/// Returns an error if the byte slice is too short or the alignment is invalid.
#[inline]
pub fn from_bytes<T: Pod>(data: &[u8]) -> Result<(&T, &[u8])> {
let size = mem::size_of::<T>();
Expand All @@ -39,9 +41,11 @@ pub fn from_bytes<T: Pod>(data: &[u8]) -> Result<(&T, &[u8])> {
Ok((val, tail))
}

/// Cast a mutable byte slice to a `Pod` type.
/// Cast the head of a mutable byte slice to a `Pod` type.
///
/// Returns the type and the tail of the byte slice.
///
/// Returns the type and the tail of the slice.
/// Returns an error if the byte slice is too short or the alignment is invalid.
#[inline]
pub fn from_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> {
let size = mem::size_of::<T>();
Expand All @@ -60,9 +64,11 @@ pub fn from_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> {
Ok((val, tail))
}

/// Cast a byte slice to a slice of a `Pod` type.
/// Cast the head of a byte slice to a slice of a `Pod` type.
///
/// Returns the type slice and the tail of the byte slice.
///
/// Returns an error if the byte slice is too short or the alignment is invalid.
#[inline]
pub fn slice_from_bytes<T: Pod>(data: &[u8], count: usize) -> Result<(&[T], &[u8])> {
let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
Expand All @@ -78,9 +84,11 @@ pub fn slice_from_bytes<T: Pod>(data: &[u8], count: usize) -> Result<(&[T], &[u8
Ok((slice, tail))
}

/// Cast a mutable byte slice to a slice of a `Pod` type.
/// Cast the head of a mutable byte slice to a slice of a `Pod` type.
///
/// Returns the type slice and the tail of the byte slice.
///
/// Returns an error if the byte slice is too short or the alignment is invalid.
#[inline]
pub fn slice_from_bytes_mut<T: Pod>(
data: &mut [u8],
Expand All @@ -102,6 +110,38 @@ pub fn slice_from_bytes_mut<T: Pod>(
Ok((slice, tail))
}

/// Cast all of a byte slice to a slice of a `Pod` type.
///
/// Returns the type slice.
///
/// Returns an error if the size of the byte slice is not an exact multiple
/// of the type size, or the alignment is invalid.
#[inline]
pub fn slice_from_all_bytes<T: Pod>(data: &[u8]) -> Result<&[T]> {
let count = data.len() / mem::size_of::<T>();
let (slice, tail) = slice_from_bytes(data, count)?;
if !tail.is_empty() {
return Err(());
}
Ok(slice)
}

/// Cast all of a byte slice to a slice of a `Pod` type.
///
/// Returns the type slice.
///
/// Returns an error if the size of the byte slice is not an exact multiple
/// of the type size, or the alignment is invalid.
#[inline]
pub fn slice_from_all_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<&mut [T]> {
let count = data.len() / mem::size_of::<T>();
let (slice, tail) = slice_from_bytes_mut(data, count)?;
if !tail.is_empty() {
return Err(());
}
Ok(slice)
}

/// Cast a `Pod` type to a byte slice.
#[inline]
pub fn bytes_of<T: Pod>(val: &T) -> &[u8] {
Expand Down
29 changes: 10 additions & 19 deletions src/read/elf/section.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use core::fmt::Debug;
use core::{iter, mem, slice, str};
use core::{iter, slice, str};

use crate::elf;
use crate::endian::{self, Endianness, U32Bytes};
use crate::pod::Pod;
use crate::pod::{self, Pod};
use crate::read::{
self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection,
ReadError, ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind, StringTable,
self, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection, ReadError,
ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind, StringTable,
};

use super::{
Expand Down Expand Up @@ -671,8 +671,7 @@ pub trait SectionHeader: Debug + Pod {
endian: Self::Endian,
data: R,
) -> read::Result<&'data [T]> {
let mut data = self.data(endian, data).map(Bytes)?;
data.read_slice(data.len() / mem::size_of::<T>())
pod::slice_from_all_bytes(self.data(endian, data)?)
.read_error("Invalid ELF section size or offset")
}

Expand Down Expand Up @@ -816,19 +815,11 @@ pub trait SectionHeader: Debug + Pod {
if self.sh_type(endian) != elf::SHT_GROUP {
return Ok(None);
}
let mut data = self
.data(endian, data)
.read_error("Invalid ELF group section offset or size")
.map(Bytes)?;
let flag = data
.read::<U32Bytes<_>>()
.read_error("Invalid ELF group section offset or size")?
.get(endian);
let count = data.len() / mem::size_of::<U32Bytes<Self::Endian>>();
let sections = data
.read_slice(count)
.read_error("Invalid ELF group section offset or size")?;
Ok(Some((flag, sections)))
let msg = "Invalid ELF group section offset or size";
let data = self.data(endian, data).read_error(msg)?;
let (flag, data) = pod::from_bytes::<U32Bytes<_>>(data).read_error(msg)?;
let sections = pod::slice_from_all_bytes(data).read_error(msg)?;
Ok(Some((flag.get(endian), sections)))
}

/// Return the header of a SysV hash section.
Expand Down
9 changes: 4 additions & 5 deletions src/read/elf/segment.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use core::fmt::Debug;
use core::{mem, slice, str};
use core::{slice, str};

use crate::elf;
use crate::endian::{self, Endianness};
use crate::pod::Pod;
use crate::read::{self, Bytes, ObjectSegment, ReadError, ReadRef, SegmentFlags};
use crate::pod::{self, Pod};
use crate::read::{self, ObjectSegment, ReadError, ReadRef, SegmentFlags};

use super::{ElfFile, FileHeader, NoteIterator};

Expand Down Expand Up @@ -180,8 +180,7 @@ pub trait ProgramHeader: Debug + Pod {
endian: Self::Endian,
data: R,
) -> Result<&'data [T], ()> {
let mut data = self.data(endian, data).map(Bytes)?;
data.read_slice(data.len() / mem::size_of::<T>())
pod::slice_from_all_bytes(self.data(endian, data)?)
}

/// Return the segment data in the given virtual address range
Expand Down
15 changes: 3 additions & 12 deletions src/read/pe/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::convert::TryInto;

use crate::endian::{LittleEndian as LE, U32};
use crate::pe;
use crate::pod::Pod;
use crate::pod::{self, Pod};
use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable};
use crate::read::{
self, Architecture, ByteString, Bytes, CodeView, ComdatKind, Error, Export, FileFlags, Import,
Expand Down Expand Up @@ -317,17 +317,8 @@ where
Some(data_dir) => data_dir,
None => return Ok(None),
};
let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?;
let debug_data_size = data_dir.size.get(LE) as usize;

let count = debug_data_size / mem::size_of::<pe::ImageDebugDirectory>();
let rem = debug_data_size % mem::size_of::<pe::ImageDebugDirectory>();
if rem != 0 || count < 1 {
return Err(Error("Invalid PE debug dir size"));
}

let debug_dirs = debug_data
.read_slice_at::<pe::ImageDebugDirectory>(0, count)
let debug_data = data_dir.data(self.data, &self.common.sections)?;
let debug_dirs = pod::slice_from_all_bytes::<pe::ImageDebugDirectory>(debug_data)
.read_error("Invalid PE debug dir size")?;

for debug_dir in debug_dirs {
Expand Down
Loading