1 | use crate::common::{Format, SectionId}; |
2 | use crate::constants; |
3 | use crate::endianity::Endianity; |
4 | use crate::leb128; |
5 | use crate::write::{Address, Error, Result}; |
6 | |
7 | /// A trait for writing the data to a DWARF section. |
8 | /// |
9 | /// All write operations append to the section unless otherwise specified. |
10 | #[allow (clippy::len_without_is_empty)] |
11 | pub trait Writer { |
12 | /// The endianity of bytes that are written. |
13 | type Endian: Endianity; |
14 | |
15 | /// Return the endianity of bytes that are written. |
16 | fn endian(&self) -> Self::Endian; |
17 | |
18 | /// Return the current section length. |
19 | /// |
20 | /// This may be used as an offset for future `write_at` calls. |
21 | fn len(&self) -> usize; |
22 | |
23 | /// Write a slice. |
24 | fn write(&mut self, bytes: &[u8]) -> Result<()>; |
25 | |
26 | /// Write a slice at a given offset. |
27 | /// |
28 | /// The write must not extend past the current section length. |
29 | fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; |
30 | |
31 | /// Write an address. |
32 | /// |
33 | /// If the writer supports relocations, then it must provide its own implementation |
34 | /// of this method. |
35 | // TODO: use write_reference instead? |
36 | fn write_address(&mut self, address: Address, size: u8) -> Result<()> { |
37 | match address { |
38 | Address::Constant(val) => self.write_udata(val, size), |
39 | Address::Symbol { .. } => Err(Error::InvalidAddress), |
40 | } |
41 | } |
42 | |
43 | /// Write an address with a `.eh_frame` pointer encoding. |
44 | /// |
45 | /// The given size is only used for `DW_EH_PE_absptr` formats. |
46 | /// |
47 | /// If the writer supports relocations, then it must provide its own implementation |
48 | /// of this method. |
49 | fn write_eh_pointer( |
50 | &mut self, |
51 | address: Address, |
52 | eh_pe: constants::DwEhPe, |
53 | size: u8, |
54 | ) -> Result<()> { |
55 | match address { |
56 | Address::Constant(val) => { |
57 | // Indirect doesn't matter here. |
58 | let val = match eh_pe.application() { |
59 | constants::DW_EH_PE_absptr => val, |
60 | constants::DW_EH_PE_pcrel => { |
61 | // TODO: better handling of sign |
62 | let offset = self.len() as u64; |
63 | val.wrapping_sub(offset) |
64 | } |
65 | _ => { |
66 | return Err(Error::UnsupportedPointerEncoding(eh_pe)); |
67 | } |
68 | }; |
69 | self.write_eh_pointer_data(val, eh_pe.format(), size) |
70 | } |
71 | Address::Symbol { .. } => Err(Error::InvalidAddress), |
72 | } |
73 | } |
74 | |
75 | /// Write a value with a `.eh_frame` pointer format. |
76 | /// |
77 | /// The given size is only used for `DW_EH_PE_absptr` formats. |
78 | /// |
79 | /// This must not be used directly for values that may require relocation. |
80 | fn write_eh_pointer_data( |
81 | &mut self, |
82 | val: u64, |
83 | format: constants::DwEhPe, |
84 | size: u8, |
85 | ) -> Result<()> { |
86 | match format { |
87 | constants::DW_EH_PE_absptr => self.write_udata(val, size), |
88 | constants::DW_EH_PE_uleb128 => self.write_uleb128(val), |
89 | constants::DW_EH_PE_udata2 => self.write_udata(val, 2), |
90 | constants::DW_EH_PE_udata4 => self.write_udata(val, 4), |
91 | constants::DW_EH_PE_udata8 => self.write_udata(val, 8), |
92 | constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64), |
93 | constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2), |
94 | constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4), |
95 | constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8), |
96 | _ => Err(Error::UnsupportedPointerEncoding(format)), |
97 | } |
98 | } |
99 | |
100 | /// Write an offset that is relative to the start of the given section. |
101 | /// |
102 | /// If the writer supports relocations, then it must provide its own implementation |
103 | /// of this method. |
104 | fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> { |
105 | self.write_udata(val as u64, size) |
106 | } |
107 | |
108 | /// Write an offset that is relative to the start of the given section. |
109 | /// |
110 | /// If the writer supports relocations, then it must provide its own implementation |
111 | /// of this method. |
112 | fn write_offset_at( |
113 | &mut self, |
114 | offset: usize, |
115 | val: usize, |
116 | _section: SectionId, |
117 | size: u8, |
118 | ) -> Result<()> { |
119 | self.write_udata_at(offset, val as u64, size) |
120 | } |
121 | |
122 | /// Write a reference to a symbol. |
123 | /// |
124 | /// If the writer supports symbols, then it must provide its own implementation |
125 | /// of this method. |
126 | fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> { |
127 | Err(Error::InvalidReference) |
128 | } |
129 | |
130 | /// Write a u8. |
131 | fn write_u8(&mut self, val: u8) -> Result<()> { |
132 | let bytes = [val]; |
133 | self.write(&bytes) |
134 | } |
135 | |
136 | /// Write a u16. |
137 | fn write_u16(&mut self, val: u16) -> Result<()> { |
138 | let mut bytes = [0; 2]; |
139 | self.endian().write_u16(&mut bytes, val); |
140 | self.write(&bytes) |
141 | } |
142 | |
143 | /// Write a u32. |
144 | fn write_u32(&mut self, val: u32) -> Result<()> { |
145 | let mut bytes = [0; 4]; |
146 | self.endian().write_u32(&mut bytes, val); |
147 | self.write(&bytes) |
148 | } |
149 | |
150 | /// Write a u64. |
151 | fn write_u64(&mut self, val: u64) -> Result<()> { |
152 | let mut bytes = [0; 8]; |
153 | self.endian().write_u64(&mut bytes, val); |
154 | self.write(&bytes) |
155 | } |
156 | |
157 | /// Write a u8 at the given offset. |
158 | fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> { |
159 | let bytes = [val]; |
160 | self.write_at(offset, &bytes) |
161 | } |
162 | |
163 | /// Write a u16 at the given offset. |
164 | fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> { |
165 | let mut bytes = [0; 2]; |
166 | self.endian().write_u16(&mut bytes, val); |
167 | self.write_at(offset, &bytes) |
168 | } |
169 | |
170 | /// Write a u32 at the given offset. |
171 | fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> { |
172 | let mut bytes = [0; 4]; |
173 | self.endian().write_u32(&mut bytes, val); |
174 | self.write_at(offset, &bytes) |
175 | } |
176 | |
177 | /// Write a u64 at the given offset. |
178 | fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> { |
179 | let mut bytes = [0; 8]; |
180 | self.endian().write_u64(&mut bytes, val); |
181 | self.write_at(offset, &bytes) |
182 | } |
183 | |
184 | /// Write unsigned data of the given size. |
185 | /// |
186 | /// Returns an error if the value is too large for the size. |
187 | /// This must not be used directly for values that may require relocation. |
188 | fn write_udata(&mut self, val: u64, size: u8) -> Result<()> { |
189 | match size { |
190 | 1 => { |
191 | let write_val = val as u8; |
192 | if val != u64::from(write_val) { |
193 | return Err(Error::ValueTooLarge); |
194 | } |
195 | self.write_u8(write_val) |
196 | } |
197 | 2 => { |
198 | let write_val = val as u16; |
199 | if val != u64::from(write_val) { |
200 | return Err(Error::ValueTooLarge); |
201 | } |
202 | self.write_u16(write_val) |
203 | } |
204 | 4 => { |
205 | let write_val = val as u32; |
206 | if val != u64::from(write_val) { |
207 | return Err(Error::ValueTooLarge); |
208 | } |
209 | self.write_u32(write_val) |
210 | } |
211 | 8 => self.write_u64(val), |
212 | otherwise => Err(Error::UnsupportedWordSize(otherwise)), |
213 | } |
214 | } |
215 | |
216 | /// Write signed data of the given size. |
217 | /// |
218 | /// Returns an error if the value is too large for the size. |
219 | /// This must not be used directly for values that may require relocation. |
220 | fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> { |
221 | match size { |
222 | 1 => { |
223 | let write_val = val as i8; |
224 | if val != i64::from(write_val) { |
225 | return Err(Error::ValueTooLarge); |
226 | } |
227 | self.write_u8(write_val as u8) |
228 | } |
229 | 2 => { |
230 | let write_val = val as i16; |
231 | if val != i64::from(write_val) { |
232 | return Err(Error::ValueTooLarge); |
233 | } |
234 | self.write_u16(write_val as u16) |
235 | } |
236 | 4 => { |
237 | let write_val = val as i32; |
238 | if val != i64::from(write_val) { |
239 | return Err(Error::ValueTooLarge); |
240 | } |
241 | self.write_u32(write_val as u32) |
242 | } |
243 | 8 => self.write_u64(val as u64), |
244 | otherwise => Err(Error::UnsupportedWordSize(otherwise)), |
245 | } |
246 | } |
247 | |
248 | /// Write a word of the given size at the given offset. |
249 | /// |
250 | /// Returns an error if the value is too large for the size. |
251 | /// This must not be used directly for values that may require relocation. |
252 | fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> { |
253 | match size { |
254 | 1 => { |
255 | let write_val = val as u8; |
256 | if val != u64::from(write_val) { |
257 | return Err(Error::ValueTooLarge); |
258 | } |
259 | self.write_u8_at(offset, write_val) |
260 | } |
261 | 2 => { |
262 | let write_val = val as u16; |
263 | if val != u64::from(write_val) { |
264 | return Err(Error::ValueTooLarge); |
265 | } |
266 | self.write_u16_at(offset, write_val) |
267 | } |
268 | 4 => { |
269 | let write_val = val as u32; |
270 | if val != u64::from(write_val) { |
271 | return Err(Error::ValueTooLarge); |
272 | } |
273 | self.write_u32_at(offset, write_val) |
274 | } |
275 | 8 => self.write_u64_at(offset, val), |
276 | otherwise => Err(Error::UnsupportedWordSize(otherwise)), |
277 | } |
278 | } |
279 | |
280 | /// Write an unsigned LEB128 encoded integer. |
281 | fn write_uleb128(&mut self, val: u64) -> Result<()> { |
282 | let mut bytes = [0u8; 10]; |
283 | // bytes is long enough so this will never fail. |
284 | let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); |
285 | self.write(&bytes[..len]) |
286 | } |
287 | |
288 | /// Read an unsigned LEB128 encoded integer. |
289 | fn write_sleb128(&mut self, val: i64) -> Result<()> { |
290 | let mut bytes = [0u8; 10]; |
291 | // bytes is long enough so this will never fail. |
292 | let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap(); |
293 | self.write(&bytes[..len]) |
294 | } |
295 | |
296 | /// Write an initial length according to the given DWARF format. |
297 | /// |
298 | /// This will only write a length of zero, since the length isn't |
299 | /// known yet, and a subsequent call to `write_initial_length_at` |
300 | /// will write the actual length. |
301 | fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> { |
302 | if format == Format::Dwarf64 { |
303 | self.write_u32(0xffff_ffff)?; |
304 | } |
305 | let offset = InitialLengthOffset(self.len()); |
306 | self.write_udata(0, format.word_size())?; |
307 | Ok(offset) |
308 | } |
309 | |
310 | /// Write an initial length at the given offset according to the given DWARF format. |
311 | /// |
312 | /// `write_initial_length` must have previously returned the offset. |
313 | fn write_initial_length_at( |
314 | &mut self, |
315 | offset: InitialLengthOffset, |
316 | length: u64, |
317 | format: Format, |
318 | ) -> Result<()> { |
319 | self.write_udata_at(offset.0, length, format.word_size()) |
320 | } |
321 | } |
322 | |
323 | /// The offset at which an initial length should be written. |
324 | #[derive(Debug, Clone, Copy)] |
325 | pub struct InitialLengthOffset(usize); |
326 | |
327 | #[cfg (test)] |
328 | mod tests { |
329 | use super::*; |
330 | use crate::write; |
331 | use crate::{BigEndian, LittleEndian}; |
332 | use std::{i64, u64}; |
333 | |
334 | #[test] |
335 | fn test_writer() { |
336 | let mut w = write::EndianVec::new(LittleEndian); |
337 | w.write_address(Address::Constant(0x1122_3344), 4).unwrap(); |
338 | assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); |
339 | assert_eq!( |
340 | w.write_address( |
341 | Address::Symbol { |
342 | symbol: 0, |
343 | addend: 0 |
344 | }, |
345 | 4 |
346 | ), |
347 | Err(Error::InvalidAddress) |
348 | ); |
349 | |
350 | let mut w = write::EndianVec::new(LittleEndian); |
351 | w.write_offset(0x1122_3344, SectionId::DebugInfo, 4) |
352 | .unwrap(); |
353 | assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); |
354 | w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2) |
355 | .unwrap(); |
356 | assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]); |
357 | |
358 | let mut w = write::EndianVec::new(LittleEndian); |
359 | w.write_u8(0x11).unwrap(); |
360 | w.write_u16(0x2233).unwrap(); |
361 | w.write_u32(0x4455_6677).unwrap(); |
362 | w.write_u64(0x8081_8283_8485_8687).unwrap(); |
363 | #[rustfmt::skip] |
364 | assert_eq!(w.slice(), &[ |
365 | 0x11, |
366 | 0x33, 0x22, |
367 | 0x77, 0x66, 0x55, 0x44, |
368 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, |
369 | ]); |
370 | w.write_u8_at(14, 0x11).unwrap(); |
371 | w.write_u16_at(12, 0x2233).unwrap(); |
372 | w.write_u32_at(8, 0x4455_6677).unwrap(); |
373 | w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); |
374 | #[rustfmt::skip] |
375 | assert_eq!(w.slice(), &[ |
376 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, |
377 | 0x77, 0x66, 0x55, 0x44, |
378 | 0x33, 0x22, |
379 | 0x11, |
380 | ]); |
381 | |
382 | let mut w = write::EndianVec::new(BigEndian); |
383 | w.write_u8(0x11).unwrap(); |
384 | w.write_u16(0x2233).unwrap(); |
385 | w.write_u32(0x4455_6677).unwrap(); |
386 | w.write_u64(0x8081_8283_8485_8687).unwrap(); |
387 | #[rustfmt::skip] |
388 | assert_eq!(w.slice(), &[ |
389 | 0x11, |
390 | 0x22, 0x33, |
391 | 0x44, 0x55, 0x66, 0x77, |
392 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, |
393 | ]); |
394 | w.write_u8_at(14, 0x11).unwrap(); |
395 | w.write_u16_at(12, 0x2233).unwrap(); |
396 | w.write_u32_at(8, 0x4455_6677).unwrap(); |
397 | w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); |
398 | #[rustfmt::skip] |
399 | assert_eq!(w.slice(), &[ |
400 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, |
401 | 0x44, 0x55, 0x66, 0x77, |
402 | 0x22, 0x33, |
403 | 0x11, |
404 | ]); |
405 | |
406 | let mut w = write::EndianVec::new(LittleEndian); |
407 | w.write_udata(0x11, 1).unwrap(); |
408 | w.write_udata(0x2233, 2).unwrap(); |
409 | w.write_udata(0x4455_6677, 4).unwrap(); |
410 | w.write_udata(0x8081_8283_8485_8687, 8).unwrap(); |
411 | #[rustfmt::skip] |
412 | assert_eq!(w.slice(), &[ |
413 | 0x11, |
414 | 0x33, 0x22, |
415 | 0x77, 0x66, 0x55, 0x44, |
416 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, |
417 | ]); |
418 | assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge)); |
419 | assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge)); |
420 | assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge)); |
421 | assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3))); |
422 | w.write_udata_at(14, 0x11, 1).unwrap(); |
423 | w.write_udata_at(12, 0x2233, 2).unwrap(); |
424 | w.write_udata_at(8, 0x4455_6677, 4).unwrap(); |
425 | w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap(); |
426 | #[rustfmt::skip] |
427 | assert_eq!(w.slice(), &[ |
428 | 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, |
429 | 0x77, 0x66, 0x55, 0x44, |
430 | 0x33, 0x22, |
431 | 0x11, |
432 | ]); |
433 | assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge)); |
434 | assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge)); |
435 | assert_eq!( |
436 | w.write_udata_at(0, 0x1_0000_0000, 4), |
437 | Err(Error::ValueTooLarge) |
438 | ); |
439 | assert_eq!( |
440 | w.write_udata_at(0, 0x00, 3), |
441 | Err(Error::UnsupportedWordSize(3)) |
442 | ); |
443 | |
444 | let mut w = write::EndianVec::new(LittleEndian); |
445 | w.write_uleb128(0).unwrap(); |
446 | assert_eq!(w.slice(), &[0]); |
447 | |
448 | let mut w = write::EndianVec::new(LittleEndian); |
449 | w.write_uleb128(u64::MAX).unwrap(); |
450 | assert_eq!( |
451 | w.slice(), |
452 | &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1] |
453 | ); |
454 | |
455 | let mut w = write::EndianVec::new(LittleEndian); |
456 | w.write_sleb128(0).unwrap(); |
457 | assert_eq!(w.slice(), &[0]); |
458 | |
459 | let mut w = write::EndianVec::new(LittleEndian); |
460 | w.write_sleb128(i64::MAX).unwrap(); |
461 | assert_eq!( |
462 | w.slice(), |
463 | &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0] |
464 | ); |
465 | |
466 | let mut w = write::EndianVec::new(LittleEndian); |
467 | w.write_sleb128(i64::MIN).unwrap(); |
468 | assert_eq!( |
469 | w.slice(), |
470 | &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f] |
471 | ); |
472 | |
473 | let mut w = write::EndianVec::new(LittleEndian); |
474 | let offset = w.write_initial_length(Format::Dwarf32).unwrap(); |
475 | assert_eq!(w.slice(), &[0, 0, 0, 0]); |
476 | w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32) |
477 | .unwrap(); |
478 | assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); |
479 | assert_eq!( |
480 | w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32), |
481 | Err(Error::ValueTooLarge) |
482 | ); |
483 | |
484 | let mut w = write::EndianVec::new(LittleEndian); |
485 | let offset = w.write_initial_length(Format::Dwarf64).unwrap(); |
486 | assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]); |
487 | w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64) |
488 | .unwrap(); |
489 | assert_eq!( |
490 | w.slice(), |
491 | &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11] |
492 | ); |
493 | } |
494 | } |
495 | |