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