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::*;
429