//! Write DWARF debugging information. //! //! ## API Structure //! //! This module works by building up a representation of the debugging information //! in memory, and then writing it all at once. It supports two major use cases: //! //! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF //! for a single compilation unit. //! //! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple //! compilation units. //! //! The module also supports reading in DWARF debugging information and writing it out //! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) //! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert //! it to a writable instance. //! //! ## Example Usage //! //! Write a compilation unit containing only the top level DIE. //! //! ```rust //! use gimli::write::{ //! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, //! }; //! //! fn example() -> Result<(), Error> { //! // Choose the encoding parameters. //! let encoding = gimli::Encoding { //! format: gimli::Format::Dwarf32, //! version: 5, //! address_size: 8, //! }; //! // Create a container for a single compilation unit. //! let mut dwarf = DwarfUnit::new(encoding); //! // Set a range attribute on the root DIE. //! let range_list = RangeList(vec![Range::StartLength { //! begin: Address::Constant(0x100), //! length: 42, //! }]); //! let range_list_id = dwarf.unit.ranges.add(range_list); //! let root = dwarf.unit.root(); //! dwarf.unit.get_mut(root).set( //! gimli::DW_AT_ranges, //! AttributeValue::RangeListRef(range_list_id), //! ); //! // Create a `Vec` for each DWARF section. //! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); //! // Finally, write the DWARF data to the sections. //! dwarf.write(&mut sections)?; //! sections.for_each(|id, data| { //! // Here you can add the data to the output object file. //! Ok(()) //! }) //! } //! # fn main() { //! # example().unwrap(); //! # } use std::error; use std::fmt; use std::result; use crate::constants; mod endian_vec; pub use self::endian_vec::*; mod writer; pub use self::writer::*; #[macro_use] mod section; pub use self::section::*; macro_rules! define_id { ($name:ident, $docs:expr) => { #[doc=$docs] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct $name { base_id: BaseId, index: usize, } impl $name { #[inline] fn new(base_id: BaseId, index: usize) -> Self { $name { base_id, index } } } }; } macro_rules! define_offsets { ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { #[doc=$off_doc] #[derive(Debug)] pub struct $offsets { base_id: BaseId, // We know ids start at 0. offsets: Vec<$offset>, } impl $offsets { /// Return an empty list of offsets. #[inline] pub fn none() -> Self { $offsets { base_id: BaseId::default(), offsets: Vec::new(), } } /// Get the offset /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get(&self, id: $id) -> $offset { debug_assert_eq!(self.base_id, id.base_id); self.offsets[id.index] } /// Return the number of offsets. #[inline] pub fn count(&self) -> usize { self.offsets.len() } } }; } mod abbrev; pub use self::abbrev::*; mod cfi; pub use self::cfi::*; mod dwarf; pub use self::dwarf::*; mod line; pub use self::line::*; mod loc; pub use self::loc::*; mod op; pub use self::op::*; mod range; pub use self::range::*; mod str; pub use self::str::*; mod unit; pub use self::unit::*; /// An error that occurred when writing. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { /// The given offset is out of bounds. OffsetOutOfBounds, /// The given length is out of bounds. LengthOutOfBounds, /// The attribute value is an invalid for writing. InvalidAttributeValue, /// The value is too large for the encoding form. ValueTooLarge, /// Unsupported word size. UnsupportedWordSize(u8), /// Unsupported DWARF version. UnsupportedVersion(u16), /// The unit length is too large for the requested DWARF format. InitialLengthOverflow, /// The address is invalid. InvalidAddress, /// The reference is invalid. InvalidReference, /// A requested feature requires a different DWARF version. NeedVersion(u16), /// Strings in line number program have mismatched forms. LineStringFormMismatch, /// The range is empty or otherwise invalid. InvalidRange, /// The line number program encoding is incompatible with the unit encoding. IncompatibleLineProgramEncoding, /// Could not encode code offset for a frame instruction. InvalidFrameCodeOffset(u32), /// Could not encode data offset for a frame instruction. InvalidFrameDataOffset(i32), /// Unsupported eh_frame pointer encoding. UnsupportedPointerEncoding(constants::DwEhPe), /// Unsupported reference in CFI expression. UnsupportedCfiExpressionReference, /// Unsupported forward reference in expression. UnsupportedExpressionForwardReference, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { match *self { Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), Error::InvalidAttributeValue => { write!(f, "The attribute value is an invalid for writing.") } Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), Error::UnsupportedVersion(version) => { write!(f, "Unsupported DWARF version: {}", version) } Error::InitialLengthOverflow => write!( f, "The unit length is too large for the requested DWARF format." ), Error::InvalidAddress => write!(f, "The address is invalid."), Error::InvalidReference => write!(f, "The reference is invalid."), Error::NeedVersion(version) => write!( f, "A requested feature requires a DWARF version {}.", version ), Error::LineStringFormMismatch => { write!(f, "Strings in line number program have mismatched forms.") } Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), Error::IncompatibleLineProgramEncoding => write!( f, "The line number program encoding is incompatible with the unit encoding." ), Error::InvalidFrameCodeOffset(offset) => write!( f, "Could not encode code offset ({}) for a frame instruction.", offset, ), Error::InvalidFrameDataOffset(offset) => write!( f, "Could not encode data offset ({}) for a frame instruction.", offset, ), Error::UnsupportedPointerEncoding(eh_pe) => { write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) } Error::UnsupportedCfiExpressionReference => { write!(f, "Unsupported reference in CFI expression.") } Error::UnsupportedExpressionForwardReference => { write!(f, "Unsupported forward reference in expression.") } } } } impl error::Error for Error {} /// The result of a write. pub type Result = result::Result; /// An address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Address { /// A fixed address that does not require relocation. Constant(u64), /// An address that is relative to a symbol which may be relocated. Symbol { /// The symbol that the address is relative to. /// /// The meaning of this value is decided by the writer, but /// will typically be an index into a symbol table. symbol: usize, /// The offset of the address relative to the symbol. /// /// This will typically be used as the addend in a relocation. addend: i64, }, } /// A reference to a `.debug_info` entry. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Reference { /// An external symbol. /// /// The meaning of this value is decided by the writer, but /// will typically be an index into a symbol table. Symbol(usize), /// An entry in the same section. /// /// This only supports references in units that are emitted together. Entry(UnitId, UnitEntryId), } // This type is only used in debug assertions. #[cfg(not(debug_assertions))] type BaseId = (); #[cfg(debug_assertions)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct BaseId(usize); #[cfg(debug_assertions)] impl Default for BaseId { fn default() -> Self { use std::sync::atomic; static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) } } #[cfg(feature = "read")] mod convert { use super::*; use crate::read; pub(crate) use super::unit::convert::*; /// An error that occurred when converting a read value into a write value. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ConvertError { /// An error occurred when reading. Read(read::Error), /// Writing of this attribute value is not implemented yet. UnsupportedAttributeValue, /// This attribute value is an invalid name/form combination. InvalidAttributeValue, /// A `.debug_info` reference does not refer to a valid entry. InvalidDebugInfoOffset, /// An address could not be converted. InvalidAddress, /// Writing this line number instruction is not implemented yet. UnsupportedLineInstruction, /// Writing this form of line string is not implemented yet. UnsupportedLineStringForm, /// A `.debug_line` file index is invalid. InvalidFileIndex, /// A `.debug_line` directory index is invalid. InvalidDirectoryIndex, /// A `.debug_line` line base is invalid. InvalidLineBase, /// A `.debug_line` reference is invalid. InvalidLineRef, /// A `.debug_info` unit entry reference is invalid. InvalidUnitRef, /// A `.debug_info` reference is invalid. InvalidDebugInfoRef, /// Invalid relative address in a range list. InvalidRangeRelativeAddress, /// Writing this CFI instruction is not implemented yet. UnsupportedCfiInstruction, /// Writing indirect pointers is not implemented yet. UnsupportedIndirectAddress, /// Writing this expression operation is not implemented yet. UnsupportedOperation, /// Operation branch target is invalid. InvalidBranchTarget, /// Writing this unit type is not supported yet. UnsupportedUnitType, } impl fmt::Display for ConvertError { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { use self::ConvertError::*; match *self { Read(ref e) => e.fmt(f), UnsupportedAttributeValue => { write!(f, "Writing of this attribute value is not implemented yet.") } InvalidAttributeValue => write!( f, "This attribute value is an invalid name/form combination." ), InvalidDebugInfoOffset => write!( f, "A `.debug_info` reference does not refer to a valid entry." ), InvalidAddress => write!(f, "An address could not be converted."), UnsupportedLineInstruction => write!( f, "Writing this line number instruction is not implemented yet." ), UnsupportedLineStringForm => write!( f, "Writing this form of line string is not implemented yet." ), InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."), InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."), InvalidRangeRelativeAddress => { write!(f, "Invalid relative address in a range list.") } UnsupportedCfiInstruction => { write!(f, "Writing this CFI instruction is not implemented yet.") } UnsupportedIndirectAddress => { write!(f, "Writing indirect pointers is not implemented yet.") } UnsupportedOperation => write!( f, "Writing this expression operation is not implemented yet." ), InvalidBranchTarget => write!(f, "Operation branch target is invalid."), UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), } } } impl error::Error for ConvertError {} impl From for ConvertError { fn from(e: read::Error) -> Self { ConvertError::Read(e) } } /// The result of a conversion. pub type ConvertResult = result::Result; } #[cfg(feature = "read")] pub use self::convert::*;