diff options
author | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
commit | a990de90fe41456a23e58bd087d2f107d321f3a1 (patch) | |
tree | 15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/gimli/src/read/unit.rs | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/gimli/src/read/unit.rs')
-rw-r--r-- | vendor/gimli/src/read/unit.rs | 6139 |
1 files changed, 0 insertions, 6139 deletions
diff --git a/vendor/gimli/src/read/unit.rs b/vendor/gimli/src/read/unit.rs deleted file mode 100644 index d799f0f..0000000 --- a/vendor/gimli/src/read/unit.rs +++ /dev/null @@ -1,6139 +0,0 @@ -//! 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. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugInfo<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - 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)?; - 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) -} - -fn length_u16_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_u16().map(R::Offset::from_u16)?; - input.split(len) -} - -fn length_u32_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_u32().map(R::Offset::from_u32)?; - input.split(len) -} - -fn length_uleb128_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - input.split(len) -} - -// Return true if the given `name` can be a section offset in DWARF version 2/3. -// This is required to correctly handle relocations. -fn allow_section_offset(name: constants::DwAt, version: u16) -> bool { - match name { - constants::DW_AT_location - | constants::DW_AT_stmt_list - | constants::DW_AT_string_length - | constants::DW_AT_return_addr - | constants::DW_AT_start_scope - | constants::DW_AT_frame_base - | constants::DW_AT_macro_info - | constants::DW_AT_macros - | constants::DW_AT_segment - | constants::DW_AT_static_link - | constants::DW_AT_use_location - | constants::DW_AT_vtable_elem_location - | constants::DW_AT_ranges => true, - constants::DW_AT_data_member_location => version == 2 || version == 3, - _ => false, - } -} - -pub(crate) fn parse_attribute<R: Reader>( - input: &mut R, - encoding: Encoding, - spec: AttributeSpecification, -) -> Result<Attribute<R>> { - let mut form = spec.form(); - loop { - let value = match form { - constants::DW_FORM_indirect => { - let dynamic_form = input.read_uleb128_u16()?; - form = constants::DwForm(dynamic_form); - continue; - } - constants::DW_FORM_addr => { - let addr = input.read_address(encoding.address_size)?; - AttributeValue::Addr(addr) - } - constants::DW_FORM_block1 => { - let block = length_u8_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block2 => { - let block = length_u16_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block4 => { - let block = length_u32_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block => { - let block = length_uleb128_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_data1 => { - let data = input.read_u8()?; - AttributeValue::Data1(data) - } - constants::DW_FORM_data2 => { - let data = input.read_u16()?; - AttributeValue::Data2(data) - } - constants::DW_FORM_data4 => { - // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. - // Ensure we handle relocations here. - if encoding.format == Format::Dwarf32 - && allow_section_offset(spec.name(), encoding.version) - { - let offset = input.read_offset(Format::Dwarf32)?; - AttributeValue::SecOffset(offset) - } else { - let data = input.read_u32()?; - AttributeValue::Data4(data) - } - } - constants::DW_FORM_data8 => { - // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. - // Ensure we handle relocations here. - if encoding.format == Format::Dwarf64 - && allow_section_offset(spec.name(), encoding.version) - { - let offset = input.read_offset(Format::Dwarf64)?; - AttributeValue::SecOffset(offset) - } else { - let data = input.read_u64()?; - AttributeValue::Data8(data) - } - } - constants::DW_FORM_data16 => { - let block = input.split(R::Offset::from_u8(16))?; - AttributeValue::Block(block) - } - constants::DW_FORM_udata => { - let data = input.read_uleb128()?; - AttributeValue::Udata(data) - } - constants::DW_FORM_sdata => { - let data = input.read_sleb128()?; - AttributeValue::Sdata(data) - } - constants::DW_FORM_exprloc => { - let block = length_uleb128_value(input)?; - AttributeValue::Exprloc(Expression(block)) - } - constants::DW_FORM_flag => { - let present = input.read_u8()?; - AttributeValue::Flag(present != 0) - } - constants::DW_FORM_flag_present => { - // FlagPresent is this weird compile time always true thing that - // isn't actually present in the serialized DIEs, only in the abbreviation. - AttributeValue::Flag(true) - } - constants::DW_FORM_sec_offset => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::SecOffset(offset) - } - constants::DW_FORM_ref1 => { - let reference = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref2 => { - let reference = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref4 => { - let reference = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref8 => { - let reference = input.read_u64().and_then(R::Offset::from_u64)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref_udata => { - let reference = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref_addr => { - // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr - // has the same size as an address on the target system. This was changed - // in DWARF version 3. - let offset = if encoding.version == 2 { - input.read_sized_offset(encoding.address_size)? - } else { - input.read_offset(encoding.format)? - }; - AttributeValue::DebugInfoRef(DebugInfoOffset(offset)) - } - constants::DW_FORM_ref_sig8 => { - let signature = input.read_u64()?; - AttributeValue::DebugTypesRef(DebugTypeSignature(signature)) - } - constants::DW_FORM_ref_sup4 => { - let offset = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_ref_sup8 => { - let offset = input.read_u64().and_then(R::Offset::from_u64)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_GNU_ref_alt => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_string => { - let string = input.read_null_terminated_slice()?; - AttributeValue::String(string) - } - constants::DW_FORM_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRef(DebugStrOffset(offset)) - } - constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) - } - constants::DW_FORM_line_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) - } - constants::DW_FORM_implicit_const => { - let data = spec - .implicit_const_value() - .ok_or(Error::InvalidImplicitConst)?; - AttributeValue::Sdata(data) - } - constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx1 => { - let index = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx2 => { - let index = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx3 => { - let index = input.read_uint(3).and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx4 => { - let index = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx1 => { - let index = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx2 => { - let index = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx3 => { - let index = input.read_uint(3).and_then(R::Offset::from_u64)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx4 => { - let index = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_loclistx => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index)) - } - constants::DW_FORM_rnglistx => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index)) - } - _ => { - return Err(Error::UnknownForm); - } - }; - let attr = Attribute { - name: spec.name(), - value, - }; - return Ok(attr); - } -} - -pub(crate) fn skip_attributes<R: Reader>( - input: &mut R, - encoding: Encoding, - specs: &[AttributeSpecification], -) -> Result<()> { - let mut skip_bytes = R::Offset::from_u8(0); - for spec in specs { - let mut form = spec.form(); - loop { - if let Some(len) = get_attribute_size(form, encoding) { - // We know the length of this attribute. Accumulate that length. - skip_bytes += R::Offset::from_u8(len); - break; - } - - // We have encountered a variable-length attribute. - if skip_bytes != R::Offset::from_u8(0) { - // Skip the accumulated skip bytes and then read the attribute normally. - input.skip(skip_bytes)?; - skip_bytes = R::Offset::from_u8(0); - } - - match form { - constants::DW_FORM_indirect => { - let dynamic_form = input.read_uleb128_u16()?; - form = constants::DwForm(dynamic_form); - continue; - } - constants::DW_FORM_block1 => { - skip_bytes = input.read_u8().map(R::Offset::from_u8)?; - } - constants::DW_FORM_block2 => { - skip_bytes = input.read_u16().map(R::Offset::from_u16)?; - } - constants::DW_FORM_block4 => { - skip_bytes = input.read_u32().map(R::Offset::from_u32)?; - } - constants::DW_FORM_block | constants::DW_FORM_exprloc => { - skip_bytes = input.read_uleb128().and_then(R::Offset::from_u64)?; - } - constants::DW_FORM_string => { - let _ = input.read_null_terminated_slice()?; - } - constants::DW_FORM_udata - | constants::DW_FORM_sdata - | constants::DW_FORM_ref_udata - | constants::DW_FORM_strx - | constants::DW_FORM_GNU_str_index - | constants::DW_FORM_addrx - | constants::DW_FORM_GNU_addr_index - | constants::DW_FORM_loclistx - | constants::DW_FORM_rnglistx => { - input.skip_leb128()?; - } - _ => { - return Err(Error::UnknownForm); - } - }; - break; - } - } - if skip_bytes != R::Offset::from_u8(0) { - // Skip the remaining accumulated skip bytes. - input.skip(skip_bytes)?; - } - Ok(()) -} - -/// An iterator over a particular entry's attributes. -/// -/// See [the documentation for -/// `DebuggingInformationEntry::attrs()`](./struct.DebuggingInformationEntry.html#method.attrs) -/// for details. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Clone, Copy, Debug)] -pub struct AttrsIter<'abbrev, 'entry, 'unit, R: Reader> { - input: R, - attributes: &'abbrev [AttributeSpecification], - entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>, -} - -impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> { - /// Advance the iterator and return the next attribute. - /// - /// Returns `None` when iteration is finished. If an error - /// occurs while parsing the next attribute, then this error - /// is returned, and all subsequent calls return `None`. - #[inline(always)] - pub fn next(&mut self) -> Result<Option<Attribute<R>>> { - if self.attributes.is_empty() { - // Now that we have parsed all of the attributes, we know where - // either (1) this entry's children start, if the abbreviation says - // this entry has children; or (2) where this entry's siblings - // begin. - if let Some(end) = self.entry.attrs_len.get() { - debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice)); - } else { - self.entry - .attrs_len - .set(Some(self.input.offset_from(&self.entry.attrs_slice))); - } - - return Ok(None); - } - - let spec = self.attributes[0]; - let rest_spec = &self.attributes[1..]; - match parse_attribute(&mut self.input, self.entry.unit.encoding(), spec) { - Ok(attr) => { - self.attributes = rest_spec; - Ok(Some(attr)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<'abbrev, 'entry, 'unit, R: Reader> fallible_iterator::FallibleIterator - for AttrsIter<'abbrev, 'entry, 'unit, R> -{ - type Item = Attribute<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - AttrsIter::next(self) - } -} - -/// A raw reader of the data that defines the Debugging Information Entries. -/// -/// `EntriesRaw` provides primitives to read the components of Debugging Information -/// Entries (DIEs). A DIE consists of an abbreviation code (read with `read_abbreviation`) -/// followed by a number of attributes (read with `read_attribute`). -/// The user must provide the control flow to read these correctly. -/// In particular, all attributes must always be read before reading another -/// abbreviation code. -/// -/// `EntriesRaw` lacks some features of `EntriesCursor`, such as the ability to skip -/// to the next sibling DIE. However, this also allows it to optimize better, since it -/// does not need to perform the extra bookkeeping required to support these features, -/// and thus it is suitable for cases where performance is important. -/// -/// ## Example Usage -/// ```rust,no_run -/// # fn example() -> Result<(), gimli::Error> { -/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); -/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); -/// let unit = get_some_unit(); -/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); -/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); -/// let abbrevs = get_abbrevs_for_unit(&unit); -/// -/// let mut entries = unit.entries_raw(&abbrevs, None)?; -/// while !entries.is_empty() { -/// let abbrev = if let Some(abbrev) = entries.read_abbreviation()? { -/// abbrev -/// } else { -/// // Null entry with no attributes. -/// continue -/// }; -/// match abbrev.tag() { -/// gimli::DW_TAG_subprogram => { -/// // Loop over attributes for DIEs we care about. -/// for spec in abbrev.attributes() { -/// let attr = entries.read_attribute(*spec)?; -/// match attr.name() { -/// // Handle attributes. -/// _ => {} -/// } -/// } -/// } -/// _ => { -/// // Skip attributes for DIEs we don't care about. -/// entries.skip_attributes(abbrev.attributes()); -/// } -/// } -/// } -/// # unreachable!() -/// # } -/// ``` -#[derive(Clone, Debug)] -pub struct EntriesRaw<'abbrev, 'unit, R> -where - R: Reader, -{ - input: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesRaw<'abbrev, 'unit, R> { - /// Return true if there is no more input. - #[inline] - pub fn is_empty(&self) -> bool { - self.input.is_empty() - } - - /// Return the unit offset at which the reader will read next. - /// - /// If you want the offset of the next entry, then this must be called prior to reading - /// the next entry. - pub fn next_offset(&self) -> UnitOffset<R::Offset> { - UnitOffset(self.unit.header_size() + self.input.offset_from(&self.unit.entries_buf)) - } - - /// Return the depth of the next entry. - /// - /// This depth is updated when `read_abbreviation` is called, and is updated - /// based on null entries and the `has_children` field in the abbreviation. - #[inline] - pub fn next_depth(&self) -> isize { - self.depth - } - - /// Read an abbreviation code and lookup the corresponding `Abbreviation`. - /// - /// Returns `Ok(None)` for null entries. - #[inline] - pub fn read_abbreviation(&mut self) -> Result<Option<&'abbrev Abbreviation>> { - let code = self.input.read_uleb128()?; - if code == 0 { - self.depth -= 1; - return Ok(None); - }; - let abbrev = self - .abbreviations - .get(code) - .ok_or(Error::UnknownAbbreviation)?; - if abbrev.has_children() { - self.depth += 1; - } - Ok(Some(abbrev)) - } - - /// Read an attribute. - #[inline] - pub fn read_attribute(&mut self, spec: AttributeSpecification) -> Result<Attribute<R>> { - parse_attribute(&mut self.input, self.unit.encoding(), spec) - } - - /// Skip all the attributes of an abbreviation. - #[inline] - pub fn skip_attributes(&mut self, specs: &[AttributeSpecification]) -> Result<()> { - skip_attributes(&mut self.input, self.unit.encoding(), specs) - } -} - -/// A cursor into the Debugging Information Entries tree for a compilation unit. -/// -/// The `EntriesCursor` can traverse the DIE tree in DFS order using `next_dfs()`, -/// or skip to the next sibling of the entry the cursor is currently pointing to -/// using `next_sibling()`. -/// -/// It is also possible to traverse the DIE tree at a lower abstraction level -/// using `next_entry()`. This method does not skip over null entries, or provide -/// any indication of the current tree depth. In this case, you must use `current()` -/// to obtain the current entry, and `current().has_children()` to determine if -/// the entry following the current entry will be a sibling or child. `current()` -/// will return `None` if the current entry is a null entry, which signifies the -/// end of the current tree depth. -#[derive(Clone, Debug)] -pub struct EntriesCursor<'abbrev, 'unit, R> -where - R: Reader, -{ - input: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - cached_current: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>, - delta_depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> { - /// Get a reference to the entry that the cursor is currently pointing to. - /// - /// If the cursor is not pointing at an entry, or if the current entry is a - /// null entry, then `None` is returned. - #[inline] - pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> { - self.cached_current.as_ref() - } - - /// Move the cursor to the next DIE in the tree. - /// - /// Returns `Some` if there is a next entry, even if this entry is null. - /// If there is no next entry, then `None` is returned. - pub fn next_entry(&mut self) -> Result<Option<()>> { - if let Some(ref current) = self.cached_current { - self.input = current.after_attrs()?; - } - - if self.input.is_empty() { - self.cached_current = None; - self.delta_depth = 0; - return Ok(None); - } - - match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { - Ok(Some(entry)) => { - self.delta_depth = entry.has_children() as isize; - self.cached_current = Some(entry); - Ok(Some(())) - } - Ok(None) => { - self.delta_depth = -1; - self.cached_current = None; - Ok(Some(())) - } - Err(e) => { - self.input.empty(); - self.delta_depth = 0; - self.cached_current = None; - Err(e) - } - } - } - - /// Move the cursor to the next DIE in the tree in DFS order. - /// - /// Upon successful movement of the cursor, return the delta traversal - /// depth and the entry: - /// - /// * If we moved down into the previous current entry's children, we get - /// `Some((1, entry))`. - /// - /// * If we moved to the previous current entry's sibling, we get - /// `Some((0, entry))`. - /// - /// * If the previous entry does not have any siblings and we move up to - /// its parent's next sibling, then we get `Some((-1, entry))`. Note that - /// if the parent doesn't have a next sibling, then it could go up to the - /// parent's parent's next sibling and return `Some((-2, entry))`, etc. - /// - /// If there is no next entry, then `None` is returned. - /// - /// Here is an example that finds the first entry in a compilation unit that - /// does not have any children. - /// - /// ``` - /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 25 - /// # 0x19, 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, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // 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 get_some_unit = || debug_info.units().next().unwrap().unwrap(); - /// - /// let unit = get_some_unit(); - /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); - /// let abbrevs = get_abbrevs_for_unit(&unit); - /// - /// let mut first_entry_with_no_children = None; - /// let mut cursor = unit.entries(&abbrevs); - /// - /// // Move the cursor to the root. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Traverse the DIE tree in depth-first search order. - /// let mut depth = 0; - /// while let Some((delta_depth, current)) = cursor.next_dfs().expect("Should parse next dfs") { - /// // Update depth value, and break out of the loop when we - /// // return to the original starting position. - /// depth += delta_depth; - /// if depth <= 0 { - /// break; - /// } - /// - /// first_entry_with_no_children = Some(current.clone()); - /// } - /// - /// println!("The first entry with no children is {:?}", - /// first_entry_with_no_children.unwrap()); - /// ``` - pub fn next_dfs( - &mut self, - ) -> Result<Option<(isize, &DebuggingInformationEntry<'abbrev, 'unit, R>)>> { - let mut delta_depth = self.delta_depth; - loop { - // The next entry should be the one we want. - if self.next_entry()?.is_some() { - if let Some(ref entry) = self.cached_current { - return Ok(Some((delta_depth, entry))); - } - - // next_entry() read a null entry. - delta_depth += self.delta_depth; - } else { - return Ok(None); - } - } - } - - /// Move the cursor to the next sibling DIE of the current one. - /// - /// Returns `Ok(Some(entry))` when the cursor has been moved to - /// the next sibling, `Ok(None)` when there is no next sibling. - /// - /// The depth of the cursor is never changed if this method returns `Ok`. - /// Once `Ok(None)` is returned, this method will continue to return - /// `Ok(None)` until either `next_entry` or `next_dfs` is called. - /// - /// Here is an example that iterates over all of the direct children of the - /// root entry: - /// - /// ``` - /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 25 - /// # 0x19, 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, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # - /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); - /// - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // 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 = get_some_unit(); - /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); - /// let abbrevs = get_abbrevs_for_unit(&unit); - /// - /// let mut cursor = unit.entries(&abbrevs); - /// - /// // Move the cursor to the root. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Move the cursor to the root's first child. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Iterate the root's children. - /// loop { - /// { - /// let current = cursor.current().expect("Should be at an entry"); - /// println!("{:?} is a child of the root", current); - /// } - /// - /// if cursor.next_sibling().expect("Should parse next sibling").is_none() { - /// break; - /// } - /// } - /// ``` - pub fn next_sibling( - &mut self, - ) -> Result<Option<&DebuggingInformationEntry<'abbrev, 'unit, R>>> { - if self.current().is_none() { - // We're already at the null for the end of the sibling list. - return Ok(None); - } - - // Loop until we find an entry at the current level. - let mut depth = 0; - loop { - // Use is_some() and unwrap() to keep borrow checker happy. - if self.current().is_some() && self.current().unwrap().has_children() { - if let Some(sibling_input) = self.current().unwrap().sibling() { - // Fast path: this entry has a DW_AT_sibling - // attribute pointing to its sibling, so jump - // to it (which keeps us at the same depth). - self.input = sibling_input; - self.cached_current = None; - } else { - // This entry has children, so the next entry is - // down one level. - depth += 1; - } - } - - if self.next_entry()?.is_none() { - // End of input. - return Ok(None); - } - - if depth == 0 { - // Found an entry at the current level. - return Ok(self.current()); - } - - if self.current().is_none() { - // A null entry means the end of a child list, so we're - // back up a level. - depth -= 1; - } - } - } -} - -/// The state information for a tree view of the Debugging Information Entries. -/// -/// The `EntriesTree` can be used to recursively iterate through the DIE -/// tree, following the parent/child relationships. The `EntriesTree` contains -/// shared state for all nodes in the tree, avoiding any duplicate parsing of -/// entries during the traversal. -/// -/// ## Example Usage -/// ```rust,no_run -/// # fn example() -> Result<(), gimli::Error> { -/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); -/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); -/// let unit = get_some_unit(); -/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); -/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); -/// let abbrevs = get_abbrevs_for_unit(&unit); -/// -/// let mut tree = unit.entries_tree(&abbrevs, None)?; -/// let root = tree.root()?; -/// process_tree(root)?; -/// # unreachable!() -/// # } -/// -/// fn process_tree<R>(mut node: gimli::EntriesTreeNode<R>) -> gimli::Result<()> -/// where R: gimli::Reader -/// { -/// { -/// // Examine the entry attributes. -/// let mut attrs = node.entry().attrs(); -/// while let Some(attr) = attrs.next()? { -/// } -/// } -/// let mut children = node.children(); -/// while let Some(child) = children.next()? { -/// // Recursively process a child. -/// process_tree(child); -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Clone, Debug)] -pub struct EntriesTree<'abbrev, 'unit, R> -where - R: Reader, -{ - root: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - input: R, - entry: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>, - depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> { - fn new(root: R, unit: &'unit UnitHeader<R>, abbreviations: &'abbrev Abbreviations) -> Self { - let input = root.clone(); - EntriesTree { - root, - unit, - abbreviations, - input, - entry: None, - depth: 0, - } - } - - /// Returns the root node of the tree. - pub fn root<'me>(&'me mut self) -> Result<EntriesTreeNode<'abbrev, 'unit, 'me, R>> { - self.input = self.root.clone(); - self.entry = - DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?; - if self.entry.is_none() { - return Err(Error::UnexpectedNull); - } - self.depth = 0; - Ok(EntriesTreeNode::new(self, 1)) - } - - /// Move the cursor to the next entry at the specified depth. - /// - /// Requires `depth <= self.depth + 1`. - /// - /// Returns `true` if successful. - fn next(&mut self, depth: isize) -> Result<bool> { - if self.depth < depth { - debug_assert_eq!(self.depth + 1, depth); - - match self.entry { - Some(ref entry) => { - if !entry.has_children() { - return Ok(false); - } - self.depth += 1; - self.input = entry.after_attrs()?; - } - None => return Ok(false), - } - - if self.input.is_empty() { - self.entry = None; - return Ok(false); - } - - return match DebuggingInformationEntry::parse( - &mut self.input, - self.unit, - self.abbreviations, - ) { - Ok(entry) => { - self.entry = entry; - Ok(self.entry.is_some()) - } - Err(e) => { - self.input.empty(); - self.entry = None; - Err(e) - } - }; - } - - loop { - match self.entry { - Some(ref entry) => { - if entry.has_children() { - if let Some(sibling_input) = entry.sibling() { - // Fast path: this entry has a DW_AT_sibling - // attribute pointing to its sibling, so jump - // to it (which keeps us at the same depth). - self.input = sibling_input; - } else { - // This entry has children, so the next entry is - // down one level. - self.depth += 1; - self.input = entry.after_attrs()?; - } - } else { - // This entry has no children, so next entry is at same depth. - self.input = entry.after_attrs()?; - } - } - None => { - // This entry is a null, so next entry is up one level. - self.depth -= 1; - } - } - - if self.input.is_empty() { - self.entry = None; - return Ok(false); - } - - match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { - Ok(entry) => { - self.entry = entry; - if self.depth == depth { - return Ok(self.entry.is_some()); - } - } - Err(e) => { - self.input.empty(); - self.entry = None; - return Err(e); - } - } - } - } -} - -/// A node in the Debugging Information Entry tree. -/// -/// The root node of a tree can be obtained -/// via [`EntriesTree::root`](./struct.EntriesTree.html#method.root). -#[derive(Debug)] -pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> { - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, -} - -impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { - fn new( - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - ) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { - debug_assert!(tree.entry.is_some()); - EntriesTreeNode { tree, depth } - } - - /// Returns the current entry in the tree. - pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> { - // We never create a node without an entry. - self.tree.entry.as_ref().unwrap() - } - - /// Create an iterator for the children of the current entry. - /// - /// The current entry can no longer be accessed after creating the - /// iterator. - pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - EntriesTreeIter::new(self.tree, self.depth) - } -} - -/// An iterator that allows traversal of the children of an -/// `EntriesTreeNode`. -/// -/// The items returned by this iterator are also `EntriesTreeNode`s, -/// which allow recursive traversal of grandchildren, etc. -#[derive(Debug)] -pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> { - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - empty: bool, -} - -impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - fn new( - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - EntriesTreeIter { - tree, - depth, - empty: false, - } - } - - /// Returns an `EntriesTreeNode` for the next child entry. - /// - /// Returns `None` if there are no more children. - pub fn next<'me>(&'me mut self) -> Result<Option<EntriesTreeNode<'abbrev, 'unit, 'me, R>>> { - if self.empty { - Ok(None) - } else if self.tree.next(self.depth)? { - Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1))) - } else { - self.empty = true; - Ok(None) - } - } -} - -/// Parse a type unit header's unique type signature. Callers should handle -/// unique-ness checking. -fn parse_type_signature<R: Reader>(input: &mut R) -> Result<DebugTypeSignature> { - input.read_u64().map(DebugTypeSignature) -} - -/// Parse a type unit header's type offset. -fn parse_type_offset<R: Reader>(input: &mut R, format: Format) -> Result<UnitOffset<R::Offset>> { - input.read_offset(format).map(UnitOffset) -} - -/// The `DebugTypes` struct represents the DWARF type information -/// found in the `.debug_types` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugTypes<R> { - debug_types_section: R, -} - -impl<'input, Endian> DebugTypes<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugTypes` instance from the data in the `.debug_types` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_types` 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::{DebugTypes, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_types_section_somehow = || &buf; - /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_types_section, endian)) - } -} - -impl<T> DebugTypes<T> { - /// Create a `DebugTypes` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugTypes<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_types_section).into() - } -} - -impl<R> Section<R> for DebugTypes<R> { - fn id() -> SectionId { - SectionId::DebugTypes - } - - fn reader(&self) -> &R { - &self.debug_types_section - } -} - -impl<R> From<R> for DebugTypes<R> { - fn from(debug_types_section: R) -> Self { - DebugTypes { - debug_types_section, - } - } -} - -impl<R: Reader> DebugTypes<R> { - /// Iterate the type-units in this `.debug_types` section. - /// - /// ``` - /// use gimli::{DebugTypes, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_types_section_somehow = || &buf; - /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); - /// - /// let mut iter = debug_types.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) -> DebugTypesUnitHeadersIter<R> { - DebugTypesUnitHeadersIter { - input: self.debug_types_section.clone(), - offset: DebugTypesOffset(R::Offset::from_u8(0)), - } - } -} - -/// An iterator over the type-units of this `.debug_types` section. -/// -/// See the [documentation on -/// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for -/// more detail. -#[derive(Clone, Debug)] -pub struct DebugTypesUnitHeadersIter<R: Reader> { - input: R, - offset: DebugTypesOffset<R::Offset>, -} - -impl<R: Reader> DebugTypesUnitHeadersIter<R> { - /// Advance the iterator to the next type 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 DebugTypesUnitHeadersIter<R> { - type Item = UnitHeader<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - DebugTypesUnitHeadersIter::next(self) - } -} - -#[cfg(test)] -// Tests require leb128::write. -#[cfg(feature = "write")] -mod tests { - use super::*; - use crate::constants; - use crate::constants::*; - use crate::endianity::{Endianity, LittleEndian}; - use crate::leb128; - use crate::read::abbrev::tests::AbbrevSectionMethods; - use crate::read::{ - Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, - }; - use crate::test_util::GimliSectionMethods; - use alloc::vec::Vec; - use core::cell::Cell; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - // Mixin methods for `Section` to help define binary test data. - - trait UnitSectionMethods { - fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self - where - E: Endianity; - fn die<F>(self, code: u64, attr: F) -> Self - where - F: Fn(Section) -> Section; - fn die_null(self) -> Self; - fn attr_string(self, s: &str) -> Self; - fn attr_ref1(self, o: u8) -> Self; - fn offset(self, offset: usize, format: Format) -> Self; - } - - impl UnitSectionMethods for Section { - fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self - where - E: Endianity, - { - let size = self.size(); - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = match unit.format() { - Format::Dwarf32 => self.L32(&length), - Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length), - }; - - let section = match unit.version() { - 2 | 3 | 4 => section - .mark(&start) - .L16(unit.version()) - .offset(unit.debug_abbrev_offset.0, unit.format()) - .D8(unit.address_size()), - 5 => section - .mark(&start) - .L16(unit.version()) - .D8(unit.type_().dw_ut().0) - .D8(unit.address_size()) - .offset(unit.debug_abbrev_offset.0, unit.format()), - _ => unreachable!(), - }; - - let section = match unit.type_() { - UnitType::Compilation | UnitType::Partial => { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - section - } - UnitType::Type { - type_signature, - type_offset, - } - | UnitType::SplitType { - type_signature, - type_offset, - } => { - if unit.version() == 5 { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - } else { - unit.unit_offset = DebugTypesOffset(size as usize).into(); - } - section - .L64(type_signature.0) - .offset(type_offset.0, unit.format()) - } - UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - section.L64(dwo_id.0) - } - }; - - let section = section.append_bytes(unit.entries_buf.slice()).mark(&end); - - unit.unit_length = (&end - &start) as usize; - length.set_const(unit.unit_length as u64); - - section - } - - fn die<F>(self, code: u64, attr: F) -> Self - where - F: Fn(Section) -> Section, - { - let section = self.uleb(code); - attr(section) - } - - fn die_null(self) -> Self { - self.D8(0) - } - - fn attr_string(self, attr: &str) -> Self { - self.append_bytes(attr.as_bytes()).D8(0) - } - - fn attr_ref1(self, attr: u8) -> Self { - self.D8(attr) - } - - fn offset(self, offset: usize, format: Format) -> Self { - match format { - Format::Dwarf32 => self.L32(offset as u32), - Format::Dwarf64 => self.L64(offset as u64), - } - } - } - - /// Ensure that `UnitHeader<R>` is covariant wrt R. - #[test] - fn test_unit_header_variance() { - /// This only needs to compile. - fn _f<'a: 'b, 'b, E: Endianity>( - x: UnitHeader<EndianSlice<'a, E>>, - ) -> UnitHeader<EndianSlice<'b, E>> { - x - } - } - - #[test] - fn test_parse_debug_abbrev_offset_32() { - let section = Section::with_endian(Endian::Little).L32(0x0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf32) { - Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_abbrev_offset_32_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_debug_abbrev_offset_64() { - let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf64) { - Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_abbrev_offset_64_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf64) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_32() { - let section = Section::with_endian(Endian::Little).L32(0x0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf32) { - Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_32_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_debug_info_offset_64() { - let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf64) { - Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_64_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf64) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_units() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let mut unit64 = UnitHeader { - encoding: Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let mut unit32 = UnitHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut unit64) - .unit(&mut unit32); - let buf = section.get_contents().unwrap(); - - let debug_info = DebugInfo::new(&buf, LittleEndian); - let mut units = debug_info.units(); - - assert_eq!(units.next(), Ok(Some(unit64))); - assert_eq!(units.next(), Ok(Some(unit32))); - assert_eq!(units.next(), Ok(None)); - } - - #[test] - fn test_unit_version_unknown_version() { - let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnknownVersion(0xcdab)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - - let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnknownVersion(1)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_unit_version_incomplete() { - let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_partial_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Partial, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_partial_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Partial, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_skeleton_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_skeleton_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_split_compilation_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_split_compilation_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_type_offset_32_ok() { - let buf = [0x12, 0x34, 0x56, 0x78, 0x00]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf32) { - Ok(offset) => { - assert_eq!(rest.len(), 1); - assert_eq!(UnitOffset(0x7856_3412), offset); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_type_offset_64_ok() { - let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf64) { - Ok(offset) => { - assert_eq!(rest.len(), 1); - assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_parse_type_offset_incomplete() { - // Need at least 4 bytes. - let buf = [0xff, 0xff, 0xff]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugTypesOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugTypesOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_split_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitType { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_split_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitType { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - fn section_contents<F>(f: F) -> Vec<u8> - where - F: Fn(Section) -> Section, - { - f(Section::with_endian(Endian::Little)) - .get_contents() - .unwrap() - } - - #[test] - fn test_attribute_value() { - let mut unit = test_parse_attribute_unit_default(); - let endian = unit.entries_buf.endian(); - - let block_data = &[1, 2, 3, 4]; - let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data)); - let block = EndianSlice::new(&buf, endian); - - let buf = section_contents(|s| s.L32(0x0102_0304)); - let data4 = EndianSlice::new(&buf, endian); - - let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708)); - let data8 = EndianSlice::new(&buf, endian); - - let tests = [ - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_block, - block, - AttributeValue::Block(EndianSlice::new(block_data, endian)), - AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))), - ), - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), - ), - ( - Format::Dwarf64, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::Data4(0x0102_0304), - AttributeValue::Udata(0x0102_0304), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::Data4(0x0102_0304), - AttributeValue::Udata(0x0102_0304), - ), - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::Data8(0x0102_0304_0506_0708), - AttributeValue::Udata(0x0102_0304_0506_0708), - ), - #[cfg(target_pointer_width = "64")] - ( - Format::Dwarf64, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::SecOffset(0x0102_0304_0506_0708), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), - ), - ( - Format::Dwarf64, - 4, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::Data8(0x0102_0304_0506_0708), - AttributeValue::Udata(0x0102_0304_0506_0708), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_location, - constants::DW_FORM_data4, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), - ), - #[cfg(target_pointer_width = "64")] - ( - Format::Dwarf64, - 4, - constants::DW_AT_location, - constants::DW_FORM_data8, - data8, - AttributeValue::SecOffset(0x0102_0304_0506_0708), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_str_offsets_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_stmt_list, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugLineRef(DebugLineOffset(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_addr_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_rnglists_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_loclists_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)), - ), - ]; - - for test in tests.iter() { - let (format, version, name, form, mut input, expect_raw, expect_value) = *test; - unit.encoding.format = format; - unit.encoding.version = version; - let spec = AttributeSpecification::new(name, form, None); - let attribute = - parse_attribute(&mut input, unit.encoding(), spec).expect("Should parse attribute"); - assert_eq!(attribute.raw_value(), expect_raw); - assert_eq!(attribute.value(), expect_value); - } - } - - #[test] - fn test_attribute_udata_sdata_value() { - let tests: &[( - AttributeValue<EndianSlice<LittleEndian>>, - Option<u64>, - Option<i64>, - )] = &[ - (AttributeValue::Data1(1), Some(1), Some(1)), - ( - AttributeValue::Data1(core::u8::MAX), - Some(u64::from(std::u8::MAX)), - Some(-1), - ), - (AttributeValue::Data2(1), Some(1), Some(1)), - ( - AttributeValue::Data2(core::u16::MAX), - Some(u64::from(std::u16::MAX)), - Some(-1), - ), - (AttributeValue::Data4(1), Some(1), Some(1)), - ( - AttributeValue::Data4(core::u32::MAX), - Some(u64::from(std::u32::MAX)), - Some(-1), - ), - (AttributeValue::Data8(1), Some(1), Some(1)), - ( - AttributeValue::Data8(core::u64::MAX), - Some(core::u64::MAX), - Some(-1), - ), - (AttributeValue::Sdata(1), Some(1), Some(1)), - (AttributeValue::Sdata(-1), None, Some(-1)), - (AttributeValue::Udata(1), Some(1), Some(1)), - (AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None), - ]; - for test in tests.iter() { - let (value, expect_udata, expect_sdata) = *test; - let attribute = Attribute { - name: DW_AT_data_member_location, - value, - }; - assert_eq!(attribute.udata_value(), expect_udata); - assert_eq!(attribute.sdata_value(), expect_sdata); - } - } - - fn test_parse_attribute_unit<Endian>( - address_size: u8, - format: Format, - endian: Endian, - ) -> UnitHeader<EndianSlice<'static, Endian>> - where - Endian: Endianity, - { - let encoding = Encoding { - format, - version: 4, - address_size, - }; - UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], endian), - ) - } - - fn test_parse_attribute_unit_default() -> UnitHeader<EndianSlice<'static, LittleEndian>> { - test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian) - } - - fn test_parse_attribute<'input, Endian>( - buf: &'input [u8], - len: usize, - unit: &UnitHeader<EndianSlice<'input, Endian>>, - form: constants::DwForm, - value: AttributeValue<EndianSlice<'input, Endian>>, - ) where - Endian: Endianity, - { - let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form, None); - - let expect = Attribute { - name: constants::DW_AT_low_pc, - value, - }; - - let rest = &mut EndianSlice::new(buf, Endian::default()); - match parse_attribute(rest, unit.encoding(), spec) { - Ok(attr) => { - assert_eq!(attr, expect); - assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default())); - if let Some(size) = spec.size(unit) { - assert_eq!(rest.len() + size, buf.len()); - } - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - }; - } - - #[test] - fn test_parse_attribute_addr() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_addr; - let value = AttributeValue::Addr(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addr8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; - let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_addr; - let value = AttributeValue::Addr(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block1() { - // Length of data (3), three bytes of data, two bytes of left over input. - let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block1; - let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block2() { - // Two byte length of data (2), two bytes of data, two bytes of left over input. - let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block2; - let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block4() { - // Four byte length of data (2), two bytes of data, no left over input. - let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block4; - let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian)); - test_parse_attribute(&buf, 6, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block() { - // LEB length of data (2, one byte), two bytes of data, no left over input. - let buf = [0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block; - let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data1() { - let buf = [0x03]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data1; - let value = AttributeValue::Data1(0x03); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data2() { - let buf = [0x02, 0x01, 0x0]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data2; - let value = AttributeValue::Data2(0x0102); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data4; - let value = AttributeValue::Data4(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data8; - let value = AttributeValue::Data8(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_udata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_udata; - let value = AttributeValue::Udata(4097); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_sdata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::signed(&mut writable, -4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_sdata; - let value = AttributeValue::Sdata(-4097); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_exprloc() { - // LEB length of data (2, one byte), two bytes of data, one byte left over input. - let buf = [0x02, 0x99, 0x99, 0x11]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_exprloc; - let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian))); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_true() { - let buf = [0x42]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag; - let value = AttributeValue::Flag(true); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_false() { - let buf = [0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag; - let value = AttributeValue::Flag(false); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_present() { - let buf = [0x01, 0x02, 0x03, 0x04]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag_present; - let value = AttributeValue::Flag(true); - // DW_FORM_flag_present does not consume any bytes of the input stream. - test_parse_attribute(&buf, 0, &unit, form, value); - } - - #[test] - fn test_parse_attribute_sec_offset_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_sec_offset; - let value = AttributeValue::SecOffset(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_sec_offset_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_sec_offset; - let value = AttributeValue::SecOffset(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref1() { - let buf = [0x03]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref1; - let value = AttributeValue::UnitRef(UnitOffset(3)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref2() { - let buf = [0x02, 0x01, 0x0]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref2; - let value = AttributeValue::UnitRef(UnitOffset(258)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref4; - let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_ref8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref8; - let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref_sup4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sup4; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_ref_sup8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sup8; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refudata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_udata; - let value = AttributeValue::UnitRef(UnitOffset(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refaddr_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_refaddr_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refaddr_version2() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - unit.encoding.version = 2; - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_refaddr8_version2() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); - unit.encoding.version = 2; - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_gnu_ref_alt_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_GNU_ref_alt; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_gnu_ref_alt_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_GNU_ref_alt; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refsig8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sig8; - let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_string() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_string; - let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian)); - test_parse_attribute(&buf, 6, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strp_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_strp; - let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_strp_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strp; - let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strp_sup_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_strp_sup; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_strp_sup_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strp_sup; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_gnu_strp_alt_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_GNU_strp_alt; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_gnu_strp_alt_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_GNU_strp_alt; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_strx; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx1() { - let buf = [0x01, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx1; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx2() { - let buf = [0x01, 0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx2; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx3() { - let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx3; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx4; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_addrx; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx1() { - let buf = [0x01, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx1; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx2() { - let buf = [0x01, 0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx2; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx3() { - let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx3; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx4; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_loclistx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_loclistx; - let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_rnglistx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_rnglistx; - let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_indirect() { - let mut buf = [0; 100]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0.into()) - .expect("should write udata") - + leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_indirect; - let value = AttributeValue::Udata(9_999_999); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_indirect_implicit_const() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut buf = [0; 100]; - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, constants::DW_FORM_implicit_const.0.into()) - .expect("should write implicit_const"); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - let spec = - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_indirect, None); - assert_eq!( - parse_attribute(input, encoding, spec), - Err(Error::InvalidImplicitConst) - ); - } - - #[test] - fn test_attrs_iter() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let unit = UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], LittleEndian), - ); - - let abbrev = Abbreviation::new( - 42, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), - AttributeSpecification::new( - constants::DW_AT_high_pc, - constants::DW_FORM_addr, - None, - ), - ] - .into(), - ); - - // "foo", 42, 1337, 4 dangling bytes of 0xaa where children would be - let buf = [ - 0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa, - 0xaa, 0xaa, - ]; - - let entry = DebuggingInformationEntry { - offset: UnitOffset(0), - attrs_slice: EndianSlice::new(&buf, LittleEndian), - attrs_len: Cell::new(None), - abbrev: &abbrev, - unit: &unit, - }; - - let mut attrs = AttrsIter { - input: EndianSlice::new(&buf, LittleEndian), - attributes: abbrev.attributes(), - entry: &entry, - }; - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_name, - value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_low_pc, - value: AttributeValue::Addr(0x2a), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_high_pc, - value: AttributeValue::Addr(0x539), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - assert!(attrs.next().expect("should parse next").is_none()); - assert!(entry.attrs_len.get().is_some()); - assert_eq!( - entry.attrs_len.get().expect("should have entry.attrs_len"), - buf.len() - 4 - ) - } - - #[test] - fn test_attrs_iter_incomplete() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let unit = UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], LittleEndian), - ); - - let abbrev = Abbreviation::new( - 42, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), - AttributeSpecification::new( - constants::DW_AT_high_pc, - constants::DW_FORM_addr, - None, - ), - ] - .into(), - ); - - // "foo" - let buf = [0x66, 0x6f, 0x6f, 0x00]; - - let entry = DebuggingInformationEntry { - offset: UnitOffset(0), - attrs_slice: EndianSlice::new(&buf, LittleEndian), - attrs_len: Cell::new(None), - abbrev: &abbrev, - unit: &unit, - }; - - let mut attrs = AttrsIter { - input: EndianSlice::new(&buf, LittleEndian), - attributes: abbrev.attributes(), - entry: &entry, - }; - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_name, - value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - // Return error for incomplete attribute. - assert!(attrs.next().is_err()); - assert!(entry.attrs_len.get().is_none()); - - // Return error for all subsequent calls. - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(entry.attrs_len.get().is_none()); - } - - fn assert_entry_name<Endian>(entry: &DebuggingInformationEntry<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - let value = entry - .attr_value(constants::DW_AT_name) - .expect("Should have parsed the name attribute") - .expect("Should have found the name attribute"); - - assert_eq!( - value, - AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default())) - ); - } - - fn assert_current_name<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - let entry = cursor.current().expect("Should have an entry result"); - assert_entry_name(entry, name); - } - - fn assert_next_entry<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - assert_current_name(cursor, name); - } - - fn assert_next_entry_null<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>) - where - Endian: Endianity, - { - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - assert!(cursor.current().is_none()); - } - - fn assert_next_dfs<Endian>( - cursor: &mut EntriesCursor<EndianSlice<Endian>>, - name: &str, - depth: isize, - ) where - Endian: Endianity, - { - { - let (val, entry) = cursor - .next_dfs() - .expect("Should parse next dfs") - .expect("Should not be done with traversal"); - assert_eq!(val, depth); - assert_entry_name(entry, name); - } - assert_current_name(cursor, name); - } - - fn assert_next_sibling<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - { - let entry = cursor - .next_sibling() - .expect("Should parse next sibling") - .expect("Should not be done with traversal"); - assert_entry_name(entry, name); - } - assert_current_name(cursor, name); - } - - fn assert_valid_sibling_ptr<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>) - where - Endian: Endianity, - { - let sibling_ptr = cursor - .current() - .expect("Should have current entry") - .attr_value(constants::DW_AT_sibling); - match sibling_ptr { - Ok(Some(AttributeValue::UnitRef(offset))) => { - cursor - .unit - .range_from(offset..) - .expect("Sibling offset should be valid"); - } - _ => panic!("Invalid sibling pointer {:?}", sibling_ptr), - } - } - - fn entries_cursor_tests_abbrev_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - section.get_contents().unwrap() - } - - fn entries_cursor_tests_debug_info_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("001")) - .die(1, |s| s.attr_string("002")) - .die(1, |s| s.attr_string("003")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("004")) - .die(1, |s| s.attr_string("005")) - .die_null() - .die(1, |s| s.attr_string("006")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("007")) - .die(1, |s| s.attr_string("008")) - .die(1, |s| s.attr_string("009")) - .die_null() - .die_null() - .die_null() - .die(1, |s| s.attr_string("010")) - .die_null() - .die_null(); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - section.get_contents().unwrap() - } - - #[test] - fn test_cursor_next_entry_incomplete() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("001")) - .die(1, |s| s.attr_string("002")) - .die(1, |s| s); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = §ion.get_contents().unwrap(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_entry(&mut cursor, "001"); - assert_next_entry(&mut cursor, "002"); - - { - // Entry code is present, but none of the attributes. - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - let entry = cursor.current().expect("Should have an entry result"); - assert!(entry.attrs().next().is_err()); - } - - assert!(cursor.next_entry().is_err()); - assert!(cursor.next_entry().is_err()); - } - - #[test] - fn test_cursor_next_entry() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_entry(&mut cursor, "001"); - assert_next_entry(&mut cursor, "002"); - assert_next_entry(&mut cursor, "003"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "004"); - assert_next_entry(&mut cursor, "005"); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "006"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "007"); - assert_next_entry(&mut cursor, "008"); - assert_next_entry(&mut cursor, "009"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "010"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - - assert!(cursor - .next_entry() - .expect("Should parse next entry") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_dfs() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - assert_next_dfs(&mut cursor, "002", 1); - assert_next_dfs(&mut cursor, "003", 1); - assert_next_dfs(&mut cursor, "004", -1); - assert_next_dfs(&mut cursor, "005", 1); - assert_next_dfs(&mut cursor, "006", 0); - assert_next_dfs(&mut cursor, "007", -1); - assert_next_dfs(&mut cursor, "008", 1); - assert_next_dfs(&mut cursor, "009", 1); - assert_next_dfs(&mut cursor, "010", -2); - - assert!(cursor.next_dfs().expect("Should parse next dfs").is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_sibling_no_sibling_ptr() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - - // Down to the first child of the root entry. - - assert_next_dfs(&mut cursor, "002", 1); - - // Now iterate all children of the root via `next_sibling`. - - assert_next_sibling(&mut cursor, "004"); - assert_next_sibling(&mut cursor, "007"); - assert_next_sibling(&mut cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_sibling_continuation() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - - // Down to the first child of the root entry. - - assert_next_dfs(&mut cursor, "002", 1); - - // Get the next sibling, then iterate its children - - assert_next_sibling(&mut cursor, "004"); - assert_next_dfs(&mut cursor, "005", 1); - assert_next_sibling(&mut cursor, "006"); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - - // And we should be able to continue with the children of the root entry. - - assert_next_dfs(&mut cursor, "007", -1); - assert_next_sibling(&mut cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - fn entries_cursor_sibling_abbrev_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr(DW_AT_sibling, DW_FORM_ref1) - .abbrev_attr_null() - .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - section.get_contents().unwrap() - } - - fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec<u8> { - let start = Label::new(); - let sibling004_ref = Label::new(); - let sibling004 = Label::new(); - let sibling009_ref = Label::new(); - let sibling009 = Label::new(); - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .mark(&start) - .die(2, |s| s.attr_string("001")) - // Valid sibling attribute. - .die(1, |s| s.attr_string("002").D8(&sibling004_ref)) - // Invalid code to ensure the sibling attribute was used. - .die(10, |s| s.attr_string("003")) - .die_null() - .die_null() - .mark(&sibling004) - // Invalid sibling attribute. - .die(1, |s| s.attr_string("004").attr_ref1(255)) - .die(2, |s| s.attr_string("005")) - .die_null() - .die_null() - // Sibling attribute in child only. - .die(2, |s| s.attr_string("006")) - // Valid sibling attribute. - .die(1, |s| s.attr_string("007").D8(&sibling009_ref)) - // Invalid code to ensure the sibling attribute was used. - .die(10, |s| s.attr_string("008")) - .die_null() - .die_null() - .mark(&sibling009) - .die(2, |s| s.attr_string("009")) - .die_null() - .die_null() - // No sibling attribute. - .die(2, |s| s.attr_string("010")) - .die(2, |s| s.attr_string("011")) - .die_null() - .die_null() - .die_null(); - - let offset = header_size as u64 + (&sibling004 - &start) as u64; - sibling004_ref.set_const(offset); - - let offset = header_size as u64 + (&sibling009 - &start) as u64; - sibling009_ref.set_const(offset); - - section.get_contents().unwrap() - } - - fn test_cursor_next_sibling_with_ptr(cursor: &mut EntriesCursor<EndianSlice<LittleEndian>>) { - assert_next_dfs(cursor, "001", 0); - - // Down to the first child of the root. - - assert_next_dfs(cursor, "002", 1); - - // Now iterate all children of the root via `next_sibling`. - - assert_valid_sibling_ptr(&cursor); - assert_next_sibling(cursor, "004"); - assert_next_sibling(cursor, "006"); - assert_next_sibling(cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_debug_info_next_sibling_with_ptr() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrev_buf = entries_cursor_sibling_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - test_cursor_next_sibling_with_ptr(&mut cursor); - } - - #[test] - fn test_debug_types_next_sibling_with_ptr() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - }, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_types = DebugTypes::new(&info_buf, LittleEndian); - - let unit = debug_types - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrev_buf = entries_cursor_sibling_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - test_cursor_next_sibling_with_ptr(&mut cursor); - } - - #[test] - fn test_entries_at_offset() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit - .entries_at_offset(&abbrevs, UnitOffset(unit.header_size())) - .unwrap(); - assert_next_entry(&mut cursor, "001"); - - let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0)); - match cursor { - Err(Error::OffsetOutOfBounds) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - fn entries_tree_tests_debug_abbrevs_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null() - .get_contents() - .unwrap(); - section - } - - fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec<u8>, UnitOffset) { - let start = Label::new(); - let entry2 = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .mark(&start) - .die(1, |s| s.attr_string("root")) - .die(1, |s| s.attr_string("1")) - .die(1, |s| s.attr_string("1a")) - .die_null() - .die(2, |s| s.attr_string("1b")) - .die_null() - .mark(&entry2) - .die(1, |s| s.attr_string("2")) - .die(1, |s| s.attr_string("2a")) - .die(1, |s| s.attr_string("2a1")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("2b")) - .die(2, |s| s.attr_string("2b1")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("3")) - .die(1, |s| s.attr_string("3a")) - .die(2, |s| s.attr_string("3a1")) - .die(2, |s| s.attr_string("3a2")) - .die_null() - .die(2, |s| s.attr_string("3b")) - .die_null() - .die(2, |s| s.attr_string("final")) - .die_null() - .get_contents() - .unwrap(); - let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize); - (section, entry2) - } - - #[test] - fn test_entries_tree() { - fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>( - node: Result< - Option<EntriesTreeNode<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>>, - >, - name: &str, - ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>> - where - Endian: Endianity, - { - let node = node - .expect("Should parse entry") - .expect("Should have entry"); - assert_entry_name(node.entry(), name); - node.children() - } - - fn assert_null<E: Endianity>(node: Result<Option<EntriesTreeNode<EndianSlice<E>>>>) { - match node { - Ok(None) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let info_buf = Section::with_endian(Endian::Little) - .unit(&mut unit) - .get_contents() - .unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("Should parse unit") - .expect("and it should be some"); - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - let mut tree = unit - .entries_tree(&abbrevs, None) - .expect("Should have entries tree"); - - // Test we can restart iteration of the tree. - { - let mut iter = assert_entry(tree.root().map(Some), "root"); - assert_entry(iter.next(), "1"); - } - { - let mut iter = assert_entry(tree.root().map(Some), "root"); - assert_entry(iter.next(), "1"); - } - - let mut iter = assert_entry(tree.root().map(Some), "root"); - { - // Test iteration with children. - let mut iter = assert_entry(iter.next(), "1"); - { - // Test iteration with children flag, but no children. - let mut iter = assert_entry(iter.next(), "1a"); - assert_null(iter.next()); - assert_null(iter.next()); - } - { - // Test iteration without children flag. - let mut iter = assert_entry(iter.next(), "1b"); - assert_null(iter.next()); - assert_null(iter.next()); - } - assert_null(iter.next()); - assert_null(iter.next()); - } - { - // Test skipping over children. - let mut iter = assert_entry(iter.next(), "2"); - assert_entry(iter.next(), "2a"); - assert_entry(iter.next(), "2b"); - assert_null(iter.next()); - } - { - // Test skipping after partial iteration. - let mut iter = assert_entry(iter.next(), "3"); - { - let mut iter = assert_entry(iter.next(), "3a"); - assert_entry(iter.next(), "3a1"); - // Parent iter should be able to skip over "3a2". - } - assert_entry(iter.next(), "3b"); - assert_null(iter.next()); - } - assert_entry(iter.next(), "final"); - assert_null(iter.next()); - - // Test starting at an offset. - let mut tree = unit - .entries_tree(&abbrevs, Some(entry2)) - .expect("Should have entries tree"); - let mut iter = assert_entry(tree.root().map(Some), "2"); - assert_entry(iter.next(), "2a"); - assert_entry(iter.next(), "2b"); - assert_null(iter.next()); - } - - #[test] - fn test_entries_raw() { - fn assert_abbrev<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - tag: DwTag, - ) -> &'abbrev Abbreviation - where - Endian: Endianity, - { - let abbrev = entries - .read_abbreviation() - .expect("Should parse abbrev") - .expect("Should have abbrev"); - assert_eq!(abbrev.tag(), tag); - abbrev - } - - fn assert_null<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - ) where - Endian: Endianity, - { - match entries.read_abbreviation() { - Ok(None) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - fn assert_attr<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - spec: Option<AttributeSpecification>, - name: DwAt, - value: &str, - ) where - Endian: Endianity, - { - let spec = spec.expect("Should have attribute specification"); - let attr = entries - .read_attribute(spec) - .expect("Should parse attribute"); - assert_eq!(attr.name(), name); - assert_eq!( - attr.value(), - AttributeValue::String(EndianSlice::new(value.as_bytes(), Endian::default())) - ); - } - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr(DW_AT_linkage_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev(2, DW_TAG_variable, DW_CHILDREN_no) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - let abbrevs_buf = section.get_contents().unwrap(); - let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("f1").attr_string("l1")) - .die(2, |s| s.attr_string("v1")) - .die(2, |s| s.attr_string("v2")) - .die(1, |s| s.attr_string("f2").attr_string("l2")) - .die_null() - .die_null(); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut entries = unit - .entries_raw(&abbrevs, None) - .expect("Should have entries"); - - assert_eq!(entries.next_depth(), 0); - let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "f1"); - assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l1"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "v1"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "v2"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "f2"); - assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l2"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 2); - assert_null(&mut entries); - - assert_eq!(entries.next_depth(), 1); - assert_null(&mut entries); - - assert_eq!(entries.next_depth(), 0); - assert!(entries.is_empty()); - } - - #[test] - fn test_debug_info_offset() { - let padding = &[0; 10]; - let entries = &[0; 20]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(entries, LittleEndian), - }; - Section::with_endian(Endian::Little) - .append_bytes(padding) - .unit(&mut unit); - let offset = padding.len(); - let header_length = unit.size_of_header(); - let length = unit.length_including_self(); - assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None); - assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None); - assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None); - assert_eq!( - DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit), - None - ); - assert_eq!( - DebugInfoOffset(offset + header_length).to_unit_offset(&unit), - Some(UnitOffset(header_length)) - ); - assert_eq!( - DebugInfoOffset(offset + length - 1).to_unit_offset(&unit), - Some(UnitOffset(length - 1)) - ); - assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None); - assert_eq!( - UnitOffset(header_length).to_debug_info_offset(&unit), - Some(DebugInfoOffset(offset + header_length)) - ); - assert_eq!( - UnitOffset(length - 1).to_debug_info_offset(&unit), - Some(DebugInfoOffset(offset + length - 1)) - ); - } - - #[test] - fn test_debug_types_offset() { - let padding = &[0; 10]; - let entries = &[0; 20]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - }, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(entries, LittleEndian), - }; - Section::with_endian(Endian::Little) - .append_bytes(padding) - .unit(&mut unit); - let offset = padding.len(); - let header_length = unit.size_of_header(); - let length = unit.length_including_self(); - assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None); - assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None); - assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None); - assert_eq!( - DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit), - None - ); - assert_eq!( - DebugTypesOffset(offset + header_length).to_unit_offset(&unit), - Some(UnitOffset(header_length)) - ); - assert_eq!( - DebugTypesOffset(offset + length - 1).to_unit_offset(&unit), - Some(UnitOffset(length - 1)) - ); - assert_eq!( - DebugTypesOffset(offset + length).to_unit_offset(&unit), - None - ); - assert_eq!( - UnitOffset(header_length).to_debug_types_offset(&unit), - Some(DebugTypesOffset(offset + header_length)) - ); - assert_eq!( - UnitOffset(length - 1).to_debug_types_offset(&unit), - Some(DebugTypesOffset(offset + length - 1)) - ); - } - - #[test] - fn test_length_including_self() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - unit.encoding.format = Format::Dwarf32; - assert_eq!(unit.length_including_self(), 4); - unit.encoding.format = Format::Dwarf64; - assert_eq!(unit.length_including_self(), 12); - unit.unit_length = 10; - assert_eq!(unit.length_including_self(), 22); - } - - #[test] - fn test_parse_type_unit_abbrevs() { - let types_buf = [ - // Type unit header - 0x25, 0x00, 0x00, 0x00, // 32-bit unit length = 37 - 0x04, 0x00, // Version 4 - 0x00, 0x00, 0x00, 0x00, // debug_abbrev_offset - 0x04, // Address size - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Type signature - 0x01, 0x02, 0x03, 0x04, // Type offset - // DIEs - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - 0x00, // End of children - 0x00, // End of children - 0x00, // End of children - ]; - let debug_types = DebugTypes::new(&types_buf, LittleEndian); - - let abbrev_buf = [ - // Code - 0x01, // DW_TAG_subprogram - 0x2e, // DW_CHILDREN_yes - 0x01, // Begin attributes - 0x03, // Attribute name = DW_AT_name - 0x08, // Attribute form = DW_FORM_string - 0x00, 0x00, // End attributes - 0x00, // Null terminator - ]; - - let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); - - let unit = get_some_type_unit(); - - let read_debug_abbrev_section_somehow = || &abbrev_buf; - let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); - } -} |