Coverage Report

Created: 2025-08-26 06:08

/src/gimli/src/write/writer.rs
Line
Count
Source (jump to first uncovered line)
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
0
    fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
37
0
        match address {
38
0
            Address::Constant(val) => self.write_udata(val, size),
39
0
            Address::Symbol { .. } => Err(Error::InvalidAddress),
40
        }
41
0
    }
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
0
    fn write_eh_pointer(
50
0
        &mut self,
51
0
        address: Address,
52
0
        eh_pe: constants::DwEhPe,
53
0
        size: u8,
54
0
    ) -> Result<()> {
55
0
        match address {
56
0
            Address::Constant(val) => {
57
                // Indirect doesn't matter here.
58
0
                let val = match eh_pe.application() {
59
0
                    constants::DW_EH_PE_absptr => val,
60
                    constants::DW_EH_PE_pcrel => {
61
                        // TODO: better handling of sign
62
0
                        let offset = self.len() as u64;
63
0
                        val.wrapping_sub(offset)
64
                    }
65
                    _ => {
66
0
                        return Err(Error::UnsupportedPointerEncoding(eh_pe));
67
                    }
68
                };
69
0
                self.write_eh_pointer_data(val, eh_pe.format(), size)
70
            }
71
0
            Address::Symbol { .. } => Err(Error::InvalidAddress),
72
        }
73
0
    }
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
0
    fn write_eh_pointer_data(
81
0
        &mut self,
82
0
        val: u64,
83
0
        format: constants::DwEhPe,
84
0
        size: u8,
85
0
    ) -> Result<()> {
86
0
        match format {
87
0
            constants::DW_EH_PE_absptr => self.write_udata(val, size),
88
0
            constants::DW_EH_PE_uleb128 => self.write_uleb128(val),
89
0
            constants::DW_EH_PE_udata2 => self.write_udata(val, 2),
90
0
            constants::DW_EH_PE_udata4 => self.write_udata(val, 4),
91
0
            constants::DW_EH_PE_udata8 => self.write_udata(val, 8),
92
0
            constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64),
93
0
            constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2),
94
0
            constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4),
95
0
            constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8),
96
0
            _ => Err(Error::UnsupportedPointerEncoding(format)),
97
        }
98
0
    }
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
0
    fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> {
105
0
        self.write_udata(val as u64, size)
106
0
    }
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
0
    fn write_offset_at(
113
0
        &mut self,
114
0
        offset: usize,
115
0
        val: usize,
116
0
        _section: SectionId,
117
0
        size: u8,
118
0
    ) -> Result<()> {
119
0
        self.write_udata_at(offset, val as u64, size)
120
0
    }
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
0
    fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> {
127
0
        Err(Error::InvalidReference)
128
0
    }
129
130
    /// Write a u8.
131
0
    fn write_u8(&mut self, val: u8) -> Result<()> {
132
0
        let bytes = [val];
133
0
        self.write(&bytes)
134
0
    }
135
136
    /// Write a u16.
137
0
    fn write_u16(&mut self, val: u16) -> Result<()> {
138
0
        let mut bytes = [0; 2];
139
0
        self.endian().write_u16(&mut bytes, val);
140
0
        self.write(&bytes)
141
0
    }
142
143
    /// Write a u32.
144
0
    fn write_u32(&mut self, val: u32) -> Result<()> {
145
0
        let mut bytes = [0; 4];
146
0
        self.endian().write_u32(&mut bytes, val);
147
0
        self.write(&bytes)
148
0
    }
149
150
    /// Write a u64.
151
0
    fn write_u64(&mut self, val: u64) -> Result<()> {
152
0
        let mut bytes = [0; 8];
153
0
        self.endian().write_u64(&mut bytes, val);
154
0
        self.write(&bytes)
155
0
    }
156
157
    /// Write a u8 at the given offset.
158
0
    fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> {
159
0
        let bytes = [val];
160
0
        self.write_at(offset, &bytes)
161
0
    }
162
163
    /// Write a u16 at the given offset.
164
0
    fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> {
165
0
        let mut bytes = [0; 2];
166
0
        self.endian().write_u16(&mut bytes, val);
167
0
        self.write_at(offset, &bytes)
168
0
    }
169
170
    /// Write a u32 at the given offset.
171
0
    fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> {
172
0
        let mut bytes = [0; 4];
173
0
        self.endian().write_u32(&mut bytes, val);
174
0
        self.write_at(offset, &bytes)
175
0
    }
176
177
    /// Write a u64 at the given offset.
178
0
    fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> {
179
0
        let mut bytes = [0; 8];
180
0
        self.endian().write_u64(&mut bytes, val);
181
0
        self.write_at(offset, &bytes)
182
0
    }
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
0
    fn write_udata(&mut self, val: u64, size: u8) -> Result<()> {
189
0
        match size {
190
            1 => {
191
0
                let write_val = val as u8;
192
0
                if val != u64::from(write_val) {
193
0
                    return Err(Error::ValueTooLarge);
194
0
                }
195
0
                self.write_u8(write_val)
196
            }
197
            2 => {
198
0
                let write_val = val as u16;
199
0
                if val != u64::from(write_val) {
200
0
                    return Err(Error::ValueTooLarge);
201
0
                }
202
0
                self.write_u16(write_val)
203
            }
204
            4 => {
205
0
                let write_val = val as u32;
206
0
                if val != u64::from(write_val) {
207
0
                    return Err(Error::ValueTooLarge);
208
0
                }
209
0
                self.write_u32(write_val)
210
            }
211
0
            8 => self.write_u64(val),
212
0
            otherwise => Err(Error::UnsupportedWordSize(otherwise)),
213
        }
214
0
    }
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
0
    fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> {
221
0
        match size {
222
            1 => {
223
0
                let write_val = val as i8;
224
0
                if val != i64::from(write_val) {
225
0
                    return Err(Error::ValueTooLarge);
226
0
                }
227
0
                self.write_u8(write_val as u8)
228
            }
229
            2 => {
230
0
                let write_val = val as i16;
231
0
                if val != i64::from(write_val) {
232
0
                    return Err(Error::ValueTooLarge);
233
0
                }
234
0
                self.write_u16(write_val as u16)
235
            }
236
            4 => {
237
0
                let write_val = val as i32;
238
0
                if val != i64::from(write_val) {
239
0
                    return Err(Error::ValueTooLarge);
240
0
                }
241
0
                self.write_u32(write_val as u32)
242
            }
243
0
            8 => self.write_u64(val as u64),
244
0
            otherwise => Err(Error::UnsupportedWordSize(otherwise)),
245
        }
246
0
    }
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
0
    fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> {
253
0
        match size {
254
            1 => {
255
0
                let write_val = val as u8;
256
0
                if val != u64::from(write_val) {
257
0
                    return Err(Error::ValueTooLarge);
258
0
                }
259
0
                self.write_u8_at(offset, write_val)
260
            }
261
            2 => {
262
0
                let write_val = val as u16;
263
0
                if val != u64::from(write_val) {
264
0
                    return Err(Error::ValueTooLarge);
265
0
                }
266
0
                self.write_u16_at(offset, write_val)
267
            }
268
            4 => {
269
0
                let write_val = val as u32;
270
0
                if val != u64::from(write_val) {
271
0
                    return Err(Error::ValueTooLarge);
272
0
                }
273
0
                self.write_u32_at(offset, write_val)
274
            }
275
0
            8 => self.write_u64_at(offset, val),
276
0
            otherwise => Err(Error::UnsupportedWordSize(otherwise)),
277
        }
278
0
    }
279
280
    /// Write an unsigned LEB128 encoded integer.
281
0
    fn write_uleb128(&mut self, val: u64) -> Result<()> {
282
0
        let mut bytes = [0u8; 10];
283
0
        // bytes is long enough so this will never fail.
284
0
        let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap();
285
0
        self.write(&bytes[..len])
286
0
    }
287
288
    /// Read an unsigned LEB128 encoded integer.
289
0
    fn write_sleb128(&mut self, val: i64) -> Result<()> {
290
0
        let mut bytes = [0u8; 10];
291
0
        // bytes is long enough so this will never fail.
292
0
        let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap();
293
0
        self.write(&bytes[..len])
294
0
    }
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
0
    fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> {
302
0
        if format == Format::Dwarf64 {
303
0
            self.write_u32(0xffff_ffff)?;
304
0
        }
305
0
        let offset = InitialLengthOffset(self.len());
306
0
        self.write_udata(0, format.word_size())?;
307
0
        Ok(offset)
308
0
    }
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
0
    fn write_initial_length_at(
314
0
        &mut self,
315
0
        offset: InitialLengthOffset,
316
0
        length: u64,
317
0
        format: Format,
318
0
    ) -> Result<()> {
319
0
        self.write_udata_at(offset.0, length, format.word_size())
320
0
    }
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
333
    #[test]
334
    fn test_writer() {
335
        let mut w = write::EndianVec::new(LittleEndian);
336
        w.write_address(Address::Constant(0x1122_3344), 4).unwrap();
337
        assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
338
        assert_eq!(
339
            w.write_address(
340
                Address::Symbol {
341
                    symbol: 0,
342
                    addend: 0
343
                },
344
                4
345
            ),
346
            Err(Error::InvalidAddress)
347
        );
348
349
        let mut w = write::EndianVec::new(LittleEndian);
350
        w.write_offset(0x1122_3344, SectionId::DebugInfo, 4)
351
            .unwrap();
352
        assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
353
        w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2)
354
            .unwrap();
355
        assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]);
356
357
        let mut w = write::EndianVec::new(LittleEndian);
358
        w.write_u8(0x11).unwrap();
359
        w.write_u16(0x2233).unwrap();
360
        w.write_u32(0x4455_6677).unwrap();
361
        w.write_u64(0x8081_8283_8485_8687).unwrap();
362
        #[rustfmt::skip]
363
        assert_eq!(w.slice(), &[
364
            0x11,
365
            0x33, 0x22,
366
            0x77, 0x66, 0x55, 0x44,
367
            0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
368
        ]);
369
        w.write_u8_at(14, 0x11).unwrap();
370
        w.write_u16_at(12, 0x2233).unwrap();
371
        w.write_u32_at(8, 0x4455_6677).unwrap();
372
        w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
373
        #[rustfmt::skip]
374
        assert_eq!(w.slice(), &[
375
            0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
376
            0x77, 0x66, 0x55, 0x44,
377
            0x33, 0x22,
378
            0x11,
379
        ]);
380
381
        let mut w = write::EndianVec::new(BigEndian);
382
        w.write_u8(0x11).unwrap();
383
        w.write_u16(0x2233).unwrap();
384
        w.write_u32(0x4455_6677).unwrap();
385
        w.write_u64(0x8081_8283_8485_8687).unwrap();
386
        #[rustfmt::skip]
387
        assert_eq!(w.slice(), &[
388
            0x11,
389
            0x22, 0x33,
390
            0x44, 0x55, 0x66, 0x77,
391
            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
392
        ]);
393
        w.write_u8_at(14, 0x11).unwrap();
394
        w.write_u16_at(12, 0x2233).unwrap();
395
        w.write_u32_at(8, 0x4455_6677).unwrap();
396
        w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
397
        #[rustfmt::skip]
398
        assert_eq!(w.slice(), &[
399
            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
400
            0x44, 0x55, 0x66, 0x77,
401
            0x22, 0x33,
402
            0x11,
403
        ]);
404
405
        let mut w = write::EndianVec::new(LittleEndian);
406
        w.write_udata(0x11, 1).unwrap();
407
        w.write_udata(0x2233, 2).unwrap();
408
        w.write_udata(0x4455_6677, 4).unwrap();
409
        w.write_udata(0x8081_8283_8485_8687, 8).unwrap();
410
        #[rustfmt::skip]
411
        assert_eq!(w.slice(), &[
412
            0x11,
413
            0x33, 0x22,
414
            0x77, 0x66, 0x55, 0x44,
415
            0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
416
        ]);
417
        assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge));
418
        assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge));
419
        assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge));
420
        assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3)));
421
        w.write_udata_at(14, 0x11, 1).unwrap();
422
        w.write_udata_at(12, 0x2233, 2).unwrap();
423
        w.write_udata_at(8, 0x4455_6677, 4).unwrap();
424
        w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap();
425
        #[rustfmt::skip]
426
        assert_eq!(w.slice(), &[
427
            0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
428
            0x77, 0x66, 0x55, 0x44,
429
            0x33, 0x22,
430
            0x11,
431
        ]);
432
        assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge));
433
        assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge));
434
        assert_eq!(
435
            w.write_udata_at(0, 0x1_0000_0000, 4),
436
            Err(Error::ValueTooLarge)
437
        );
438
        assert_eq!(
439
            w.write_udata_at(0, 0x00, 3),
440
            Err(Error::UnsupportedWordSize(3))
441
        );
442
443
        let mut w = write::EndianVec::new(LittleEndian);
444
        w.write_uleb128(0).unwrap();
445
        assert_eq!(w.slice(), &[0]);
446
447
        let mut w = write::EndianVec::new(LittleEndian);
448
        w.write_uleb128(u64::MAX).unwrap();
449
        assert_eq!(
450
            w.slice(),
451
            &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
452
        );
453
454
        let mut w = write::EndianVec::new(LittleEndian);
455
        w.write_sleb128(0).unwrap();
456
        assert_eq!(w.slice(), &[0]);
457
458
        let mut w = write::EndianVec::new(LittleEndian);
459
        w.write_sleb128(i64::MAX).unwrap();
460
        assert_eq!(
461
            w.slice(),
462
            &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0]
463
        );
464
465
        let mut w = write::EndianVec::new(LittleEndian);
466
        w.write_sleb128(i64::MIN).unwrap();
467
        assert_eq!(
468
            w.slice(),
469
            &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f]
470
        );
471
472
        let mut w = write::EndianVec::new(LittleEndian);
473
        let offset = w.write_initial_length(Format::Dwarf32).unwrap();
474
        assert_eq!(w.slice(), &[0, 0, 0, 0]);
475
        w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32)
476
            .unwrap();
477
        assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
478
        assert_eq!(
479
            w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32),
480
            Err(Error::ValueTooLarge)
481
        );
482
483
        let mut w = write::EndianVec::new(LittleEndian);
484
        let offset = w.write_initial_length(Format::Dwarf64).unwrap();
485
        assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]);
486
        w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64)
487
            .unwrap();
488
        assert_eq!(
489
            w.slice(),
490
            &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]
491
        );
492
    }
493
}