//! Functions for parsing DWARF debugging abbreviations.
use alloc::collections::btree_map; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryFrom; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::Deref;
/// The `DebugAbbrev` struct represents the abbreviations describing /// `DebuggingInformationEntry`s' attribute names and forms found in the /// `.debug_abbrev` section. #[derive(Debug, Default, Clone, Copy)] pubstruct DebugAbbrev<R> {
debug_abbrev_section: R,
}
impl<'input, Endian> DebugAbbrev<EndianSlice<'input, Endian>> where
Endian: Endianity,
{ /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` /// section. /// /// It is the caller's responsibility to read the `.debug_abbrev` 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::{DebugAbbrev, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_abbrev_section_somehow = || &buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// ``` pubfn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_abbrev_section, endian))
}
}
impl<R: Reader> DebugAbbrev<R> { /// Parse the abbreviations at the given `offset` within this /// `.debug_abbrev` section. /// /// The `offset` should generally be retrieved from a unit header. pubfn abbreviations(
&self,
debug_abbrev_offset: DebugAbbrevOffset<R::Offset>,
) -> Result<Abbreviations> { let input = &mutself.debug_abbrev_section.clone();
input.skip(debug_abbrev_offset.0)?;
Abbreviations::parse(input)
}
}
impl<T> DebugAbbrev<T> { /// Create a `DebugAbbrev` 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) -> DebugAbbrev<R> where
F: FnMut(&'a T) -> R,
{
borrow(&self.debug_abbrev_section).into()
}
}
/// The strategy to use for caching abbreviations. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[non_exhaustive] pubenum AbbreviationsCacheStrategy { /// Cache abbreviations that are used more than once. /// /// This is useful if the units in the `.debug_info` section will be parsed only once.
Duplicates, /// Cache all abbreviations. /// /// This is useful if the units in the `.debug_info` section will be parsed more than once.
All,
}
/// A cache of previously parsed `Abbreviations`. #[derive(Debug, Default)] pubstruct AbbreviationsCache {
abbreviations: btree_map::BTreeMap<u64, Result<Arc<Abbreviations>>>,
}
/// Parse abbreviations and store them in the cache. /// /// This will iterate over the given units to determine the abbreviations /// offsets. Any existing cache entries are discarded. /// /// Errors during parsing abbreviations are also stored in the cache. /// Errors during iterating over the units are ignored. pubfn populate<R: Reader>(
&mutself,
strategy: AbbreviationsCacheStrategy,
debug_abbrev: &DebugAbbrev<R>, mut units: DebugInfoUnitHeadersIter<R>,
) { letmut offsets = Vec::new(); match strategy {
AbbreviationsCacheStrategy::Duplicates => { whilelet Ok(Some(unit)) = units.next() {
offsets.push(unit.debug_abbrev_offset());
}
offsets.sort_unstable_by_key(|offset| offset.0); letmut prev_offset = R::Offset::from_u8(0); letmut count = 0;
offsets.retain(|offset| { if count == 0 || prev_offset != offset.0 {
prev_offset = offset.0;
count = 1;
} else {
count += 1;
}
count == 2
});
}
AbbreviationsCacheStrategy::All => { whilelet Ok(Some(unit)) = units.next() {
offsets.push(unit.debug_abbrev_offset());
}
offsets.sort_unstable_by_key(|offset| offset.0);
offsets.dedup();
}
} self.abbreviations = offsets
.into_iter()
.map(|offset| {
(
offset.0.into_u64(),
debug_abbrev.abbreviations(offset).map(Arc::new),
)
})
.collect();
}
/// Set an entry in the abbreviations cache. /// /// This is only required if you want to manually populate the cache. pubfn set<R: Reader>(
&mutself,
offset: DebugAbbrevOffset<R::Offset>,
abbreviations: Arc<Abbreviations>,
) { self.abbreviations
.insert(offset.0.into_u64(), Ok(abbreviations));
}
/// Parse the abbreviations at the given offset. /// /// This uses the cache if possible, but does not update it. pubfn get<R: Reader>(
&self,
debug_abbrev: &DebugAbbrev<R>,
offset: DebugAbbrevOffset<R::Offset>,
) -> Result<Arc<Abbreviations>> { matchself.abbreviations.get(&offset.0.into_u64()) {
Some(entry) => entry.clone(),
None => debug_abbrev.abbreviations(offset).map(Arc::new),
}
}
}
/// A set of type abbreviations. /// /// Construct an `Abbreviations` instance with the /// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) /// method. #[derive(Debug, Default, Clone)] pubstruct Abbreviations {
vec: Vec<Abbreviation>,
map: btree_map::BTreeMap<u64, Abbreviation>,
}
impl Abbreviations { /// Construct a new, empty set of abbreviations. fn empty() -> Abbreviations {
Abbreviations {
vec: Vec::new(),
map: btree_map::BTreeMap::new(),
}
}
/// Insert an abbreviation into the set. /// /// Returns `Ok` if it is the first abbreviation in the set with its code, /// `Err` if the code is a duplicate and there already exists an /// abbreviation in the set with the given abbreviation's code. fn insert(&mutself, abbrev: Abbreviation) -> ::core::result::Result<(), ()> { let code_usize = abbrev.code as usize; if code_usize as u64 == abbrev.code { // Optimize for sequential abbreviation codes by storing them // in a Vec, as long as the map doesn't already contain them. // A potential further optimization would be to allow some // holes in the Vec, but there's no need for that yet. if code_usize - 1 < self.vec.len() { return Err(());
} elseif code_usize - 1 == self.vec.len() { if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { return Err(());
} else { self.vec.push(abbrev); return Ok(());
}
}
} matchself.map.entry(abbrev.code) {
btree_map::Entry::Occupied(_) => Err(()),
btree_map::Entry::Vacant(entry) => {
entry.insert(abbrev);
Ok(())
}
}
}
/// Get the abbreviation associated with the given code. #[inline] pubfn get(&self, code: u64) -> Option<&Abbreviation> { iflet Ok(code) = usize::try_from(code) { let index = code.checked_sub(1)?; if index < self.vec.len() { return Some(&self.vec[index]);
}
}
self.map.get(&code)
}
/// Parse a series of abbreviations, terminated by a null abbreviation. fn parse<R: Reader>(input: &mut R) -> Result<Abbreviations> { letmut abbrevs = Abbreviations::empty();
/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: /// its code, tag type, whether it has children, and its set of attributes. #[derive(Debug, Clone, PartialEq, Eq)] pubstruct Abbreviation {
code: u64,
tag: constants::DwTag,
has_children: constants::DwChildren,
attributes: Attributes,
}
/// Get this abbreviation's code. #[inline] pubfn code(&self) -> u64 { self.code
}
/// Get this abbreviation's tag. #[inline] pubfn tag(&self) -> constants::DwTag { self.tag
}
/// Return true if this abbreviation's type has children, false otherwise. #[inline] pubfn has_children(&self) -> bool { self.has_children == constants::DW_CHILDREN_yes
}
/// Get this abbreviation's attributes. #[inline] pubfn attributes(&self) -> &[AttributeSpecification] {
&self.attributes[..]
}
/// Parse an abbreviation's tag. fn parse_tag<R: Reader>(input: &mut R) -> Result<constants::DwTag> { let val = input.read_uleb128_u16()?; if val == 0 {
Err(Error::AbbreviationTagZero)
} else {
Ok(constants::DwTag(val))
}
}
/// Parse an abbreviation's "does the type have children?" byte. fn parse_has_children<R: Reader>(input: &mut R) -> Result<constants::DwChildren> { let val = input.read_u8()?; let val = constants::DwChildren(val); if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes {
Ok(val)
} else {
Err(Error::BadHasChildren)
}
}
/// Parse a series of attribute specifications, terminated by a null attribute /// specification. fn parse_attributes<R: Reader>(input: &mut R) -> Result<Attributes> { letmut attrs = Attributes::new();
/// Parse an abbreviation. Return `None` for the null abbreviation, `Some` /// for an actual abbreviation. fn parse<R: Reader>(input: &mut R) -> Result<Option<Abbreviation>> { let code = input.read_uleb128()?; if code == 0 { return Ok(None);
}
let tag = Self::parse_tag(input)?; let has_children = Self::parse_has_children(input)?; let attributes = Self::parse_attributes(input)?; let abbrev = Abbreviation::new(code, tag, has_children, attributes);
Ok(Some(abbrev))
}
}
/// A list of attributes found in an `Abbreviation` #[derive(Clone)] pub(crate) enum Attributes {
Inline {
buf: [AttributeSpecification; MAX_ATTRIBUTES_INLINE],
len: usize,
},
Heap(Vec<AttributeSpecification>),
}
// Length of 5 based on benchmark results for both x86-64 and i686. const MAX_ATTRIBUTES_INLINE: usize = 5;
impl Attributes { /// Returns a new empty list of attributes fn new() -> Attributes { let default =
AttributeSpecification::new(constants::DW_AT_null, constants::DW_FORM_null, None);
Attributes::Inline {
buf: [default; 5],
len: 0,
}
}
/// Pushes a new value onto this list of attributes. fn push(&mutself, attr: AttributeSpecification) { matchself {
Attributes::Heap(list) => list.push(attr),
Attributes::Inline {
buf,
len: MAX_ATTRIBUTES_INLINE,
} => { letmut list = buf.to_vec();
list.push(attr);
*self = Attributes::Heap(list);
}
Attributes::Inline { buf, len } => {
buf[*len] = attr;
*len += 1;
}
}
}
}
impl Deref for Attributes { type Target = [AttributeSpecification]; fn deref(&self) -> &[AttributeSpecification] { matchself {
Attributes::Inline { buf, len } => &buf[..*len],
Attributes::Heap(list) => list,
}
}
}
impl FromIterator<AttributeSpecification> for Attributes { fn from_iter<I>(iter: I) -> Attributes where
I: IntoIterator<Item = AttributeSpecification>,
{ letmut list = Attributes::new(); for item in iter {
list.push(item);
}
list
}
}
/// The description of an attribute in an abbreviated type. It is a pair of name /// and form. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pubstruct AttributeSpecification {
name: constants::DwAt,
form: constants::DwForm,
implicit_const_value: i64,
}
impl AttributeSpecification { /// Construct a new `AttributeSpecification` from the given name and form /// and implicit const value. #[inline] pubfn new(
name: constants::DwAt,
form: constants::DwForm,
implicit_const_value: Option<i64>,
) -> AttributeSpecification {
debug_assert!(
(form == constants::DW_FORM_implicit_const && implicit_const_value.is_some())
|| (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none())
);
AttributeSpecification {
name,
form,
implicit_const_value: implicit_const_value.unwrap_or(0),
}
}
/// Get the attribute's name. #[inline] pubfn name(&self) -> constants::DwAt { self.name
}
/// Get the attribute's form. #[inline] pubfn form(&self) -> constants::DwForm { self.form
}
/// Return the size of the attribute, in bytes. /// /// Note that because some attributes are variably sized, the size cannot /// always be known without parsing, in which case we return `None`. pubfn size<R: Reader>(&self, header: &UnitHeader<R>) -> Option<usize> {
get_attribute_size(self.form, header.encoding()).map(usize::from)
}
/// Parse an attribute's form. fn parse_form<R: Reader>(input: &mut R) -> Result<constants::DwForm> { let val = input.read_uleb128_u16()?; if val == 0 {
Err(Error::AttributeFormZero)
} else {
Ok(constants::DwForm(val))
}
}
/// Parse an attribute specification. Returns `None` for the null attribute /// specification, `Some` for an actual attribute specification. fn parse<R: Reader>(input: &mut R) -> Result<Option<AttributeSpecification>> { let name = input.read_uleb128_u16()?; if name == 0 { // Parse the null attribute specification. let form = input.read_uleb128_u16()?; returnif form == 0 {
Ok(None)
} else {
Err(Error::ExpectedZero)
};
}
let name = constants::DwAt(name); let form = Self::parse_form(input)?; let implicit_const_value = if form == constants::DW_FORM_implicit_const {
Some(input.read_sleb128()?)
} else {
None
}; let spec = AttributeSpecification::new(name, form, implicit_const_value);
Ok(Some(spec))
}
}
#[inline] pub(crate) fn get_attribute_size(form: constants::DwForm, encoding: Encoding) -> Option<u8> { match form {
constants::DW_FORM_addr => Some(encoding.address_size),
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.
Some(if encoding.version == 2 {
encoding.address_size
} else {
encoding.format.word_size()
})
}
let wrap_code = (u32::MAX as u64 + 1) + 1; // `get` should not treat the wrapped code as `1`.
assert_eq!(abbrevs.get(wrap_code), None); // `insert` should not treat the wrapped code as `1`.
abbrevs.insert(abbrev(wrap_code)).unwrap();
assert_abbrev(&abbrevs, 1);
assert_abbrev(&abbrevs, wrap_code);
}
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.