stackdump_core/
memory_region.rs

1//! Module containing the definitions for memory regions
2
3use arrayvec::ArrayVec;
4use serde::{Deserialize, Serialize};
5
6/// The identifier that is being used in the byte iterator to be able to differentiate between memory regions and register data
7pub const MEMORY_REGION_IDENTIFIER: u8 = 0x01;
8
9/// A collection of bytes that capture a memory region
10#[cfg(feature = "std")]
11pub trait MemoryRegion {
12    /// Get the address range of this region
13    fn range(&self) -> std::ops::Range<u64>;
14
15    /// Returns the slice of memory that can be found at the given address_range.
16    /// If the given address range is not fully within the captured region, then None is returned.
17    fn read(
18        &self,
19        address_range: core::ops::Range<u64>,
20    ) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError>;
21
22    /// Reads a byte from the given address if it is present in the region
23    fn read_u8(&self, address: u64) -> Result<Option<u8>, crate::device_memory::MemoryReadError> {
24        Ok(self.read(address..address + 1)?.map(|b| b[0]))
25    }
26
27    /// Reads a u32 from the given address if it is present in the region
28    fn read_u32(
29        &self,
30        address: u64,
31        endianness: gimli::RunTimeEndian,
32    ) -> Result<Option<u32>, crate::device_memory::MemoryReadError> {
33        if let Some(slice) = self
34            .read(address..address + 4)?
35            .map(|slice| slice[..].try_into().unwrap())
36        {
37            if gimli::Endianity::is_little_endian(endianness) {
38                Ok(Some(u32::from_le_bytes(slice)))
39            } else {
40                Ok(Some(u32::from_be_bytes(slice)))
41            }
42        } else {
43            Ok(None)
44        }
45    }
46}
47
48/// A memory region that is backed by a stack allocated array
49#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
50pub struct ArrayMemoryRegion<const SIZE: usize> {
51    start_address: u64,
52    data: ArrayVec<u8, SIZE>,
53}
54
55impl<const SIZE: usize> ArrayMemoryRegion<SIZE> {
56    /// Creates a new memory region starting at the given address with the given data
57    pub fn new(start_address: u64, data: ArrayVec<u8, SIZE>) -> Self {
58        Self {
59            start_address,
60            data,
61        }
62    }
63
64    /// Get a byte iterator for this region.
65    ///
66    /// This iterator can be used to store the region as bytes or to stream over a network.
67    /// The iterated bytes include the length so that if you use the FromIterator implementation,
68    /// it consumes only the bytes that are part of the collection.
69    /// This means you can chain multiple of these iterators after each other.
70    ///
71    /// ```
72    /// use arrayvec::ArrayVec;
73    /// use stackdump_core::memory_region::{ArrayMemoryRegion, MemoryRegion};
74    ///
75    /// let region1 = ArrayMemoryRegion::<4>::new(0, ArrayVec::from([1, 2, 3, 4]));
76    /// let region2 = ArrayMemoryRegion::<4>::new(100, ArrayVec::from([5, 6, 7, 8]));
77    ///
78    /// let mut intermediate_buffer = Vec::new();
79    ///
80    /// intermediate_buffer.extend(region1.bytes());
81    /// intermediate_buffer.extend(region2.bytes());
82    ///
83    /// let mut intermediate_iter = intermediate_buffer.iter();
84    ///
85    /// assert_eq!(region1, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
86    /// assert_eq!(region2, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
87    /// ```
88    pub fn bytes(&self) -> MemoryRegionIterator<'_> {
89        MemoryRegionIterator::new(self.start_address, &self.data)
90    }
91
92    /// Clears the existing memory data and copies the new data from the given pointer
93    ///
94    /// If the data_len is greater than the capacity of this memory region, then this function will panic.
95    ///
96    /// ## Safety
97    ///
98    /// The entire block of memory from `data_ptr .. data_ptr + data_len` must be readable.
99    /// (A memcpy must be possible with the pointer as source)
100    pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
101        self.start_address = data_ptr as u64;
102        self.data.clear();
103
104        assert!(data_len <= self.data.capacity());
105
106        self.data.set_len(data_len);
107        self.data.as_mut_ptr().copy_from(data_ptr, data_len);
108    }
109}
110
111#[cfg(feature = "std")]
112impl<const SIZE: usize> MemoryRegion for ArrayMemoryRegion<SIZE> {
113    fn range(&self) -> std::ops::Range<u64> {
114        self.start_address..self.start_address + self.data.len() as u64
115    }
116
117    fn read(
118        &self,
119        index: core::ops::Range<u64>,
120    ) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
121        let start = match index.start.checked_sub(self.start_address) {
122            Some(start) => start,
123            None => return Ok(None),
124        };
125        let end = match index.end.checked_sub(self.start_address) {
126            Some(end) => end,
127            None => return Ok(None),
128        };
129        Ok(self
130            .data
131            .get(start as usize..end as usize)
132            .map(|slice| slice.to_vec()))
133    }
134}
135
136impl<'a, const SIZE: usize> FromIterator<&'a u8> for ArrayMemoryRegion<SIZE> {
137    fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
138        Self::from_iter(iter.into_iter().copied())
139    }
140}
141
142impl<const SIZE: usize> FromIterator<u8> for ArrayMemoryRegion<SIZE> {
143    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
144        let mut iter = iter.into_iter();
145
146        assert_eq!(
147            iter.next().unwrap(),
148            MEMORY_REGION_IDENTIFIER,
149            "The given iterator is not for a memory region"
150        );
151
152        let start_address = u64::from_le_bytes([
153            iter.next().unwrap(),
154            iter.next().unwrap(),
155            iter.next().unwrap(),
156            iter.next().unwrap(),
157            iter.next().unwrap(),
158            iter.next().unwrap(),
159            iter.next().unwrap(),
160            iter.next().unwrap(),
161        ]);
162
163        let length = u64::from_le_bytes([
164            iter.next().unwrap(),
165            iter.next().unwrap(),
166            iter.next().unwrap(),
167            iter.next().unwrap(),
168            iter.next().unwrap(),
169            iter.next().unwrap(),
170            iter.next().unwrap(),
171            iter.next().unwrap(),
172        ]);
173
174        let data = ArrayVec::from_iter(iter.take(length as usize));
175
176        Self {
177            start_address,
178            data,
179        }
180    }
181}
182
183/// A memory region that is backed by a stack allocated array
184#[cfg(feature = "std")]
185#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
186pub struct VecMemoryRegion {
187    start_address: u64,
188    data: Vec<u8>,
189}
190
191#[cfg(feature = "std")]
192impl VecMemoryRegion {
193    /// Creates a new memory region starting at the given address with the given data
194    pub fn new(start_address: u64, data: Vec<u8>) -> Self {
195        Self {
196            start_address,
197            data,
198        }
199    }
200
201    /// Get a byte iterator for this region.
202    ///
203    /// This iterator can be used to store the region as bytes or to stream over a network.
204    /// The iterated bytes include the length so that if you use the FromIterator implementation,
205    /// it consumes only the bytes that are part of the collection.
206    /// This means you can chain multiple of these iterators after each other.
207    ///
208    /// ```
209    /// use arrayvec::ArrayVec;
210    /// use stackdump_core::memory_region::{ArrayMemoryRegion, MemoryRegion};
211    ///
212    /// let region1 = ArrayMemoryRegion::<4>::new(0, ArrayVec::from([1, 2, 3, 4]));
213    /// let region2 = ArrayMemoryRegion::<4>::new(100, ArrayVec::from([5, 6, 7, 8]));
214    ///
215    /// let mut intermediate_buffer = Vec::new();
216    ///
217    /// intermediate_buffer.extend(region1.bytes());
218    /// intermediate_buffer.extend(region2.bytes());
219    ///
220    /// let mut intermediate_iter = intermediate_buffer.iter();
221    ///
222    /// assert_eq!(region1, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
223    /// assert_eq!(region2, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
224    /// ```
225    pub fn bytes(&self) -> MemoryRegionIterator<'_> {
226        MemoryRegionIterator::new(self.start_address, &self.data)
227    }
228
229    /// Clears the existing memory data and copies the new data from the given pointer
230    ///
231    /// If the data_len is greater than the capacity of this memory region, then this function will panic.
232    ///
233    /// ## Safety
234    ///
235    /// The entire block of memory from `data_ptr .. data_ptr + data_len` must be readable.
236    /// (A memcpy must be possible with the pointer as source)
237    pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
238        self.start_address = data_ptr as u64;
239        self.data.clear();
240        self.data.resize(data_len, 0);
241
242        self.data.as_mut_ptr().copy_from(data_ptr, data_len);
243    }
244}
245
246#[cfg(feature = "std")]
247impl MemoryRegion for VecMemoryRegion {
248    fn range(&self) -> std::ops::Range<u64> {
249        self.start_address..self.start_address + self.data.len() as u64
250    }
251
252    fn read(
253        &self,
254        index: core::ops::Range<u64>,
255    ) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
256        let start = match index.start.checked_sub(self.start_address) {
257            Some(start) => start,
258            None => return Ok(None),
259        };
260        let end = match index.end.checked_sub(self.start_address) {
261            Some(end) => end,
262            None => return Ok(None),
263        };
264        Ok(self
265            .data
266            .get(start as usize..end as usize)
267            .map(|slice| slice.to_vec()))
268    }
269}
270
271#[cfg(feature = "std")]
272impl<'a> FromIterator<&'a u8> for VecMemoryRegion {
273    fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
274        Self::from_iter(iter.into_iter().copied())
275    }
276}
277
278#[cfg(feature = "std")]
279impl FromIterator<u8> for VecMemoryRegion {
280    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
281        let mut iter = iter.into_iter();
282
283        assert_eq!(
284            iter.next().unwrap(),
285            MEMORY_REGION_IDENTIFIER,
286            "The given iterator is not for a memory region"
287        );
288
289        let start_address = u64::from_le_bytes([
290            iter.next().unwrap(),
291            iter.next().unwrap(),
292            iter.next().unwrap(),
293            iter.next().unwrap(),
294            iter.next().unwrap(),
295            iter.next().unwrap(),
296            iter.next().unwrap(),
297            iter.next().unwrap(),
298        ]);
299
300        let length = u64::from_le_bytes([
301            iter.next().unwrap(),
302            iter.next().unwrap(),
303            iter.next().unwrap(),
304            iter.next().unwrap(),
305            iter.next().unwrap(),
306            iter.next().unwrap(),
307            iter.next().unwrap(),
308            iter.next().unwrap(),
309        ]);
310
311        let data = Vec::from_iter(iter.take(length as usize));
312
313        Self {
314            start_address,
315            data,
316        }
317    }
318}
319
320/// A memory region that is backed by a slice
321#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
322pub struct SliceMemoryRegion<'a> {
323    data: &'a [u8],
324}
325
326impl<'a> SliceMemoryRegion<'a> {
327    /// Creates a new memory region starting at the given address with the given data
328    pub fn new(data: &'a [u8]) -> Self {
329        Self { data }
330    }
331
332    /// Get a byte iterator for this region.
333    ///
334    /// This iterator can be used to store the region as bytes or to stream over a network.
335    /// The iterated bytes include the length so that if you use the FromIterator implementation,
336    /// it consumes only the bytes that are part of the collection.
337    /// This means you can chain multiple of these iterators after each other.
338    ///
339    /// ```
340    /// use arrayvec::ArrayVec;
341    /// use stackdump_core::memory_region::{ArrayMemoryRegion, MemoryRegion};
342    ///
343    /// let region1 = ArrayMemoryRegion::<4>::new(0, ArrayVec::from([1, 2, 3, 4]));
344    /// let region2 = ArrayMemoryRegion::<4>::new(100, ArrayVec::from([5, 6, 7, 8]));
345    ///
346    /// let mut intermediate_buffer = Vec::new();
347    ///
348    /// intermediate_buffer.extend(region1.bytes());
349    /// intermediate_buffer.extend(region2.bytes());
350    ///
351    /// let mut intermediate_iter = intermediate_buffer.iter();
352    ///
353    /// assert_eq!(region1, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
354    /// assert_eq!(region2, ArrayMemoryRegion::<4>::from_iter(&mut intermediate_iter));
355    /// ```
356    pub fn bytes(&self) -> MemoryRegionIterator<'_> {
357        let start_address = self.data.as_ptr() as u64;
358        MemoryRegionIterator::new(start_address, self.data)
359    }
360
361    /// This function is especially unsafe.
362    /// The memory region will reference the given data for its entire lifetime.
363    ///
364    /// ## Safety
365    ///
366    /// The entire block of memory from `data_ptr .. data_ptr + data_len` must be readable.
367    /// (A memcpy must be possible with the pointer as source)
368    ///
369    /// You must not have another reference to this block of memory or any object that resides in this memory
370    /// during the entire lifetime of the object
371    pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
372        self.data = core::slice::from_raw_parts(data_ptr, data_len);
373    }
374}
375
376#[cfg(feature = "std")]
377impl<'a> MemoryRegion for SliceMemoryRegion<'a> {
378    fn range(&self) -> std::ops::Range<u64> {
379        let range = self.data.as_ptr_range();
380        range.start as u64..range.end as u64
381    }
382
383    fn read(
384        &self,
385        index: core::ops::Range<u64>,
386    ) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
387        let start_address = self.data.as_ptr() as u64;
388        let start = match index.start.checked_sub(start_address) {
389            Some(start) => start,
390            None => return Ok(None),
391        };
392        let end = match index.end.checked_sub(start_address) {
393            Some(end) => end,
394            None => return Ok(None),
395        };
396        Ok(self
397            .data
398            .get(start as usize..end as usize)
399            .map(|slice| slice.to_vec()))
400    }
401}
402
403/// An iterator that iterates over the serialized bytes of a memory region
404pub struct MemoryRegionIterator<'a> {
405    start_address: u64,
406    data: &'a [u8],
407    index: usize,
408}
409
410impl<'a> MemoryRegionIterator<'a> {
411    fn new(start_address: u64, data: &'a [u8]) -> Self {
412        Self {
413            start_address,
414            data,
415            index: 0,
416        }
417    }
418}
419
420impl<'a> Iterator for MemoryRegionIterator<'a> {
421    type Item = u8;
422
423    fn next(&mut self) -> Option<Self::Item> {
424        match self.index {
425            0 => {
426                self.index += 1;
427                Some(MEMORY_REGION_IDENTIFIER)
428            }
429            index @ 1..=8 => {
430                self.index += 1;
431                Some(self.start_address.to_le_bytes()[index - 1])
432            }
433            index @ 9..=16 => {
434                self.index += 1;
435                Some((self.data.len() as u64).to_le_bytes()[index - 9])
436            }
437            index => {
438                self.index += 1;
439                self.data.get(index - 17).copied()
440            }
441        }
442    }
443
444    fn size_hint(&self) -> (usize, Option<usize>) {
445        let remaining_length = 17 + self.data.len() - self.index;
446        (remaining_length, Some(remaining_length))
447    }
448}
449
450impl<'a> ExactSizeIterator for MemoryRegionIterator<'a> {}
451
452#[cfg(test)]
453mod tests {
454    use super::*;
455
456    #[test]
457    fn iterator() {
458        let region = VecMemoryRegion::new(0x2000_0000, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
459        let copied_region = VecMemoryRegion::from_iter(region.bytes());
460
461        assert_eq!(region, copied_region);
462    }
463
464    #[test]
465    fn iterator_len() {
466        let region = VecMemoryRegion::new(0x2000_0000, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
467        let iter = region.bytes();
468        assert_eq!(iter.len(), iter.count());
469
470        let mut iter = region.bytes();
471        iter.nth(10).unwrap();
472        assert_eq!(iter.len(), iter.count());
473    }
474}