Skip to main content

gimli/write/
mod.rs

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