Skip to main content

gimli/write/
writer.rs

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