Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/gimli-0.26.2/src/write/mod.rs
Line
Count
Source (jump to first uncovered line)
1
//! Write DWARF debugging information.
2
//!
3
//! ## API Structure
4
//!
5
//! This module works by building up a representation of the debugging information
6
//! in memory, and then writing it all at once. It supports two major use cases:
7
//!
8
//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF
9
//! for a single compilation unit.
10
//!
11
//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple
12
//! compilation units.
13
//!
14
//! The module also supports reading in DWARF debugging information and writing it out
15
//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html)
16
//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert
17
//! it to a writable instance.
18
//!
19
//! ## Example Usage
20
//!
21
//! Write a compilation unit containing only the top level DIE.
22
//!
23
//! ```rust
24
//! use gimli::write::{
25
//!     Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections,
26
//! };
27
//!
28
//! fn example() -> Result<(), Error> {
29
//!     // Choose the encoding parameters.
30
//!     let encoding = gimli::Encoding {
31
//!         format: gimli::Format::Dwarf32,
32
//!         version: 5,
33
//!         address_size: 8,
34
//!     };
35
//!     // Create a container for a single compilation unit.
36
//!     let mut dwarf = DwarfUnit::new(encoding);
37
//!     // Set a range attribute on the root DIE.
38
//!     let range_list = RangeList(vec![Range::StartLength {
39
//!         begin: Address::Constant(0x100),
40
//!         length: 42,
41
//!     }]);
42
//!     let range_list_id = dwarf.unit.ranges.add(range_list);
43
//!     let root = dwarf.unit.root();
44
//!     dwarf.unit.get_mut(root).set(
45
//!         gimli::DW_AT_ranges,
46
//!         AttributeValue::RangeListRef(range_list_id),
47
//!     );
48
//!     // Create a `Vec` for each DWARF section.
49
//!     let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian));
50
//!     // Finally, write the DWARF data to the sections.
51
//!     dwarf.write(&mut sections)?;
52
//!     sections.for_each(|id, data| {
53
//!         // Here you can add the data to the output object file.
54
//!         Ok(())
55
//!     })
56
//! }
57
//! # fn main() {
58
//! #     example().unwrap();
59
//! # }
60
61
use std::error;
62
use std::fmt;
63
use std::result;
64
65
use crate::constants;
66
67
mod endian_vec;
68
pub use self::endian_vec::*;
69
70
mod writer;
71
pub use self::writer::*;
72
73
#[macro_use]
74
mod section;
75
pub use self::section::*;
76
77
macro_rules! define_id {
78
    ($name:ident, $docs:expr) => {
79
        #[doc=$docs]
80
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81
        pub struct $name {
82
            base_id: BaseId,
83
            index: usize,
84
        }
85
86
        impl $name {
87
            #[inline]
88
28.4k
            fn new(base_id: BaseId, index: usize) -> Self {
89
28.4k
                $name { base_id, index }
90
28.4k
            }
<gimli::write::cfi::CieId>::new
Line
Count
Source
88
28.4k
            fn new(base_id: BaseId, index: usize) -> Self {
89
28.4k
                $name { base_id, index }
90
28.4k
            }
Unexecuted instantiation: <gimli::write::loc::LocationListId>::new
Unexecuted instantiation: <gimli::write::range::RangeListId>::new
Unexecuted instantiation: <gimli::write::unit::UnitId>::new
Unexecuted instantiation: <gimli::write::unit::UnitEntryId>::new
Unexecuted instantiation: <gimli::write::str::StringId>::new
Unexecuted instantiation: <gimli::write::str::LineStringId>::new
91
        }
92
    };
93
}
94
95
macro_rules! define_offsets {
96
    ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => {
97
        #[doc=$off_doc]
98
        #[derive(Debug)]
99
        pub struct $offsets {
100
            base_id: BaseId,
101
            // We know ids start at 0.
102
            offsets: Vec<$offset>,
103
        }
104
105
        impl $offsets {
106
            /// Return an empty list of offsets.
107
            #[inline]
108
0
            pub fn none() -> Self {
109
0
                $offsets {
110
0
                    base_id: BaseId::default(),
111
0
                    offsets: Vec::new(),
112
0
                }
113
0
            }
Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::none
Unexecuted instantiation: <gimli::write::range::RangeListOffsets>::none
Unexecuted instantiation: <gimli::write::str::DebugStrOffsets>::none
Unexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::none
114
115
            /// Get the offset
116
            ///
117
            /// # Panics
118
            ///
119
            /// Panics if `id` is invalid.
120
            #[inline]
121
0
            pub fn get(&self, id: $id) -> $offset {
122
0
                debug_assert_eq!(self.base_id, id.base_id);
123
0
                self.offsets[id.index]
124
0
            }
Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::get
Unexecuted instantiation: <gimli::write::range::RangeListOffsets>::get
Unexecuted instantiation: <gimli::write::str::DebugStrOffsets>::get
Unexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::get
125
126
            /// Return the number of offsets.
127
            #[inline]
128
0
            pub fn count(&self) -> usize {
129
0
                self.offsets.len()
130
0
            }
Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::count
Unexecuted instantiation: <gimli::write::range::RangeListOffsets>::count
Unexecuted instantiation: <gimli::write::str::DebugStrOffsets>::count
Unexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::count
131
        }
132
    };
133
}
134
135
mod abbrev;
136
pub use self::abbrev::*;
137
138
mod cfi;
139
pub use self::cfi::*;
140
141
mod dwarf;
142
pub use self::dwarf::*;
143
144
mod line;
145
pub use self::line::*;
146
147
mod loc;
148
pub use self::loc::*;
149
150
mod op;
151
pub use self::op::*;
152
153
mod range;
154
pub use self::range::*;
155
156
mod str;
157
pub use self::str::*;
158
159
mod unit;
160
pub use self::unit::*;
161
162
/// An error that occurred when writing.
163
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164
pub enum Error {
165
    /// The given offset is out of bounds.
166
    OffsetOutOfBounds,
167
    /// The given length is out of bounds.
168
    LengthOutOfBounds,
169
    /// The attribute value is an invalid for writing.
170
    InvalidAttributeValue,
171
    /// The value is too large for the encoding form.
172
    ValueTooLarge,
173
    /// Unsupported word size.
174
    UnsupportedWordSize(u8),
175
    /// Unsupported DWARF version.
176
    UnsupportedVersion(u16),
177
    /// The unit length is too large for the requested DWARF format.
178
    InitialLengthOverflow,
179
    /// The address is invalid.
180
    InvalidAddress,
181
    /// The reference is invalid.
182
    InvalidReference,
183
    /// A requested feature requires a different DWARF version.
184
    NeedVersion(u16),
185
    /// Strings in line number program have mismatched forms.
186
    LineStringFormMismatch,
187
    /// The range is empty or otherwise invalid.
188
    InvalidRange,
189
    /// The line number program encoding is incompatible with the unit encoding.
190
    IncompatibleLineProgramEncoding,
191
    /// Could not encode code offset for a frame instruction.
192
    InvalidFrameCodeOffset(u32),
193
    /// Could not encode data offset for a frame instruction.
194
    InvalidFrameDataOffset(i32),
195
    /// Unsupported eh_frame pointer encoding.
196
    UnsupportedPointerEncoding(constants::DwEhPe),
197
    /// Unsupported reference in CFI expression.
198
    UnsupportedCfiExpressionReference,
199
    /// Unsupported forward reference in expression.
200
    UnsupportedExpressionForwardReference,
201
}
202
203
impl fmt::Display for Error {
204
0
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
205
0
        match *self {
206
0
            Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."),
207
0
            Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."),
208
            Error::InvalidAttributeValue => {
209
0
                write!(f, "The attribute value is an invalid for writing.")
210
            }
211
0
            Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."),
212
0
            Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size),
213
0
            Error::UnsupportedVersion(version) => {
214
0
                write!(f, "Unsupported DWARF version: {}", version)
215
            }
216
0
            Error::InitialLengthOverflow => write!(
217
0
                f,
218
0
                "The unit length is too large for the requested DWARF format."
219
0
            ),
220
0
            Error::InvalidAddress => write!(f, "The address is invalid."),
221
0
            Error::InvalidReference => write!(f, "The reference is invalid."),
222
0
            Error::NeedVersion(version) => write!(
223
0
                f,
224
0
                "A requested feature requires a DWARF version {}.",
225
0
                version
226
0
            ),
227
            Error::LineStringFormMismatch => {
228
0
                write!(f, "Strings in line number program have mismatched forms.")
229
            }
230
0
            Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."),
231
0
            Error::IncompatibleLineProgramEncoding => write!(
232
0
                f,
233
0
                "The line number program encoding is incompatible with the unit encoding."
234
0
            ),
235
0
            Error::InvalidFrameCodeOffset(offset) => write!(
236
0
                f,
237
0
                "Could not encode code offset ({}) for a frame instruction.",
238
0
                offset,
239
0
            ),
240
0
            Error::InvalidFrameDataOffset(offset) => write!(
241
0
                f,
242
0
                "Could not encode data offset ({}) for a frame instruction.",
243
0
                offset,
244
0
            ),
245
0
            Error::UnsupportedPointerEncoding(eh_pe) => {
246
0
                write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe)
247
            }
248
            Error::UnsupportedCfiExpressionReference => {
249
0
                write!(f, "Unsupported reference in CFI expression.")
250
            }
251
            Error::UnsupportedExpressionForwardReference => {
252
0
                write!(f, "Unsupported forward reference in expression.")
253
            }
254
        }
255
0
    }
256
}
257
258
impl error::Error for Error {}
259
260
/// The result of a write.
261
pub type Result<T> = result::Result<T, Error>;
262
263
/// An address.
264
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
265
pub enum Address {
266
    /// A fixed address that does not require relocation.
267
    Constant(u64),
268
    /// An address that is relative to a symbol which may be relocated.
269
    Symbol {
270
        /// The symbol that the address is relative to.
271
        ///
272
        /// The meaning of this value is decided by the writer, but
273
        /// will typically be an index into a symbol table.
274
        symbol: usize,
275
        /// The offset of the address relative to the symbol.
276
        ///
277
        /// This will typically be used as the addend in a relocation.
278
        addend: i64,
279
    },
280
}
281
282
/// A reference to a `.debug_info` entry.
283
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
284
pub enum Reference {
285
    /// An external symbol.
286
    ///
287
    /// The meaning of this value is decided by the writer, but
288
    /// will typically be an index into a symbol table.
289
    Symbol(usize),
290
    /// An entry in the same section.
291
    ///
292
    /// This only supports references in units that are emitted together.
293
    Entry(UnitId, UnitEntryId),
294
}
295
296
// This type is only used in debug assertions.
297
#[cfg(not(debug_assertions))]
298
type BaseId = ();
299
300
#[cfg(debug_assertions)]
301
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302
struct BaseId(usize);
303
304
#[cfg(debug_assertions)]
305
impl Default for BaseId {
306
    fn default() -> Self {
307
        use std::sync::atomic;
308
        static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
309
        BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed))
310
    }
311
}
312
313
#[cfg(feature = "read")]
314
mod convert {
315
    use super::*;
316
    use crate::read;
317
318
    pub(crate) use super::unit::convert::*;
319
320
    /// An error that occurred when converting a read value into a write value.
321
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
322
    pub enum ConvertError {
323
        /// An error occurred when reading.
324
        Read(read::Error),
325
        /// Writing of this attribute value is not implemented yet.
326
        UnsupportedAttributeValue,
327
        /// This attribute value is an invalid name/form combination.
328
        InvalidAttributeValue,
329
        /// A `.debug_info` reference does not refer to a valid entry.
330
        InvalidDebugInfoOffset,
331
        /// An address could not be converted.
332
        InvalidAddress,
333
        /// Writing this line number instruction is not implemented yet.
334
        UnsupportedLineInstruction,
335
        /// Writing this form of line string is not implemented yet.
336
        UnsupportedLineStringForm,
337
        /// A `.debug_line` file index is invalid.
338
        InvalidFileIndex,
339
        /// A `.debug_line` directory index is invalid.
340
        InvalidDirectoryIndex,
341
        /// A `.debug_line` line base is invalid.
342
        InvalidLineBase,
343
        /// A `.debug_line` reference is invalid.
344
        InvalidLineRef,
345
        /// A `.debug_info` unit entry reference is invalid.
346
        InvalidUnitRef,
347
        /// A `.debug_info` reference is invalid.
348
        InvalidDebugInfoRef,
349
        /// Invalid relative address in a range list.
350
        InvalidRangeRelativeAddress,
351
        /// Writing this CFI instruction is not implemented yet.
352
        UnsupportedCfiInstruction,
353
        /// Writing indirect pointers is not implemented yet.
354
        UnsupportedIndirectAddress,
355
        /// Writing this expression operation is not implemented yet.
356
        UnsupportedOperation,
357
        /// Operation branch target is invalid.
358
        InvalidBranchTarget,
359
        /// Writing this unit type is not supported yet.
360
        UnsupportedUnitType,
361
    }
362
363
    impl fmt::Display for ConvertError {
364
0
        fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
365
0
            use self::ConvertError::*;
366
0
            match *self {
367
0
                Read(ref e) => e.fmt(f),
368
                UnsupportedAttributeValue => {
369
0
                    write!(f, "Writing of this attribute value is not implemented yet.")
370
                }
371
0
                InvalidAttributeValue => write!(
372
0
                    f,
373
0
                    "This attribute value is an invalid name/form combination."
374
0
                ),
375
0
                InvalidDebugInfoOffset => write!(
376
0
                    f,
377
0
                    "A `.debug_info` reference does not refer to a valid entry."
378
0
                ),
379
0
                InvalidAddress => write!(f, "An address could not be converted."),
380
0
                UnsupportedLineInstruction => write!(
381
0
                    f,
382
0
                    "Writing this line number instruction is not implemented yet."
383
0
                ),
384
0
                UnsupportedLineStringForm => write!(
385
0
                    f,
386
0
                    "Writing this form of line string is not implemented yet."
387
0
                ),
388
0
                InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."),
389
0
                InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."),
390
0
                InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."),
391
0
                InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."),
392
0
                InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."),
393
0
                InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."),
394
                InvalidRangeRelativeAddress => {
395
0
                    write!(f, "Invalid relative address in a range list.")
396
                }
397
                UnsupportedCfiInstruction => {
398
0
                    write!(f, "Writing this CFI instruction is not implemented yet.")
399
                }
400
                UnsupportedIndirectAddress => {
401
0
                    write!(f, "Writing indirect pointers is not implemented yet.")
402
                }
403
0
                UnsupportedOperation => write!(
404
0
                    f,
405
0
                    "Writing this expression operation is not implemented yet."
406
0
                ),
407
0
                InvalidBranchTarget => write!(f, "Operation branch target is invalid."),
408
0
                UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."),
409
            }
410
0
        }
411
    }
412
413
    impl error::Error for ConvertError {}
414
415
    impl From<read::Error> for ConvertError {
416
0
        fn from(e: read::Error) -> Self {
417
0
            ConvertError::Read(e)
418
0
        }
419
    }
420
421
    /// The result of a conversion.
422
    pub type ConvertResult<T> = result::Result<T, ConvertError>;
423
}
424
#[cfg(feature = "read")]
425
pub use self::convert::*;