1 pub mod app_memory;
2 pub mod exception_stream;
3 pub mod mappings;
4 pub mod memory_list_stream;
5 pub mod systeminfo_stream;
6 pub mod thread_list_stream;
7 pub mod thread_names_stream;
8
9 use crate::errors::MemoryWriterError;
10 use crate::minidump_format::*;
11 use std::convert::TryInto;
12 use std::io::{Cursor, Write};
13
14 type Result<T> = std::result::Result<T, MemoryWriterError>;
15
16 #[derive(Debug, PartialEq)]
17 pub struct MemoryWriter<T: Default + Sized> {
18 pub position: MDRVA,
19 pub size: usize,
20 phantom: std::marker::PhantomData<T>,
21 }
22
23 impl<T> MemoryWriter<T>
24 where
25 T: Default + Sized,
26 {
27 /// Create a slot for a type T in the buffer, we can fill right now with real values.
alloc_with_val(buffer: &mut Cursor<Vec<u8>>, val: T) -> Result<Self>28 pub fn alloc_with_val(buffer: &mut Cursor<Vec<u8>>, val: T) -> Result<Self> {
29 // Get position of this value (e.g. before we add ourselves there)
30 let position = buffer.position();
31 let size = std::mem::size_of::<T>();
32 let bytes = unsafe { std::slice::from_raw_parts(&val as *const T as *const u8, size) };
33 buffer.write_all(bytes)?;
34
35 Ok(MemoryWriter {
36 position: position as u32,
37 size,
38 phantom: std::marker::PhantomData::<T> {},
39 })
40 }
41
42 /// Create a slot for a type T in the buffer, we can fill later with real values.
43 /// This function fills it with `Default::default()`, which is less performant than
44 /// using uninitialized memory, but safe.
alloc(buffer: &mut Cursor<Vec<u8>>) -> Result<Self>45 pub fn alloc(buffer: &mut Cursor<Vec<u8>>) -> Result<Self> {
46 // Filling out the buffer with default-values
47 let val: T = Default::default();
48 Self::alloc_with_val(buffer, val)
49 }
50
51 /// Write actual values in the buffer-slot we got during `alloc()`
set_value(&mut self, buffer: &mut Cursor<Vec<u8>>, val: T) -> Result<()>52 pub fn set_value(&mut self, buffer: &mut Cursor<Vec<u8>>, val: T) -> Result<()> {
53 // Save whereever the current cursor stands in the buffer
54 let curr_pos = buffer.position();
55
56 // Write the actual value we want at our position that
57 // was determined by `alloc()` into the buffer
58 buffer.set_position(self.position as u64);
59 let bytes = unsafe {
60 std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::<T>())
61 };
62 let res = buffer.write_all(bytes);
63
64 // Resetting whereever we were before updating this
65 // regardless of the write-result
66 buffer.set_position(curr_pos);
67
68 res?;
69 Ok(())
70 }
71
location(&self) -> MDLocationDescriptor72 pub fn location(&self) -> MDLocationDescriptor {
73 MDLocationDescriptor {
74 data_size: std::mem::size_of::<T>() as u32,
75 rva: self.position,
76 }
77 }
78 }
79
80 #[derive(Debug, PartialEq)]
81 pub struct MemoryArrayWriter<T: Default + Sized> {
82 pub position: MDRVA,
83 array_size: usize,
84 phantom: std::marker::PhantomData<T>,
85 }
86
87 impl<T> MemoryArrayWriter<T>
88 where
89 T: Default + Sized,
90 {
91 /// Create a slot for a type T in the buffer, we can fill in the values in one go.
alloc_from_array(buffer: &mut Cursor<Vec<u8>>, array: &[T]) -> Result<Self>92 pub fn alloc_from_array(buffer: &mut Cursor<Vec<u8>>, array: &[T]) -> Result<Self> {
93 // Get position of this value (e.g. before we add ourselves there)
94 let position = buffer.position();
95 for val in array {
96 let bytes = unsafe {
97 std::slice::from_raw_parts(val as *const T as *const u8, std::mem::size_of::<T>())
98 };
99 buffer.write_all(bytes)?;
100 }
101
102 Ok(MemoryArrayWriter {
103 position: position as u32,
104 array_size: array.len(),
105 phantom: std::marker::PhantomData::<T> {},
106 })
107 }
108
109 /// Create a slot for a type T in the buffer, we can fill later with real values.
110 /// This function fills it with `Default::default()`, which is less performant than
111 /// using uninitialized memory, but safe.
alloc_array(buffer: &mut Cursor<Vec<u8>>, array_size: usize) -> Result<Self>112 pub fn alloc_array(buffer: &mut Cursor<Vec<u8>>, array_size: usize) -> Result<Self> {
113 // Get position of this value (e.g. before we add ourselves there)
114 let position = buffer.position();
115 for _ in 0..array_size {
116 // Filling out the buffer with default-values
117 let val: T = Default::default();
118 let bytes = unsafe {
119 std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::<T>())
120 };
121 buffer.write_all(bytes)?;
122 }
123
124 Ok(MemoryArrayWriter {
125 position: position as u32,
126 array_size,
127 phantom: std::marker::PhantomData::<T> {},
128 })
129 }
130
131 /// Write actual values in the buffer-slot we got during `alloc()`
set_value_at( &mut self, buffer: &mut Cursor<Vec<u8>>, val: T, index: usize, ) -> Result<()>132 pub fn set_value_at(
133 &mut self,
134 buffer: &mut Cursor<Vec<u8>>,
135 val: T,
136 index: usize,
137 ) -> Result<()> {
138 // Save whereever the current cursor stands in the buffer
139 let curr_pos = buffer.position();
140
141 // Write the actual value we want at our position that
142 // was determined by `alloc()` into the buffer
143 buffer.set_position(self.position as u64 + (std::mem::size_of::<T>() * index) as u64);
144 let bytes = unsafe {
145 std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::<T>())
146 };
147 let res = buffer.write_all(bytes);
148
149 // Resetting whereever we were before updating this
150 // regardless of the write-result
151 buffer.set_position(curr_pos);
152
153 res?;
154 Ok(())
155 }
156
location(&self) -> MDLocationDescriptor157 pub fn location(&self) -> MDLocationDescriptor {
158 MDLocationDescriptor {
159 data_size: (self.array_size * std::mem::size_of::<T>()) as u32,
160 rva: self.position,
161 }
162 }
163
location_of_index(&self, idx: usize) -> MDLocationDescriptor164 pub fn location_of_index(&self, idx: usize) -> MDLocationDescriptor {
165 MDLocationDescriptor {
166 data_size: std::mem::size_of::<T>() as u32,
167 rva: self.position + (std::mem::size_of::<T>() * idx) as u32,
168 }
169 }
170 }
171
write_string_to_location( buffer: &mut Cursor<Vec<u8>>, text: &str, ) -> Result<MDLocationDescriptor>172 pub fn write_string_to_location(
173 buffer: &mut Cursor<Vec<u8>>,
174 text: &str,
175 ) -> Result<MDLocationDescriptor> {
176 let letters: Vec<u16> = text.encode_utf16().collect();
177
178 // First write size of the string (x letters in u16, times the size of u16)
179 let text_header = MemoryWriter::<u32>::alloc_with_val(
180 buffer,
181 (letters.len() * std::mem::size_of::<u16>()).try_into()?,
182 )?;
183
184 // Then write utf-16 letters after that
185 let mut text_section = MemoryArrayWriter::<u16>::alloc_array(buffer, letters.len())?;
186 for (index, letter) in letters.iter().enumerate() {
187 text_section.set_value_at(buffer, *letter, index)?;
188 }
189
190 let mut location = text_header.location();
191 location.data_size += text_section.location().data_size;
192
193 Ok(location)
194 }
195