#[cfg(feature = "read")] use alloc::borrow::Cow; use core::fmt::Debug; use crate::common::Format; use crate::read::{Reader, ReaderOffset, ReaderOffsetId, Result}; /// Trait for relocating addresses and offsets while reading a section. pub trait Relocate { /// Relocate an address which was read from the given section offset. fn relocate_address(&self, offset: T, value: u64) -> Result; /// Relocate a value which was read from the given section offset. fn relocate_offset(&self, offset: T, value: T) -> Result; } /// A `Reader` which applies relocations to addresses and offsets. /// /// This is useful for reading sections which contain relocations, /// such as those in a relocatable object file. /// It is generally not used for reading sections in an executable file. #[derive(Debug, Clone)] pub struct RelocateReader, T: Relocate> { section: R, reader: R, relocate: T, } impl RelocateReader where R: Reader, T: Relocate, { /// Create a new `RelocateReader` which applies relocations to the given section reader. pub fn new(section: R, relocate: T) -> Self { let reader = section.clone(); Self { section, reader, relocate, } } } impl Reader for RelocateReader where R: Reader, T: Relocate + Debug + Clone, { type Endian = R::Endian; type Offset = R::Offset; fn read_address(&mut self, address_size: u8) -> Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_address(address_size)?; self.relocate.relocate_address(offset, value) } fn read_offset(&mut self, format: Format) -> Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_offset(format)?; self.relocate.relocate_offset(offset, value) } fn read_sized_offset(&mut self, size: u8) -> Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_sized_offset(size)?; self.relocate.relocate_offset(offset, value) } #[inline] fn split(&mut self, len: Self::Offset) -> Result { let mut other = self.clone(); other.reader.truncate(len)?; self.reader.skip(len)?; Ok(other) } // All remaining methods simply delegate to `self.reader`. #[inline] fn endian(&self) -> Self::Endian { self.reader.endian() } #[inline] fn len(&self) -> Self::Offset { self.reader.len() } #[inline] fn empty(&mut self) { self.reader.empty() } #[inline] fn truncate(&mut self, len: Self::Offset) -> Result<()> { self.reader.truncate(len) } #[inline] fn offset_from(&self, base: &Self) -> Self::Offset { self.reader.offset_from(&base.reader) } #[inline] fn offset_id(&self) -> ReaderOffsetId { self.reader.offset_id() } #[inline] fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { self.reader.lookup_offset_id(id) } #[inline] fn find(&self, byte: u8) -> Result { self.reader.find(byte) } #[inline] fn skip(&mut self, len: Self::Offset) -> Result<()> { self.reader.skip(len) } #[cfg(not(feature = "read"))] fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed { super::reader::seal_if_no_alloc::Sealed } #[cfg(feature = "read")] #[inline] fn to_slice(&self) -> Result> { self.reader.to_slice() } #[cfg(feature = "read")] #[inline] fn to_string(&self) -> Result> { self.reader.to_string() } #[cfg(feature = "read")] #[inline] fn to_string_lossy(&self) -> Result> { self.reader.to_string_lossy() } #[inline] fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { self.reader.read_slice(buf) } }