1use {
2 crate::{
3 minidump_format::{MDLocationDescriptor, MDRVA},
4 serializers::*,
5 },
6 scroll::ctx::{SizeWith, TryIntoCtx},
7};
8
9#[derive(Debug, thiserror::Error, serde::Serialize)]
10pub enum MemoryWriterError {
11 #[error("IO error when writing to DumpBuf")]
12 IOError(
13 #[from]
14 #[serde(serialize_with = "serialize_io_error")]
15 std::io::Error,
16 ),
17 #[error("Failed integer conversion")]
18 TryFromIntError(
19 #[from]
20 #[serde(skip)]
21 std::num::TryFromIntError,
22 ),
23 #[error("Failed to write to buffer")]
24 Scroll(
25 #[from]
26 #[serde(serialize_with = "serialize_scroll_error")]
27 scroll::Error,
28 ),
29}
30
31type WriteResult<T> = std::result::Result<T, MemoryWriterError>;
32
33macro_rules! size {
34 ($t:ty) => {
35 <$t>::size_with(&scroll::Endian::Little)
36 };
37}
38
39pub struct Buffer {
40 inner: Vec<u8>,
41}
42
43impl Buffer {
44 pub fn with_capacity(cap: usize) -> Self {
45 Self {
46 inner: Vec::with_capacity(cap),
47 }
48 }
49
50 #[inline]
51 pub fn position(&self) -> u64 {
52 self.inner.len() as u64
53 }
54
55 #[inline]
56 #[must_use]
57 fn reserve(&mut self, len: usize) -> usize {
58 let mark = self.inner.len();
59 self.inner.resize(self.inner.len() + len, 0);
60 mark
61 }
62
63 #[inline]
64 fn write<N, E>(&mut self, val: N) -> Result<usize, E>
65 where
66 N: TryIntoCtx<scroll::Endian, Error = E> + SizeWith<scroll::Endian>,
67 E: From<scroll::Error>,
68 {
69 self.write_at(self.inner.len(), val)
70 }
71
72 fn write_at<N, E>(&mut self, offset: usize, val: N) -> Result<usize, E>
73 where
74 N: TryIntoCtx<scroll::Endian, Error = E> + SizeWith<scroll::Endian>,
75 E: From<scroll::Error>,
76 {
77 let to_write = size!(N);
78 let remainder = self.inner.len() - offset;
79 if remainder < to_write {
80 self.inner
81 .resize(self.inner.len() + to_write - remainder, 0);
82 }
83
84 let dst = &mut self.inner[offset..offset + to_write];
85 val.try_into_ctx(dst, scroll::Endian::Little)
86 }
87
88 #[inline]
89 pub fn write_all(&mut self, buffer: &[u8]) {
90 self.inner.extend_from_slice(buffer);
91 }
92}
93
94impl From<Buffer> for Vec<u8> {
95 fn from(b: Buffer) -> Self {
96 b.inner
97 }
98}
99
100impl std::ops::Deref for Buffer {
101 type Target = [u8];
102
103 fn deref(&self) -> &Self::Target {
104 &self.inner
105 }
106}
107
108#[derive(Debug)]
109pub struct MemoryWriter<T> {
110 pub position: MDRVA,
111 pub size: usize,
112 phantom: std::marker::PhantomData<T>,
113}
114
115impl<T> MemoryWriter<T>
116where
117 T: TryIntoCtx<scroll::Endian, Error = scroll::Error> + SizeWith<scroll::Endian>,
118{
119 pub fn alloc_with_val(buffer: &mut Buffer, val: T) -> WriteResult<Self> {
121 let position = buffer.position();
123 let size = buffer.write(val)?;
124
125 Ok(Self {
126 position: position as u32,
127 size,
128 phantom: std::marker::PhantomData,
129 })
130 }
131
132 pub fn alloc(buffer: &mut Buffer) -> WriteResult<Self> {
134 let size = size!(T);
135 let position = buffer.reserve(size) as u32;
136
137 Ok(Self {
138 position,
139 size,
140 phantom: std::marker::PhantomData,
141 })
142 }
143
144 #[inline]
146 pub fn set_value(&mut self, buffer: &mut Buffer, val: T) -> WriteResult<()> {
147 Ok(buffer.write_at(self.position as usize, val).map(|_sz| ())?)
148 }
149
150 #[inline]
151 pub fn location(&self) -> MDLocationDescriptor {
152 MDLocationDescriptor {
153 data_size: size!(T) as u32,
154 rva: self.position,
155 }
156 }
157}
158
159#[derive(Debug)]
160pub struct MemoryArrayWriter<T> {
161 pub position: MDRVA,
162 array_size: usize,
163 phantom: std::marker::PhantomData<T>,
164}
165
166#[cfg(any(target_os = "linux", target_os = "android"))]
167impl MemoryArrayWriter<u8> {
168 #[inline]
169 pub fn write_bytes(buffer: &mut Buffer, slice: &[u8]) -> Self {
170 let position = buffer.position();
171 buffer.write_all(slice);
172
173 Self {
174 position: position as u32,
175 array_size: slice.len(),
176 phantom: std::marker::PhantomData,
177 }
178 }
179}
180
181impl<T> MemoryArrayWriter<T>
182where
183 T: TryIntoCtx<scroll::Endian, Error = scroll::Error> + SizeWith<scroll::Endian> + Copy,
184{
185 pub fn alloc_from_array(buffer: &mut Buffer, array: &[T]) -> WriteResult<Self> {
186 let array_size = array.len();
187 let position = buffer.reserve(array_size * size!(T));
188
189 for (idx, val) in array.iter().enumerate() {
190 buffer.write_at(position + idx * size!(T), *val)?;
191 }
192
193 Ok(Self {
194 position: position as u32,
195 array_size,
196 phantom: std::marker::PhantomData,
197 })
198 }
199}
200
201impl<T> MemoryArrayWriter<T>
202where
203 T: TryIntoCtx<scroll::Endian, Error = scroll::Error> + SizeWith<scroll::Endian>,
204{
205 pub fn alloc_from_iter<I>(
207 buffer: &mut Buffer,
208 iter: impl IntoIterator<Item = T, IntoIter = I>,
209 ) -> WriteResult<Self>
210 where
211 I: std::iter::ExactSizeIterator<Item = T>,
212 {
213 let iter = iter.into_iter();
214 let array_size = iter.len();
215 let size = size!(T);
216 let position = buffer.reserve(array_size * size);
217
218 for (idx, val) in iter.enumerate() {
219 buffer.write_at(position + idx * size, val)?;
220 }
221
222 Ok(Self {
223 position: position as u32,
224 array_size,
225 phantom: std::marker::PhantomData,
226 })
227 }
228
229 pub fn alloc_array(buffer: &mut Buffer, array_size: usize) -> WriteResult<Self> {
233 let position = buffer.reserve(array_size * size!(T));
234
235 Ok(Self {
236 position: position as u32,
237 array_size,
238 phantom: std::marker::PhantomData,
239 })
240 }
241
242 #[inline]
244 pub fn set_value_at(&mut self, buffer: &mut Buffer, val: T, index: usize) -> WriteResult<()> {
245 Ok(buffer
246 .write_at(self.position as usize + size!(T) * index, val)
247 .map(|_sz| ())?)
248 }
249
250 #[inline]
251 pub fn location(&self) -> MDLocationDescriptor {
252 MDLocationDescriptor {
253 data_size: (self.array_size * size!(T)) as u32,
254 rva: self.position,
255 }
256 }
257
258 #[inline]
259 pub fn location_of_index(&self, idx: usize) -> MDLocationDescriptor {
260 MDLocationDescriptor {
261 data_size: size!(T) as u32,
262 rva: self.position + (size!(T) * idx) as u32,
263 }
264 }
265}
266
267pub fn write_string_to_location(
268 buffer: &mut Buffer,
269 text: &str,
270) -> WriteResult<MDLocationDescriptor> {
271 let letters: Vec<u16> = text.encode_utf16().collect();
272
273 let text_header = MemoryWriter::<u32>::alloc_with_val(
275 buffer,
276 (letters.len() * std::mem::size_of::<u16>()).try_into()?,
277 )?;
278
279 let mut text_section = MemoryArrayWriter::<u16>::alloc_array(buffer, letters.len())?;
281 for (index, letter) in letters.iter().enumerate() {
282 text_section.set_value_at(buffer, *letter, index)?;
283 }
284
285 let mut location = text_header.location();
286 location.data_size += text_section.location().data_size;
287
288 Ok(location)
289}