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