aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/write/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli/src/write/mod.rs')
-rw-r--r--vendor/gimli/src/write/mod.rs425
1 files changed, 425 insertions, 0 deletions
diff --git a/vendor/gimli/src/write/mod.rs b/vendor/gimli/src/write/mod.rs
new file mode 100644
index 0000000..47ba631
--- /dev/null
+++ b/vendor/gimli/src/write/mod.rs
@@ -0,0 +1,425 @@
+//! 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<T> = result::Result<T, Error>;
+
+/// 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<read::Error> for ConvertError {
+ fn from(e: read::Error) -> Self {
+ ConvertError::Read(e)
+ }
+ }
+
+ /// The result of a conversion.
+ pub type ConvertResult<T> = result::Result<T, ConvertError>;
+}
+#[cfg(feature = "read")]
+pub use self::convert::*;