|
|
|
|
SSL unit.rs
Interaktion und Portierbarkeitunbekannt
|
|
//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections.
use core::cell::Cell;
use core::ops::{Range, RangeFrom, RangeTo};
use core::{u16, u8};
use crate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset,
DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset,
DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format,
LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset,
};
use crate::constants;
use crate::endianity::Endianity;
use crate::read::abbrev::get_attribute_size;
use crate::read::{
Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error,
Expression, Reader, ReaderOffset, Result, Section, UnitOffset,
};
impl<T: ReaderOffset> DebugTypesOffset<T> {
/// Convert an offset to be relative to the start of the given unit,
/// instead of relative to the start of the .debug_types section.
/// Returns `None` if the offset is not within the unit entries.
pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_types_offset()?;
let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
if !unit.is_valid_offset(offset) {
return None;
}
Some(offset)
}
}
impl<T: ReaderOffset> DebugInfoOffset<T> {
/// Convert an offset to be relative to the start of the given unit,
/// instead of relative to the start of the .debug_info section.
/// Returns `None` if the offset is not within this unit entries.
pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_info_offset()?;
let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
if !unit.is_valid_offset(offset) {
return None;
}
Some(offset)
}
}
impl<T: ReaderOffset> UnitOffset<T> {
/// Convert an offset to be relative to the start of the .debug_info section,
/// instead of relative to the start of the given unit. Returns None if the
/// provided unit lives in the .debug_types section.
pub fn to_debug_info_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugInfoOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_info_offset()?;
Some(DebugInfoOffset(unit_offset.0 + self.0))
}
/// Convert an offset to be relative to the start of the .debug_types section,
/// instead of relative to the start of the given unit. Returns None if the
/// provided unit lives in the .debug_info section.
pub fn to_debug_types_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugTypesOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_types_offset()?;
Some(DebugTypesOffset(unit_offset.0 + self.0))
}
}
/// The `DebugInfo` struct represents the DWARF debugging information found in
/// the `.debug_info` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugInfo<R> {
debug_info_section: R,
}
impl<'input, Endian> DebugInfo<EndianSlice<'input, Endian>>
where
Endian: Endianity,
{
/// Construct a new `DebugInfo` instance from the data in the `.debug_info`
/// section.
///
/// It is the caller's responsibility to read the `.debug_info` section and
/// present it as a `&[u8]` slice. That means using some ELF loader on
/// Linux, a Mach-O loader on macOS, etc.
///
/// ```
/// use gimli::{DebugInfo, LittleEndian};
///
/// # let buf = [0x00, 0x01, 0x02, 0x03];
/// # let read_debug_info_section_somehow = || &buf;
/// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
/// ```
pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self {
Self::from(EndianSlice::new(debug_info_section, endian))
}
}
impl<R: Reader> DebugInfo<R> {
/// Iterate the units in this `.debug_info` section.
///
/// ```
/// use gimli::{DebugInfo, LittleEndian};
///
/// # let buf = [];
/// # let read_debug_info_section_somehow = || &buf;
/// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
///
/// let mut iter = debug_info.units();
/// while let Some(unit) = iter.next().unwrap() {
/// println!("unit's length is {}", unit.unit_length());
/// }
/// ```
///
/// Can be [used with
/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
DebugInfoUnitHeadersIter {
input: self.debug_info_section.clone(),
offset: DebugInfoOffset(R::Offset::from_u8(0)),
}
}
/// Get the UnitHeader located at offset from this .debug_info section.
///
///
pub fn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> {
let input = &mut self.debug_info_section.clone();
input.skip(offset.0)?;
parse_unit_header(input, offset.into())
}
}
impl<T> DebugInfo<T> {
/// Create a `DebugInfo` section that references the data in `self`.
///
/// This is useful when `R` implements `Reader` but `T` does not.
///
/// Used by `DwarfSections::borrow`.
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R>
where
F: FnMut(&'a T) -> R,
{
borrow(&self.debug_info_section).into()
}
}
impl<R> Section<R> for DebugInfo<R> {
fn id() -> SectionId {
SectionId::DebugInfo
}
fn reader(&self) -> &R {
&self.debug_info_section
}
}
impl<R> From<R> for DebugInfo<R> {
fn from(debug_info_section: R) -> Self {
DebugInfo { debug_info_section }
}
}
/// An iterator over the units of a .debug_info section.
///
/// See the [documentation on
/// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail.
#[derive(Clone, Debug)]
pub struct DebugInfoUnitHeadersIter<R: Reader> {
input: R,
offset: DebugInfoOffset<R::Offset>,
}
impl<R: Reader> DebugInfoUnitHeadersIter<R> {
/// Advance the iterator to the next unit header.
pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
if self.input.is_empty() {
Ok(None)
} else {
let len = self.input.len();
match parse_unit_header(&mut self.input, self.offset.into()) {
Ok(header) => {
self.offset.0 += len - self.input.len();
Ok(Some(header))
}
Err(e) => {
self.input.empty();
Err(e)
}
}
}
}
}
#[cfg(feature = "fallible-iterator")]
impl<R: Reader> fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter<R> {
type Item = UnitHeader<R>;
type Error = Error;
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
DebugInfoUnitHeadersIter::next(self)
}
}
/// Parse the unit type from the unit header.
fn parse_unit_type<R: Reader>(input: &mut R) -> Result<constants::DwUt> {
let val = input.read_u8()?;
Ok(constants::DwUt(val))
}
/// Parse the `debug_abbrev_offset` in the compilation unit header.
fn parse_debug_abbrev_offset<R: Reader>(
input: &mut R,
format: Format,
) -> Result<DebugAbbrevOffset<R::Offset>> {
input.read_offset(format).map(DebugAbbrevOffset)
}
/// Parse the `debug_info_offset` in the arange header.
pub(crate) fn parse_debug_info_offset<R: Reader>(
input: &mut R,
format: Format,
) -> Result<DebugInfoOffset<R::Offset>> {
input.read_offset(format).map(DebugInfoOffset)
}
/// This enum specifies the type of the unit and any type
/// specific data carried in the header (e.g. the type
/// signature/type offset of a type unit).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnitType<Offset>
where
Offset: ReaderOffset,
{
/// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions,
/// any unit appearing in the .debug_info section.
Compilation,
/// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing
/// in the .debug_types section.
Type {
/// The unique type signature for this type unit.
type_signature: DebugTypeSignature,
/// The offset within this type unit where the type is defined.
type_offset: UnitOffset<Offset>,
},
/// A unit with type `DW_UT_partial`. The root DIE of this unit should be a
/// `DW_TAG_partial_unit`.
Partial,
/// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to
/// link this with the corresponding `SplitCompilation` unit in a dwo file.
/// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
/// be a `Compilation` unit with the dwo_id present as an attribute on the
/// root DIE.
Skeleton(DwoId),
/// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to
/// link this with the corresponding `Skeleton` unit in the original binary.
/// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
/// be a `Compilation` unit with the dwo_id present as an attribute on the
/// root DIE.
SplitCompilation(DwoId),
/// A unit with type `DW_UT_split_type`. A split type unit is identical to a
/// conventional type unit except for the section in which it appears.
SplitType {
/// The unique type signature for this type unit.
type_signature: DebugTypeSignature,
/// The offset within this type unit where the type is defined.
type_offset: UnitOffset<Offset>,
},
}
impl<Offset> UnitType<Offset>
where
Offset: ReaderOffset,
{
// TODO: This will be used by the DWARF writing code once it
// supports unit types other than simple compilation units.
#[allow(unused)]
pub(crate) fn dw_ut(&self) -> constants::DwUt {
match self {
UnitType::Compilation => constants::DW_UT_compile,
UnitType::Type { .. } => constants::DW_UT_type,
UnitType::Partial => constants::DW_UT_partial,
UnitType::Skeleton(_) => constants::DW_UT_skeleton,
UnitType::SplitCompilation(_) => constants::DW_UT_split_compile,
UnitType::SplitType { .. } => constants::DW_UT_split_type,
}
}
}
/// The common fields for the headers of compilation units and
/// type units.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnitHeader<R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
encoding: Encoding,
unit_length: Offset,
unit_type: UnitType<Offset>,
debug_abbrev_offset: DebugAbbrevOffset<Offset>,
unit_offset: UnitSectionOffset<Offset>,
entries_buf: R,
}
/// Static methods.
impl<R, Offset> UnitHeader<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
/// Construct a new `UnitHeader`.
pub fn new(
encoding: Encoding,
unit_length: Offset,
unit_type: UnitType<Offset>,
debug_abbrev_offset: DebugAbbrevOffset<Offset>,
unit_offset: UnitSectionOffset<Offset>,
entries_buf: R,
) -> Self {
UnitHeader {
encoding,
unit_length,
unit_type,
debug_abbrev_offset,
unit_offset,
entries_buf,
}
}
}
/// Instance methods.
impl<R, Offset> UnitHeader<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
/// Get the offset of this unit within its section.
pub fn offset(&self) -> UnitSectionOffset<Offset> {
self.unit_offset
}
/// Return the serialized size of the common unit header for the given
/// DWARF format.
pub fn size_of_header(&self) -> usize {
let unit_length_size = self.encoding.format.initial_length_size() as usize;
let version_size = 2;
let debug_abbrev_offset_size = self.encoding.format.word_size() as usize;
let address_size_size = 1;
let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 };
let type_specific_size = match self.unit_type {
UnitType::Compilation | UnitType::Partial => 0,
UnitType::Type { .. } | UnitType::SplitType { .. } => {
let type_signature_size = 8;
let type_offset_size = self.encoding.format.word_size() as usize;
type_signature_size + type_offset_size
}
UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8,
};
unit_length_size
+ version_size
+ debug_abbrev_offset_size
+ address_size_size
+ unit_type_size
+ type_specific_size
}
/// Get the length of the debugging info for this compilation unit, not
/// including the byte length of the encoded length itself.
pub fn unit_length(&self) -> Offset {
self.unit_length
}
/// Get the length of the debugging info for this compilation unit,
/// including the byte length of the encoded length itself.
pub fn length_including_self(&self) -> Offset {
Offset::from_u8(self.format().initial_length_size()) + self.unit_length
}
/// Return the encoding parameters for this unit.
pub fn encoding(&self) -> Encoding {
self.encoding
}
/// Get the DWARF version of the debugging info for this compilation unit.
pub fn version(&self) -> u16 {
self.encoding.version
}
/// Get the UnitType of this unit.
pub fn type_(&self) -> UnitType<Offset> {
self.unit_type
}
/// The offset into the `.debug_abbrev` section for this compilation unit's
/// debugging information entries' abbreviations.
pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> {
self.debug_abbrev_offset
}
/// The size of addresses (in bytes) in this compilation unit.
pub fn address_size(&self) -> u8 {
self.encoding.address_size
}
/// Whether this compilation unit is encoded in 64- or 32-bit DWARF.
pub fn format(&self) -> Format {
self.encoding.format
}
/// The serialized size of the header for this compilation unit.
pub fn header_size(&self) -> Offset {
self.length_including_self() - self.entries_buf.len()
}
pub(crate) fn is_valid_offset(&self, offset: UnitOffset<Offset>) -> bool {
let size_of_header = self.header_size();
if offset.0 < size_of_header {
return false;
}
let relative_to_entries_buf = offset.0 - size_of_header;
relative_to_entries_buf < self.entries_buf.len()
}
/// Get the underlying bytes for the supplied range.
pub fn range(&self, idx: Range<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.start) {
return Err(Error::OffsetOutOfBounds);
}
if !self.is_valid_offset(idx.end) {
return Err(Error::OffsetOutOfBounds);
}
assert!(idx.start <= idx.end);
let size_of_header = self.header_size();
let start = idx.start.0 - size_of_header;
let end = idx.end.0 - size_of_header;
let mut input = self.entries_buf.clone();
input.skip(start)?;
input.truncate(end - start)?;
Ok(input)
}
/// Get the underlying bytes for the supplied range.
pub fn range_from(&self, idx: RangeFrom<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.start) {
return Err(Error::OffsetOutOfBounds);
}
let start = idx.start.0 - self.header_size();
let mut input = self.entries_buf.clone();
input.skip(start)?;
Ok(input)
}
/// Get the underlying bytes for the supplied range.
pub fn range_to(&self, idx: RangeTo<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.end) {
return Err(Error::OffsetOutOfBounds);
}
let end = idx.end.0 - self.header_size();
let mut input = self.entries_buf.clone();
input.truncate(end)?;
Ok(input)
}
/// Read the `DebuggingInformationEntry` at the given offset.
pub fn entry<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: UnitOffset<Offset>,
) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> {
let mut input = self.range_from(offset..)?;
let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?;
entry.ok_or(Error::NoEntryAtGivenOffset)
}
/// Navigate this unit's `DebuggingInformationEntry`s.
pub fn entries<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
) -> EntriesCursor<'abbrev, 'me, R> {
EntriesCursor {
unit: self,
input: self.entries_buf.clone(),
abbreviations,
cached_current: None,
delta_depth: 0,
}
}
/// Navigate this compilation unit's `DebuggingInformationEntry`s
/// starting at the given offset.
pub fn entries_at_offset<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: UnitOffset<Offset>,
) -> Result<EntriesCursor<'abbrev, 'me, R>> {
let input = self.range_from(offset..)?;
Ok(EntriesCursor {
unit: self,
input,
abbreviations,
cached_current: None,
delta_depth: 0,
})
}
/// Navigate this unit's `DebuggingInformationEntry`s as a tree
/// starting at the given offset.
pub fn entries_tree<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: Option<UnitOffset<Offset>>,
) -> Result<EntriesTree<'abbrev, 'me, R>> {
let input = match offset {
Some(offset) => self.range_from(offset..)?,
None => self.entries_buf.clone(),
};
Ok(EntriesTree::new(input, self, abbreviations))
}
/// Read the raw data that defines the Debugging Information Entries.
pub fn entries_raw<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: Option<UnitOffset<Offset>>,
) -> Result<EntriesRaw<'abbrev, 'me, R>> {
let input = match offset {
Some(offset) => self.range_from(offset..)?,
None => self.entries_buf.clone(),
};
Ok(EntriesRaw {
input,
unit: self,
abbreviations,
depth: 0,
})
}
/// Parse this unit's abbreviations.
pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev<R>) -> Result<Abbreviations> {
debug_abbrev.abbreviations(self.debug_abbrev_offset())
}
}
/// Parse a unit header.
fn parse_unit_header<R, Offset>(
input: &mut R,
unit_offset: UnitSectionOffset<Offset>,
) -> Result<UnitHeader<R>>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
let (unit_length, format) = input.read_initial_length()?;
let mut rest = input.split(unit_length)?;
let version = rest.read_u16()?;
let abbrev_offset;
let address_size;
let unit_type;
// DWARF 1 was very different, and is obsolete, so isn't supported by this
// reader.
if 2 <= version && version <= 4 {
abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
address_size = rest.read_u8()?;
// Before DWARF5, all units in the .debug_info section are compilation
// units, and all units in the .debug_types section are type units.
unit_type = match unit_offset {
UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile,
UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type,
};
} else if version == 5 {
unit_type = parse_unit_type(&mut rest)?;
address_size = rest.read_u8()?;
abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
} else {
return Err(Error::UnknownVersion(u64::from(version)));
}
let encoding = Encoding {
format,
version,
address_size,
};
// Parse any data specific to this type of unit.
let unit_type = match unit_type {
constants::DW_UT_compile => UnitType::Compilation,
constants::DW_UT_type => {
let type_signature = parse_type_signature(&mut rest)?;
let type_offset = parse_type_offset(&mut rest, format)?;
UnitType::Type {
type_signature,
type_offset,
}
}
constants::DW_UT_partial => UnitType::Partial,
constants::DW_UT_skeleton => {
let dwo_id = parse_dwo_id(&mut rest)?;
UnitType::Skeleton(dwo_id)
}
constants::DW_UT_split_compile => {
let dwo_id = parse_dwo_id(&mut rest)?;
UnitType::SplitCompilation(dwo_id)
}
constants::DW_UT_split_type => {
let type_signature = parse_type_signature(&mut rest)?;
let type_offset = parse_type_offset(&mut rest, format)?;
UnitType::SplitType {
type_signature,
type_offset,
}
}
_ => return Err(Error::UnsupportedUnitType),
};
Ok(UnitHeader::new(
encoding,
unit_length,
unit_type,
abbrev_offset,
unit_offset,
rest,
))
}
/// Parse a dwo_id from a header
fn parse_dwo_id<R: Reader>(input: &mut R) -> Result<DwoId> {
Ok(DwoId(input.read_u64()?))
}
/// A Debugging Information Entry (DIE).
///
/// DIEs have a set of attributes and optionally have children DIEs as well.
#[derive(Clone, Debug)]
pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
offset: UnitOffset<Offset>,
attrs_slice: R,
attrs_len: Cell<Option<Offset>>,
abbrev: &'abbrev Abbreviation,
unit: &'unit UnitHeader<R, Offset>,
}
impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
/// Construct a new `DebuggingInformationEntry`.
pub fn new(
offset: UnitOffset<Offset>,
attrs_slice: R,
abbrev: &'abbrev Abbreviation,
unit: &'unit UnitHeader<R, Offset>,
) -> Self {
DebuggingInformationEntry {
offset,
attrs_slice,
attrs_len: Cell::new(None),
abbrev,
unit,
}
}
/// Get this entry's code.
pub fn code(&self) -> u64 {
self.abbrev.code()
}
/// Get this entry's offset.
pub fn offset(&self) -> UnitOffset<Offset> {
self.offset
}
/// Get this entry's `DW_TAG_whatever` tag.
///
/// ```
/// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
/// # let info_buf = [
/// # // Comilation unit header
/// #
/// # // 32-bit unit length = 12
/// # 0x0c, 0x00, 0x00, 0x00,
/// # // Version 4
/// # 0x04, 0x00,
/// # // debug_abbrev_offset
/// # 0x00, 0x00, 0x00, 0x00,
/// # // Address size
/// # 0x04,
/// #
/// # // DIEs
/// #
/// # // Abbreviation code
/// # 0x01,
/// # // Attribute of form DW_FORM_string = "foo\0"
/// # 0x66, 0x6f, 0x6f, 0x00,
/// # ];
/// # let debug_info = DebugInfo::new(&info_buf, LittleEndian);
/// # let abbrev_buf = [
/// # // Code
/// # 0x01,
/// # // DW_TAG_subprogram
/// # 0x2e,
/// # // DW_CHILDREN_no
/// # 0x00,
/// # // Begin attributes
/// # // Attribute name = DW_AT_name
/// # 0x03,
/// # // Attribute form = DW_FORM_string
/// # 0x08,
/// # // End attributes
/// # 0x00,
/// # 0x00,
/// # // Null terminator
/// # 0x00
/// # ];
/// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
/// # let unit = debug_info.units().next().unwrap().unwrap();
/// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
/// # let mut cursor = unit.entries(&abbrevs);
/// # let (_, entry) = cursor.next_dfs().unwrap().unwrap();
/// # let mut get_some_entry = || entry;
/// let entry = get_some_entry();
///
/// match entry.tag() {
/// gimli::DW_TAG_subprogram =>
/// println!("this entry contains debug info about a function"),
/// gimli::DW_TAG_inlined_subroutine =>
/// println!("this entry contains debug info about a particular instance of inlining"),
/// gimli::DW_TAG_variable =>
/// println!("this entry contains debug info about a local variable"),
/// gimli::DW_TAG_formal_parameter =>
/// println!("this entry contains debug info about a function parameter"),
/// otherwise =>
/// println!("this entry is some other kind of data: {:?}", otherwise),
/// };
/// ```
pub fn tag(&self) -> constants::DwTag {
self.abbrev.tag()
}
/// Return true if this entry's type can have children, false otherwise.
pub fn has_children(&self) -> bool {
self.abbrev.has_children()
}
/// Iterate over this entry's set of attributes.
///
/// ```
/// use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
///
/// // Read the `.debug_info` section.
///
/// # let info_buf = [
/// # // Comilation unit header
/// #
/// # // 32-bit unit length = 12
/// # 0x0c, 0x00, 0x00, 0x00,
/// # // Version 4
/// # 0x04, 0x00,
/// # // debug_abbrev_offset
/// # 0x00, 0x00, 0x00, 0x00,
/// # // Address size
/// # 0x04,
/// #
/// # // DIEs
/// #
/// # // Abbreviation code
/// # 0x01,
/// # // Attribute of form DW_FORM_string = "foo\0"
/// # 0x66, 0x6f, 0x6f, 0x00,
/// # ];
/// # let read_debug_info_section_somehow = || &info_buf;
/// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
///
/// // Get the data about the first compilation unit out of the `.debug_info`.
///
/// let unit = debug_info.units().next()
/// .expect("Should have at least one compilation unit")
/// .expect("and it should parse ok");
///
/// // Read the `.debug_abbrev` section and parse the
/// // abbreviations for our compilation unit.
///
/// # let abbrev_buf = [
/// # // Code
/// # 0x01,
/// # // DW_TAG_subprogram
/// # 0x2e,
/// # // DW_CHILDREN_no
/// # 0x00,
/// # // Begin attributes
/// # // Attribute name = DW_AT_name
/// # 0x03,
/// # // Attribute form = DW_FORM_string
/// # 0x08,
/// # // End attributes
/// # 0x00,
/// # 0x00,
/// # // Null terminator
/// # 0x00
/// # ];
/// # let read_debug_abbrev_section_somehow = || &abbrev_buf;
/// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian);
/// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
///
/// // Get the first entry from that compilation unit.
///
/// let mut cursor = unit.entries(&abbrevs);
/// let (_, entry) = cursor.next_dfs()
/// .expect("Should parse next entry")
/// .expect("Should have at least one entry");
///
/// // Finally, print the first entry's attributes.
///
/// let mut attrs = entry.attrs();
/// while let Some(attr) = attrs.next().unwrap() {
/// println!("Attribute name = {:?}", attr.name());
/// println!("Attribute value = {:?}", attr.value());
/// }
/// ```
///
/// Can be [used with
/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> {
AttrsIter {
input: self.attrs_slice.clone(),
attributes: self.abbrev.attributes(),
entry: self,
}
}
/// Find the first attribute in this entry which has the given name,
/// and return it. Returns `Ok(None)` if no attribute is found.
pub fn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> {
let mut attrs = self.attrs();
while let Some(attr) = attrs.next()? {
if attr.name() == name {
return Ok(Some(attr));
}
}
Ok(None)
}
/// Find the first attribute in this entry which has the given name,
/// and return its raw value. Returns `Ok(None)` if no attribute is found.
pub fn attr_value_raw(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
self.attr(name)
.map(|attr| attr.map(|attr| attr.raw_value()))
}
/// Find the first attribute in this entry which has the given name,
/// and return its normalized value. Returns `Ok(None)` if no
/// attribute is found.
pub fn attr_value(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
self.attr(name).map(|attr| attr.map(|attr| attr.value()))
}
/// Return the input buffer after the last attribute.
#[inline(always)]
fn after_attrs(&self) -> Result<R> {
if let Some(attrs_len) = self.attrs_len.get() {
let mut input = self.attrs_slice.clone();
input.skip(attrs_len)?;
Ok(input)
} else {
let mut attrs = self.attrs();
while attrs.next()?.is_some() {}
Ok(attrs.input)
}
}
/// Use the `DW_AT_sibling` attribute to find the input buffer for the
/// next sibling. Returns `None` if the attribute is missing or invalid.
fn sibling(&self) -> Option<R> {
let attr = self.attr_value(constants::DW_AT_sibling);
if let Ok(Some(AttributeValue::UnitRef(offset))) = attr {
if offset.0 > self.offset.0 {
if let Ok(input) = self.unit.range_from(offset..) {
return Some(input);
}
}
}
None
}
/// Parse an entry. Returns `Ok(None)` for null entries.
#[inline(always)]
fn parse(
input: &mut R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
) -> Result<Option<Self>> {
let offset = unit.header_size() + input.offset_from(&unit.entries_buf);
let code = input.read_uleb128()?;
if code == 0 {
return Ok(None);
};
let abbrev = abbreviations
.get(code)
.ok_or(Error::UnknownAbbreviation(code))?;
Ok(Some(DebuggingInformationEntry {
offset: UnitOffset(offset),
attrs_slice: input.clone(),
attrs_len: Cell::new(None),
abbrev,
unit,
}))
}
}
/// The value of an attribute in a `DebuggingInformationEntry`.
//
// Set the discriminant size so that all variants use the same alignment
// for their data. This gives better code generation in `parse_attribute`.
#[repr(u64)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AttributeValue<R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
/// "Refers to some location in the address space of the described program."
Addr(u64),
/// A slice of an arbitrary number of bytes.
Block(R),
/// A one byte constant data value. How to interpret the byte depends on context.
///
/// From section 7 of the standard: "Depending on context, it may be a
/// signed integer, an unsigned integer, a floating-point constant, or
/// anything else."
Data1(u8),
/// A two byte constant data value. How to interpret the bytes depends on context.
///
/// These bytes have been converted from `R::Endian`. This may need to be reversed
/// if this was not required.
///
/// From section 7 of the standard: "Depending on context, it may be a
/// signed integer, an unsigned integer, a floating-point constant, or
/// anything else."
Data2(u16),
/// A four byte constant data value. How to interpret the bytes depends on context.
///
/// These bytes have been converted from `R::Endian`. This may need to be reversed
/// if this was not required.
///
/// From section 7 of the standard: "Depending on context, it may be a
/// signed integer, an unsigned integer, a floating-point constant, or
/// anything else."
Data4(u32),
/// An eight byte constant data value. How to interpret the bytes depends on context.
///
/// These bytes have been converted from `R::Endian`. This may need to be reversed
/// if this was not required.
///
/// From section 7 of the standard: "Depending on context, it may be a
/// signed integer, an unsigned integer, a floating-point constant, or
/// anything else."
Data8(u64),
/// A signed integer constant.
Sdata(i64),
/// An unsigned integer constant.
Udata(u64),
/// "The information bytes contain a DWARF expression (see Section 2.5) or
/// location description (see Section 2.6)."
Exprloc(Expression<R>),
/// A boolean that indicates presence or absence of the attribute.
Flag(bool),
/// An offset into another section. Which section this is an offset into
/// depends on context.
SecOffset(Offset),
/// An offset to a set of addresses in the `.debug_addr` section.
DebugAddrBase(DebugAddrBase<Offset>),
/// An index into a set of addresses in the `.debug_addr` section.
DebugAddrIndex(DebugAddrIndex<Offset>),
/// An offset into the current compilation unit.
UnitRef(UnitOffset<Offset>),
/// An offset into the current `.debug_info` section, but possibly a
/// different compilation unit from the current one.
DebugInfoRef(DebugInfoOffset<Offset>),
/// An offset into the `.debug_info` section of the supplementary object file.
DebugInfoRefSup(DebugInfoOffset<Offset>),
/// An offset into the `.debug_line` section.
DebugLineRef(DebugLineOffset<Offset>),
/// An offset into either the `.debug_loc` section or the `.debug_loclists` section.
LocationListsRef(LocationListsOffset<Offset>),
/// An offset to a set of offsets in the `.debug_loclists` section.
DebugLocListsBase(DebugLocListsBase<Offset>),
/// An index into a set of offsets in the `.debug_loclists` section.
DebugLocListsIndex(DebugLocListsIndex<Offset>),
/// An offset into the `.debug_macinfo` section.
DebugMacinfoRef(DebugMacinfoOffset<Offset>),
/// An offset into the `.debug_macro` section.
DebugMacroRef(DebugMacroOffset<Offset>),
/// An offset into the `.debug_ranges` section.
RangeListsRef(RawRangeListsOffset<Offset>),
/// An offset to a set of offsets in the `.debug_rnglists` section.
DebugRngListsBase(DebugRngListsBase<Offset>),
/// An index into a set of offsets in the `.debug_rnglists` section.
DebugRngListsIndex(DebugRngListsIndex<Offset>),
/// A type signature.
DebugTypesRef(DebugTypeSignature),
/// An offset into the `.debug_str` section.
DebugStrRef(DebugStrOffset<Offset>),
/// An offset into the `.debug_str` section of the supplementary object file.
DebugStrRefSup(DebugStrOffset<Offset>),
/// An offset to a set of entries in the `.debug_str_offsets` section.
DebugStrOffsetsBase(DebugStrOffsetsBase<Offset>),
/// An index into a set of entries in the `.debug_str_offsets` section.
DebugStrOffsetsIndex(DebugStrOffsetsIndex<Offset>),
/// An offset into the `.debug_line_str` section.
DebugLineStrRef(DebugLineStrOffset<Offset>),
/// A slice of bytes representing a string. Does not include a final null byte.
/// Not guaranteed to be UTF-8 or anything like that.
String(R),
/// The value of a `DW_AT_encoding` attribute.
Encoding(constants::DwAte),
/// The value of a `DW_AT_decimal_sign` attribute.
DecimalSign(constants::DwDs),
/// The value of a `DW_AT_endianity` attribute.
Endianity(constants::DwEnd),
/// The value of a `DW_AT_accessibility` attribute.
Accessibility(constants::DwAccess),
/// The value of a `DW_AT_visibility` attribute.
Visibility(constants::DwVis),
/// The value of a `DW_AT_virtuality` attribute.
Virtuality(constants::DwVirtuality),
/// The value of a `DW_AT_language` attribute.
Language(constants::DwLang),
/// The value of a `DW_AT_address_class` attribute.
AddressClass(constants::DwAddr),
/// The value of a `DW_AT_identifier_case` attribute.
IdentifierCase(constants::DwId),
/// The value of a `DW_AT_calling_convention` attribute.
CallingConvention(constants::DwCc),
/// The value of a `DW_AT_inline` attribute.
Inline(constants::DwInl),
/// The value of a `DW_AT_ordering` attribute.
Ordering(constants::DwOrd),
/// An index into the filename entries from the line number information
/// table for the compilation unit containing this value.
FileIndex(u64),
/// An implementation-defined identifier uniquely identifying a compilation
/// unit.
DwoId(DwoId),
}
/// An attribute in a `DebuggingInformationEntry`, consisting of a name and
/// associated value.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Attribute<R: Reader> {
name: constants::DwAt,
value: AttributeValue<R>,
}
impl<R: Reader> Attribute<R> {
/// Get this attribute's name.
pub fn name(&self) -> constants::DwAt {
self.name
}
/// Get this attribute's raw value.
pub fn raw_value(&self) -> AttributeValue<R> {
self.value.clone()
}
/// Get this attribute's normalized value.
///
/// Attribute values can potentially be encoded in multiple equivalent forms,
/// and may have special meaning depending on the attribute name. This method
/// converts the attribute value to a normalized form based on the attribute
/// name.
///
/// See "Table 7.5: Attribute encodings" and "Table 7.6: Attribute form encodings".
pub fn value(&self) -> AttributeValue<R> {
// Table 7.5 shows the possible attribute classes for each name.
// Table 7.6 shows the possible attribute classes for each form.
// For each attribute name, we need to match on the form, and
// convert it to one of the classes that is allowed for both
// the name and the form.
//
// The individual class conversions rarely vary for each name,
// so for each class conversion we define a macro that matches
// on the allowed forms for that class.
//
// For some classes, we don't need to do any conversion, so their
// macro is empty. In the future we may want to fill them in to
// provide strict checking of the forms for each class. For now,
// they simply provide a way to document the allowed classes for
// each name.
// DW_FORM_addr
// DW_FORM_addrx
// DW_FORM_addrx1
// DW_FORM_addrx2
// DW_FORM_addrx3
// DW_FORM_addrx4
macro_rules! address {
() => {};
}
// DW_FORM_sec_offset
macro_rules! addrptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugAddrBase(DebugAddrBase(offset));
}
};
}
// DW_FORM_block
// DW_FORM_block1
// DW_FORM_block2
// DW_FORM_block4
macro_rules! block {
() => {};
}
// DW_FORM_sdata
// DW_FORM_udata
// DW_FORM_data1
// DW_FORM_data2
// DW_FORM_data4
// DW_FORM_data8
// DW_FORM_data16
// DW_FORM_implicit_const
macro_rules! constant {
($value:ident, $variant:ident) => {
if let Some(value) = self.$value() {
return AttributeValue::$variant(value);
}
};
($value:ident, $variant:ident, $constant:ident) => {
if let Some(value) = self.$value() {
return AttributeValue::$variant(constants::$constant(value));
}
};
}
// DW_FORM_exprloc
macro_rules! exprloc {
() => {
if let Some(value) = self.exprloc_value() {
return AttributeValue::Exprloc(value);
}
};
}
// DW_FORM_flag
// DW_FORM_flag_present
macro_rules! flag {
() => {};
}
// DW_FORM_sec_offset
macro_rules! lineptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugLineRef(DebugLineOffset(offset));
}
};
}
// This also covers `loclist` in DWARF version 5.
// DW_FORM_sec_offset
// DW_FORM_loclistx
macro_rules! loclistptr {
() => {
// DebugLocListsIndex is also an allowed form in DWARF version 5.
if let Some(offset) = self.offset_value() {
return AttributeValue::LocationListsRef(LocationListsOffset(offset));
}
};
}
// DW_FORM_sec_offset
macro_rules! loclistsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset));
}
};
}
// DWARF version <= 4.
// DW_FORM_sec_offset
macro_rules! macinfoptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset));
}
};
}
// DWARF version >= 5.
// DW_FORM_sec_offset
macro_rules! macroptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugMacroRef(DebugMacroOffset(offset));
}
};
}
// DW_FORM_ref_addr
// DW_FORM_ref1
// DW_FORM_ref2
// DW_FORM_ref4
// DW_FORM_ref8
// DW_FORM_ref_udata
// DW_FORM_ref_sig8
// DW_FORM_ref_sup4
// DW_FORM_ref_sup8
macro_rules! reference {
() => {};
}
// This also covers `rnglist` in DWARF version 5.
// DW_FORM_sec_offset
// DW_FORM_rnglistx
macro_rules! rangelistptr {
() => {
// DebugRngListsIndex is also an allowed form in DWARF version 5.
if let Some(offset) = self.offset_value() {
return AttributeValue::RangeListsRef(RawRangeListsOffset(offset));
}
};
}
// DW_FORM_sec_offset
macro_rules! rnglistsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset));
}
};
}
// DW_FORM_string
// DW_FORM_strp
// DW_FORM_strx
// DW_FORM_strx1
// DW_FORM_strx2
// DW_FORM_strx3
// DW_FORM_strx4
// DW_FORM_strp_sup
// DW_FORM_line_strp
macro_rules! string {
() => {};
}
// DW_FORM_sec_offset
macro_rules! stroffsetsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset));
}
};
}
// This isn't a separate form but it's useful to distinguish it from a generic udata.
macro_rules! dwoid {
() => {
if let Some(value) = self.udata_value() {
return AttributeValue::DwoId(DwoId(value));
}
};
}
// Perform the allowed class conversions for each attribute name.
match self.name {
constants::DW_AT_sibling => {
reference!();
}
constants::DW_AT_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_name => {
string!();
}
constants::DW_AT_ordering => {
constant!(u8_value, Ordering, DwOrd);
}
constants::DW_AT_byte_size
| constants::DW_AT_bit_offset
| constants::DW_AT_bit_size => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_stmt_list => {
lineptr!();
}
constants::DW_AT_low_pc => {
address!();
}
constants::DW_AT_high_pc => {
address!();
constant!(udata_value, Udata);
}
constants::DW_AT_language => {
constant!(u16_value, Language, DwLang);
}
constants::DW_AT_discr => {
reference!();
}
constants::DW_AT_discr_value => {
// constant: depends on type of DW_TAG_variant_part,
// so caller must normalize.
}
constants::DW_AT_visibility => {
constant!(u8_value, Visibility, DwVis);
}
constants::DW_AT_import => {
reference!();
}
constants::DW_AT_string_length => {
exprloc!();
loclistptr!();
reference!();
}
constants::DW_AT_common_reference => {
reference!();
}
constants::DW_AT_comp_dir => {
string!();
}
constants::DW_AT_const_value => {
// TODO: constant: sign depends on DW_AT_type.
block!();
string!();
}
constants::DW_AT_containing_type => {
reference!();
}
constants::DW_AT_default_value => {
// TODO: constant: sign depends on DW_AT_type.
reference!();
flag!();
}
constants::DW_AT_inline => {
constant!(u8_value, Inline, DwInl);
}
constants::DW_AT_is_optional => {
flag!();
}
constants::DW_AT_lower_bound => {
// TODO: constant: sign depends on DW_AT_type.
exprloc!();
reference!();
}
constants::DW_AT_producer => {
string!();
}
constants::DW_AT_prototyped => {
flag!();
}
constants::DW_AT_return_addr => {
exprloc!();
loclistptr!();
}
constants::DW_AT_start_scope => {
// TODO: constant
rangelistptr!();
}
constants::DW_AT_bit_stride => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_upper_bound => {
// TODO: constant: sign depends on DW_AT_type.
exprloc!();
reference!();
}
constants::DW_AT_abstract_origin => {
reference!();
}
constants::DW_AT_accessibility => {
constant!(u8_value, Accessibility, DwAccess);
}
constants::DW_AT_address_class => {
constant!(udata_value, AddressClass, DwAddr);
}
constants::DW_AT_artificial => {
flag!();
}
constants::DW_AT_base_types => {
reference!();
}
constants::DW_AT_calling_convention => {
constant!(u8_value, CallingConvention, DwCc);
}
constants::DW_AT_count => {
// TODO: constant
exprloc!();
reference!();
}
constants::DW_AT_data_member_location => {
// Constants must be handled before loclistptr so that DW_FORM_data4/8
// are correctly interpreted for DWARF version 4+.
constant!(udata_value, Udata);
exprloc!();
loclistptr!();
}
constants::DW_AT_decl_column => {
constant!(udata_value, Udata);
}
constants::DW_AT_decl_file => {
constant!(udata_value, FileIndex);
}
constants::DW_AT_decl_line => {
constant!(udata_value, Udata);
}
constants::DW_AT_declaration => {
flag!();
}
constants::DW_AT_discr_list => {
block!();
}
constants::DW_AT_encoding => {
constant!(u8_value, Encoding, DwAte);
}
constants::DW_AT_external => {
flag!();
}
constants::DW_AT_frame_base => {
exprloc!();
loclistptr!();
}
constants::DW_AT_friend => {
reference!();
}
constants::DW_AT_identifier_case => {
constant!(u8_value, IdentifierCase, DwId);
}
constants::DW_AT_macro_info => {
macinfoptr!();
}
constants::DW_AT_namelist_item => {
reference!();
}
constants::DW_AT_priority => {
reference!();
}
constants::DW_AT_segment => {
exprloc!();
loclistptr!();
}
constants::DW_AT_specification => {
reference!();
}
constants::DW_AT_static_link => {
exprloc!();
loclistptr!();
}
constants::DW_AT_type => {
reference!();
}
constants::DW_AT_use_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_variable_parameter => {
flag!();
}
constants::DW_AT_virtuality => {
constant!(u8_value, Virtuality, DwVirtuality);
}
constants::DW_AT_vtable_elem_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_allocated => {
// TODO: constant
exprloc!();
reference!();
}
constants::DW_AT_associated => {
// TODO: constant
exprloc!();
reference!();
}
constants::DW_AT_data_location => {
exprloc!();
}
constants::DW_AT_byte_stride => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_entry_pc => {
// TODO: constant
address!();
}
constants::DW_AT_use_UTF8 => {
flag!();
}
constants::DW_AT_extension => {
reference!();
}
constants::DW_AT_ranges => {
rangelistptr!();
}
constants::DW_AT_trampoline => {
address!();
flag!();
reference!();
string!();
}
constants::DW_AT_call_column => {
constant!(udata_value, Udata);
}
constants::DW_AT_call_file => {
constant!(udata_value, FileIndex);
}
constants::DW_AT_call_line => {
constant!(udata_value, Udata);
}
constants::DW_AT_description => {
string!();
}
constants::DW_AT_binary_scale => {
// TODO: constant
}
constants::DW_AT_decimal_scale => {
// TODO: constant
}
constants::DW_AT_small => {
reference!();
}
constants::DW_AT_decimal_sign => {
constant!(u8_value, DecimalSign, DwDs);
}
constants::DW_AT_digit_count => {
// TODO: constant
}
constants::DW_AT_picture_string => {
string!();
}
constants::DW_AT_mutable => {
flag!();
}
constants::DW_AT_threads_scaled => {
flag!();
}
constants::DW_AT_explicit => {
flag!();
}
constants::DW_AT_object_pointer => {
reference!();
}
constants::DW_AT_endianity => {
constant!(u8_value, Endianity, DwEnd);
}
constants::DW_AT_elemental => {
flag!();
}
constants::DW_AT_pure => {
flag!();
}
constants::DW_AT_recursive => {
flag!();
}
constants::DW_AT_signature => {
reference!();
}
constants::DW_AT_main_subprogram => {
flag!();
}
constants::DW_AT_data_bit_offset => {
// TODO: constant
}
constants::DW_AT_const_expr => {
flag!();
}
constants::DW_AT_enum_class => {
flag!();
}
constants::DW_AT_linkage_name => {
string!();
}
constants::DW_AT_string_length_bit_size => {
// TODO: constant
}
constants::DW_AT_string_length_byte_size => {
// TODO: constant
}
constants::DW_AT_rank => {
// TODO: constant
exprloc!();
}
constants::DW_AT_str_offsets_base => {
stroffsetsptr!();
}
constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
addrptr!();
}
constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
rnglistsptr!();
}
constants::DW_AT_dwo_name => {
string!();
}
constants::DW_AT_reference => {
flag!();
}
constants::DW_AT_rvalue_reference => {
flag!();
}
constants::DW_AT_macros => {
macroptr!();
}
constants::DW_AT_call_all_calls => {
flag!();
}
constants::DW_AT_call_all_source_calls => {
flag!();
}
constants::DW_AT_call_all_tail_calls => {
flag!();
}
constants::DW_AT_call_return_pc => {
address!();
}
constants::DW_AT_call_value => {
exprloc!();
}
constants::DW_AT_call_origin => {
exprloc!();
}
constants::DW_AT_call_parameter => {
reference!();
}
constants::DW_AT_call_pc => {
address!();
}
constants::DW_AT_call_tail_call => {
flag!();
}
constants::DW_AT_call_target => {
exprloc!();
}
constants::DW_AT_call_target_clobbered => {
exprloc!();
}
constants::DW_AT_call_data_location => {
exprloc!();
}
constants::DW_AT_call_data_value => {
exprloc!();
}
constants::DW_AT_noreturn => {
flag!();
}
constants::DW_AT_alignment => {
// TODO: constant
}
constants::DW_AT_export_symbols => {
flag!();
}
constants::DW_AT_deleted => {
flag!();
}
constants::DW_AT_defaulted => {
// TODO: constant
}
constants::DW_AT_loclists_base => {
loclistsptr!();
}
constants::DW_AT_GNU_dwo_id => {
dwoid!();
}
_ => {}
}
self.value.clone()
}
/// Try to convert this attribute's value to a u8.
#[inline]
pub fn u8_value(&self) -> Option<u8> {
self.value.u8_value()
}
/// Try to convert this attribute's value to a u16.
#[inline]
pub fn u16_value(&self) -> Option<u16> {
self.value.u16_value()
}
/// Try to convert this attribute's value to an unsigned integer.
#[inline]
pub fn udata_value(&self) -> Option<u64> {
self.value.udata_value()
}
/// Try to convert this attribute's value to a signed integer.
#[inline]
pub fn sdata_value(&self) -> Option<i64> {
self.value.sdata_value()
}
/// Try to convert this attribute's value to an offset.
#[inline]
pub fn offset_value(&self) -> Option<R::Offset> {
self.value.offset_value()
}
/// Try to convert this attribute's value to an expression or location buffer.
///
/// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
/// The standard doesn't mention `DW_FORM_block*` as a possible form, but
/// it is encountered in practice.
#[inline]
pub fn exprloc_value(&self) -> Option<Expression<R>> {
self.value.exprloc_value()
}
/// Try to return this attribute's value as a string slice.
///
/// If this attribute's value is either an inline `DW_FORM_string` string,
/// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
/// section, return the attribute's string value as `Some`. Other attribute
/// value forms are returned as `None`.
///
/// Warning: this function does not handle all possible string forms.
/// Use `Dwarf::attr_string` instead.
#[inline]
pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
self.value.string_value(debug_str)
}
/// Try to return this attribute's value as a string slice.
///
/// If this attribute's value is either an inline `DW_FORM_string` string,
/// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
/// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
/// object file, return the attribute's string value as `Some`. Other attribute
/// value forms are returned as `None`.
///
/// Warning: this function does not handle all possible string forms.
/// Use `Dwarf::attr_string` instead.
#[inline]
pub fn string_value_sup(
&self,
debug_str: &DebugStr<R>,
debug_str_sup: Option<&DebugStr<R>>,
) -> Option<R> {
self.value.string_value_sup(debug_str, debug_str_sup)
}
}
impl<R, Offset> AttributeValue<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
/// Try to convert this attribute's value to a u8.
pub fn u8_value(&self) -> Option<u8> {
if let Some(value) = self.udata_value() {
if value <= u64::from(u8::MAX) {
return Some(value as u8);
}
}
None
}
/// Try to convert this attribute's value to a u16.
pub fn u16_value(&self) -> Option<u16> {
if let Some(value) = self.udata_value() {
if value <= u64::from(u16::MAX) {
return Some(value as u16);
}
}
None
}
/// Try to convert this attribute's value to an unsigned integer.
pub fn udata_value(&self) -> Option<u64> {
Some(match *self {
AttributeValue::Data1(data) => u64::from(data),
AttributeValue::Data2(data) => u64::from(data),
AttributeValue::Data4(data) => u64::from(data),
AttributeValue::Data8(data) => data,
AttributeValue::Udata(data) => data,
AttributeValue::Sdata(data) => {
if data < 0 {
// Maybe we should emit a warning here
return None;
}
data as u64
}
_ => return None,
})
}
/// Try to convert this attribute's value to a signed integer.
pub fn sdata_value(&self) -> Option<i64> {
Some(match *self {
AttributeValue::Data1(data) => i64::from(data as i8),
AttributeValue::Data2(data) => i64::from(data as i16),
AttributeValue::Data4(data) => i64::from(data as i32),
AttributeValue::Data8(data) => data as i64,
AttributeValue::Sdata(data) => data,
AttributeValue::Udata(data) => {
if data > i64::max_value() as u64 {
// Maybe we should emit a warning here
return None;
}
data as i64
}
_ => return None,
})
}
/// Try to convert this attribute's value to an offset.
pub fn offset_value(&self) -> Option<R::Offset> {
// While offsets will be DW_FORM_data4/8 in DWARF version 2/3,
// these have already been converted to `SecOffset.
if let AttributeValue::SecOffset(offset) = *self {
Some(offset)
} else {
None
}
}
/// Try to convert this attribute's value to an expression or location buffer.
///
/// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
/// The standard doesn't mention `DW_FORM_block*` as a possible form, but
/// it is encountered in practice.
pub fn exprloc_value(&self) -> Option<Expression<R>> {
Some(match *self {
AttributeValue::Block(ref data) => Expression(data.clone()),
AttributeValue::Exprloc(ref data) => data.clone(),
_ => return None,
})
}
/// Try to return this attribute's value as a string slice.
///
/// If this attribute's value is either an inline `DW_FORM_string` string,
/// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
/// section, return the attribute's string value as `Some`. Other attribute
/// value forms are returned as `None`.
///
/// Warning: this function does not handle all possible string forms.
/// Use `Dwarf::attr_string` instead.
pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
match *self {
AttributeValue::String(ref string) => Some(string.clone()),
AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
_ => None,
}
}
/// Try to return this attribute's value as a string slice.
///
/// If this attribute's value is either an inline `DW_FORM_string` string,
/// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
/// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
/// object file, return the attribute's string value as `Some`. Other attribute
/// value forms are returned as `None`.
///
/// Warning: this function does not handle all possible string forms.
/// Use `Dwarf::attr_string` instead.
pub fn string_value_sup(
&self,
debug_str: &DebugStr<R>,
debug_str_sup: Option<&DebugStr<R>>,
) -> Option<R> {
match *self {
AttributeValue::String(ref string) => Some(string.clone()),
AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
AttributeValue::DebugStrRefSup(offset) => {
debug_str_sup.and_then(|s| s.get_str(offset).ok())
}
_ => None,
}
}
}
fn length_u8_value<R: Reader>(input: &mut R) -> Result<R> {
let len = input.read_u8().map(R::Offset::from_u8)?;
input.split(len)
}
--> --------------------
--> maximum size reached
--> --------------------
[ Verzeichnis aufwärts0.46unsichere Verbindung
Übersetzung europäischer Sprachen durch Browser
]
|
2026-04-04
|
|
|
|
|