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.copy_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