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 fn new(base_id: BaseId, index: usize) -> Self { 89 $name { base_id, index } 90 } 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 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 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 { fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::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 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 { default() -> Self306 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 { fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error>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 { from(e: read::Error) -> Self416 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")] 425 pub use self::convert::*; 426