Skip to main content

elb/
io.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::ffi::CStr;
4
5use crate::ByteOrder;
6use crate::Class;
7use crate::Error;
8
9use ByteOrder::*;
10use Class::*;
11
12macro_rules! define_read {
13    ($func: ident, $uint: ident) => {
14        #[doc = concat!("Read `", stringify!($uint), "`.")]
15        fn $func(&mut self, byte_order: ByteOrder) -> Result<$uint, crate::Error> {
16            let mut bytes = [0_u8; ::core::mem::size_of::<$uint>()];
17            self.read_bytes(&mut bytes[..])?;
18            let ret = match byte_order {
19                LittleEndian => $uint::from_le_bytes(bytes),
20                BigEndian => $uint::from_be_bytes(bytes),
21            };
22            Ok(ret)
23        }
24    };
25}
26
27/// ELF-specific read functions.
28pub trait ElfRead {
29    /// Read enough bytes to fill the buffer `buf`.
30    ///
31    /// Similar to [`Read::read_exact`](std::io::Read::read_exact).
32    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), crate::Error>;
33
34    /// Read one byte as `u8`.
35    fn read_u8(&mut self) -> Result<u8, crate::Error> {
36        let mut bytes = [0_u8; 1];
37        self.read_bytes(&mut bytes[..])?;
38        Ok(bytes[0])
39    }
40
41    /// Read one byte as `i8`.
42    fn read_i8(&mut self) -> Result<i8, crate::Error> {
43        let mut bytes = [0_u8; 1];
44        self.read_bytes(&mut bytes[..])?;
45        Ok(bytes[0] as i8)
46    }
47
48    define_read!(read_i16, i16);
49    define_read!(read_i32, i32);
50    define_read!(read_i64, i64);
51
52    define_read!(read_u16, u16);
53    define_read!(read_u32, u32);
54    define_read!(read_u64, u64);
55
56    /// Read one word.
57    ///
58    /// Reads `u32` when the class is [`Class::Elf32`], reads `u64` otherwise.
59    fn read_word(&mut self, class: Class, byte_order: ByteOrder) -> Result<u64, crate::Error> {
60        match class {
61            Elf32 => self.read_u32(byte_order).map(Into::into),
62            Elf64 => self.read_u64(byte_order),
63        }
64    }
65}
66
67#[cfg(feature = "std")]
68#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
69impl<R: std::io::Read + ?Sized> ElfRead for R {
70    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), crate::Error> {
71        Ok(self.read_exact(buf)?)
72    }
73}
74
75#[cfg(not(feature = "std"))]
76#[cfg_attr(docsrs, doc(cfg(not(feature = "std"))))]
77impl ElfRead for &[u8] {
78    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), crate::Error> {
79        let n = buf.len();
80        if n > self.len() {
81            return Err(Error::UnexpectedEof);
82        }
83        buf.copy_from_slice(&self[..n]);
84        *self = &self[n..];
85        Ok(())
86    }
87}
88
89macro_rules! define_write {
90    ($func: ident, $uint: ident) => {
91        #[doc = concat!("Write `", stringify!($uint), "`.")]
92        fn $func(&mut self, byte_order: ByteOrder, value: $uint) -> Result<(), Error> {
93            let bytes = match byte_order {
94                LittleEndian => value.to_le_bytes(),
95                BigEndian => value.to_be_bytes(),
96            };
97            self.write_bytes(&bytes)
98        }
99    };
100}
101
102/// ELF-specific write functions.
103pub trait ElfWrite {
104    /// Write one byte as `u8`.
105    fn write_u8(&mut self, value: u8) -> Result<(), Error> {
106        self.write_bytes(&[value])
107    }
108
109    /// Write one byte as `i8`.
110    fn write_i8(&mut self, value: i8) -> Result<(), Error> {
111        self.write_bytes(&value.to_ne_bytes())
112    }
113
114    define_write!(write_u16, u16);
115    define_write!(write_u32, u32);
116    define_write!(write_u64, u64);
117
118    define_write!(write_i16, i16);
119    define_write!(write_i32, i32);
120    define_write!(write_i64, i64);
121
122    /// Write one word.
123    ///
124    /// Writes `u32` when the class is [`Class::Elf32`], writes `u64` otherwise.
125    fn write_word(&mut self, class: Class, byte_order: ByteOrder, value: u64) -> Result<(), Error> {
126        match class {
127            Elf32 => {
128                let value: u32 = value.try_into().map_err(|_| Error::TooBigWord(value))?;
129                self.write_u32(byte_order, value)?;
130            }
131            Elf64 => self.write_u64(byte_order, value)?,
132        }
133        Ok(())
134    }
135
136    /// Write a word specified by `value`.
137    fn write_word_as_u32(
138        &mut self,
139        class: Class,
140        byte_order: ByteOrder,
141        value: u32,
142    ) -> Result<(), Error> {
143        match class {
144            Elf32 => self.write_u32(byte_order, value),
145            Elf64 => self.write_u64(byte_order, value.into()),
146        }
147    }
148
149    /// Write `value` as `u64`.
150    fn write_u32_as_u64(&mut self, byte_order: ByteOrder, value: u64) -> Result<(), Error> {
151        self.write_u32(
152            byte_order,
153            value.try_into().map_err(|_| Error::TooBigWord(value))?,
154        )
155    }
156
157    /// Write `value` as `i32`.
158    fn write_i32_as_i64(&mut self, byte_order: ByteOrder, value: i64) -> Result<(), Error> {
159        self.write_i32(
160            byte_order,
161            value
162                .try_into()
163                .map_err(|_| Error::TooBigSignedWord(value))?,
164        )
165    }
166
167    /// Write all bytes.
168    ///
169    /// Similar to [`Write::write_all`](std::io::Write::write_all).
170    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Error>;
171}
172
173#[cfg(feature = "std")]
174#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
175impl<W: std::io::Write + ?Sized> ElfWrite for W {
176    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> {
177        Ok(self.write_all(bytes)?)
178    }
179}
180
181/// ELF-specific seek functions.
182pub trait ElfSeek {
183    /// Seek to the specified offset from the start of the file.
184    fn seek(&mut self, offset: u64) -> Result<(), Error>;
185}
186
187#[cfg(feature = "std")]
188#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
189impl<S: std::io::Seek + ?Sized> ElfSeek for S {
190    fn seek(&mut self, offset: u64) -> Result<(), Error> {
191        self.seek(std::io::SeekFrom::Start(offset))?;
192        Ok(())
193    }
194}
195
196/// Read an entity from a file or write an entity to a file.
197///
198/// Usually an entity doesn't occupy the whole section or segment.
199pub trait EntityIo {
200    /// Read the entity from the `reader`.
201    fn read<R: ElfRead>(reader: &mut R, class: Class, byte_order: ByteOrder) -> Result<Self, Error>
202    where
203        Self: Sized;
204
205    /// Write the entity to the `writer`.
206    fn write<W: ElfWrite>(
207        &self,
208        writer: &mut W,
209        class: Class,
210        byte_order: ByteOrder,
211    ) -> Result<(), Error>;
212}
213
214/// Read a block of data from a file.
215///
216/// Usually a block occupies the whole section or segment.
217pub trait BlockRead {
218    /// Read the table from the `reader`.
219    fn read<R: ElfRead>(
220        reader: &mut R,
221        class: Class,
222        byte_order: ByteOrder,
223        len: u64,
224    ) -> Result<Self, Error>
225    where
226        Self: Sized;
227}
228
229/// Write a block of data to a file.
230///
231/// Usually a block occupies the whole section or segment.
232pub trait BlockWrite {
233    /// Write the table to the `writer`.
234    fn write<W: ElfWrite>(
235        &self,
236        writer: &mut W,
237        class: Class,
238        byte_order: ByteOrder,
239    ) -> Result<(), Error>;
240}
241
242impl BlockRead for Vec<u8> {
243    fn read<R: ElfRead>(
244        reader: &mut R,
245        _class: Class,
246        _byte_order: ByteOrder,
247        len: u64,
248    ) -> Result<Self, Error> {
249        let n: usize = len.try_into().map_err(|_| Error::TooBig("Block size"))?;
250        let mut buf = vec![0_u8; n];
251        reader.read_bytes(&mut buf[..])?;
252        Ok(buf)
253    }
254}
255
256impl<T: AsRef<[u8]>> BlockWrite for T {
257    fn write<W: ElfWrite>(
258        &self,
259        writer: &mut W,
260        _class: Class,
261        _byte_order: ByteOrder,
262    ) -> Result<(), Error> {
263        writer.write_bytes(self.as_ref())?;
264        Ok(())
265    }
266}
267
268impl BlockWrite for CStr {
269    fn write<W: ElfWrite>(
270        &self,
271        writer: &mut W,
272        _class: Class,
273        _byte_order: ByteOrder,
274    ) -> Result<(), Error> {
275        writer.write_bytes(self.to_bytes_with_nul())?;
276        Ok(())
277    }
278}
279
280pub(crate) fn zero<W: ElfWrite + ElfSeek>(
281    writer: &mut W,
282    offset: u64,
283    size: u64,
284) -> Result<(), Error> {
285    writer.seek(offset)?;
286    write_zeroes(writer, size)?;
287    Ok(())
288}
289
290pub(crate) fn write_zeroes<W: ElfWrite + ElfSeek>(writer: &mut W, size: u64) -> Result<(), Error> {
291    const BUF_LEN: usize = 4096;
292    let buf = [0_u8; BUF_LEN];
293    for offset in (0..size).step_by(BUF_LEN) {
294        let n = (offset + BUF_LEN as u64).min(size) - offset;
295        writer.write_bytes(&buf[..n as usize])?;
296    }
297    Ok(())
298}