Skip to content

Commit

Permalink
pod: add slice_from_all_bytes{_mut} (#672)
Browse files Browse the repository at this point in the history
Also convert some code to use it.
  • Loading branch information
philipc authored Apr 25, 2024
1 parent 9398058 commit 9650d64
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 42 deletions.
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

0 comments on commit 9650d64

Please sign in to comment.