1use crate::abi;
17use crate::parse::ParseError;
18
19macro_rules! safe_from {
26 ( $self:ident, $typ:ty, $off:ident, $data:ident) => {{
27 const SIZE: usize = core::mem::size_of::<$typ>();
28
29 let end = (*$off)
30 .checked_add(SIZE)
31 .ok_or(ParseError::IntegerOverflow)?;
32
33 let buf: [u8; SIZE] = $data
34 .get(*$off..end)
35 .ok_or(ParseError::SliceReadError((*$off, end)))?
36 .try_into()?;
37
38 *$off = end;
39
40 if $self.is_little() {
43 Ok(<$typ>::from_le_bytes(buf))
44 } else {
45 Ok(<$typ>::from_be_bytes(buf))
46 }
47 }};
48}
49
50pub trait EndianParse: Clone + Copy + Default + PartialEq + Eq {
59 fn parse_u8_at(self, offset: &mut usize, data: &[u8]) -> Result<u8, ParseError> {
60 safe_from!(self, u8, offset, data)
61 }
62
63 fn parse_u16_at(self, offset: &mut usize, data: &[u8]) -> Result<u16, ParseError> {
64 safe_from!(self, u16, offset, data)
65 }
66
67 fn parse_u32_at(self, offset: &mut usize, data: &[u8]) -> Result<u32, ParseError> {
68 safe_from!(self, u32, offset, data)
69 }
70
71 fn parse_u64_at(self, offset: &mut usize, data: &[u8]) -> Result<u64, ParseError> {
72 safe_from!(self, u64, offset, data)
73 }
74
75 fn parse_i32_at(self, offset: &mut usize, data: &[u8]) -> Result<i32, ParseError> {
76 safe_from!(self, i32, offset, data)
77 }
78
79 fn parse_i64_at(self, offset: &mut usize, data: &[u8]) -> Result<i64, ParseError> {
80 safe_from!(self, i64, offset, data)
81 }
82
83 fn from_ei_data(ei_data: u8) -> Result<Self, ParseError>;
91
92 fn is_little(self) -> bool;
93
94 #[inline(always)]
95 fn is_big(self) -> bool {
96 !self.is_little()
97 }
98}
99
100#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
104pub enum AnyEndian {
105 #[default]
107 Little,
108 Big,
110}
111
112#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
117pub struct LittleEndian;
118
119#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
124pub struct BigEndian;
125
126#[cfg(target_endian = "little")]
131pub type NativeEndian = LittleEndian;
132
133#[cfg(target_endian = "little")]
134#[allow(non_upper_case_globals)]
135#[doc(hidden)]
136pub const NativeEndian: LittleEndian = LittleEndian;
137
138#[cfg(target_endian = "big")]
143pub type NativeEndian = BigEndian;
144
145#[cfg(target_endian = "big")]
146#[allow(non_upper_case_globals)]
147#[doc(hidden)]
148pub const NativeEndian: BigEndian = BigEndian;
149
150impl EndianParse for LittleEndian {
151 fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
152 match ei_data {
153 abi::ELFDATA2LSB => Ok(LittleEndian),
154 _ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
155 }
156 }
157
158 #[inline(always)]
159 fn is_little(self) -> bool {
160 true
161 }
162}
163
164impl EndianParse for BigEndian {
165 fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
166 match ei_data {
167 abi::ELFDATA2MSB => Ok(BigEndian),
168 _ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
169 }
170 }
171
172 #[inline(always)]
173 fn is_little(self) -> bool {
174 false
175 }
176}
177
178impl EndianParse for AnyEndian {
179 fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
180 match ei_data {
181 abi::ELFDATA2LSB => Ok(AnyEndian::Little),
182 abi::ELFDATA2MSB => Ok(AnyEndian::Big),
183 _ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
184 }
185 }
186
187 #[inline(always)]
188 fn is_little(self) -> bool {
189 match self {
190 AnyEndian::Little => true,
191 AnyEndian::Big => false,
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 macro_rules! parse_test {
201 ( $endian:expr, $res_typ:ty, $method:ident, $expect:expr) => {{
202 let bytes = [
203 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8,
204 ];
205 let mut offset = 0;
206 let result = $endian.$method(&mut offset, &bytes).unwrap();
207 assert_eq!(result, $expect);
208 assert_eq!(offset, core::mem::size_of::<$res_typ>());
209 }};
210 }
211
212 macro_rules! fuzz_too_short_test {
213 ( $endian:expr, $res_typ:ty, $method:ident) => {{
214 let bytes = [
215 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8,
216 ];
217 let size = core::mem::size_of::<$res_typ>();
218 for n in 0..size {
219 let buf = bytes.split_at(n).0.as_ref();
220 let mut offset: usize = 0;
221 let error = $endian
222 .$method(&mut offset, buf)
223 .expect_err("Expected an error, but parsed: ");
224 assert!(
225 matches!(error, ParseError::SliceReadError(_)),
226 "Unexpected Error type found: {error}"
227 );
228 }
229 }};
230 }
231
232 #[test]
233 fn parse_u8_at() {
234 parse_test!(LittleEndian, u8, parse_u8_at, 0x01u8);
235 parse_test!(BigEndian, u8, parse_u8_at, 0x01u8);
236 parse_test!(AnyEndian::Little, u8, parse_u8_at, 0x01u8);
237 parse_test!(AnyEndian::Big, u8, parse_u8_at, 0x01u8);
238 }
239
240 #[test]
241 fn parse_u16_at() {
242 parse_test!(LittleEndian, u16, parse_u16_at, 0x0201u16);
243 parse_test!(BigEndian, u16, parse_u16_at, 0x0102u16);
244 parse_test!(AnyEndian::Little, u16, parse_u16_at, 0x0201u16);
245 parse_test!(AnyEndian::Big, u16, parse_u16_at, 0x0102u16);
246 }
247
248 #[test]
249 fn parse_u32_at() {
250 parse_test!(LittleEndian, u32, parse_u32_at, 0x04030201u32);
251 parse_test!(BigEndian, u32, parse_u32_at, 0x01020304u32);
252 parse_test!(AnyEndian::Little, u32, parse_u32_at, 0x04030201u32);
253 parse_test!(AnyEndian::Big, u32, parse_u32_at, 0x01020304u32);
254 }
255
256 #[test]
257 fn parse_u64_at() {
258 parse_test!(LittleEndian, u64, parse_u64_at, 0x0807060504030201u64);
259 parse_test!(BigEndian, u64, parse_u64_at, 0x0102030405060708u64);
260 parse_test!(AnyEndian::Little, u64, parse_u64_at, 0x0807060504030201u64);
261 parse_test!(AnyEndian::Big, u64, parse_u64_at, 0x0102030405060708u64);
262 }
263
264 #[test]
265 fn parse_i32_at() {
266 parse_test!(LittleEndian, i32, parse_i32_at, 0x04030201i32);
267 parse_test!(BigEndian, i32, parse_i32_at, 0x01020304i32);
268 parse_test!(AnyEndian::Little, i32, parse_i32_at, 0x04030201i32);
269 parse_test!(AnyEndian::Big, i32, parse_i32_at, 0x01020304i32);
270 }
271
272 #[test]
273 fn parse_i64_at() {
274 parse_test!(LittleEndian, i64, parse_i64_at, 0x0807060504030201i64);
275 parse_test!(BigEndian, i64, parse_i64_at, 0x0102030405060708i64);
276 parse_test!(AnyEndian::Little, i64, parse_i64_at, 0x0807060504030201i64);
277 parse_test!(AnyEndian::Big, i64, parse_i64_at, 0x0102030405060708i64);
278 }
279
280 #[test]
281 fn fuzz_u8_too_short() {
282 fuzz_too_short_test!(LittleEndian, u8, parse_u8_at);
283 fuzz_too_short_test!(BigEndian, u8, parse_u8_at);
284 fuzz_too_short_test!(AnyEndian::Little, u8, parse_u8_at);
285 fuzz_too_short_test!(AnyEndian::Big, u8, parse_u8_at);
286 }
287
288 #[test]
289 fn fuzz_u16_too_short() {
290 fuzz_too_short_test!(LittleEndian, u16, parse_u16_at);
291 fuzz_too_short_test!(BigEndian, u16, parse_u16_at);
292 fuzz_too_short_test!(AnyEndian::Little, u16, parse_u16_at);
293 fuzz_too_short_test!(AnyEndian::Big, u16, parse_u16_at);
294 }
295
296 #[test]
297 fn fuzz_u32_too_short() {
298 fuzz_too_short_test!(LittleEndian, u32, parse_u32_at);
299 fuzz_too_short_test!(BigEndian, u32, parse_u32_at);
300 fuzz_too_short_test!(AnyEndian::Little, u32, parse_u32_at);
301 fuzz_too_short_test!(AnyEndian::Big, u32, parse_u32_at);
302 }
303
304 #[test]
305 fn fuzz_i32_too_short() {
306 fuzz_too_short_test!(LittleEndian, i32, parse_i32_at);
307 fuzz_too_short_test!(BigEndian, i32, parse_i32_at);
308 fuzz_too_short_test!(AnyEndian::Little, i32, parse_i32_at);
309 fuzz_too_short_test!(AnyEndian::Big, i32, parse_i32_at);
310 }
311
312 #[test]
313 fn fuzz_u64_too_short() {
314 fuzz_too_short_test!(LittleEndian, u64, parse_u64_at);
315 fuzz_too_short_test!(BigEndian, u64, parse_u64_at);
316 fuzz_too_short_test!(AnyEndian::Little, u64, parse_u64_at);
317 fuzz_too_short_test!(AnyEndian::Big, u64, parse_u64_at);
318 }
319
320 #[test]
321 fn fuzz_i64_too_short() {
322 fuzz_too_short_test!(LittleEndian, i64, parse_i64_at);
323 fuzz_too_short_test!(BigEndian, i64, parse_i64_at);
324 fuzz_too_short_test!(AnyEndian::Little, i64, parse_i64_at);
325 fuzz_too_short_test!(AnyEndian::Big, i64, parse_i64_at);
326 }
327}