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. pubfn 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. pubfn 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. pubfn 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. pubfn 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)] pubstruct 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); /// ``` pubfn 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). pubfn 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. /// /// pubfn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> { let input = &mutself.debug_info_section.clone();
input.skip(offset.0)?;
parse_unit_header(input, offset.into())
}
}
impl<T> DebugInfo<T> { /// Create a `DebugInfo` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// Used by `DwarfSections::borrow`. pubfn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R> where
F: FnMut(&'a T) -> R,
{
borrow(&self.debug_info_section).into()
}
}
/// 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)] pubstruct DebugInfoUnitHeadersIter<R: Reader> {
input: R,
offset: DebugInfoOffset<R::Offset>,
}
impl<R: Reader> DebugInfoUnitHeadersIter<R> { /// Advance the iterator to the next unit header. pubfn next(&mutself) -> Result<Option<UnitHeader<R>>> { ifself.input.is_empty() {
Ok(None)
} else { let len = self.input.len(); match parse_unit_header(&mutself.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;
/// 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)] pubenum 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 { matchself {
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)] pubstruct 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,
}
/// Instance methods. impl<R, Offset> UnitHeader<R, Offset> where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{ /// Get the offset of this unit within its section. pubfn offset(&self) -> UnitSectionOffset<Offset> { self.unit_offset
}
/// Return the serialized size of the common unit header for the given /// DWARF format. pubfn 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 = ifself.encoding.version == 5 { 1 } else { 0 }; let type_specific_size = matchself.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,
};
/// Get the length of the debugging info for this compilation unit, not /// including the byte length of the encoded length itself. pubfn 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. pubfn length_including_self(&self) -> Offset {
Offset::from_u8(self.format().initial_length_size()) + self.unit_length
}
/// Return the encoding parameters for this unit. pubfn encoding(&self) -> Encoding { self.encoding
}
/// Get the DWARF version of the debugging info for this compilation unit. pubfn version(&self) -> u16 { self.encoding.version
}
/// Get the UnitType of this unit. pubfn type_(&self) -> UnitType<Offset> { self.unit_type
}
/// The offset into the `.debug_abbrev` section for this compilation unit's /// debugging information entries' abbreviations. pubfn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> { self.debug_abbrev_offset
}
/// The size of addresses (in bytes) in this compilation unit. pubfn address_size(&self) -> u8 { self.encoding.address_size
}
/// Whether this compilation unit is encoded in 64- or 32-bit DWARF. pubfn format(&self) -> Format { self.encoding.format
}
/// The serialized size of the header for this compilation unit. pubfn 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 { returnfalse;
}
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. pubfn 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; letmut input = self.entries_buf.clone();
input.skip(start)?;
input.truncate(end - start)?;
Ok(input)
}
/// Get the underlying bytes for the supplied range. pubfn 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(); letmut input = self.entries_buf.clone();
input.skip(start)?;
Ok(input)
}
/// Get the underlying bytes for the supplied range. pubfn 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(); letmut input = self.entries_buf.clone();
input.truncate(end)?;
Ok(input)
}
/// Read the `DebuggingInformationEntry` at the given offset. pubfn entry<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: UnitOffset<Offset>,
) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> { letmut input = self.range_from(offset..)?; let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?;
entry.ok_or(Error::NoEntryAtGivenOffset)
}
/// 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()?; letmut 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. if2 <= 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,
};
} elseif 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),
};
/// 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)] pubstruct 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>,
}
/// Get this entry's code. pubfn code(&self) -> u64 { self.abbrev.code()
}
/// Get this entry's offset. pubfn 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), /// }; /// ``` pubfn tag(&self) -> constants::DwTag { self.abbrev.tag()
}
/// Return true if this entry's type can have children, false otherwise. pubfn 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). pubfn 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. pubfn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> { letmut attrs = self.attrs(); whilelet 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. pubfn 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. pubfn 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> { iflet Some(attrs_len) = self.attrs_len.get() { letmut input = self.attrs_slice.clone();
input.skip(attrs_len)?;
Ok(input)
} else { letmut 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); iflet Ok(Some(AttributeValue::UnitRef(offset))) = attr { if offset.0 > self.offset.0 { iflet Ok(input) = self.unit.range_from(offset..) { return Some(input);
}
}
}
None
}
/// Parse an entry. Returns `Ok(None)` for null entries. #[inline(always)] fn parse(
input: &mut R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
) -> Result<Option<Self>> { let offset = unit.header_size() + input.offset_from(&unit.entries_buf); let code = input.read_uleb128()?; if code == 0 { return Ok(None);
}; let abbrev = abbreviations
.get(code)
.ok_or(Error::UnknownAbbreviation(code))?;
Ok(Some(DebuggingInformationEntry {
offset: UnitOffset(offset),
attrs_slice: input.clone(),
attrs_len: Cell::new(None),
abbrev,
unit,
}))
}
}
/// The value of an attribute in a `DebuggingInformationEntry`. // // Set the discriminant size so that all variants use the same alignment // for their data. This gives better code generation in `parse_attribute`. #[repr(u64)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pubenum 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)] pubstruct Attribute<R: Reader> {
name: constants::DwAt,
value: AttributeValue<R>,
}
impl<R: Reader> Attribute<R> { /// Get this attribute's name. pubfn name(&self) -> constants::DwAt { self.name
}
/// Get this attribute's raw value. pubfn 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". pubfn 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.
/// Try to convert this attribute's value to a u8. #[inline] pubfn u8_value(&self) -> Option<u8> { self.value.u8_value()
}
/// Try to convert this attribute's value to a u16. #[inline] pubfn u16_value(&self) -> Option<u16> { self.value.u16_value()
}
/// Try to convert this attribute's value to an unsigned integer. #[inline] pubfn udata_value(&self) -> Option<u64> { self.value.udata_value()
}
/// Try to convert this attribute's value to a signed integer. #[inline] pubfn sdata_value(&self) -> Option<i64> { self.value.sdata_value()
}
/// Try to convert this attribute's value to an offset. #[inline] pubfn 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] pubfn 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] pubfn 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] pubfn 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. pubfn u8_value(&self) -> Option<u8> { iflet 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. pubfn u16_value(&self) -> Option<u16> { iflet 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. pubfn 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. pubfn 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. pubfn 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. iflet 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. pubfn 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. pubfn 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. pubfn 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>> { letmut 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(form));
}
}; 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<()> { letmut skip_bytes = R::Offset::from_u8(0); for spec in specs { letmut form = spec.form(); loop { iflet 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);
}
/// 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)] pubstruct 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)] pubfn next(&mutself) -> Result<Option<Attribute<R>>> { ifself.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. iflet 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(&mutself.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;
/// 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)] pubstruct 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] pubfn 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. pubfn 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] pubfn next_depth(&self) -> isize { self.depth
}
/// Read an abbreviation code and lookup the corresponding `Abbreviation`. /// /// Returns `Ok(None)` for null entries. #[inline] pubfn read_abbreviation(&mutself) -> 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(code))?; if abbrev.has_children() { self.depth += 1;
}
Ok(Some(abbrev))
}
/// Skip all the attributes of an abbreviation. #[inline] pubfn skip_attributes(&mutself, specs: &[AttributeSpecification]) -> Result<()> {
skip_attributes(&mutself.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)] pubstruct 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] pubfn 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. pubfn next_entry(&mutself) -> Result<Option<()>> { iflet Some(ref current) = self.cached_current { self.input = current.after_attrs()?;
}
/// 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()); /// ``` pubfn next_dfs(
&mutself,
) -> Result<Option<(isize, &DebuggingInformationEntry<'abbrev, 'unit, R>)>> { letmut delta_depth = self.delta_depth; loop { // The next entry should be the one we want. ifself.next_entry()?.is_some() { iflet Some(ref entry) = self.cached_current { return Ok(Some((delta_depth, entry)));
}
/// 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; /// } /// } /// ``` pubfn next_sibling(
&mutself,
) -> Result<Option<&DebuggingInformationEntry<'abbrev, 'unit, R>>> { ifself.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. letmut depth = 0; loop { // Use is_some() and unwrap() to keep borrow checker happy. ifself.current().is_some() && self.current().unwrap().has_children() { iflet 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;
}
}
ifself.next_entry()?.is_none() { // End of input. return Ok(None);
}
if depth == 0 { // Found an entry at the current level. return Ok(self.current());
}
ifself.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)] pubstruct 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,
}
loop { matchself.entry {
Some(ref entry) => { if entry.has_children() { iflet 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;
}
}
/// 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)] pubstruct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> {
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
}
/// Returns the current entry in the tree. pubfn 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. pubfn 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)] pubstruct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> {
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
empty: bool,
}
/// Returns an `EntriesTreeNode` for the next child entry. /// /// Returns `None` if there are no more children. pubfn next<'me>(&'me mutself) -> Result<Option<EntriesTreeNode<'abbrev, 'unit, 'me, R>>> { ifself.empty {
Ok(None)
} elseifself.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)] pubstruct 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); /// ``` pubfn 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. /// /// Used by `DwarfSections::borrow`. pubfn 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: 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). pubfn 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)] pubstruct DebugTypesUnitHeadersIter<R: Reader> {
input: R,
offset: DebugTypesOffset<R::Offset>,
}
impl<R: Reader> DebugTypesUnitHeadersIter<R> { /// Advance the iterator to the next type unit header. pubfn next(&mutself) -> Result<Option<UnitHeader<R>>> { ifself.input.is_empty() {
Ok(None)
} else { let len = self.input.len(); match parse_unit_header(&mutself.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;
impl UnitSectionMethods for Section { fn unit<E>(self, unit: &mut UnitHeader<EndianSlice<'_, 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),
};
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);
#[test] fn test_parse_type_offset_incomplete() { // Need at least 4 bytes. let buf = [0xff, 0xff, 0xff]; let rest = &mut EndianSlice::new(&buf, LittleEndian);
#[test] fn test_attribute_value() { letmut 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);
#[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);
}
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);
}
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);
}
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]; letmut 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]; letmut 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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
// 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");
{ // 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());
}
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,
}; letmut 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"); letmut tree = unit
.entries_tree(&abbrevs, None)
.expect("Should have entries tree");
// Test we can restart iteration of the tree.
{ letmut iter = assert_entry(tree.root().map(Some), "root");
assert_entry(iter.next(), "1");
}
{ letmut iter = assert_entry(tree.root().map(Some), "root");
assert_entry(iter.next(), "1");
}
letmut iter = assert_entry(tree.root().map(Some), "root");
{ // Test iteration with children. letmut iter = assert_entry(iter.next(), "1");
{ // Test iteration with children flag, but no children. letmut iter = assert_entry(iter.next(), "1a");
assert_null(iter.next());
assert_null(iter.next());
}
{ // Test iteration without children flag. letmut 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. letmut 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. letmut iter = assert_entry(iter.next(), "3");
{ letmut 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. letmut tree = unit
.entries_tree(&abbrevs, Some(entry2))
.expect("Should have entries tree"); letmut 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_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();
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.148 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.