]> git.proxmox.com Git - rustc.git/blob - vendor/gimli/src/write/writer.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / vendor / gimli / src / write / writer.rs
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 offset.wrapping_sub(val)
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 _ => {
97 return Err(Error::UnsupportedPointerEncoding(format));
98 }
99 }
100 }
101
102 /// Write an offset that is relative to the start of the given section.
103 ///
104 /// If the writer supports relocations, then it must provide its own implementation
105 /// of this method.
106 fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> {
107 self.write_udata(val as u64, size)
108 }
109
110 /// Write an offset that is relative to the start of the given section.
111 ///
112 /// If the writer supports relocations, then it must provide its own implementation
113 /// of this method.
114 fn write_offset_at(
115 &mut self,
116 offset: usize,
117 val: usize,
118 _section: SectionId,
119 size: u8,
120 ) -> Result<()> {
121 self.write_udata_at(offset, val as u64, size)
122 }
123
124 /// Write a reference to a symbol.
125 ///
126 /// If the writer supports symbols, then it must provide its own implementation
127 /// of this method.
128 fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> {
129 Err(Error::InvalidReference)
130 }
131
132 /// Write a u8.
133 fn write_u8(&mut self, val: u8) -> Result<()> {
134 let bytes = [val];
135 self.write(&bytes)
136 }
137
138 /// Write a u16.
139 fn write_u16(&mut self, val: u16) -> Result<()> {
140 let mut bytes = [0; 2];
141 self.endian().write_u16(&mut bytes, val);
142 self.write(&bytes)
143 }
144
145 /// Write a u32.
146 fn write_u32(&mut self, val: u32) -> Result<()> {
147 let mut bytes = [0; 4];
148 self.endian().write_u32(&mut bytes, val);
149 self.write(&bytes)
150 }
151
152 /// Write a u64.
153 fn write_u64(&mut self, val: u64) -> Result<()> {
154 let mut bytes = [0; 8];
155 self.endian().write_u64(&mut bytes, val);
156 self.write(&bytes)
157 }
158
159 /// Write a u8 at the given offset.
160 fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> {
161 let bytes = [val];
162 self.write_at(offset, &bytes)
163 }
164
165 /// Write a u16 at the given offset.
166 fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> {
167 let mut bytes = [0; 2];
168 self.endian().write_u16(&mut bytes, val);
169 self.write_at(offset, &bytes)
170 }
171
172 /// Write a u32 at the given offset.
173 fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> {
174 let mut bytes = [0; 4];
175 self.endian().write_u32(&mut bytes, val);
176 self.write_at(offset, &bytes)
177 }
178
179 /// Write a u64 at the given offset.
180 fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> {
181 let mut bytes = [0; 8];
182 self.endian().write_u64(&mut bytes, val);
183 self.write_at(offset, &bytes)
184 }
185
186 /// Write unsigned data of the given size.
187 ///
188 /// Returns an error if the value is too large for the size.
189 /// This must not be used directly for values that may require relocation.
190 fn write_udata(&mut self, val: u64, size: u8) -> Result<()> {
191 match size {
192 1 => {
193 let write_val = val as u8;
194 if val != u64::from(write_val) {
195 return Err(Error::ValueTooLarge);
196 }
197 self.write_u8(write_val)
198 }
199 2 => {
200 let write_val = val as u16;
201 if val != u64::from(write_val) {
202 return Err(Error::ValueTooLarge);
203 }
204 self.write_u16(write_val)
205 }
206 4 => {
207 let write_val = val as u32;
208 if val != u64::from(write_val) {
209 return Err(Error::ValueTooLarge);
210 }
211 self.write_u32(write_val)
212 }
213 8 => self.write_u64(val),
214 otherwise => Err(Error::UnsupportedWordSize(otherwise)),
215 }
216 }
217
218 /// Write signed data of the given size.
219 ///
220 /// Returns an error if the value is too large for the size.
221 /// This must not be used directly for values that may require relocation.
222 fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> {
223 match size {
224 1 => {
225 let write_val = val as i8;
226 if val != i64::from(write_val) {
227 return Err(Error::ValueTooLarge);
228 }
229 self.write_u8(write_val as u8)
230 }
231 2 => {
232 let write_val = val as i16;
233 if val != i64::from(write_val) {
234 return Err(Error::ValueTooLarge);
235 }
236 self.write_u16(write_val as u16)
237 }
238 4 => {
239 let write_val = val as i32;
240 if val != i64::from(write_val) {
241 return Err(Error::ValueTooLarge);
242 }
243 self.write_u32(write_val as u32)
244 }
245 8 => self.write_u64(val as u64),
246 otherwise => Err(Error::UnsupportedWordSize(otherwise)),
247 }
248 }
249
250 /// Write a word of the given size at the given offset.
251 ///
252 /// Returns an error if the value is too large for the size.
253 /// This must not be used directly for values that may require relocation.
254 fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> {
255 match size {
256 1 => {
257 let write_val = val as u8;
258 if val != u64::from(write_val) {
259 return Err(Error::ValueTooLarge);
260 }
261 self.write_u8_at(offset, write_val)
262 }
263 2 => {
264 let write_val = val as u16;
265 if val != u64::from(write_val) {
266 return Err(Error::ValueTooLarge);
267 }
268 self.write_u16_at(offset, write_val)
269 }
270 4 => {
271 let write_val = val as u32;
272 if val != u64::from(write_val) {
273 return Err(Error::ValueTooLarge);
274 }
275 self.write_u32_at(offset, write_val)
276 }
277 8 => self.write_u64_at(offset, val),
278 otherwise => Err(Error::UnsupportedWordSize(otherwise)),
279 }
280 }
281
282 /// Write an unsigned LEB128 encoded integer.
283 fn write_uleb128(&mut self, val: u64) -> Result<()> {
284 let mut bytes = [0u8; 10];
285 // bytes is long enough so this will never fail.
286 let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap();
287 self.write(&bytes[..len])
288 }
289
290 /// Read an unsigned LEB128 encoded integer.
291 fn write_sleb128(&mut self, val: i64) -> Result<()> {
292 let mut bytes = [0u8; 10];
293 // bytes is long enough so this will never fail.
294 let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap();
295 self.write(&bytes[..len])
296 }
297
298 /// Write an initial length according to the given DWARF format.
299 ///
300 /// This will only write a length of zero, since the length isn't
301 /// known yet, and a subsequent call to `write_initial_length_at`
302 /// will write the actual length.
303 fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> {
304 if format == Format::Dwarf64 {
305 self.write_u32(0xffff_ffff)?;
306 }
307 let offset = InitialLengthOffset(self.len());
308 self.write_udata(0, format.word_size())?;
309 Ok(offset)
310 }
311
312 /// Write an initial length at the given offset according to the given DWARF format.
313 ///
314 /// `write_initial_length` must have previously returned the offset.
315 fn write_initial_length_at(
316 &mut self,
317 offset: InitialLengthOffset,
318 length: u64,
319 format: Format,
320 ) -> Result<()> {
321 self.write_udata_at(offset.0, length, format.word_size())
322 }
323 }
324
325 /// The offset at which an initial length should be written.
326 #[derive(Debug, Clone, Copy)]
327 pub struct InitialLengthOffset(usize);
328
329 #[cfg(test)]
330 mod tests {
331 use super::*;
332 use crate::write;
333 use crate::{BigEndian, LittleEndian};
334 use std::{i64, u64};
335
336 #[test]
337 #[allow(clippy::cyclomatic_complexity)]
338 fn test_writer() {
339 let mut w = write::EndianVec::new(LittleEndian);
340 w.write_address(Address::Constant(0x1122_3344), 4).unwrap();
341 assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
342 assert_eq!(
343 w.write_address(
344 Address::Symbol {
345 symbol: 0,
346 addend: 0
347 },
348 4
349 ),
350 Err(Error::InvalidAddress)
351 );
352
353 let mut w = write::EndianVec::new(LittleEndian);
354 w.write_offset(0x1122_3344, SectionId::DebugInfo, 4)
355 .unwrap();
356 assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
357 w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2)
358 .unwrap();
359 assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]);
360
361 let mut w = write::EndianVec::new(LittleEndian);
362 w.write_u8(0x11).unwrap();
363 w.write_u16(0x2233).unwrap();
364 w.write_u32(0x4455_6677).unwrap();
365 w.write_u64(0x8081_8283_8485_8687).unwrap();
366 #[rustfmt::skip]
367 assert_eq!(w.slice(), &[
368 0x11,
369 0x33, 0x22,
370 0x77, 0x66, 0x55, 0x44,
371 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
372 ]);
373 w.write_u8_at(14, 0x11).unwrap();
374 w.write_u16_at(12, 0x2233).unwrap();
375 w.write_u32_at(8, 0x4455_6677).unwrap();
376 w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
377 #[rustfmt::skip]
378 assert_eq!(w.slice(), &[
379 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
380 0x77, 0x66, 0x55, 0x44,
381 0x33, 0x22,
382 0x11,
383 ]);
384
385 let mut w = write::EndianVec::new(BigEndian);
386 w.write_u8(0x11).unwrap();
387 w.write_u16(0x2233).unwrap();
388 w.write_u32(0x4455_6677).unwrap();
389 w.write_u64(0x8081_8283_8485_8687).unwrap();
390 #[rustfmt::skip]
391 assert_eq!(w.slice(), &[
392 0x11,
393 0x22, 0x33,
394 0x44, 0x55, 0x66, 0x77,
395 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
396 ]);
397 w.write_u8_at(14, 0x11).unwrap();
398 w.write_u16_at(12, 0x2233).unwrap();
399 w.write_u32_at(8, 0x4455_6677).unwrap();
400 w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
401 #[rustfmt::skip]
402 assert_eq!(w.slice(), &[
403 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
404 0x44, 0x55, 0x66, 0x77,
405 0x22, 0x33,
406 0x11,
407 ]);
408
409 let mut w = write::EndianVec::new(LittleEndian);
410 w.write_udata(0x11, 1).unwrap();
411 w.write_udata(0x2233, 2).unwrap();
412 w.write_udata(0x4455_6677, 4).unwrap();
413 w.write_udata(0x8081_8283_8485_8687, 8).unwrap();
414 #[rustfmt::skip]
415 assert_eq!(w.slice(), &[
416 0x11,
417 0x33, 0x22,
418 0x77, 0x66, 0x55, 0x44,
419 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
420 ]);
421 assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge));
422 assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge));
423 assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge));
424 assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3)));
425 w.write_udata_at(14, 0x11, 1).unwrap();
426 w.write_udata_at(12, 0x2233, 2).unwrap();
427 w.write_udata_at(8, 0x4455_6677, 4).unwrap();
428 w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap();
429 #[rustfmt::skip]
430 assert_eq!(w.slice(), &[
431 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
432 0x77, 0x66, 0x55, 0x44,
433 0x33, 0x22,
434 0x11,
435 ]);
436 assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge));
437 assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge));
438 assert_eq!(
439 w.write_udata_at(0, 0x1_0000_0000, 4),
440 Err(Error::ValueTooLarge)
441 );
442 assert_eq!(
443 w.write_udata_at(0, 0x00, 3),
444 Err(Error::UnsupportedWordSize(3))
445 );
446
447 let mut w = write::EndianVec::new(LittleEndian);
448 w.write_uleb128(0).unwrap();
449 assert_eq!(w.slice(), &[0]);
450
451 let mut w = write::EndianVec::new(LittleEndian);
452 w.write_uleb128(u64::MAX).unwrap();
453 assert_eq!(
454 w.slice(),
455 &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
456 );
457
458 let mut w = write::EndianVec::new(LittleEndian);
459 w.write_sleb128(0).unwrap();
460 assert_eq!(w.slice(), &[0]);
461
462 let mut w = write::EndianVec::new(LittleEndian);
463 w.write_sleb128(i64::MAX).unwrap();
464 assert_eq!(
465 w.slice(),
466 &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0]
467 );
468
469 let mut w = write::EndianVec::new(LittleEndian);
470 w.write_sleb128(i64::MIN).unwrap();
471 assert_eq!(
472 w.slice(),
473 &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f]
474 );
475
476 let mut w = write::EndianVec::new(LittleEndian);
477 let offset = w.write_initial_length(Format::Dwarf32).unwrap();
478 assert_eq!(w.slice(), &[0, 0, 0, 0]);
479 w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32)
480 .unwrap();
481 assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
482 assert_eq!(
483 w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32),
484 Err(Error::ValueTooLarge)
485 );
486
487 let mut w = write::EndianVec::new(LittleEndian);
488 let offset = w.write_initial_length(Format::Dwarf64).unwrap();
489 assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]);
490 w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64)
491 .unwrap();
492 assert_eq!(
493 w.slice(),
494 &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]
495 );
496 }
497 }