1 //! Working with byte slices that have an associated endianity.
2 
3 use alloc::borrow::Cow;
4 use alloc::string::String;
5 use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
6 use core::str;
7 
8 use crate::endianity::Endianity;
9 use crate::read::{Error, Reader, ReaderOffsetId, Result};
10 
11 /// A `&[u8]` slice with endianity metadata.
12 ///
13 /// This implements the `Reader` trait, which is used for all reading of DWARF sections.
14 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
15 pub struct EndianSlice<'input, Endian>
16 where
17     Endian: Endianity,
18 {
19     slice: &'input [u8],
20     endian: Endian,
21 }
22 
23 impl<'input, Endian> EndianSlice<'input, Endian>
24 where
25     Endian: Endianity,
26 {
27     /// Construct a new `EndianSlice` with the given slice and endianity.
28     #[inline]
new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian>29     pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> {
30         EndianSlice { slice, endian }
31     }
32 
33     /// Return a reference to the raw slice.
34     #[inline]
35     #[doc(hidden)]
36     #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")]
buf(&self) -> &'input [u8]37     pub fn buf(&self) -> &'input [u8] {
38         self.slice
39     }
40 
41     /// Return a reference to the raw slice.
42     #[inline]
slice(&self) -> &'input [u8]43     pub fn slice(&self) -> &'input [u8] {
44         self.slice
45     }
46 
47     /// Split the slice in two at the given index, resulting in the tuple where
48     /// the first item has range [0, idx), and the second has range [idx,
49     /// len). Panics if the index is out of bounds.
50     #[inline]
split_at( &self, idx: usize, ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>)51     pub fn split_at(
52         &self,
53         idx: usize,
54     ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) {
55         (self.range_to(..idx), self.range_from(idx..))
56     }
57 
58     /// Find the first occurence of a byte in the slice, and return its index.
59     #[inline]
find(&self, byte: u8) -> Option<usize>60     pub fn find(&self, byte: u8) -> Option<usize> {
61         self.slice.iter().position(|ch| *ch == byte)
62     }
63 
64     /// Return the offset of the start of the slice relative to the start
65     /// of the given slice.
66     #[inline]
offset_from(&self, base: EndianSlice<'input, Endian>) -> usize67     pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize {
68         let base_ptr = base.slice.as_ptr() as *const u8 as usize;
69         let ptr = self.slice.as_ptr() as *const u8 as usize;
70         debug_assert!(base_ptr <= ptr);
71         debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len());
72         ptr - base_ptr
73     }
74 
75     /// Converts the slice to a string using `str::from_utf8`.
76     ///
77     /// Returns an error if the slice contains invalid characters.
78     #[inline]
to_string(&self) -> Result<&'input str>79     pub fn to_string(&self) -> Result<&'input str> {
80         str::from_utf8(self.slice).map_err(|_| Error::BadUtf8)
81     }
82 
83     /// Converts the slice to a string, including invalid characters,
84     /// using `String::from_utf8_lossy`.
85     #[inline]
to_string_lossy(&self) -> Cow<'input, str>86     pub fn to_string_lossy(&self) -> Cow<'input, str> {
87         String::from_utf8_lossy(self.slice)
88     }
89 
90     #[inline]
read_slice(&mut self, len: usize) -> Result<&'input [u8]>91     fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> {
92         if self.slice.len() < len {
93             Err(Error::UnexpectedEof(self.offset_id()))
94         } else {
95             let val = &self.slice[..len];
96             self.slice = &self.slice[len..];
97             Ok(val)
98         }
99     }
100 }
101 
102 /// # Range Methods
103 ///
104 /// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
105 /// implement `Index<Range<usize>>` to return a new `EndianSlice` the way we would
106 /// like to. Instead, we abandon fancy indexing operators and have these plain
107 /// old methods.
108 impl<'input, Endian> EndianSlice<'input, Endian>
109 where
110     Endian: Endianity,
111 {
112     /// Take the given `start..end` range of the underlying slice and return a
113     /// new `EndianSlice`.
114     ///
115     /// ```
116     /// use gimli::{EndianSlice, LittleEndian};
117     ///
118     /// let slice = &[0x01, 0x02, 0x03, 0x04];
119     /// let endian_slice = EndianSlice::new(slice, LittleEndian);
120     /// assert_eq!(endian_slice.range(1..3),
121     ///            EndianSlice::new(&slice[1..3], LittleEndian));
122     /// ```
range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian>123     pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> {
124         EndianSlice {
125             slice: &self.slice[idx],
126             endian: self.endian,
127         }
128     }
129 
130     /// Take the given `start..` range of the underlying slice and return a new
131     /// `EndianSlice`.
132     ///
133     /// ```
134     /// use gimli::{EndianSlice, LittleEndian};
135     ///
136     /// let slice = &[0x01, 0x02, 0x03, 0x04];
137     /// let endian_slice = EndianSlice::new(slice, LittleEndian);
138     /// assert_eq!(endian_slice.range_from(2..),
139     ///            EndianSlice::new(&slice[2..], LittleEndian));
140     /// ```
range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian>141     pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> {
142         EndianSlice {
143             slice: &self.slice[idx],
144             endian: self.endian,
145         }
146     }
147 
148     /// Take the given `..end` range of the underlying slice and return a new
149     /// `EndianSlice`.
150     ///
151     /// ```
152     /// use gimli::{EndianSlice, LittleEndian};
153     ///
154     /// let slice = &[0x01, 0x02, 0x03, 0x04];
155     /// let endian_slice = EndianSlice::new(slice, LittleEndian);
156     /// assert_eq!(endian_slice.range_to(..3),
157     ///            EndianSlice::new(&slice[..3], LittleEndian));
158     /// ```
range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian>159     pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> {
160         EndianSlice {
161             slice: &self.slice[idx],
162             endian: self.endian,
163         }
164     }
165 }
166 
167 impl<'input, Endian> Index<usize> for EndianSlice<'input, Endian>
168 where
169     Endian: Endianity,
170 {
171     type Output = u8;
index(&self, idx: usize) -> &Self::Output172     fn index(&self, idx: usize) -> &Self::Output {
173         &self.slice[idx]
174     }
175 }
176 
177 impl<'input, Endian> Index<RangeFrom<usize>> for EndianSlice<'input, Endian>
178 where
179     Endian: Endianity,
180 {
181     type Output = [u8];
index(&self, idx: RangeFrom<usize>) -> &Self::Output182     fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
183         &self.slice[idx]
184     }
185 }
186 
187 impl<'input, Endian> Deref for EndianSlice<'input, Endian>
188 where
189     Endian: Endianity,
190 {
191     type Target = [u8];
deref(&self) -> &Self::Target192     fn deref(&self) -> &Self::Target {
193         self.slice
194     }
195 }
196 
197 impl<'input, Endian> Into<&'input [u8]> for EndianSlice<'input, Endian>
198 where
199     Endian: Endianity,
200 {
into(self) -> &'input [u8]201     fn into(self) -> &'input [u8] {
202         self.slice
203     }
204 }
205 
206 impl<'input, Endian> Reader for EndianSlice<'input, Endian>
207 where
208     Endian: Endianity,
209 {
210     type Endian = Endian;
211     type Offset = usize;
212 
213     #[inline]
endian(&self) -> Endian214     fn endian(&self) -> Endian {
215         self.endian
216     }
217 
218     #[inline]
len(&self) -> usize219     fn len(&self) -> usize {
220         self.slice.len()
221     }
222 
223     #[inline]
is_empty(&self) -> bool224     fn is_empty(&self) -> bool {
225         self.slice.is_empty()
226     }
227 
228     #[inline]
empty(&mut self)229     fn empty(&mut self) {
230         self.slice = &[];
231     }
232 
233     #[inline]
truncate(&mut self, len: usize) -> Result<()>234     fn truncate(&mut self, len: usize) -> Result<()> {
235         if self.slice.len() < len {
236             Err(Error::UnexpectedEof(self.offset_id()))
237         } else {
238             self.slice = &self.slice[..len];
239             Ok(())
240         }
241     }
242 
243     #[inline]
offset_from(&self, base: &Self) -> usize244     fn offset_from(&self, base: &Self) -> usize {
245         self.offset_from(*base)
246     }
247 
248     #[inline]
offset_id(&self) -> ReaderOffsetId249     fn offset_id(&self) -> ReaderOffsetId {
250         ReaderOffsetId(self.slice.as_ptr() as u64)
251     }
252 
253     #[inline]
lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset>254     fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
255         let id = id.0;
256         let self_id = self.slice.as_ptr() as u64;
257         let self_len = self.slice.len() as u64;
258         if id >= self_id && id <= self_id + self_len {
259             Some((id - self_id) as usize)
260         } else {
261             None
262         }
263     }
264 
265     #[inline]
find(&self, byte: u8) -> Result<usize>266     fn find(&self, byte: u8) -> Result<usize> {
267         self.find(byte)
268             .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
269     }
270 
271     #[inline]
skip(&mut self, len: usize) -> Result<()>272     fn skip(&mut self, len: usize) -> Result<()> {
273         if self.slice.len() < len {
274             Err(Error::UnexpectedEof(self.offset_id()))
275         } else {
276             self.slice = &self.slice[len..];
277             Ok(())
278         }
279     }
280 
281     #[inline]
split(&mut self, len: usize) -> Result<Self>282     fn split(&mut self, len: usize) -> Result<Self> {
283         let slice = self.read_slice(len)?;
284         Ok(EndianSlice::new(slice, self.endian))
285     }
286 
287     #[inline]
to_slice(&self) -> Result<Cow<[u8]>>288     fn to_slice(&self) -> Result<Cow<[u8]>> {
289         Ok(self.slice.into())
290     }
291 
292     #[inline]
to_string(&self) -> Result<Cow<str>>293     fn to_string(&self) -> Result<Cow<str>> {
294         match str::from_utf8(self.slice) {
295             Ok(s) => Ok(s.into()),
296             _ => Err(Error::BadUtf8),
297         }
298     }
299 
300     #[inline]
to_string_lossy(&self) -> Result<Cow<str>>301     fn to_string_lossy(&self) -> Result<Cow<str>> {
302         Ok(String::from_utf8_lossy(self.slice))
303     }
304 
305     #[inline]
read_slice(&mut self, buf: &mut [u8]) -> Result<()>306     fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
307         let slice = self.read_slice(buf.len())?;
308         buf.clone_from_slice(slice);
309         Ok(())
310     }
311 }
312 
313 #[cfg(test)]
314 mod tests {
315     use super::*;
316     use crate::endianity::NativeEndian;
317 
318     #[test]
test_endian_slice_split_at()319     fn test_endian_slice_split_at() {
320         let endian = NativeEndian;
321         let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
322         let eb = EndianSlice::new(slice, endian);
323         assert_eq!(
324             eb.split_at(3),
325             (
326                 EndianSlice::new(&slice[..3], endian),
327                 EndianSlice::new(&slice[3..], endian)
328             )
329         );
330     }
331 
332     #[test]
333     #[should_panic]
test_endian_slice_split_at_out_of_bounds()334     fn test_endian_slice_split_at_out_of_bounds() {
335         let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
336         let eb = EndianSlice::new(slice, NativeEndian);
337         eb.split_at(30);
338     }
339 }
340