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
73#[macro_use]
74mod section;
75pub use self::section::*;
76
77macro_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 fn new(base_id: BaseId, index: usize) -> Self {
89 $name { base_id, index }
90 }
91 }
92 };
93}
94
95macro_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 pub fn none() -> Self {
109 $offsets {
110 base_id: BaseId::default(),
111 offsets: Vec::new(),
112 }
113 }
114
115 /// Get the offset
116 ///
117 /// # Panics
118 ///
119 /// Panics if `id` is invalid.
120 #[inline]
121 pub fn get(&self, id: $id) -> $offset {
122 debug_assert_eq!(self.base_id, id.base_id);
123 self.offsets[id.index]
124 }
125
126 /// Return the number of offsets.
127 #[inline]
128 pub fn count(&self) -> usize {
129 self.offsets.len()
130 }
131 }
132 };
133}
134
135mod abbrev;
136pub use self::abbrev::*;
137
138mod cfi;
139pub use self::cfi::*;
140
141mod dwarf;
142pub use self::dwarf::*;
143
144mod line;
145pub use self::line::*;
146
147mod loc;
148pub use self::loc::*;
149
150mod op;
151pub use self::op::*;
152
153mod range;
154pub use self::range::*;
155
156mod str;
157pub use self::str::*;
158
159mod unit;
160pub use self::unit::*;
161
162/// An error that occurred when writing.
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub 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
203impl fmt::Display for Error {
204 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
205 match *self {
206 Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."),
207 Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."),
208 Error::InvalidAttributeValue => {
209 write!(f, "The attribute value is an invalid for writing.")
210 }
211 Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."),
212 Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size),
213 Error::UnsupportedVersion(version) => {
214 write!(f, "Unsupported DWARF version: {}", version)
215 }
216 Error::InitialLengthOverflow => write!(
217 f,
218 "The unit length is too large for the requested DWARF format."
219 ),
220 Error::InvalidAddress => write!(f, "The address is invalid."),
221 Error::InvalidReference => write!(f, "The reference is invalid."),
222 Error::NeedVersion(version) => write!(
223 f,
224 "A requested feature requires a DWARF version {}.",
225 version
226 ),
227 Error::LineStringFormMismatch => {
228 write!(f, "Strings in line number program have mismatched forms.")
229 }
230 Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."),
231 Error::IncompatibleLineProgramEncoding => write!(
232 f,
233 "The line number program encoding is incompatible with the unit encoding."
234 ),
235 Error::InvalidFrameCodeOffset(offset) => write!(
236 f,
237 "Could not encode code offset ({}) for a frame instruction.",
238 offset,
239 ),
240 Error::InvalidFrameDataOffset(offset) => write!(
241 f,
242 "Could not encode data offset ({}) for a frame instruction.",
243 offset,
244 ),
245 Error::UnsupportedPointerEncoding(eh_pe) => {
246 write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe)
247 }
248 Error::UnsupportedCfiExpressionReference => {
249 write!(f, "Unsupported reference in CFI expression.")
250 }
251 Error::UnsupportedExpressionForwardReference => {
252 write!(f, "Unsupported forward reference in expression.")
253 }
254 }
255 }
256}
257
258impl error::Error for Error {}
259
260/// The result of a write.
261pub type Result<T> = result::Result<T, Error>;
262
263/// An address.
264#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
265pub 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)]
284pub 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))]
298type BaseId = ();
299
300#[cfg(debug_assertions)]
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302struct BaseId(usize);
303
304#[cfg(debug_assertions)]
305impl 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(val:1, order:atomic::Ordering::Relaxed))
310 }
311}
312
313#[cfg(feature = "read")]
314mod 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 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
365 use self::ConvertError::*;
366 match *self {
367 Read(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 InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."),
389 InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."),
390 InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."),
391 InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."),
392 InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."),
393 InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."),
394 InvalidRangeRelativeAddress => {
395 write!(f, "Invalid relative address in a range list.")
396 }
397 UnsupportedCfiInstruction => {
398 write!(f, "Writing this CFI instruction is not implemented yet.")
399 }
400 UnsupportedIndirectAddress => {
401 write!(f, "Writing indirect pointers is not implemented yet.")
402 }
403 UnsupportedOperation => write!(
404 f,
405 "Writing this expression operation is not implemented yet."
406 ),
407 InvalidBranchTarget => write!(f, "Operation branch target is invalid."),
408 UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."),
409 }
410 }
411 }
412
413 impl error::Error for ConvertError {}
414
415 impl From<read::Error> for ConvertError {
416 fn from(e: read::Error) -> Self {
417 ConvertError::Read(e)
418 }
419 }
420
421 /// The result of a conversion.
422 pub type ConvertResult<T> = result::Result<T, ConvertError>;
423}
424#[cfg(feature = "read")]
425pub use self::convert::*;
426