Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL unit.rs   Interaktion und
Portierbarkeitunbekannt

 
//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections.

use core::cell::Cell;
use core::ops::{Range, RangeFrom, RangeTo};
use core::{u16, u8};

use crate::common::{
    DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset,
    DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset,
    DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
    DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format,
    LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset,
};
use crate::constants;
use crate::endianity::Endianity;
use crate::read::abbrev::get_attribute_size;
use crate::read::{
    Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error,
    Expression, Reader, ReaderOffset, Result, Section, UnitOffset,
};

impl<T: ReaderOffset> DebugTypesOffset<T> {
    /// Convert an offset to be relative to the start of the given unit,
    /// instead of relative to the start of the .debug_types section.
    /// Returns `None` if the offset is not within the unit entries.
    pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
    where
        R: Reader<Offset = T>,
    {
        let unit_offset = unit.offset().as_debug_types_offset()?;
        let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
        if !unit.is_valid_offset(offset) {
            return None;
        }
        Some(offset)
    }
}

impl<T: ReaderOffset> DebugInfoOffset<T> {
    /// Convert an offset to be relative to the start of the given unit,
    /// instead of relative to the start of the .debug_info section.
    /// Returns `None` if the offset is not within this unit entries.
    pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
    where
        R: Reader<Offset = T>,
    {
        let unit_offset = unit.offset().as_debug_info_offset()?;
        let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
        if !unit.is_valid_offset(offset) {
            return None;
        }
        Some(offset)
    }
}

impl<T: ReaderOffset> UnitOffset<T> {
    /// Convert an offset to be relative to the start of the .debug_info section,
    /// instead of relative to the start of the given unit. Returns None if the
    /// provided unit lives in the .debug_types section.
    pub fn to_debug_info_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugInfoOffset<T>>
    where
        R: Reader<Offset = T>,
    {
        let unit_offset = unit.offset().as_debug_info_offset()?;
        Some(DebugInfoOffset(unit_offset.0 + self.0))
    }

    /// Convert an offset to be relative to the start of the .debug_types section,
    /// instead of relative to the start of the given unit. Returns None if the
    /// provided unit lives in the .debug_info section.
    pub fn to_debug_types_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugTypesOffset<T>>
    where
        R: Reader<Offset = T>,
    {
        let unit_offset = unit.offset().as_debug_types_offset()?;
        Some(DebugTypesOffset(unit_offset.0 + self.0))
    }
}

/// The `DebugInfo` struct represents the DWARF debugging information found in
/// the `.debug_info` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugInfo<R> {
    debug_info_section: R,
}

impl<'input, Endian> DebugInfo<EndianSlice<'input, Endian>>
where
    Endian: Endianity,
{
    /// Construct a new `DebugInfo` instance from the data in the `.debug_info`
    /// section.
    ///
    /// It is the caller's responsibility to read the `.debug_info` section and
    /// present it as a `&[u8]` slice. That means using some ELF loader on
    /// Linux, a Mach-O loader on macOS, etc.
    ///
    /// ```
    /// use gimli::{DebugInfo, LittleEndian};
    ///
    /// # let buf = [0x00, 0x01, 0x02, 0x03];
    /// # let read_debug_info_section_somehow = || &buf;
    /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
    /// ```
    pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self {
        Self::from(EndianSlice::new(debug_info_section, endian))
    }
}

impl<R: Reader> DebugInfo<R> {
    /// Iterate the units in this `.debug_info` section.
    ///
    /// ```
    /// use gimli::{DebugInfo, LittleEndian};
    ///
    /// # let buf = [];
    /// # let read_debug_info_section_somehow = || &buf;
    /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
    ///
    /// let mut iter = debug_info.units();
    /// while let Some(unit) = iter.next().unwrap() {
    ///     println!("unit's length is {}", unit.unit_length());
    /// }
    /// ```
    ///
    /// Can be [used with
    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
    pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
        DebugInfoUnitHeadersIter {
            input: self.debug_info_section.clone(),
            offset: DebugInfoOffset(R::Offset::from_u8(0)),
        }
    }

    /// Get the UnitHeader located at offset from this .debug_info section.
    ///
    ///
    pub fn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> {
        let input = &mut self.debug_info_section.clone();
        input.skip(offset.0)?;
        parse_unit_header(input, offset.into())
    }
}

impl<T> DebugInfo<T> {
    /// Create a `DebugInfo` section that references the data in `self`.
    ///
    /// This is useful when `R` implements `Reader` but `T` does not.
    ///
    /// Used by `DwarfSections::borrow`.
    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R>
    where
        F: FnMut(&'a T) -> R,
    {
        borrow(&self.debug_info_section).into()
    }
}

impl<R> Section<R> for DebugInfo<R> {
    fn id() -> SectionId {
        SectionId::DebugInfo
    }

    fn reader(&self) -> &R {
        &self.debug_info_section
    }
}

impl<R> From<R> for DebugInfo<R> {
    fn from(debug_info_section: R) -> Self {
        DebugInfo { debug_info_section }
    }
}

/// An iterator over the units of a .debug_info section.
///
/// See the [documentation on
/// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail.
#[derive(Clone, Debug)]
pub struct DebugInfoUnitHeadersIter<R: Reader> {
    input: R,
    offset: DebugInfoOffset<R::Offset>,
}

impl<R: Reader> DebugInfoUnitHeadersIter<R> {
    /// Advance the iterator to the next unit header.
    pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
        if self.input.is_empty() {
            Ok(None)
        } else {
            let len = self.input.len();
            match parse_unit_header(&mut self.input, self.offset.into()) {
                Ok(header) => {
                    self.offset.0 += len - self.input.len();
                    Ok(Some(header))
                }
                Err(e) => {
                    self.input.empty();
                    Err(e)
                }
            }
        }
    }
}

#[cfg(feature = "fallible-iterator")]
impl<R: Reader> fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter<R> {
    type Item = UnitHeader<R>;
    type Error = Error;

    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
        DebugInfoUnitHeadersIter::next(self)
    }
}

/// Parse the unit type from the unit header.
fn parse_unit_type<R: Reader>(input: &mut R) -> Result<constants::DwUt> {
    let val = input.read_u8()?;
    Ok(constants::DwUt(val))
}

/// Parse the `debug_abbrev_offset` in the compilation unit header.
fn parse_debug_abbrev_offset<R: Reader>(
    input: &mut R,
    format: Format,
) -> Result<DebugAbbrevOffset<R::Offset>> {
    input.read_offset(format).map(DebugAbbrevOffset)
}

/// Parse the `debug_info_offset` in the arange header.
pub(crate) fn parse_debug_info_offset<R: Reader>(
    input: &mut R,
    format: Format,
) -> Result<DebugInfoOffset<R::Offset>> {
    input.read_offset(format).map(DebugInfoOffset)
}

/// This enum specifies the type of the unit and any type
/// specific data carried in the header (e.g. the type
/// signature/type offset of a type unit).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnitType<Offset>
where
    Offset: ReaderOffset,
{
    /// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions,
    /// any unit appearing in the .debug_info section.
    Compilation,
    /// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing
    /// in the .debug_types section.
    Type {
        /// The unique type signature for this type unit.
        type_signature: DebugTypeSignature,
        /// The offset within this type unit where the type is defined.
        type_offset: UnitOffset<Offset>,
    },
    /// A unit with type `DW_UT_partial`. The root DIE of this unit should be a
    /// `DW_TAG_partial_unit`.
    Partial,
    /// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to
    /// link this with the corresponding `SplitCompilation` unit in a dwo file.
    /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
    /// be a `Compilation` unit with the dwo_id present as an attribute on the
    /// root DIE.
    Skeleton(DwoId),
    /// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to
    /// link this with the corresponding `Skeleton` unit in the original binary.
    /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
    /// be a `Compilation` unit with the dwo_id present as an attribute on the
    /// root DIE.
    SplitCompilation(DwoId),
    /// A unit with type `DW_UT_split_type`. A split type unit is identical to a
    /// conventional type unit except for the section in which it appears.
    SplitType {
        /// The unique type signature for this type unit.
        type_signature: DebugTypeSignature,
        /// The offset within this type unit where the type is defined.
        type_offset: UnitOffset<Offset>,
    },
}

impl<Offset> UnitType<Offset>
where
    Offset: ReaderOffset,
{
    // TODO: This will be used by the DWARF writing code once it
    // supports unit types other than simple compilation units.
    #[allow(unused)]
    pub(crate) fn dw_ut(&self) -> constants::DwUt {
        match self {
            UnitType::Compilation => constants::DW_UT_compile,
            UnitType::Type { .. } => constants::DW_UT_type,
            UnitType::Partial => constants::DW_UT_partial,
            UnitType::Skeleton(_) => constants::DW_UT_skeleton,
            UnitType::SplitCompilation(_) => constants::DW_UT_split_compile,
            UnitType::SplitType { .. } => constants::DW_UT_split_type,
        }
    }
}

/// The common fields for the headers of compilation units and
/// type units.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnitHeader<R, Offset = <R as Reader>::Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    encoding: Encoding,
    unit_length: Offset,
    unit_type: UnitType<Offset>,
    debug_abbrev_offset: DebugAbbrevOffset<Offset>,
    unit_offset: UnitSectionOffset<Offset>,
    entries_buf: R,
}

/// Static methods.
impl<R, Offset> UnitHeader<R, Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// Construct a new `UnitHeader`.
    pub fn new(
        encoding: Encoding,
        unit_length: Offset,
        unit_type: UnitType<Offset>,
        debug_abbrev_offset: DebugAbbrevOffset<Offset>,
        unit_offset: UnitSectionOffset<Offset>,
        entries_buf: R,
    ) -> Self {
        UnitHeader {
            encoding,
            unit_length,
            unit_type,
            debug_abbrev_offset,
            unit_offset,
            entries_buf,
        }
    }
}

/// Instance methods.
impl<R, Offset> UnitHeader<R, Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// Get the offset of this unit within its section.
    pub fn offset(&self) -> UnitSectionOffset<Offset> {
        self.unit_offset
    }

    /// Return the serialized size of the common unit header for the given
    /// DWARF format.
    pub fn size_of_header(&self) -> usize {
        let unit_length_size = self.encoding.format.initial_length_size() as usize;
        let version_size = 2;
        let debug_abbrev_offset_size = self.encoding.format.word_size() as usize;
        let address_size_size = 1;
        let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 };
        let type_specific_size = match self.unit_type {
            UnitType::Compilation | UnitType::Partial => 0,
            UnitType::Type { .. } | UnitType::SplitType { .. } => {
                let type_signature_size = 8;
                let type_offset_size = self.encoding.format.word_size() as usize;
                type_signature_size + type_offset_size
            }
            UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8,
        };

        unit_length_size
            + version_size
            + debug_abbrev_offset_size
            + address_size_size
            + unit_type_size
            + type_specific_size
    }

    /// Get the length of the debugging info for this compilation unit, not
    /// including the byte length of the encoded length itself.
    pub fn unit_length(&self) -> Offset {
        self.unit_length
    }

    /// Get the length of the debugging info for this compilation unit,
    /// including the byte length of the encoded length itself.
    pub fn length_including_self(&self) -> Offset {
        Offset::from_u8(self.format().initial_length_size()) + self.unit_length
    }

    /// Return the encoding parameters for this unit.
    pub fn encoding(&self) -> Encoding {
        self.encoding
    }

    /// Get the DWARF version of the debugging info for this compilation unit.
    pub fn version(&self) -> u16 {
        self.encoding.version
    }

    /// Get the UnitType of this unit.
    pub fn type_(&self) -> UnitType<Offset> {
        self.unit_type
    }

    /// The offset into the `.debug_abbrev` section for this compilation unit's
    /// debugging information entries' abbreviations.
    pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> {
        self.debug_abbrev_offset
    }

    /// The size of addresses (in bytes) in this compilation unit.
    pub fn address_size(&self) -> u8 {
        self.encoding.address_size
    }

    /// Whether this compilation unit is encoded in 64- or 32-bit DWARF.
    pub fn format(&self) -> Format {
        self.encoding.format
    }

    /// The serialized size of the header for this compilation unit.
    pub fn header_size(&self) -> Offset {
        self.length_including_self() - self.entries_buf.len()
    }

    pub(crate) fn is_valid_offset(&self, offset: UnitOffset<Offset>) -> bool {
        let size_of_header = self.header_size();
        if offset.0 < size_of_header {
            return false;
        }

        let relative_to_entries_buf = offset.0 - size_of_header;
        relative_to_entries_buf < self.entries_buf.len()
    }

    /// Get the underlying bytes for the supplied range.
    pub fn range(&self, idx: Range<UnitOffset<Offset>>) -> Result<R> {
        if !self.is_valid_offset(idx.start) {
            return Err(Error::OffsetOutOfBounds);
        }
        if !self.is_valid_offset(idx.end) {
            return Err(Error::OffsetOutOfBounds);
        }
        assert!(idx.start <= idx.end);
        let size_of_header = self.header_size();
        let start = idx.start.0 - size_of_header;
        let end = idx.end.0 - size_of_header;
        let mut input = self.entries_buf.clone();
        input.skip(start)?;
        input.truncate(end - start)?;
        Ok(input)
    }

    /// Get the underlying bytes for the supplied range.
    pub fn range_from(&self, idx: RangeFrom<UnitOffset<Offset>>) -> Result<R> {
        if !self.is_valid_offset(idx.start) {
            return Err(Error::OffsetOutOfBounds);
        }
        let start = idx.start.0 - self.header_size();
        let mut input = self.entries_buf.clone();
        input.skip(start)?;
        Ok(input)
    }

    /// Get the underlying bytes for the supplied range.
    pub fn range_to(&self, idx: RangeTo<UnitOffset<Offset>>) -> Result<R> {
        if !self.is_valid_offset(idx.end) {
            return Err(Error::OffsetOutOfBounds);
        }
        let end = idx.end.0 - self.header_size();
        let mut input = self.entries_buf.clone();
        input.truncate(end)?;
        Ok(input)
    }

    /// Read the `DebuggingInformationEntry` at the given offset.
    pub fn entry<'me, 'abbrev>(
        &'me self,
        abbreviations: &'abbrev Abbreviations,
        offset: UnitOffset<Offset>,
    ) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> {
        let mut input = self.range_from(offset..)?;
        let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?;
        entry.ok_or(Error::NoEntryAtGivenOffset)
    }

    /// Navigate this unit's `DebuggingInformationEntry`s.
    pub fn entries<'me, 'abbrev>(
        &'me self,
        abbreviations: &'abbrev Abbreviations,
    ) -> EntriesCursor<'abbrev, 'me, R> {
        EntriesCursor {
            unit: self,
            input: self.entries_buf.clone(),
            abbreviations,
            cached_current: None,
            delta_depth: 0,
        }
    }

    /// Navigate this compilation unit's `DebuggingInformationEntry`s
    /// starting at the given offset.
    pub fn entries_at_offset<'me, 'abbrev>(
        &'me self,
        abbreviations: &'abbrev Abbreviations,
        offset: UnitOffset<Offset>,
    ) -> Result<EntriesCursor<'abbrev, 'me, R>> {
        let input = self.range_from(offset..)?;
        Ok(EntriesCursor {
            unit: self,
            input,
            abbreviations,
            cached_current: None,
            delta_depth: 0,
        })
    }

    /// Navigate this unit's `DebuggingInformationEntry`s as a tree
    /// starting at the given offset.
    pub fn entries_tree<'me, 'abbrev>(
        &'me self,
        abbreviations: &'abbrev Abbreviations,
        offset: Option<UnitOffset<Offset>>,
    ) -> Result<EntriesTree<'abbrev, 'me, R>> {
        let input = match offset {
            Some(offset) => self.range_from(offset..)?,
            None => self.entries_buf.clone(),
        };
        Ok(EntriesTree::new(input, self, abbreviations))
    }

    /// Read the raw data that defines the Debugging Information Entries.
    pub fn entries_raw<'me, 'abbrev>(
        &'me self,
        abbreviations: &'abbrev Abbreviations,
        offset: Option<UnitOffset<Offset>>,
    ) -> Result<EntriesRaw<'abbrev, 'me, R>> {
        let input = match offset {
            Some(offset) => self.range_from(offset..)?,
            None => self.entries_buf.clone(),
        };
        Ok(EntriesRaw {
            input,
            unit: self,
            abbreviations,
            depth: 0,
        })
    }

    /// Parse this unit's abbreviations.
    pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev<R>) -> Result<Abbreviations> {
        debug_abbrev.abbreviations(self.debug_abbrev_offset())
    }
}

/// Parse a unit header.
fn parse_unit_header<R, Offset>(
    input: &mut R,
    unit_offset: UnitSectionOffset<Offset>,
) -> Result<UnitHeader<R>>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    let (unit_length, format) = input.read_initial_length()?;
    let mut rest = input.split(unit_length)?;

    let version = rest.read_u16()?;
    let abbrev_offset;
    let address_size;
    let unit_type;
    // DWARF 1 was very different, and is obsolete, so isn't supported by this
    // reader.
    if 2 <= version && version <= 4 {
        abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
        address_size = rest.read_u8()?;
        // Before DWARF5, all units in the .debug_info section are compilation
        // units, and all units in the .debug_types section are type units.
        unit_type = match unit_offset {
            UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile,
            UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type,
        };
    } else if version == 5 {
        unit_type = parse_unit_type(&mut rest)?;
        address_size = rest.read_u8()?;
        abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
    } else {
        return Err(Error::UnknownVersion(u64::from(version)));
    }
    let encoding = Encoding {
        format,
        version,
        address_size,
    };

    // Parse any data specific to this type of unit.
    let unit_type = match unit_type {
        constants::DW_UT_compile => UnitType::Compilation,
        constants::DW_UT_type => {
            let type_signature = parse_type_signature(&mut rest)?;
            let type_offset = parse_type_offset(&mut rest, format)?;
            UnitType::Type {
                type_signature,
                type_offset,
            }
        }
        constants::DW_UT_partial => UnitType::Partial,
        constants::DW_UT_skeleton => {
            let dwo_id = parse_dwo_id(&mut rest)?;
            UnitType::Skeleton(dwo_id)
        }
        constants::DW_UT_split_compile => {
            let dwo_id = parse_dwo_id(&mut rest)?;
            UnitType::SplitCompilation(dwo_id)
        }
        constants::DW_UT_split_type => {
            let type_signature = parse_type_signature(&mut rest)?;
            let type_offset = parse_type_offset(&mut rest, format)?;
            UnitType::SplitType {
                type_signature,
                type_offset,
            }
        }
        _ => return Err(Error::UnsupportedUnitType),
    };

    Ok(UnitHeader::new(
        encoding,
        unit_length,
        unit_type,
        abbrev_offset,
        unit_offset,
        rest,
    ))
}

/// Parse a dwo_id from a header
fn parse_dwo_id<R: Reader>(input: &mut R) -> Result<DwoId> {
    Ok(DwoId(input.read_u64()?))
}

/// A Debugging Information Entry (DIE).
///
/// DIEs have a set of attributes and optionally have children DIEs as well.
#[derive(Clone, Debug)]
pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = <R as Reader>::Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    offset: UnitOffset<Offset>,
    attrs_slice: R,
    attrs_len: Cell<Option<Offset>>,
    abbrev: &'abbrev Abbreviation,
    unit: &'unit UnitHeader<R, Offset>,
}

impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// Construct a new `DebuggingInformationEntry`.
    pub fn new(
        offset: UnitOffset<Offset>,
        attrs_slice: R,
        abbrev: &'abbrev Abbreviation,
        unit: &'unit UnitHeader<R, Offset>,
    ) -> Self {
        DebuggingInformationEntry {
            offset,
            attrs_slice,
            attrs_len: Cell::new(None),
            abbrev,
            unit,
        }
    }

    /// Get this entry's code.
    pub fn code(&self) -> u64 {
        self.abbrev.code()
    }

    /// Get this entry's offset.
    pub fn offset(&self) -> UnitOffset<Offset> {
        self.offset
    }

    /// Get this entry's `DW_TAG_whatever` tag.
    ///
    /// ```
    /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
    /// # let info_buf = [
    /// #     // Comilation unit header
    /// #
    /// #     // 32-bit unit length = 12
    /// #     0x0c, 0x00, 0x00, 0x00,
    /// #     // Version 4
    /// #     0x04, 0x00,
    /// #     // debug_abbrev_offset
    /// #     0x00, 0x00, 0x00, 0x00,
    /// #     // Address size
    /// #     0x04,
    /// #
    /// #     // DIEs
    /// #
    /// #     // Abbreviation code
    /// #     0x01,
    /// #     // Attribute of form DW_FORM_string = "foo\0"
    /// #     0x66, 0x6f, 0x6f, 0x00,
    /// # ];
    /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian);
    /// # let abbrev_buf = [
    /// #     // Code
    /// #     0x01,
    /// #     // DW_TAG_subprogram
    /// #     0x2e,
    /// #     // DW_CHILDREN_no
    /// #     0x00,
    /// #     // Begin attributes
    /// #       // Attribute name = DW_AT_name
    /// #       0x03,
    /// #       // Attribute form = DW_FORM_string
    /// #       0x08,
    /// #     // End attributes
    /// #     0x00,
    /// #     0x00,
    /// #     // Null terminator
    /// #     0x00
    /// # ];
    /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
    /// # let unit = debug_info.units().next().unwrap().unwrap();
    /// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
    /// # let mut cursor = unit.entries(&abbrevs);
    /// # let (_, entry) = cursor.next_dfs().unwrap().unwrap();
    /// # let mut get_some_entry = || entry;
    /// let entry = get_some_entry();
    ///
    /// match entry.tag() {
    ///     gimli::DW_TAG_subprogram =>
    ///         println!("this entry contains debug info about a function"),
    ///     gimli::DW_TAG_inlined_subroutine =>
    ///         println!("this entry contains debug info about a particular instance of inlining"),
    ///     gimli::DW_TAG_variable =>
    ///         println!("this entry contains debug info about a local variable"),
    ///     gimli::DW_TAG_formal_parameter =>
    ///         println!("this entry contains debug info about a function parameter"),
    ///     otherwise =>
    ///         println!("this entry is some other kind of data: {:?}", otherwise),
    /// };
    /// ```
    pub fn tag(&self) -> constants::DwTag {
        self.abbrev.tag()
    }

    /// Return true if this entry's type can have children, false otherwise.
    pub fn has_children(&self) -> bool {
        self.abbrev.has_children()
    }

    /// Iterate over this entry's set of attributes.
    ///
    /// ```
    /// use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
    ///
    /// // Read the `.debug_info` section.
    ///
    /// # let info_buf = [
    /// #     // Comilation unit header
    /// #
    /// #     // 32-bit unit length = 12
    /// #     0x0c, 0x00, 0x00, 0x00,
    /// #     // Version 4
    /// #     0x04, 0x00,
    /// #     // debug_abbrev_offset
    /// #     0x00, 0x00, 0x00, 0x00,
    /// #     // Address size
    /// #     0x04,
    /// #
    /// #     // DIEs
    /// #
    /// #     // Abbreviation code
    /// #     0x01,
    /// #     // Attribute of form DW_FORM_string = "foo\0"
    /// #     0x66, 0x6f, 0x6f, 0x00,
    /// # ];
    /// # let read_debug_info_section_somehow = || &info_buf;
    /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
    ///
    /// // Get the data about the first compilation unit out of the `.debug_info`.
    ///
    /// let unit = debug_info.units().next()
    ///     .expect("Should have at least one compilation unit")
    ///     .expect("and it should parse ok");
    ///
    /// // Read the `.debug_abbrev` section and parse the
    /// // abbreviations for our compilation unit.
    ///
    /// # let abbrev_buf = [
    /// #     // Code
    /// #     0x01,
    /// #     // DW_TAG_subprogram
    /// #     0x2e,
    /// #     // DW_CHILDREN_no
    /// #     0x00,
    /// #     // Begin attributes
    /// #       // Attribute name = DW_AT_name
    /// #       0x03,
    /// #       // Attribute form = DW_FORM_string
    /// #       0x08,
    /// #     // End attributes
    /// #     0x00,
    /// #     0x00,
    /// #     // Null terminator
    /// #     0x00
    /// # ];
    /// # let read_debug_abbrev_section_somehow = || &abbrev_buf;
    /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian);
    /// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
    ///
    /// // Get the first entry from that compilation unit.
    ///
    /// let mut cursor = unit.entries(&abbrevs);
    /// let (_, entry) = cursor.next_dfs()
    ///     .expect("Should parse next entry")
    ///     .expect("Should have at least one entry");
    ///
    /// // Finally, print the first entry's attributes.
    ///
    /// let mut attrs = entry.attrs();
    /// while let Some(attr) = attrs.next().unwrap() {
    ///     println!("Attribute name = {:?}", attr.name());
    ///     println!("Attribute value = {:?}", attr.value());
    /// }
    /// ```
    ///
    /// Can be [used with
    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
    pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> {
        AttrsIter {
            input: self.attrs_slice.clone(),
            attributes: self.abbrev.attributes(),
            entry: self,
        }
    }

    /// Find the first attribute in this entry which has the given name,
    /// and return it. Returns `Ok(None)` if no attribute is found.
    pub fn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> {
        let mut attrs = self.attrs();
        while let Some(attr) = attrs.next()? {
            if attr.name() == name {
                return Ok(Some(attr));
            }
        }
        Ok(None)
    }

    /// Find the first attribute in this entry which has the given name,
    /// and return its raw value. Returns `Ok(None)` if no attribute is found.
    pub fn attr_value_raw(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
        self.attr(name)
            .map(|attr| attr.map(|attr| attr.raw_value()))
    }

    /// Find the first attribute in this entry which has the given name,
    /// and return its normalized value.  Returns `Ok(None)` if no
    /// attribute is found.
    pub fn attr_value(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
        self.attr(name).map(|attr| attr.map(|attr| attr.value()))
    }

    /// Return the input buffer after the last attribute.
    #[inline(always)]
    fn after_attrs(&self) -> Result<R> {
        if let Some(attrs_len) = self.attrs_len.get() {
            let mut input = self.attrs_slice.clone();
            input.skip(attrs_len)?;
            Ok(input)
        } else {
            let mut attrs = self.attrs();
            while attrs.next()?.is_some() {}
            Ok(attrs.input)
        }
    }

    /// Use the `DW_AT_sibling` attribute to find the input buffer for the
    /// next sibling. Returns `None` if the attribute is missing or invalid.
    fn sibling(&self) -> Option<R> {
        let attr = self.attr_value(constants::DW_AT_sibling);
        if let Ok(Some(AttributeValue::UnitRef(offset))) = attr {
            if offset.0 > self.offset.0 {
                if let Ok(input) = self.unit.range_from(offset..) {
                    return Some(input);
                }
            }
        }
        None
    }

    /// Parse an entry. Returns `Ok(None)` for null entries.
    #[inline(always)]
    fn parse(
        input: &mut R,
        unit: &'unit UnitHeader<R>,
        abbreviations: &'abbrev Abbreviations,
    ) -> Result<Option<Self>> {
        let offset = unit.header_size() + input.offset_from(&unit.entries_buf);
        let code = input.read_uleb128()?;
        if code == 0 {
            return Ok(None);
        };
        let abbrev = abbreviations
            .get(code)
            .ok_or(Error::UnknownAbbreviation(code))?;
        Ok(Some(DebuggingInformationEntry {
            offset: UnitOffset(offset),
            attrs_slice: input.clone(),
            attrs_len: Cell::new(None),
            abbrev,
            unit,
        }))
    }
}

/// The value of an attribute in a `DebuggingInformationEntry`.
//
// Set the discriminant size so that all variants use the same alignment
// for their data.  This gives better code generation in `parse_attribute`.
#[repr(u64)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AttributeValue<R, Offset = <R as Reader>::Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// "Refers to some location in the address space of the described program."
    Addr(u64),

    /// A slice of an arbitrary number of bytes.
    Block(R),

    /// A one byte constant data value. How to interpret the byte depends on context.
    ///
    /// From section 7 of the standard: "Depending on context, it may be a
    /// signed integer, an unsigned integer, a floating-point constant, or
    /// anything else."
    Data1(u8),

    /// A two byte constant data value. How to interpret the bytes depends on context.
    ///
    /// These bytes have been converted from `R::Endian`. This may need to be reversed
    /// if this was not required.
    ///
    /// From section 7 of the standard: "Depending on context, it may be a
    /// signed integer, an unsigned integer, a floating-point constant, or
    /// anything else."
    Data2(u16),

    /// A four byte constant data value. How to interpret the bytes depends on context.
    ///
    /// These bytes have been converted from `R::Endian`. This may need to be reversed
    /// if this was not required.
    ///
    /// From section 7 of the standard: "Depending on context, it may be a
    /// signed integer, an unsigned integer, a floating-point constant, or
    /// anything else."
    Data4(u32),

    /// An eight byte constant data value. How to interpret the bytes depends on context.
    ///
    /// These bytes have been converted from `R::Endian`. This may need to be reversed
    /// if this was not required.
    ///
    /// From section 7 of the standard: "Depending on context, it may be a
    /// signed integer, an unsigned integer, a floating-point constant, or
    /// anything else."
    Data8(u64),

    /// A signed integer constant.
    Sdata(i64),

    /// An unsigned integer constant.
    Udata(u64),

    /// "The information bytes contain a DWARF expression (see Section 2.5) or
    /// location description (see Section 2.6)."
    Exprloc(Expression<R>),

    /// A boolean that indicates presence or absence of the attribute.
    Flag(bool),

    /// An offset into another section. Which section this is an offset into
    /// depends on context.
    SecOffset(Offset),

    /// An offset to a set of addresses in the `.debug_addr` section.
    DebugAddrBase(DebugAddrBase<Offset>),

    /// An index into a set of addresses in the `.debug_addr` section.
    DebugAddrIndex(DebugAddrIndex<Offset>),

    /// An offset into the current compilation unit.
    UnitRef(UnitOffset<Offset>),

    /// An offset into the current `.debug_info` section, but possibly a
    /// different compilation unit from the current one.
    DebugInfoRef(DebugInfoOffset<Offset>),

    /// An offset into the `.debug_info` section of the supplementary object file.
    DebugInfoRefSup(DebugInfoOffset<Offset>),

    /// An offset into the `.debug_line` section.
    DebugLineRef(DebugLineOffset<Offset>),

    /// An offset into either the `.debug_loc` section or the `.debug_loclists` section.
    LocationListsRef(LocationListsOffset<Offset>),

    /// An offset to a set of offsets in the `.debug_loclists` section.
    DebugLocListsBase(DebugLocListsBase<Offset>),

    /// An index into a set of offsets in the `.debug_loclists` section.
    DebugLocListsIndex(DebugLocListsIndex<Offset>),

    /// An offset into the `.debug_macinfo` section.
    DebugMacinfoRef(DebugMacinfoOffset<Offset>),

    /// An offset into the `.debug_macro` section.
    DebugMacroRef(DebugMacroOffset<Offset>),

    /// An offset into the `.debug_ranges` section.
    RangeListsRef(RawRangeListsOffset<Offset>),

    /// An offset to a set of offsets in the `.debug_rnglists` section.
    DebugRngListsBase(DebugRngListsBase<Offset>),

    /// An index into a set of offsets in the `.debug_rnglists` section.
    DebugRngListsIndex(DebugRngListsIndex<Offset>),

    /// A type signature.
    DebugTypesRef(DebugTypeSignature),

    /// An offset into the `.debug_str` section.
    DebugStrRef(DebugStrOffset<Offset>),

    /// An offset into the `.debug_str` section of the supplementary object file.
    DebugStrRefSup(DebugStrOffset<Offset>),

    /// An offset to a set of entries in the `.debug_str_offsets` section.
    DebugStrOffsetsBase(DebugStrOffsetsBase<Offset>),

    /// An index into a set of entries in the `.debug_str_offsets` section.
    DebugStrOffsetsIndex(DebugStrOffsetsIndex<Offset>),

    /// An offset into the `.debug_line_str` section.
    DebugLineStrRef(DebugLineStrOffset<Offset>),

    /// A slice of bytes representing a string. Does not include a final null byte.
    /// Not guaranteed to be UTF-8 or anything like that.
    String(R),

    /// The value of a `DW_AT_encoding` attribute.
    Encoding(constants::DwAte),

    /// The value of a `DW_AT_decimal_sign` attribute.
    DecimalSign(constants::DwDs),

    /// The value of a `DW_AT_endianity` attribute.
    Endianity(constants::DwEnd),

    /// The value of a `DW_AT_accessibility` attribute.
    Accessibility(constants::DwAccess),

    /// The value of a `DW_AT_visibility` attribute.
    Visibility(constants::DwVis),

    /// The value of a `DW_AT_virtuality` attribute.
    Virtuality(constants::DwVirtuality),

    /// The value of a `DW_AT_language` attribute.
    Language(constants::DwLang),

    /// The value of a `DW_AT_address_class` attribute.
    AddressClass(constants::DwAddr),

    /// The value of a `DW_AT_identifier_case` attribute.
    IdentifierCase(constants::DwId),

    /// The value of a `DW_AT_calling_convention` attribute.
    CallingConvention(constants::DwCc),

    /// The value of a `DW_AT_inline` attribute.
    Inline(constants::DwInl),

    /// The value of a `DW_AT_ordering` attribute.
    Ordering(constants::DwOrd),

    /// An index into the filename entries from the line number information
    /// table for the compilation unit containing this value.
    FileIndex(u64),

    /// An implementation-defined identifier uniquely identifying a compilation
    /// unit.
    DwoId(DwoId),
}

/// An attribute in a `DebuggingInformationEntry`, consisting of a name and
/// associated value.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Attribute<R: Reader> {
    name: constants::DwAt,
    value: AttributeValue<R>,
}

impl<R: Reader> Attribute<R> {
    /// Get this attribute's name.
    pub fn name(&self) -> constants::DwAt {
        self.name
    }

    /// Get this attribute's raw value.
    pub fn raw_value(&self) -> AttributeValue<R> {
        self.value.clone()
    }

    /// Get this attribute's normalized value.
    ///
    /// Attribute values can potentially be encoded in multiple equivalent forms,
    /// and may have special meaning depending on the attribute name.  This method
    /// converts the attribute value to a normalized form based on the attribute
    /// name.
    ///
    /// See "Table 7.5: Attribute encodings" and "Table 7.6: Attribute form encodings".
    pub fn value(&self) -> AttributeValue<R> {
        // Table 7.5 shows the possible attribute classes for each name.
        // Table 7.6 shows the possible attribute classes for each form.
        // For each attribute name, we need to match on the form, and
        // convert it to one of the classes that is allowed for both
        // the name and the form.
        //
        // The individual class conversions rarely vary for each name,
        // so for each class conversion we define a macro that matches
        // on the allowed forms for that class.
        //
        // For some classes, we don't need to do any conversion, so their
        // macro is empty.  In the future we may want to fill them in to
        // provide strict checking of the forms for each class.  For now,
        // they simply provide a way to document the allowed classes for
        // each name.

        // DW_FORM_addr
        // DW_FORM_addrx
        // DW_FORM_addrx1
        // DW_FORM_addrx2
        // DW_FORM_addrx3
        // DW_FORM_addrx4
        macro_rules! address {
            () => {};
        }
        // DW_FORM_sec_offset
        macro_rules! addrptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugAddrBase(DebugAddrBase(offset));
                }
            };
        }
        // DW_FORM_block
        // DW_FORM_block1
        // DW_FORM_block2
        // DW_FORM_block4
        macro_rules! block {
            () => {};
        }
        // DW_FORM_sdata
        // DW_FORM_udata
        // DW_FORM_data1
        // DW_FORM_data2
        // DW_FORM_data4
        // DW_FORM_data8
        // DW_FORM_data16
        // DW_FORM_implicit_const
        macro_rules! constant {
            ($value:ident, $variant:ident) => {
                if let Some(value) = self.$value() {
                    return AttributeValue::$variant(value);
                }
            };
            ($value:ident, $variant:ident, $constant:ident) => {
                if let Some(value) = self.$value() {
                    return AttributeValue::$variant(constants::$constant(value));
                }
            };
        }
        // DW_FORM_exprloc
        macro_rules! exprloc {
            () => {
                if let Some(value) = self.exprloc_value() {
                    return AttributeValue::Exprloc(value);
                }
            };
        }
        // DW_FORM_flag
        // DW_FORM_flag_present
        macro_rules! flag {
            () => {};
        }
        // DW_FORM_sec_offset
        macro_rules! lineptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugLineRef(DebugLineOffset(offset));
                }
            };
        }
        // This also covers `loclist` in DWARF version 5.
        // DW_FORM_sec_offset
        // DW_FORM_loclistx
        macro_rules! loclistptr {
            () => {
                // DebugLocListsIndex is also an allowed form in DWARF version 5.
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::LocationListsRef(LocationListsOffset(offset));
                }
            };
        }
        // DW_FORM_sec_offset
        macro_rules! loclistsptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset));
                }
            };
        }
        // DWARF version <= 4.
        // DW_FORM_sec_offset
        macro_rules! macinfoptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset));
                }
            };
        }
        // DWARF version >= 5.
        // DW_FORM_sec_offset
        macro_rules! macroptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugMacroRef(DebugMacroOffset(offset));
                }
            };
        }
        // DW_FORM_ref_addr
        // DW_FORM_ref1
        // DW_FORM_ref2
        // DW_FORM_ref4
        // DW_FORM_ref8
        // DW_FORM_ref_udata
        // DW_FORM_ref_sig8
        // DW_FORM_ref_sup4
        // DW_FORM_ref_sup8
        macro_rules! reference {
            () => {};
        }
        // This also covers `rnglist` in DWARF version 5.
        // DW_FORM_sec_offset
        // DW_FORM_rnglistx
        macro_rules! rangelistptr {
            () => {
                // DebugRngListsIndex is also an allowed form in DWARF version 5.
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::RangeListsRef(RawRangeListsOffset(offset));
                }
            };
        }
        // DW_FORM_sec_offset
        macro_rules! rnglistsptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset));
                }
            };
        }
        // DW_FORM_string
        // DW_FORM_strp
        // DW_FORM_strx
        // DW_FORM_strx1
        // DW_FORM_strx2
        // DW_FORM_strx3
        // DW_FORM_strx4
        // DW_FORM_strp_sup
        // DW_FORM_line_strp
        macro_rules! string {
            () => {};
        }
        // DW_FORM_sec_offset
        macro_rules! stroffsetsptr {
            () => {
                if let Some(offset) = self.offset_value() {
                    return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset));
                }
            };
        }
        // This isn't a separate form but it's useful to distinguish it from a generic udata.
        macro_rules! dwoid {
            () => {
                if let Some(value) = self.udata_value() {
                    return AttributeValue::DwoId(DwoId(value));
                }
            };
        }

        // Perform the allowed class conversions for each attribute name.
        match self.name {
            constants::DW_AT_sibling => {
                reference!();
            }
            constants::DW_AT_location => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_name => {
                string!();
            }
            constants::DW_AT_ordering => {
                constant!(u8_value, Ordering, DwOrd);
            }
            constants::DW_AT_byte_size
            | constants::DW_AT_bit_offset
            | constants::DW_AT_bit_size => {
                constant!(udata_value, Udata);
                exprloc!();
                reference!();
            }
            constants::DW_AT_stmt_list => {
                lineptr!();
            }
            constants::DW_AT_low_pc => {
                address!();
            }
            constants::DW_AT_high_pc => {
                address!();
                constant!(udata_value, Udata);
            }
            constants::DW_AT_language => {
                constant!(u16_value, Language, DwLang);
            }
            constants::DW_AT_discr => {
                reference!();
            }
            constants::DW_AT_discr_value => {
                // constant: depends on type of DW_TAG_variant_part,
                // so caller must normalize.
            }
            constants::DW_AT_visibility => {
                constant!(u8_value, Visibility, DwVis);
            }
            constants::DW_AT_import => {
                reference!();
            }
            constants::DW_AT_string_length => {
                exprloc!();
                loclistptr!();
                reference!();
            }
            constants::DW_AT_common_reference => {
                reference!();
            }
            constants::DW_AT_comp_dir => {
                string!();
            }
            constants::DW_AT_const_value => {
                // TODO: constant: sign depends on DW_AT_type.
                block!();
                string!();
            }
            constants::DW_AT_containing_type => {
                reference!();
            }
            constants::DW_AT_default_value => {
                // TODO: constant: sign depends on DW_AT_type.
                reference!();
                flag!();
            }
            constants::DW_AT_inline => {
                constant!(u8_value, Inline, DwInl);
            }
            constants::DW_AT_is_optional => {
                flag!();
            }
            constants::DW_AT_lower_bound => {
                // TODO: constant: sign depends on DW_AT_type.
                exprloc!();
                reference!();
            }
            constants::DW_AT_producer => {
                string!();
            }
            constants::DW_AT_prototyped => {
                flag!();
            }
            constants::DW_AT_return_addr => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_start_scope => {
                // TODO: constant
                rangelistptr!();
            }
            constants::DW_AT_bit_stride => {
                constant!(udata_value, Udata);
                exprloc!();
                reference!();
            }
            constants::DW_AT_upper_bound => {
                // TODO: constant: sign depends on DW_AT_type.
                exprloc!();
                reference!();
            }
            constants::DW_AT_abstract_origin => {
                reference!();
            }
            constants::DW_AT_accessibility => {
                constant!(u8_value, Accessibility, DwAccess);
            }
            constants::DW_AT_address_class => {
                constant!(udata_value, AddressClass, DwAddr);
            }
            constants::DW_AT_artificial => {
                flag!();
            }
            constants::DW_AT_base_types => {
                reference!();
            }
            constants::DW_AT_calling_convention => {
                constant!(u8_value, CallingConvention, DwCc);
            }
            constants::DW_AT_count => {
                // TODO: constant
                exprloc!();
                reference!();
            }
            constants::DW_AT_data_member_location => {
                // Constants must be handled before loclistptr so that DW_FORM_data4/8
                // are correctly interpreted for DWARF version 4+.
                constant!(udata_value, Udata);
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_decl_column => {
                constant!(udata_value, Udata);
            }
            constants::DW_AT_decl_file => {
                constant!(udata_value, FileIndex);
            }
            constants::DW_AT_decl_line => {
                constant!(udata_value, Udata);
            }
            constants::DW_AT_declaration => {
                flag!();
            }
            constants::DW_AT_discr_list => {
                block!();
            }
            constants::DW_AT_encoding => {
                constant!(u8_value, Encoding, DwAte);
            }
            constants::DW_AT_external => {
                flag!();
            }
            constants::DW_AT_frame_base => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_friend => {
                reference!();
            }
            constants::DW_AT_identifier_case => {
                constant!(u8_value, IdentifierCase, DwId);
            }
            constants::DW_AT_macro_info => {
                macinfoptr!();
            }
            constants::DW_AT_namelist_item => {
                reference!();
            }
            constants::DW_AT_priority => {
                reference!();
            }
            constants::DW_AT_segment => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_specification => {
                reference!();
            }
            constants::DW_AT_static_link => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_type => {
                reference!();
            }
            constants::DW_AT_use_location => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_variable_parameter => {
                flag!();
            }
            constants::DW_AT_virtuality => {
                constant!(u8_value, Virtuality, DwVirtuality);
            }
            constants::DW_AT_vtable_elem_location => {
                exprloc!();
                loclistptr!();
            }
            constants::DW_AT_allocated => {
                // TODO: constant
                exprloc!();
                reference!();
            }
            constants::DW_AT_associated => {
                // TODO: constant
                exprloc!();
                reference!();
            }
            constants::DW_AT_data_location => {
                exprloc!();
            }
            constants::DW_AT_byte_stride => {
                constant!(udata_value, Udata);
                exprloc!();
                reference!();
            }
            constants::DW_AT_entry_pc => {
                // TODO: constant
                address!();
            }
            constants::DW_AT_use_UTF8 => {
                flag!();
            }
            constants::DW_AT_extension => {
                reference!();
            }
            constants::DW_AT_ranges => {
                rangelistptr!();
            }
            constants::DW_AT_trampoline => {
                address!();
                flag!();
                reference!();
                string!();
            }
            constants::DW_AT_call_column => {
                constant!(udata_value, Udata);
            }
            constants::DW_AT_call_file => {
                constant!(udata_value, FileIndex);
            }
            constants::DW_AT_call_line => {
                constant!(udata_value, Udata);
            }
            constants::DW_AT_description => {
                string!();
            }
            constants::DW_AT_binary_scale => {
                // TODO: constant
            }
            constants::DW_AT_decimal_scale => {
                // TODO: constant
            }
            constants::DW_AT_small => {
                reference!();
            }
            constants::DW_AT_decimal_sign => {
                constant!(u8_value, DecimalSign, DwDs);
            }
            constants::DW_AT_digit_count => {
                // TODO: constant
            }
            constants::DW_AT_picture_string => {
                string!();
            }
            constants::DW_AT_mutable => {
                flag!();
            }
            constants::DW_AT_threads_scaled => {
                flag!();
            }
            constants::DW_AT_explicit => {
                flag!();
            }
            constants::DW_AT_object_pointer => {
                reference!();
            }
            constants::DW_AT_endianity => {
                constant!(u8_value, Endianity, DwEnd);
            }
            constants::DW_AT_elemental => {
                flag!();
            }
            constants::DW_AT_pure => {
                flag!();
            }
            constants::DW_AT_recursive => {
                flag!();
            }
            constants::DW_AT_signature => {
                reference!();
            }
            constants::DW_AT_main_subprogram => {
                flag!();
            }
            constants::DW_AT_data_bit_offset => {
                // TODO: constant
            }
            constants::DW_AT_const_expr => {
                flag!();
            }
            constants::DW_AT_enum_class => {
                flag!();
            }
            constants::DW_AT_linkage_name => {
                string!();
            }
            constants::DW_AT_string_length_bit_size => {
                // TODO: constant
            }
            constants::DW_AT_string_length_byte_size => {
                // TODO: constant
            }
            constants::DW_AT_rank => {
                // TODO: constant
                exprloc!();
            }
            constants::DW_AT_str_offsets_base => {
                stroffsetsptr!();
            }
            constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
                addrptr!();
            }
            constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
                rnglistsptr!();
            }
            constants::DW_AT_dwo_name => {
                string!();
            }
            constants::DW_AT_reference => {
                flag!();
            }
            constants::DW_AT_rvalue_reference => {
                flag!();
            }
            constants::DW_AT_macros => {
                macroptr!();
            }
            constants::DW_AT_call_all_calls => {
                flag!();
            }
            constants::DW_AT_call_all_source_calls => {
                flag!();
            }
            constants::DW_AT_call_all_tail_calls => {
                flag!();
            }
            constants::DW_AT_call_return_pc => {
                address!();
            }
            constants::DW_AT_call_value => {
                exprloc!();
            }
            constants::DW_AT_call_origin => {
                exprloc!();
            }
            constants::DW_AT_call_parameter => {
                reference!();
            }
            constants::DW_AT_call_pc => {
                address!();
            }
            constants::DW_AT_call_tail_call => {
                flag!();
            }
            constants::DW_AT_call_target => {
                exprloc!();
            }
            constants::DW_AT_call_target_clobbered => {
                exprloc!();
            }
            constants::DW_AT_call_data_location => {
                exprloc!();
            }
            constants::DW_AT_call_data_value => {
                exprloc!();
            }
            constants::DW_AT_noreturn => {
                flag!();
            }
            constants::DW_AT_alignment => {
                // TODO: constant
            }
            constants::DW_AT_export_symbols => {
                flag!();
            }
            constants::DW_AT_deleted => {
                flag!();
            }
            constants::DW_AT_defaulted => {
                // TODO: constant
            }
            constants::DW_AT_loclists_base => {
                loclistsptr!();
            }
            constants::DW_AT_GNU_dwo_id => {
                dwoid!();
            }
            _ => {}
        }
        self.value.clone()
    }

    /// Try to convert this attribute's value to a u8.
    #[inline]
    pub fn u8_value(&self) -> Option<u8> {
        self.value.u8_value()
    }

    /// Try to convert this attribute's value to a u16.
    #[inline]
    pub fn u16_value(&self) -> Option<u16> {
        self.value.u16_value()
    }

    /// Try to convert this attribute's value to an unsigned integer.
    #[inline]
    pub fn udata_value(&self) -> Option<u64> {
        self.value.udata_value()
    }

    /// Try to convert this attribute's value to a signed integer.
    #[inline]
    pub fn sdata_value(&self) -> Option<i64> {
        self.value.sdata_value()
    }

    /// Try to convert this attribute's value to an offset.
    #[inline]
    pub fn offset_value(&self) -> Option<R::Offset> {
        self.value.offset_value()
    }

    /// Try to convert this attribute's value to an expression or location buffer.
    ///
    /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
    /// The standard doesn't mention `DW_FORM_block*` as a possible form, but
    /// it is encountered in practice.
    #[inline]
    pub fn exprloc_value(&self) -> Option<Expression<R>> {
        self.value.exprloc_value()
    }

    /// Try to return this attribute's value as a string slice.
    ///
    /// If this attribute's value is either an inline `DW_FORM_string` string,
    /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
    /// section, return the attribute's string value as `Some`. Other attribute
    /// value forms are returned as `None`.
    ///
    /// Warning: this function does not handle all possible string forms.
    /// Use `Dwarf::attr_string` instead.
    #[inline]
    pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
        self.value.string_value(debug_str)
    }

    /// Try to return this attribute's value as a string slice.
    ///
    /// If this attribute's value is either an inline `DW_FORM_string` string,
    /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
    /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
    /// object file, return the attribute's string value as `Some`. Other attribute
    /// value forms are returned as `None`.
    ///
    /// Warning: this function does not handle all possible string forms.
    /// Use `Dwarf::attr_string` instead.
    #[inline]
    pub fn string_value_sup(
        &self,
        debug_str: &DebugStr<R>,
        debug_str_sup: Option<&DebugStr<R>>,
    ) -> Option<R> {
        self.value.string_value_sup(debug_str, debug_str_sup)
    }
}

impl<R, Offset> AttributeValue<R, Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// Try to convert this attribute's value to a u8.
    pub fn u8_value(&self) -> Option<u8> {
        if let Some(value) = self.udata_value() {
            if value <= u64::from(u8::MAX) {
                return Some(value as u8);
            }
        }
        None
    }

    /// Try to convert this attribute's value to a u16.
    pub fn u16_value(&self) -> Option<u16> {
        if let Some(value) = self.udata_value() {
            if value <= u64::from(u16::MAX) {
                return Some(value as u16);
            }
        }
        None
    }

    /// Try to convert this attribute's value to an unsigned integer.
    pub fn udata_value(&self) -> Option<u64> {
        Some(match *self {
            AttributeValue::Data1(data) => u64::from(data),
            AttributeValue::Data2(data) => u64::from(data),
            AttributeValue::Data4(data) => u64::from(data),
            AttributeValue::Data8(data) => data,
            AttributeValue::Udata(data) => data,
            AttributeValue::Sdata(data) => {
                if data < 0 {
                    // Maybe we should emit a warning here
                    return None;
                }
                data as u64
            }
            _ => return None,
        })
    }

    /// Try to convert this attribute's value to a signed integer.
    pub fn sdata_value(&self) -> Option<i64> {
        Some(match *self {
            AttributeValue::Data1(data) => i64::from(data as i8),
            AttributeValue::Data2(data) => i64::from(data as i16),
            AttributeValue::Data4(data) => i64::from(data as i32),
            AttributeValue::Data8(data) => data as i64,
            AttributeValue::Sdata(data) => data,
            AttributeValue::Udata(data) => {
                if data > i64::max_value() as u64 {
                    // Maybe we should emit a warning here
                    return None;
                }
                data as i64
            }
            _ => return None,
        })
    }

    /// Try to convert this attribute's value to an offset.
    pub fn offset_value(&self) -> Option<R::Offset> {
        // While offsets will be DW_FORM_data4/8 in DWARF version 2/3,
        // these have already been converted to `SecOffset.
        if let AttributeValue::SecOffset(offset) = *self {
            Some(offset)
        } else {
            None
        }
    }

    /// Try to convert this attribute's value to an expression or location buffer.
    ///
    /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
    /// The standard doesn't mention `DW_FORM_block*` as a possible form, but
    /// it is encountered in practice.
    pub fn exprloc_value(&self) -> Option<Expression<R>> {
        Some(match *self {
            AttributeValue::Block(ref data) => Expression(data.clone()),
            AttributeValue::Exprloc(ref data) => data.clone(),
            _ => return None,
        })
    }

    /// Try to return this attribute's value as a string slice.
    ///
    /// If this attribute's value is either an inline `DW_FORM_string` string,
    /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
    /// section, return the attribute's string value as `Some`. Other attribute
    /// value forms are returned as `None`.
    ///
    /// Warning: this function does not handle all possible string forms.
    /// Use `Dwarf::attr_string` instead.
    pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
        match *self {
            AttributeValue::String(ref string) => Some(string.clone()),
            AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
            _ => None,
        }
    }

    /// Try to return this attribute's value as a string slice.
    ///
    /// If this attribute's value is either an inline `DW_FORM_string` string,
    /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
    /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
    /// object file, return the attribute's string value as `Some`. Other attribute
    /// value forms are returned as `None`.
    ///
    /// Warning: this function does not handle all possible string forms.
    /// Use `Dwarf::attr_string` instead.
    pub fn string_value_sup(
        &self,
        debug_str: &DebugStr<R>,
        debug_str_sup: Option<&DebugStr<R>>,
    ) -> Option<R> {
        match *self {
            AttributeValue::String(ref string) => Some(string.clone()),
            AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
            AttributeValue::DebugStrRefSup(offset) => {
                debug_str_sup.and_then(|s| s.get_str(offset).ok())
            }
            _ => None,
        }
    }
}

fn length_u8_value<R: Reader>(input: &mut R) -> Result<R> {
    let len = input.read_u8().map(R::Offset::from_u8)?;
    input.split(len)
}

--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.46unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge