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