aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/read
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
committerValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
commita990de90fe41456a23e58bd087d2f107d321f3a1 (patch)
tree15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/gimli/src/read
parent3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff)
downloadfparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz
fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip
Deleted vendor folder
Diffstat (limited to 'vendor/gimli/src/read')
-rw-r--r--vendor/gimli/src/read/abbrev.rs1102
-rw-r--r--vendor/gimli/src/read/addr.rs128
-rw-r--r--vendor/gimli/src/read/aranges.rs660
-rw-r--r--vendor/gimli/src/read/cfi.rs7823
-rw-r--r--vendor/gimli/src/read/dwarf.rs1210
-rw-r--r--vendor/gimli/src/read/endian_reader.rs639
-rw-r--r--vendor/gimli/src/read/endian_slice.rs360
-rw-r--r--vendor/gimli/src/read/index.rs535
-rw-r--r--vendor/gimli/src/read/line.rs3130
-rw-r--r--vendor/gimli/src/read/lists.rs68
-rw-r--r--vendor/gimli/src/read/loclists.rs1627
-rw-r--r--vendor/gimli/src/read/lookup.rs202
-rw-r--r--vendor/gimli/src/read/mod.rs827
-rw-r--r--vendor/gimli/src/read/op.rs4140
-rw-r--r--vendor/gimli/src/read/pubnames.rs141
-rw-r--r--vendor/gimli/src/read/pubtypes.rs141
-rw-r--r--vendor/gimli/src/read/reader.rs502
-rw-r--r--vendor/gimli/src/read/rnglists.rs1458
-rw-r--r--vendor/gimli/src/read/str.rs321
-rw-r--r--vendor/gimli/src/read/unit.rs6139
-rw-r--r--vendor/gimli/src/read/util.rs283
-rw-r--r--vendor/gimli/src/read/value.rs1621
22 files changed, 0 insertions, 33057 deletions
diff --git a/vendor/gimli/src/read/abbrev.rs b/vendor/gimli/src/read/abbrev.rs
deleted file mode 100644
index 1162583..0000000
--- a/vendor/gimli/src/read/abbrev.rs
+++ /dev/null
@@ -1,1102 +0,0 @@
-//! 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;
-
-use crate::common::{DebugAbbrevOffset, Encoding, SectionId};
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::{
- DebugInfoUnitHeadersIter, EndianSlice, Error, Reader, ReaderOffset, Result, Section, UnitHeader,
-};
-
-/// The `DebugAbbrev` struct represents the abbreviations describing
-/// `DebuggingInformationEntry`s' attribute names and forms found in the
-/// `.debug_abbrev` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct 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);
- /// ```
- pub fn 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.
- pub fn abbreviations(
- &self,
- debug_abbrev_offset: DebugAbbrevOffset<R::Offset>,
- ) -> Result<Abbreviations> {
- let input = &mut self.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.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugAbbrev<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.debug_abbrev_section).into()
- }
-}
-
-impl<R> Section<R> for DebugAbbrev<R> {
- fn id() -> SectionId {
- SectionId::DebugAbbrev
- }
-
- fn reader(&self) -> &R {
- &self.debug_abbrev_section
- }
-}
-
-impl<R> From<R> for DebugAbbrev<R> {
- fn from(debug_abbrev_section: R) -> Self {
- DebugAbbrev {
- debug_abbrev_section,
- }
- }
-}
-
-/// The strategy to use for caching abbreviations.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum 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)]
-pub struct AbbreviationsCache {
- abbreviations: btree_map::BTreeMap<u64, Result<Arc<Abbreviations>>>,
-}
-
-impl AbbreviationsCache {
- /// Create an empty abbreviations cache.
- pub fn new() -> Self {
- Self::default()
- }
-
- /// 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.
- pub fn populate<R: Reader>(
- &mut self,
- strategy: AbbreviationsCacheStrategy,
- debug_abbrev: &DebugAbbrev<R>,
- mut units: DebugInfoUnitHeadersIter<R>,
- ) {
- let mut offsets = Vec::new();
- match strategy {
- AbbreviationsCacheStrategy::Duplicates => {
- while let Ok(Some(unit)) = units.next() {
- offsets.push(unit.debug_abbrev_offset());
- }
- offsets.sort_unstable_by_key(|offset| offset.0);
- let mut prev_offset = R::Offset::from_u8(0);
- let mut 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 => {
- while let 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.
- pub fn set<R: Reader>(
- &mut self,
- 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.
- pub fn get<R: Reader>(
- &self,
- debug_abbrev: &DebugAbbrev<R>,
- offset: DebugAbbrevOffset<R::Offset>,
- ) -> Result<Arc<Abbreviations>> {
- match self.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)]
-pub struct 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(&mut self, 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(());
- } else if 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(());
- }
- }
- }
- match self.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]
- pub fn get(&self, code: u64) -> Option<&Abbreviation> {
- if let 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> {
- let mut abbrevs = Abbreviations::empty();
-
- while let Some(abbrev) = Abbreviation::parse(input)? {
- if abbrevs.insert(abbrev).is_err() {
- return Err(Error::DuplicateAbbreviationCode);
- }
- }
-
- Ok(abbrevs)
- }
-}
-
-/// 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)]
-pub struct Abbreviation {
- code: u64,
- tag: constants::DwTag,
- has_children: constants::DwChildren,
- attributes: Attributes,
-}
-
-impl Abbreviation {
- /// Construct a new `Abbreviation`.
- ///
- /// ### Panics
- ///
- /// Panics if `code` is `0`.
- pub(crate) fn new(
- code: u64,
- tag: constants::DwTag,
- has_children: constants::DwChildren,
- attributes: Attributes,
- ) -> Abbreviation {
- assert_ne!(code, 0);
- Abbreviation {
- code,
- tag,
- has_children,
- attributes,
- }
- }
-
- /// Get this abbreviation's code.
- #[inline]
- pub fn code(&self) -> u64 {
- self.code
- }
-
- /// Get this abbreviation's tag.
- #[inline]
- pub fn tag(&self) -> constants::DwTag {
- self.tag
- }
-
- /// Return true if this abbreviation's type has children, false otherwise.
- #[inline]
- pub fn has_children(&self) -> bool {
- self.has_children == constants::DW_CHILDREN_yes
- }
-
- /// Get this abbreviation's attributes.
- #[inline]
- pub fn 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> {
- let mut attrs = Attributes::new();
-
- while let Some(attr) = AttributeSpecification::parse(input)? {
- attrs.push(attr);
- }
-
- Ok(attrs)
- }
-
- /// 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(&mut self, attr: AttributeSpecification) {
- match self {
- Attributes::Heap(list) => list.push(attr),
- Attributes::Inline {
- buf,
- len: MAX_ATTRIBUTES_INLINE,
- } => {
- let mut list = buf.to_vec();
- list.push(attr);
- *self = Attributes::Heap(list);
- }
- Attributes::Inline { buf, len } => {
- buf[*len] = attr;
- *len += 1;
- }
- }
- }
-}
-
-impl Debug for Attributes {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- (**self).fmt(f)
- }
-}
-
-impl PartialEq for Attributes {
- fn eq(&self, other: &Attributes) -> bool {
- **self == **other
- }
-}
-
-impl Eq for Attributes {}
-
-impl Deref for Attributes {
- type Target = [AttributeSpecification];
- fn deref(&self) -> &[AttributeSpecification] {
- match self {
- 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>,
- {
- let mut list = Attributes::new();
- for item in iter {
- list.push(item);
- }
- list
- }
-}
-
-impl From<Vec<AttributeSpecification>> for Attributes {
- fn from(list: Vec<AttributeSpecification>) -> Attributes {
- Attributes::Heap(list)
- }
-}
-
-/// The description of an attribute in an abbreviated type. It is a pair of name
-/// and form.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct 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]
- pub fn 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]
- pub fn name(&self) -> constants::DwAt {
- self.name
- }
-
- /// Get the attribute's form.
- #[inline]
- pub fn form(&self) -> constants::DwForm {
- self.form
- }
-
- /// Get the attribute's implicit const value.
- #[inline]
- pub fn implicit_const_value(&self) -> Option<i64> {
- if self.form == constants::DW_FORM_implicit_const {
- Some(self.implicit_const_value)
- } else {
- None
- }
- }
-
- /// 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`.
- pub fn 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()?;
- return if 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_implicit_const | constants::DW_FORM_flag_present => Some(0),
-
- constants::DW_FORM_data1
- | constants::DW_FORM_flag
- | constants::DW_FORM_strx1
- | constants::DW_FORM_ref1
- | constants::DW_FORM_addrx1 => Some(1),
-
- constants::DW_FORM_data2
- | constants::DW_FORM_ref2
- | constants::DW_FORM_addrx2
- | constants::DW_FORM_strx2 => Some(2),
-
- constants::DW_FORM_addrx3 | constants::DW_FORM_strx3 => Some(3),
-
- constants::DW_FORM_data4
- | constants::DW_FORM_ref_sup4
- | constants::DW_FORM_ref4
- | constants::DW_FORM_strx4
- | constants::DW_FORM_addrx4 => Some(4),
-
- constants::DW_FORM_data8
- | constants::DW_FORM_ref8
- | constants::DW_FORM_ref_sig8
- | constants::DW_FORM_ref_sup8 => Some(8),
-
- constants::DW_FORM_data16 => Some(16),
-
- constants::DW_FORM_sec_offset
- | constants::DW_FORM_GNU_ref_alt
- | constants::DW_FORM_strp
- | constants::DW_FORM_strp_sup
- | constants::DW_FORM_GNU_strp_alt
- | constants::DW_FORM_line_strp => Some(encoding.format.word_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()
- })
- }
-
- // Variably sized forms.
- constants::DW_FORM_block
- | constants::DW_FORM_block1
- | constants::DW_FORM_block2
- | constants::DW_FORM_block4
- | constants::DW_FORM_exprloc
- | constants::DW_FORM_ref_udata
- | constants::DW_FORM_string
- | constants::DW_FORM_sdata
- | constants::DW_FORM_udata
- | constants::DW_FORM_indirect => None,
-
- // We don't know the size of unknown forms.
- _ => None,
- }
-}
-
-#[cfg(test)]
-pub mod tests {
- use super::*;
- use crate::constants;
- use crate::endianity::LittleEndian;
- use crate::read::{EndianSlice, Error};
- use crate::test_util::GimliSectionMethods;
- #[cfg(target_pointer_width = "32")]
- use core::u32;
- use test_assembler::Section;
-
- pub trait AbbrevSectionMethods {
- fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self;
- fn abbrev_null(self) -> Self;
- fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self;
- fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self;
- fn abbrev_attr_null(self) -> Self;
- }
-
- impl AbbrevSectionMethods for Section {
- fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self {
- self.uleb(code).uleb(tag.0.into()).D8(children.0)
- }
-
- fn abbrev_null(self) -> Self {
- self.D8(0)
- }
-
- fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self {
- self.uleb(name.0.into()).uleb(form.0.into())
- }
-
- fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self {
- self.uleb(name.0.into())
- .uleb(constants::DW_FORM_implicit_const.0.into())
- .sleb(value)
- }
-
- fn abbrev_attr_null(self) -> Self {
- self.D8(0).D8(0)
- }
- }
-
- #[test]
- fn test_debug_abbrev_ok() {
- let extra_start = [1, 2, 3, 4];
- let expected_rest = [5, 6, 7, 8];
- #[rustfmt::skip]
- let buf = Section::new()
- .append_bytes(&extra_start)
- .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
- .abbrev_attr_null()
- .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes)
- .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
- .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
- .abbrev_attr_null()
- .abbrev_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
-
- let abbrev1 = Abbreviation::new(
- 1,
- constants::DW_TAG_compile_unit,
- constants::DW_CHILDREN_yes,
- vec![
- AttributeSpecification::new(
- constants::DW_AT_producer,
- constants::DW_FORM_strp,
- None,
- ),
- AttributeSpecification::new(
- constants::DW_AT_language,
- constants::DW_FORM_data2,
- None,
- ),
- ]
- .into(),
- );
-
- let abbrev2 = Abbreviation::new(
- 2,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_no,
- vec![AttributeSpecification::new(
- constants::DW_AT_name,
- constants::DW_FORM_string,
- None,
- )]
- .into(),
- );
-
- let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian);
- let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len());
- let abbrevs = debug_abbrev
- .abbreviations(debug_abbrev_offset)
- .expect("Should parse abbreviations");
- assert_eq!(abbrevs.get(1), Some(&abbrev1));
- assert_eq!(abbrevs.get(2), Some(&abbrev2));
- }
-
- #[test]
- fn test_abbreviations_insert() {
- fn abbrev(code: u16) -> Abbreviation {
- Abbreviation::new(
- code.into(),
- constants::DwTag(code),
- constants::DW_CHILDREN_no,
- vec![].into(),
- )
- }
-
- fn assert_abbrev(abbrevs: &Abbreviations, code: u16) {
- let abbrev = abbrevs.get(code.into()).unwrap();
- assert_eq!(abbrev.tag(), constants::DwTag(code));
- }
-
- // Sequential insert.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(1)).unwrap();
- abbrevs.insert(abbrev(2)).unwrap();
- assert_eq!(abbrevs.vec.len(), 2);
- assert!(abbrevs.map.is_empty());
- assert_abbrev(&abbrevs, 1);
- assert_abbrev(&abbrevs, 2);
-
- // Out of order insert.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(2)).unwrap();
- abbrevs.insert(abbrev(3)).unwrap();
- assert!(abbrevs.vec.is_empty());
- assert_abbrev(&abbrevs, 2);
- assert_abbrev(&abbrevs, 3);
-
- // Mixed order insert.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(1)).unwrap();
- abbrevs.insert(abbrev(3)).unwrap();
- abbrevs.insert(abbrev(2)).unwrap();
- assert_eq!(abbrevs.vec.len(), 2);
- assert_abbrev(&abbrevs, 1);
- assert_abbrev(&abbrevs, 2);
- assert_abbrev(&abbrevs, 3);
-
- // Duplicate code in vec.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(1)).unwrap();
- abbrevs.insert(abbrev(2)).unwrap();
- assert_eq!(abbrevs.insert(abbrev(1)), Err(()));
- assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
-
- // Duplicate code in map when adding to map.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(2)).unwrap();
- assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
-
- // Duplicate code in map when adding to vec.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(2)).unwrap();
- abbrevs.insert(abbrev(1)).unwrap();
- assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
-
- // 32-bit usize conversions.
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(2)).unwrap();
- }
-
- #[test]
- #[cfg(target_pointer_width = "32")]
- fn test_abbreviations_insert_32() {
- fn abbrev(code: u64) -> Abbreviation {
- Abbreviation::new(
- code,
- constants::DwTag(code as u16),
- constants::DW_CHILDREN_no,
- vec![].into(),
- )
- }
-
- fn assert_abbrev(abbrevs: &Abbreviations, code: u64) {
- let abbrev = abbrevs.get(code).unwrap();
- assert_eq!(abbrev.tag(), constants::DwTag(code as u16));
- }
-
- let mut abbrevs = Abbreviations::empty();
- abbrevs.insert(abbrev(1)).unwrap();
-
- 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);
- }
-
- #[test]
- fn test_parse_abbreviations_ok() {
- let expected_rest = [1, 2, 3, 4];
- #[rustfmt::skip]
- let buf = Section::new()
- .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
- .abbrev_attr_null()
- .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes)
- .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
- .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
- .abbrev_attr_null()
- .abbrev_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
- let rest = &mut EndianSlice::new(&*buf, LittleEndian);
-
- let abbrev1 = Abbreviation::new(
- 1,
- constants::DW_TAG_compile_unit,
- constants::DW_CHILDREN_yes,
- vec![
- AttributeSpecification::new(
- constants::DW_AT_producer,
- constants::DW_FORM_strp,
- None,
- ),
- AttributeSpecification::new(
- constants::DW_AT_language,
- constants::DW_FORM_data2,
- None,
- ),
- ]
- .into(),
- );
-
- let abbrev2 = Abbreviation::new(
- 2,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_no,
- vec![AttributeSpecification::new(
- constants::DW_AT_name,
- constants::DW_FORM_string,
- None,
- )]
- .into(),
- );
-
- let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations");
- assert_eq!(abbrevs.get(1), Some(&abbrev1));
- assert_eq!(abbrevs.get(2), Some(&abbrev2));
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_abbreviations_duplicate() {
- let expected_rest = [1, 2, 3, 4];
- #[rustfmt::skip]
- let buf = Section::new()
- .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
- .abbrev_attr_null()
- .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes)
- .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
- .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
- .abbrev_attr_null()
- .abbrev_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
- let buf = &mut EndianSlice::new(&*buf, LittleEndian);
-
- match Abbreviations::parse(buf) {
- Err(Error::DuplicateAbbreviationCode) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_abbreviation_tag_ok() {
- let buf = [0x01, 0x02];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let tag = Abbreviation::parse_tag(rest).expect("Should parse tag");
- assert_eq!(tag, constants::DW_TAG_array_type);
- assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian));
- }
-
- #[test]
- fn test_parse_abbreviation_tag_zero() {
- let buf = [0x00];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
- match Abbreviation::parse_tag(buf) {
- Err(Error::AbbreviationTagZero) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_abbreviation_has_children() {
- let buf = [0x00, 0x01, 0x02];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let val = Abbreviation::parse_has_children(rest).expect("Should parse children");
- assert_eq!(val, constants::DW_CHILDREN_no);
- let val = Abbreviation::parse_has_children(rest).expect("Should parse children");
- assert_eq!(val, constants::DW_CHILDREN_yes);
- match Abbreviation::parse_has_children(rest) {
- Err(Error::BadHasChildren) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_abbreviation_ok() {
- let expected_rest = [0x01, 0x02, 0x03, 0x04];
- let buf = Section::new()
- .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
- .abbrev_attr_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
- let rest = &mut EndianSlice::new(&*buf, LittleEndian);
-
- let expect = Some(Abbreviation::new(
- 1,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_no,
- vec![AttributeSpecification::new(
- constants::DW_AT_name,
- constants::DW_FORM_string,
- None,
- )]
- .into(),
- ));
-
- let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation");
- assert_eq!(abbrev, expect);
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_abbreviation_implicit_const_ok() {
- let expected_rest = [0x01, 0x02, 0x03, 0x04];
- let buf = Section::new()
- .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr_implicit_const(constants::DW_AT_name, -42)
- .abbrev_attr_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
- let rest = &mut EndianSlice::new(&*buf, LittleEndian);
-
- let expect = Some(Abbreviation::new(
- 1,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_no,
- vec![AttributeSpecification::new(
- constants::DW_AT_name,
- constants::DW_FORM_implicit_const,
- Some(-42),
- )]
- .into(),
- ));
-
- let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation");
- assert_eq!(abbrev, expect);
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_abbreviation_implicit_const_no_const() {
- let buf = Section::new()
- .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
- .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const)
- .get_contents()
- .unwrap();
- let buf = &mut EndianSlice::new(&*buf, LittleEndian);
-
- match Abbreviation::parse(buf) {
- Err(Error::UnexpectedEof(_)) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_parse_null_abbreviation_ok() {
- let expected_rest = [0x01, 0x02, 0x03, 0x04];
- let buf = Section::new()
- .abbrev_null()
- .append_bytes(&expected_rest)
- .get_contents()
- .unwrap();
- let rest = &mut EndianSlice::new(&*buf, LittleEndian);
-
- let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation");
- assert!(abbrev.is_none());
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_attribute_form_ok() {
- let buf = [0x01, 0x02];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let tag = AttributeSpecification::parse_form(rest).expect("Should parse form");
- assert_eq!(tag, constants::DW_FORM_addr);
- assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian));
- }
-
- #[test]
- fn test_parse_attribute_form_zero() {
- let buf = [0x00];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
- match AttributeSpecification::parse_form(buf) {
- Err(Error::AttributeFormZero) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_null_attribute_specification_ok() {
- let buf = [0x00, 0x00, 0x01];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let attr =
- AttributeSpecification::parse(rest).expect("Should parse null attribute specification");
- assert!(attr.is_none());
- assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian));
- }
-
- #[test]
- fn test_parse_attribute_specifications_name_zero() {
- let buf = [0x00, 0x01, 0x00, 0x00];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
- match AttributeSpecification::parse(buf) {
- Err(Error::ExpectedZero) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_attribute_specifications_form_zero() {
- let buf = [0x01, 0x00, 0x00, 0x00];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
- match AttributeSpecification::parse(buf) {
- Err(Error::AttributeFormZero) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_get_abbrev_zero() {
- let mut abbrevs = Abbreviations::empty();
- abbrevs
- .insert(Abbreviation::new(
- 1,
- constants::DwTag(1),
- constants::DW_CHILDREN_no,
- vec![].into(),
- ))
- .unwrap();
- assert!(abbrevs.get(0).is_none());
- }
-}
diff --git a/vendor/gimli/src/read/addr.rs b/vendor/gimli/src/read/addr.rs
deleted file mode 100644
index 593f9fe..0000000
--- a/vendor/gimli/src/read/addr.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-use crate::common::{DebugAddrBase, DebugAddrIndex, SectionId};
-use crate::read::{Reader, ReaderOffset, Result, Section};
-
-/// The raw contents of the `.debug_addr` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugAddr<R> {
- section: R,
-}
-
-impl<R: Reader> DebugAddr<R> {
- // TODO: add an iterator over the sets of addresses in the section.
- // This is not needed for common usage of the section though.
-
- /// Returns the address at the given `base` and `index`.
- ///
- /// A set of addresses in the `.debug_addr` section consists of a header
- /// followed by a series of addresses.
- ///
- /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE.
- /// This is an offset that points to the first address following the header.
- ///
- /// The `index` is the value of a `DW_FORM_addrx` attribute.
- ///
- /// The `address_size` must be the size of the address for the compilation unit.
- /// This value must also match the header. However, note that we do not parse the
- /// header to validate this, since locating the header is unreliable, and the GNU
- /// extensions do not emit it.
- pub fn get_address(
- &self,
- address_size: u8,
- base: DebugAddrBase<R::Offset>,
- index: DebugAddrIndex<R::Offset>,
- ) -> Result<u64> {
- let input = &mut self.section.clone();
- input.skip(base.0)?;
- input.skip(R::Offset::from_u64(
- index.0.into_u64() * u64::from(address_size),
- )?)?;
- input.read_address(address_size)
- }
-}
-
-impl<T> DebugAddr<T> {
- /// Create a `DebugAddr` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugAddr<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.section).into()
- }
-}
-
-impl<R> Section<R> for DebugAddr<R> {
- fn id() -> SectionId {
- SectionId::DebugAddr
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugAddr<R> {
- fn from(section: R) -> Self {
- DebugAddr { section }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::read::EndianSlice;
- use crate::test_util::GimliSectionMethods;
- use crate::{Format, LittleEndian};
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- #[test]
- fn test_get_address() {
- for format in vec![Format::Dwarf32, Format::Dwarf64] {
- for address_size in vec![4, 8] {
- let zero = Label::new();
- let length = Label::new();
- let start = Label::new();
- let first = Label::new();
- let end = Label::new();
- let mut section = Section::with_endian(Endian::Little)
- .mark(&zero)
- .initial_length(format, &length, &start)
- .D16(5)
- .D8(address_size)
- .D8(0)
- .mark(&first);
- for i in 0..20 {
- section = section.word(address_size, 1000 + i);
- }
- section = section.mark(&end);
- length.set_const((&end - &start) as u64);
-
- let section = section.get_contents().unwrap();
- let debug_addr = DebugAddr::from(EndianSlice::new(&section, LittleEndian));
- let base = DebugAddrBase((&first - &zero) as usize);
-
- assert_eq!(
- debug_addr.get_address(address_size, base, DebugAddrIndex(0)),
- Ok(1000)
- );
- assert_eq!(
- debug_addr.get_address(address_size, base, DebugAddrIndex(19)),
- Ok(1019)
- );
- }
- }
- }
-}
diff --git a/vendor/gimli/src/read/aranges.rs b/vendor/gimli/src/read/aranges.rs
deleted file mode 100644
index 83159b6..0000000
--- a/vendor/gimli/src/read/aranges.rs
+++ /dev/null
@@ -1,660 +0,0 @@
-use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId};
-use crate::endianity::Endianity;
-use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section};
-
-/// The `DebugAranges` struct represents the DWARF address range information
-/// found in the `.debug_aranges` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugAranges<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugAranges<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_aranges` 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::{DebugAranges, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_aranges_section = || &buf;
- /// let debug_aranges =
- /// DebugAranges::new(read_debug_aranges_section(), LittleEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- DebugAranges {
- section: EndianSlice::new(section, endian),
- }
- }
-}
-
-impl<R: Reader> DebugAranges<R> {
- /// Iterate the sets of entries in the `.debug_aranges` section.
- ///
- /// Each set of entries belongs to a single unit.
- pub fn headers(&self) -> ArangeHeaderIter<R> {
- ArangeHeaderIter {
- input: self.section.clone(),
- offset: DebugArangesOffset(R::Offset::from_u8(0)),
- }
- }
-
- /// Get the header at the given offset.
- pub fn header(&self, offset: DebugArangesOffset<R::Offset>) -> Result<ArangeHeader<R>> {
- let mut input = self.section.clone();
- input.skip(offset.0)?;
- ArangeHeader::parse(&mut input, offset)
- }
-}
-
-impl<T> DebugAranges<T> {
- /// Create a `DebugAranges` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugAranges<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAranges<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.section).into()
- }
-}
-
-impl<R> Section<R> for DebugAranges<R> {
- fn id() -> SectionId {
- SectionId::DebugAranges
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugAranges<R> {
- fn from(section: R) -> Self {
- DebugAranges { section }
- }
-}
-
-/// An iterator over the headers of a `.debug_aranges` section.
-#[derive(Clone, Debug)]
-pub struct ArangeHeaderIter<R: Reader> {
- input: R,
- offset: DebugArangesOffset<R::Offset>,
-}
-
-impl<R: Reader> ArangeHeaderIter<R> {
- /// Advance the iterator to the next header.
- pub fn next(&mut self) -> Result<Option<ArangeHeader<R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- let len = self.input.len();
- match ArangeHeader::parse(&mut self.input, self.offset) {
- 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 ArangeHeaderIter<R> {
- type Item = ArangeHeader<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- ArangeHeaderIter::next(self)
- }
-}
-
-/// A header for a set of entries in the `.debug_arange` section.
-///
-/// These entries all belong to a single unit.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct ArangeHeader<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- offset: DebugArangesOffset<Offset>,
- encoding: Encoding,
- length: Offset,
- debug_info_offset: DebugInfoOffset<Offset>,
- segment_size: u8,
- entries: R,
-}
-
-impl<R, Offset> ArangeHeader<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn parse(input: &mut R, offset: DebugArangesOffset<Offset>) -> Result<Self> {
- let (length, format) = input.read_initial_length()?;
- let mut rest = input.split(length)?;
-
- // Check the version. The DWARF 5 spec says that this is always 2, but version 3
- // has been observed in the wild, potentially due to a bug; see
- // https://github.com/gimli-rs/gimli/issues/559 for more information.
- // lldb allows versions 2 through 5, possibly by mistake.
- let version = rest.read_u16()?;
- if version != 2 && version != 3 {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
-
- let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?;
- let address_size = rest.read_u8()?;
- let segment_size = rest.read_u8()?;
-
- // unit_length + version + offset + address_size + segment_size
- let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1;
-
- // The first tuple following the header in each set begins at an offset that is
- // a multiple of the size of a single tuple (that is, the size of a segment selector
- // plus twice the size of an address).
- let tuple_length = address_size
- .checked_mul(2)
- .and_then(|x| x.checked_add(segment_size))
- .ok_or(Error::InvalidAddressRange)?;
- if tuple_length == 0 {
- return Err(Error::InvalidAddressRange)?;
- }
- let padding = if header_length % tuple_length == 0 {
- 0
- } else {
- tuple_length - header_length % tuple_length
- };
- rest.skip(R::Offset::from_u8(padding))?;
-
- let encoding = Encoding {
- format,
- version,
- address_size,
- // TODO: segment_size
- };
- Ok(ArangeHeader {
- offset,
- encoding,
- length,
- debug_info_offset,
- segment_size,
- entries: rest,
- })
- }
-
- /// Return the offset of this header within the `.debug_aranges` section.
- #[inline]
- pub fn offset(&self) -> DebugArangesOffset<Offset> {
- self.offset
- }
-
- /// Return the length of this set of entries, including the header.
- #[inline]
- pub fn length(&self) -> Offset {
- self.length
- }
-
- /// Return the encoding parameters for this set of entries.
- #[inline]
- pub fn encoding(&self) -> Encoding {
- self.encoding
- }
-
- /// Return the segment size for this set of entries.
- #[inline]
- pub fn segment_size(&self) -> u8 {
- self.segment_size
- }
-
- /// Return the offset into the .debug_info section for this set of arange entries.
- #[inline]
- pub fn debug_info_offset(&self) -> DebugInfoOffset<Offset> {
- self.debug_info_offset
- }
-
- /// Return the arange entries in this set.
- #[inline]
- pub fn entries(&self) -> ArangeEntryIter<R> {
- ArangeEntryIter {
- input: self.entries.clone(),
- encoding: self.encoding,
- segment_size: self.segment_size,
- }
- }
-}
-
-/// An iterator over the aranges from a `.debug_aranges` section.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-#[derive(Debug, Clone)]
-pub struct ArangeEntryIter<R: Reader> {
- input: R,
- encoding: Encoding,
- segment_size: u8,
-}
-
-impl<R: Reader> ArangeEntryIter<R> {
- /// Advance the iterator and return the next arange.
- ///
- /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)`
- /// when iteration is complete and all aranges have already been parsed and
- /// yielded. If an error occurs while parsing the next arange, then this error
- /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`.
- pub fn next(&mut self) -> Result<Option<ArangeEntry>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match ArangeEntry::parse(&mut self.input, self.encoding, self.segment_size) {
- Ok(Some(entry)) => Ok(Some(entry)),
- Ok(None) => {
- self.input.empty();
- Ok(None)
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for ArangeEntryIter<R> {
- type Item = ArangeEntry;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- ArangeEntryIter::next(self)
- }
-}
-
-/// A single parsed arange.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct ArangeEntry {
- segment: Option<u64>,
- address: u64,
- length: u64,
-}
-
-impl ArangeEntry {
- /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
- fn parse<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- segment_size: u8,
- ) -> Result<Option<Self>> {
- let address_size = encoding.address_size;
-
- let tuple_length = R::Offset::from_u8(2 * address_size + segment_size);
- if tuple_length > input.len() {
- input.empty();
- return Ok(None);
- }
-
- let segment = if segment_size != 0 {
- input.read_address(segment_size)?
- } else {
- 0
- };
- let address = input.read_address(address_size)?;
- let length = input.read_address(address_size)?;
-
- match (segment, address, length) {
- // This is meant to be a null terminator, but in practice it can occur
- // before the end, possibly due to a linker omitting a function and
- // leaving an unrelocated entry.
- (0, 0, 0) => Self::parse(input, encoding, segment_size),
- _ => Ok(Some(ArangeEntry {
- segment: if segment_size != 0 {
- Some(segment)
- } else {
- None
- },
- address,
- length,
- })),
- }
- }
-
- /// Return the segment selector of this arange.
- #[inline]
- pub fn segment(&self) -> Option<u64> {
- self.segment
- }
-
- /// Return the beginning address of this arange.
- #[inline]
- pub fn address(&self) -> u64 {
- self.address
- }
-
- /// Return the length of this arange.
- #[inline]
- pub fn length(&self) -> u64 {
- self.length
- }
-
- /// Return the range.
- #[inline]
- pub fn range(&self) -> Range {
- Range {
- begin: self.address,
- end: self.address.wrapping_add(self.length),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::common::{DebugInfoOffset, Format};
- use crate::endianity::LittleEndian;
- use crate::read::EndianSlice;
-
- #[test]
- fn test_iterate_headers() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 28.
- 0x1c, 0x00, 0x00, 0x00,
- // Version.
- 0x02, 0x00,
- // Offset.
- 0x01, 0x02, 0x03, 0x04,
- // Address size.
- 0x04,
- // Segment size.
- 0x00,
- // Dummy padding and arange tuples.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- // 32-bit length = 36.
- 0x24, 0x00, 0x00, 0x00,
- // Version.
- 0x02, 0x00,
- // Offset.
- 0x11, 0x12, 0x13, 0x14,
- // Address size.
- 0x04,
- // Segment size.
- 0x00,
- // Dummy padding and arange tuples.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ];
-
- let debug_aranges = DebugAranges::new(&buf, LittleEndian);
- let mut headers = debug_aranges.headers();
-
- let header = headers
- .next()
- .expect("should parse header ok")
- .expect("should have a header");
- assert_eq!(header.offset(), DebugArangesOffset(0));
- assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x0403_0201));
-
- let header = headers
- .next()
- .expect("should parse header ok")
- .expect("should have a header");
- assert_eq!(header.offset(), DebugArangesOffset(0x20));
- assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x1413_1211));
- }
-
- #[test]
- fn test_parse_header_ok() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 32.
- 0x20, 0x00, 0x00, 0x00,
- // Version.
- 0x02, 0x00,
- // Offset.
- 0x01, 0x02, 0x03, 0x04,
- // Address size.
- 0x08,
- // Segment size.
- 0x04,
- // Length to here = 12, tuple length = 20.
- // Padding to tuple length multiple = 4.
- 0x10, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy arange tuple data.
- 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next arange.
- 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- let header =
- ArangeHeader::parse(rest, DebugArangesOffset(0x10)).expect("should parse header ok");
-
- assert_eq!(
- *rest,
- EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
- );
- assert_eq!(
- header,
- ArangeHeader {
- offset: DebugArangesOffset(0x10),
- encoding: Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 8,
- },
- length: 0x20,
- debug_info_offset: DebugInfoOffset(0x0403_0201),
- segment_size: 4,
- entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian),
- }
- );
- }
-
- #[test]
- fn test_parse_header_overflow_error() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 32.
- 0x20, 0x00, 0x00, 0x00,
- // Version.
- 0x02, 0x00,
- // Offset.
- 0x01, 0x02, 0x03, 0x04,
- // Address size.
- 0xff,
- // Segment size.
- 0xff,
- // Length to here = 12, tuple length = 20.
- // Padding to tuple length multiple = 4.
- 0x10, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy arange tuple data.
- 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next arange.
- 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
- .expect_err("should fail to parse header");
- assert_eq!(error, Error::InvalidAddressRange);
- }
-
- #[test]
- fn test_parse_header_div_by_zero_error() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 32.
- 0x20, 0x00, 0x00, 0x00,
- // Version.
- 0x02, 0x00,
- // Offset.
- 0x01, 0x02, 0x03, 0x04,
- // Address size = 0. Could cause a division by zero if we aren't
- // careful.
- 0x00,
- // Segment size.
- 0x00,
- // Length to here = 12, tuple length = 20.
- // Padding to tuple length multiple = 4.
- 0x10, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy arange tuple data.
- 0x20, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next arange.
- 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
- .expect_err("should fail to parse header");
- assert_eq!(error, Error::InvalidAddressRange);
- }
-
- #[test]
- fn test_parse_entry_ok() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 4,
- };
- let segment_size = 0;
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let entry =
- ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok");
- assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
- assert_eq!(
- entry,
- Some(ArangeEntry {
- segment: None,
- address: 0x0403_0201,
- length: 0x0807_0605,
- })
- );
- }
-
- #[test]
- fn test_parse_entry_segment() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 4,
- };
- let segment_size = 8;
- #[rustfmt::skip]
- let buf = [
- // Segment.
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- // Address.
- 0x01, 0x02, 0x03, 0x04,
- // Length.
- 0x05, 0x06, 0x07, 0x08,
- // Next tuple.
- 0x09
- ];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let entry =
- ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok");
- assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
- assert_eq!(
- entry,
- Some(ArangeEntry {
- segment: Some(0x1817_1615_1413_1211),
- address: 0x0403_0201,
- length: 0x0807_0605,
- })
- );
- }
-
- #[test]
- fn test_parse_entry_zero() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 4,
- };
- let segment_size = 0;
- #[rustfmt::skip]
- let buf = [
- // Zero tuple.
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Address.
- 0x01, 0x02, 0x03, 0x04,
- // Length.
- 0x05, 0x06, 0x07, 0x08,
- // Next tuple.
- 0x09
- ];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let entry =
- ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok");
- assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
- assert_eq!(
- entry,
- Some(ArangeEntry {
- segment: None,
- address: 0x0403_0201,
- length: 0x0807_0605,
- })
- );
- }
-}
diff --git a/vendor/gimli/src/read/cfi.rs b/vendor/gimli/src/read/cfi.rs
deleted file mode 100644
index d92c8b2..0000000
--- a/vendor/gimli/src/read/cfi.rs
+++ /dev/null
@@ -1,7823 +0,0 @@
-#[cfg(feature = "read")]
-use alloc::boxed::Box;
-
-use core::cmp::{Ord, Ordering};
-use core::fmt::{self, Debug};
-use core::iter::FromIterator;
-use core::mem;
-use core::num::Wrapping;
-
-use super::util::{ArrayLike, ArrayVec};
-use crate::common::{
- DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor,
-};
-use crate::constants::{self, DwEhPe};
-use crate::endianity::Endianity;
-use crate::read::{
- EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, StoreOnHeap,
-};
-
-/// `DebugFrame` contains the `.debug_frame` section's frame unwinding
-/// information required to unwind to and recover registers from older frames on
-/// the stack. For example, this is useful for a debugger that wants to print
-/// locals in a backtrace.
-///
-/// Most interesting methods are defined in the
-/// [`UnwindSection`](trait.UnwindSection.html) trait.
-///
-/// ### Differences between `.debug_frame` and `.eh_frame`
-///
-/// While the `.debug_frame` section's information has a lot of overlap with the
-/// `.eh_frame` section's information, the `.eh_frame` information tends to only
-/// encode the subset of information needed for exception handling. Often, only
-/// one of `.eh_frame` or `.debug_frame` will be present in an object file.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct DebugFrame<R: Reader> {
- section: R,
- address_size: u8,
- segment_size: u8,
- vendor: Vendor,
-}
-
-impl<R: Reader> DebugFrame<R> {
- /// Set the size of a target address in bytes.
- ///
- /// This defaults to the native word size.
- /// This is only used if the CIE version is less than 4.
- pub fn set_address_size(&mut self, address_size: u8) {
- self.address_size = address_size
- }
-
- /// Set the size of a segment selector in bytes.
- ///
- /// This defaults to 0.
- /// This is only used if the CIE version is less than 4.
- pub fn set_segment_size(&mut self, segment_size: u8) {
- self.segment_size = segment_size
- }
-
- /// Set the vendor extensions to use.
- ///
- /// This defaults to `Vendor::Default`.
- pub fn set_vendor(&mut self, vendor: Vendor) {
- self.vendor = vendor;
- }
-}
-
-impl<'input, Endian> DebugFrame<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugFrame` instance from the data in the
- /// `.debug_frame` section.
- ///
- /// It is the caller's responsibility to read the 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::{DebugFrame, NativeEndian};
- ///
- /// // Use with `.debug_frame`
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_frame_section_somehow = || &buf;
- /// let debug_frame = DebugFrame::new(read_debug_frame_section_somehow(), NativeEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R: Reader> Section<R> for DebugFrame<R> {
- fn id() -> SectionId {
- SectionId::DebugFrame
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R: Reader> From<R> for DebugFrame<R> {
- fn from(section: R) -> Self {
- // Default to no segments and native word size.
- DebugFrame {
- section,
- address_size: mem::size_of::<usize>() as u8,
- segment_size: 0,
- vendor: Vendor::Default,
- }
- }
-}
-
-/// `EhFrameHdr` contains the information about the `.eh_frame_hdr` section.
-///
-/// A pointer to the start of the `.eh_frame` data, and optionally, a binary
-/// search table of pointers to the `.eh_frame` records that are found in this section.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct EhFrameHdr<R: Reader>(R);
-
-/// `ParsedEhFrameHdr` contains the parsed information from the `.eh_frame_hdr` section.
-#[derive(Clone, Debug)]
-pub struct ParsedEhFrameHdr<R: Reader> {
- address_size: u8,
- section: R,
-
- eh_frame_ptr: Pointer,
- fde_count: u64,
- table_enc: DwEhPe,
- table: R,
-}
-
-impl<'input, Endian> EhFrameHdr<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Constructs a new `EhFrameHdr` instance from the data in the `.eh_frame_hdr` section.
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R: Reader> EhFrameHdr<R> {
- /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`.
- pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result<ParsedEhFrameHdr<R>> {
- let mut reader = self.0.clone();
- let version = reader.read_u8()?;
- if version != 1 {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
-
- let eh_frame_ptr_enc = parse_pointer_encoding(&mut reader)?;
- let fde_count_enc = parse_pointer_encoding(&mut reader)?;
- let table_enc = parse_pointer_encoding(&mut reader)?;
-
- let parameters = PointerEncodingParameters {
- bases: &bases.eh_frame_hdr,
- func_base: None,
- address_size,
- section: &self.0,
- };
-
- // Omitting this pointer is not valid (defeats the purpose of .eh_frame_hdr entirely)
- if eh_frame_ptr_enc == constants::DW_EH_PE_omit {
- return Err(Error::CannotParseOmitPointerEncoding);
- }
- let eh_frame_ptr = parse_encoded_pointer(eh_frame_ptr_enc, &parameters, &mut reader)?;
-
- let fde_count;
- if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit {
- fde_count = 0
- } else {
- fde_count = parse_encoded_pointer(fde_count_enc, &parameters, &mut reader)?.direct()?;
- }
-
- Ok(ParsedEhFrameHdr {
- address_size,
- section: self.0.clone(),
-
- eh_frame_ptr,
- fde_count,
- table_enc,
- table: reader,
- })
- }
-}
-
-impl<R: Reader> Section<R> for EhFrameHdr<R> {
- fn id() -> SectionId {
- SectionId::EhFrameHdr
- }
-
- fn reader(&self) -> &R {
- &self.0
- }
-}
-
-impl<R: Reader> From<R> for EhFrameHdr<R> {
- fn from(section: R) -> Self {
- EhFrameHdr(section)
- }
-}
-
-impl<R: Reader> ParsedEhFrameHdr<R> {
- /// Returns the address of the binary's `.eh_frame` section.
- pub fn eh_frame_ptr(&self) -> Pointer {
- self.eh_frame_ptr
- }
-
- /// Retrieves the CFI binary search table, if there is one.
- pub fn table(&self) -> Option<EhHdrTable<R>> {
- // There are two big edge cases here:
- // * You search the table for an invalid address. As this is just a binary
- // search table, we always have to return a valid result for that (unless
- // you specify an address that is lower than the first address in the
- // table). Since this means that you have to recheck that the FDE contains
- // your address anyways, we just return the first FDE even when the address
- // is too low. After all, we're just doing a normal binary search.
- // * This falls apart when the table is empty - there is no entry we could
- // return. We conclude that an empty table is not really a table at all.
- if self.fde_count == 0 {
- None
- } else {
- Some(EhHdrTable { hdr: self })
- }
- }
-}
-
-/// An iterator for `.eh_frame_hdr` section's binary search table.
-///
-/// Each table entry consists of a tuple containing an `initial_location` and `address`.
-/// The `initial location` represents the first address that the targeted FDE
-/// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section.
-/// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE.
-#[derive(Debug)]
-pub struct EhHdrTableIter<'a, 'bases, R: Reader> {
- hdr: &'a ParsedEhFrameHdr<R>,
- table: R,
- bases: &'bases BaseAddresses,
- remain: u64,
-}
-
-impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> {
- /// Yield the next entry in the `EhHdrTableIter`.
- pub fn next(&mut self) -> Result<Option<(Pointer, Pointer)>> {
- if self.remain == 0 {
- return Ok(None);
- }
-
- let parameters = PointerEncodingParameters {
- bases: &self.bases.eh_frame_hdr,
- func_base: None,
- address_size: self.hdr.address_size,
- section: &self.hdr.section,
- };
-
- self.remain -= 1;
- let from = parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut self.table)?;
- let to = parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut self.table)?;
- Ok(Some((from, to)))
- }
- /// Yield the nth entry in the `EhHdrTableIter`
- pub fn nth(&mut self, n: usize) -> Result<Option<(Pointer, Pointer)>> {
- use core::convert::TryFrom;
- let size = match self.hdr.table_enc.format() {
- constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
- return Err(Error::VariableLengthSearchTable);
- }
- constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
- constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
- constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8,
- _ => return Err(Error::UnknownPointerEncoding),
- };
-
- let row_size = size * 2;
- let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?;
- self.remain = self.remain.saturating_sub(n);
- self.table.skip(R::Offset::from_u64(n * row_size)?)?;
- self.next()
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> {
- type Item = (Pointer, Pointer);
- type Error = Error;
- fn next(&mut self) -> Result<Option<Self::Item>> {
- EhHdrTableIter::next(self)
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- use core::convert::TryInto;
- (
- self.remain.try_into().unwrap_or(0),
- self.remain.try_into().ok(),
- )
- }
-
- fn nth(&mut self, n: usize) -> Result<Option<Self::Item>> {
- EhHdrTableIter::nth(self, n)
- }
-}
-
-/// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section.
-#[derive(Debug, Clone)]
-pub struct EhHdrTable<'a, R: Reader> {
- hdr: &'a ParsedEhFrameHdr<R>,
-}
-
-impl<'a, R: Reader + 'a> EhHdrTable<'a, R> {
- /// Return an iterator that can walk the `.eh_frame_hdr` table.
- ///
- /// Each table entry consists of a tuple containing an `initial_location` and `address`.
- /// The `initial location` represents the first address that the targeted FDE
- /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section.
- /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE.
- pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> {
- EhHdrTableIter {
- hdr: self.hdr,
- bases,
- remain: self.hdr.fde_count,
- table: self.hdr.table.clone(),
- }
- }
- /// *Probably* returns a pointer to the FDE for the given address.
- ///
- /// This performs a binary search, so if there is no FDE for the given address,
- /// this function **will** return a pointer to any other FDE that's close by.
- ///
- /// To be sure, you **must** call `contains` on the FDE.
- pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result<Pointer> {
- let size = match self.hdr.table_enc.format() {
- constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
- return Err(Error::VariableLengthSearchTable);
- }
- constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
- constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
- constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8,
- _ => return Err(Error::UnknownPointerEncoding),
- };
-
- let row_size = size * 2;
-
- let mut len = self.hdr.fde_count;
-
- let mut reader = self.hdr.table.clone();
-
- let parameters = PointerEncodingParameters {
- bases: &bases.eh_frame_hdr,
- func_base: None,
- address_size: self.hdr.address_size,
- section: &self.hdr.section,
- };
-
- while len > 1 {
- let head = reader.split(R::Offset::from_u64((len / 2) * row_size)?)?;
- let tail = reader.clone();
-
- let pivot =
- parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut reader)?.direct()?;
-
- match pivot.cmp(&address) {
- Ordering::Equal => {
- reader = tail;
- break;
- }
- Ordering::Less => {
- reader = tail;
- len = len - (len / 2);
- }
- Ordering::Greater => {
- reader = head;
- len /= 2;
- }
- }
- }
-
- reader.skip(R::Offset::from_u64(size)?)?;
-
- parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut reader)
- }
-
- /// Convert a `Pointer` to a section offset.
- ///
- /// This does not support indirect pointers.
- pub fn pointer_to_offset(&self, ptr: Pointer) -> Result<EhFrameOffset<R::Offset>> {
- let ptr = ptr.direct()?;
- let eh_frame_ptr = self.hdr.eh_frame_ptr().direct()?;
-
- // Calculate the offset in the EhFrame section
- R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset)
- }
-
- /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress`
- /// if there are none.
- ///
- /// You must provide a function to get its associated CIE. See
- /// `PartialFrameDescriptionEntry::parse` for more information.
- ///
- /// # Example
- ///
- /// ```
- /// # use gimli::{BaseAddresses, EhFrame, ParsedEhFrameHdr, EndianSlice, NativeEndian, Error, UnwindSection};
- /// # fn foo() -> Result<(), Error> {
- /// # let eh_frame: EhFrame<EndianSlice<NativeEndian>> = unreachable!();
- /// # let eh_frame_hdr: ParsedEhFrameHdr<EndianSlice<NativeEndian>> = unimplemented!();
- /// # let addr = 0;
- /// # let bases = unimplemented!();
- /// let table = eh_frame_hdr.table().unwrap();
- /// let fde = table.fde_for_address(&eh_frame, &bases, addr, EhFrame::cie_from_offset)?;
- /// # Ok(())
- /// # }
- /// ```
- pub fn fde_for_address<F>(
- &self,
- frame: &EhFrame<R>,
- bases: &BaseAddresses,
- address: u64,
- get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- F: FnMut(
- &EhFrame<R>,
- &BaseAddresses,
- EhFrameOffset<R::Offset>,
- ) -> Result<CommonInformationEntry<R>>,
- {
- let fdeptr = self.lookup(address, bases)?;
- let offset = self.pointer_to_offset(fdeptr)?;
- let entry = frame.fde_from_offset(bases, offset, get_cie)?;
- if entry.contains(address) {
- Ok(entry)
- } else {
- Err(Error::NoUnwindInfoForAddress)
- }
- }
-
- #[inline]
- #[doc(hidden)]
- #[deprecated(note = "Method renamed to fde_for_address; use that instead.")]
- pub fn lookup_and_parse<F>(
- &self,
- address: u64,
- bases: &BaseAddresses,
- frame: EhFrame<R>,
- get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- F: FnMut(
- &EhFrame<R>,
- &BaseAddresses,
- EhFrameOffset<R::Offset>,
- ) -> Result<CommonInformationEntry<R>>,
- {
- self.fde_for_address(&frame, bases, address, get_cie)
- }
-
- /// Returns the frame unwind information for the given address,
- /// or `NoUnwindInfoForAddress` if there are none.
- ///
- /// You must provide a function to get the associated CIE. See
- /// `PartialFrameDescriptionEntry::parse` for more information.
- pub fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage<R>>(
- &self,
- frame: &EhFrame<R>,
- bases: &BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- address: u64,
- get_cie: F,
- ) -> Result<&'ctx UnwindTableRow<R, A>>
- where
- F: FnMut(
- &EhFrame<R>,
- &BaseAddresses,
- EhFrameOffset<R::Offset>,
- ) -> Result<CommonInformationEntry<R>>,
- {
- let fde = self.fde_for_address(frame, bases, address, get_cie)?;
- fde.unwind_info_for_address(frame, bases, ctx, address)
- }
-}
-
-/// `EhFrame` contains the frame unwinding information needed during exception
-/// handling found in the `.eh_frame` section.
-///
-/// Most interesting methods are defined in the
-/// [`UnwindSection`](trait.UnwindSection.html) trait.
-///
-/// See
-/// [`DebugFrame`](./struct.DebugFrame.html#differences-between-debug_frame-and-eh_frame)
-/// for some discussion on the differences between `.debug_frame` and
-/// `.eh_frame`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct EhFrame<R: Reader> {
- section: R,
- address_size: u8,
- vendor: Vendor,
-}
-
-impl<R: Reader> EhFrame<R> {
- /// Set the size of a target address in bytes.
- ///
- /// This defaults to the native word size.
- pub fn set_address_size(&mut self, address_size: u8) {
- self.address_size = address_size
- }
-
- /// Set the vendor extensions to use.
- ///
- /// This defaults to `Vendor::Default`.
- pub fn set_vendor(&mut self, vendor: Vendor) {
- self.vendor = vendor;
- }
-}
-
-impl<'input, Endian> EhFrame<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `EhFrame` instance from the data in the
- /// `.eh_frame` section.
- ///
- /// It is the caller's responsibility to read the 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::{EhFrame, EndianSlice, NativeEndian};
- ///
- /// // Use with `.eh_frame`
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_eh_frame_section_somehow = || &buf;
- /// let eh_frame = EhFrame::new(read_eh_frame_section_somehow(), NativeEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R: Reader> Section<R> for EhFrame<R> {
- fn id() -> SectionId {
- SectionId::EhFrame
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R: Reader> From<R> for EhFrame<R> {
- fn from(section: R) -> Self {
- // Default to native word size.
- EhFrame {
- section,
- address_size: mem::size_of::<usize>() as u8,
- vendor: Vendor::Default,
- }
- }
-}
-
-// This has to be `pub` to silence a warning (that is deny(..)'d by default) in
-// rustc. Eventually, not having this `pub` will become a hard error.
-#[doc(hidden)]
-#[allow(missing_docs)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum CieOffsetEncoding {
- U32,
- U64,
-}
-
-/// An offset into an `UnwindSection`.
-//
-// Needed to avoid conflicting implementations of `Into<T>`.
-pub trait UnwindOffset<T = usize>: Copy + Debug + Eq + From<T>
-where
- T: ReaderOffset,
-{
- /// Convert an `UnwindOffset<T>` into a `T`.
- fn into(self) -> T;
-}
-
-impl<T> UnwindOffset<T> for DebugFrameOffset<T>
-where
- T: ReaderOffset,
-{
- #[inline]
- fn into(self) -> T {
- self.0
- }
-}
-
-impl<T> UnwindOffset<T> for EhFrameOffset<T>
-where
- T: ReaderOffset,
-{
- #[inline]
- fn into(self) -> T {
- self.0
- }
-}
-
-/// This trait completely encapsulates everything that is different between
-/// `.eh_frame` and `.debug_frame`, as well as all the bits that can change
-/// between DWARF versions.
-#[doc(hidden)]
-pub trait _UnwindSectionPrivate<R: Reader> {
- /// Get the underlying section data.
- fn section(&self) -> &R;
-
- /// Returns true if the given length value should be considered an
- /// end-of-entries sentinel.
- fn length_value_is_end_of_entries(length: R::Offset) -> bool;
-
- /// Return true if the given offset if the CIE sentinel, false otherwise.
- fn is_cie(format: Format, id: u64) -> bool;
-
- /// Return the CIE offset/ID encoding used by this unwind section with the
- /// given DWARF format.
- fn cie_offset_encoding(format: Format) -> CieOffsetEncoding;
-
- /// For `.eh_frame`, CIE offsets are relative to the current position. For
- /// `.debug_frame`, they are relative to the start of the section. We always
- /// internally store them relative to the section, so we handle translating
- /// `.eh_frame`'s relative offsets in this method. If the offset calculation
- /// underflows, return `None`.
- fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset>;
-
- /// Does this version of this unwind section encode address and segment
- /// sizes in its CIEs?
- fn has_address_and_segment_sizes(version: u8) -> bool;
-
- /// The address size to use if `has_address_and_segment_sizes` returns false.
- fn address_size(&self) -> u8;
-
- /// The segment size to use if `has_address_and_segment_sizes` returns false.
- fn segment_size(&self) -> u8;
-
- /// The vendor extensions to use.
- fn vendor(&self) -> Vendor;
-}
-
-/// A section holding unwind information: either `.debug_frame` or
-/// `.eh_frame`. See [`DebugFrame`](./struct.DebugFrame.html) and
-/// [`EhFrame`](./struct.EhFrame.html) respectively.
-pub trait UnwindSection<R: Reader>: Clone + Debug + _UnwindSectionPrivate<R> {
- /// The offset type associated with this CFI section. Either
- /// `DebugFrameOffset` or `EhFrameOffset`.
- type Offset: UnwindOffset<R::Offset>;
-
- /// Iterate over the `CommonInformationEntry`s and `FrameDescriptionEntry`s
- /// in this `.debug_frame` section.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> {
- CfiEntriesIter {
- section: self.clone(),
- bases,
- input: self.section().clone(),
- }
- }
-
- /// Parse the `CommonInformationEntry` at the given offset.
- fn cie_from_offset(
- &self,
- bases: &BaseAddresses,
- offset: Self::Offset,
- ) -> Result<CommonInformationEntry<R>> {
- let offset = UnwindOffset::into(offset);
- let input = &mut self.section().clone();
- input.skip(offset)?;
- CommonInformationEntry::parse(bases, self, input)
- }
-
- /// Parse the `PartialFrameDescriptionEntry` at the given offset.
- fn partial_fde_from_offset<'bases>(
- &self,
- bases: &'bases BaseAddresses,
- offset: Self::Offset,
- ) -> Result<PartialFrameDescriptionEntry<'bases, Self, R>> {
- let offset = UnwindOffset::into(offset);
- let input = &mut self.section().clone();
- input.skip(offset)?;
- PartialFrameDescriptionEntry::parse_partial(self, bases, input)
- }
-
- /// Parse the `FrameDescriptionEntry` at the given offset.
- fn fde_from_offset<F>(
- &self,
- bases: &BaseAddresses,
- offset: Self::Offset,
- get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
- {
- let partial = self.partial_fde_from_offset(bases, offset)?;
- partial.parse(get_cie)
- }
-
- /// Find the `FrameDescriptionEntry` for the given address.
- ///
- /// If found, the FDE is returned. If not found,
- /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned.
- /// If parsing fails, the error is returned.
- ///
- /// You must provide a function to get its associated CIE. See
- /// `PartialFrameDescriptionEntry::parse` for more information.
- ///
- /// Note: this iterates over all FDEs. If available, it is possible
- /// to do a binary search with `EhFrameHdr::fde_for_address` instead.
- fn fde_for_address<F>(
- &self,
- bases: &BaseAddresses,
- address: u64,
- mut get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
- {
- let mut entries = self.entries(bases);
- while let Some(entry) = entries.next()? {
- match entry {
- CieOrFde::Cie(_) => {}
- CieOrFde::Fde(partial) => {
- let fde = partial.parse(&mut get_cie)?;
- if fde.contains(address) {
- return Ok(fde);
- }
- }
- }
- }
- Err(Error::NoUnwindInfoForAddress)
- }
-
- /// Find the frame unwind information for the given address.
- ///
- /// If found, the unwind information is returned. If not found,
- /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or
- /// CFI evaluation fails, the error is returned.
- ///
- /// ```
- /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindContext,
- /// UnwindSection};
- ///
- /// # fn foo() -> gimli::Result<()> {
- /// # let read_eh_frame_section = || unimplemented!();
- /// // Get the `.eh_frame` section from the object file. Alternatively,
- /// // use `EhFrame` with the `.eh_frame` section of the object file.
- /// let eh_frame = EhFrame::new(read_eh_frame_section(), NativeEndian);
- ///
- /// # let get_frame_pc = || unimplemented!();
- /// // Get the address of the PC for a frame you'd like to unwind.
- /// let address = get_frame_pc();
- ///
- /// // This context is reusable, which cuts down on heap allocations.
- /// let ctx = UnwindContext::new();
- ///
- /// // Optionally provide base addresses for any relative pointers. If a
- /// // base address isn't provided and a pointer is found that is relative to
- /// // it, we will return an `Err`.
- /// # let address_of_text_section_in_memory = unimplemented!();
- /// # let address_of_got_section_in_memory = unimplemented!();
- /// let bases = BaseAddresses::default()
- /// .set_text(address_of_text_section_in_memory)
- /// .set_got(address_of_got_section_in_memory);
- ///
- /// let unwind_info = eh_frame.unwind_info_for_address(
- /// &bases,
- /// &mut ctx,
- /// address,
- /// EhFrame::cie_from_offset,
- /// )?;
- ///
- /// # let do_stuff_with = |_| unimplemented!();
- /// do_stuff_with(unwind_info);
- /// # let _ = ctx;
- /// # unreachable!()
- /// # }
- /// ```
- #[inline]
- fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage<R>>(
- &self,
- bases: &BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- address: u64,
- get_cie: F,
- ) -> Result<&'ctx UnwindTableRow<R, A>>
- where
- F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
- {
- let fde = self.fde_for_address(bases, address, get_cie)?;
- fde.unwind_info_for_address(self, bases, ctx, address)
- }
-}
-
-impl<R: Reader> _UnwindSectionPrivate<R> for DebugFrame<R> {
- fn section(&self) -> &R {
- &self.section
- }
-
- fn length_value_is_end_of_entries(_: R::Offset) -> bool {
- false
- }
-
- fn is_cie(format: Format, id: u64) -> bool {
- match format {
- Format::Dwarf32 => id == 0xffff_ffff,
- Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff,
- }
- }
-
- fn cie_offset_encoding(format: Format) -> CieOffsetEncoding {
- match format {
- Format::Dwarf32 => CieOffsetEncoding::U32,
- Format::Dwarf64 => CieOffsetEncoding::U64,
- }
- }
-
- fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option<R::Offset> {
- Some(offset)
- }
-
- fn has_address_and_segment_sizes(version: u8) -> bool {
- version == 4
- }
-
- fn address_size(&self) -> u8 {
- self.address_size
- }
-
- fn segment_size(&self) -> u8 {
- self.segment_size
- }
-
- fn vendor(&self) -> Vendor {
- self.vendor
- }
-}
-
-impl<R: Reader> UnwindSection<R> for DebugFrame<R> {
- type Offset = DebugFrameOffset<R::Offset>;
-}
-
-impl<R: Reader> _UnwindSectionPrivate<R> for EhFrame<R> {
- fn section(&self) -> &R {
- &self.section
- }
-
- fn length_value_is_end_of_entries(length: R::Offset) -> bool {
- length.into_u64() == 0
- }
-
- fn is_cie(_: Format, id: u64) -> bool {
- id == 0
- }
-
- fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding {
- // `.eh_frame` offsets are always 4 bytes, regardless of the DWARF
- // format.
- CieOffsetEncoding::U32
- }
-
- fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset> {
- base.checked_sub(offset)
- }
-
- fn has_address_and_segment_sizes(_version: u8) -> bool {
- false
- }
-
- fn address_size(&self) -> u8 {
- self.address_size
- }
-
- fn segment_size(&self) -> u8 {
- 0
- }
-
- fn vendor(&self) -> Vendor {
- self.vendor
- }
-}
-
-impl<R: Reader> UnwindSection<R> for EhFrame<R> {
- type Offset = EhFrameOffset<R::Offset>;
-}
-
-/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers.
-///
-/// During CIE/FDE parsing, if a relative pointer is encountered for a base
-/// address that is unknown, an Err will be returned.
-///
-/// ```
-/// use gimli::BaseAddresses;
-///
-/// # fn foo() {
-/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!();
-/// # let address_of_eh_frame_section_in_memory = unimplemented!();
-/// # let address_of_text_section_in_memory = unimplemented!();
-/// # let address_of_got_section_in_memory = unimplemented!();
-/// # let address_of_the_start_of_current_func = unimplemented!();
-/// let bases = BaseAddresses::default()
-/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory)
-/// .set_eh_frame(address_of_eh_frame_section_in_memory)
-/// .set_text(address_of_text_section_in_memory)
-/// .set_got(address_of_got_section_in_memory);
-/// # let _ = bases;
-/// # }
-/// ```
-#[derive(Clone, Default, Debug, PartialEq, Eq)]
-pub struct BaseAddresses {
- /// The base addresses to use for pointers in the `.eh_frame_hdr` section.
- pub eh_frame_hdr: SectionBaseAddresses,
-
- /// The base addresses to use for pointers in the `.eh_frame` section.
- pub eh_frame: SectionBaseAddresses,
-}
-
-/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers
-/// in a particular section.
-///
-/// See `BaseAddresses` for methods that are helpful in setting these addresses.
-#[derive(Clone, Default, Debug, PartialEq, Eq)]
-pub struct SectionBaseAddresses {
- /// The address of the section containing the pointer.
- pub section: Option<u64>,
-
- /// The base address for text relative pointers.
- /// This is generally the address of the `.text` section.
- pub text: Option<u64>,
-
- /// The base address for data relative pointers.
- ///
- /// For pointers in the `.eh_frame_hdr` section, this is the address
- /// of the `.eh_frame_hdr` section
- ///
- /// For pointers in the `.eh_frame` section, this is generally the
- /// global pointer, such as the address of the `.got` section.
- pub data: Option<u64>,
-}
-
-impl BaseAddresses {
- /// Set the `.eh_frame_hdr` section base address.
- #[inline]
- pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self {
- self.eh_frame_hdr.section = Some(addr);
- self.eh_frame_hdr.data = Some(addr);
- self
- }
-
- /// Set the `.eh_frame` section base address.
- #[inline]
- pub fn set_eh_frame(mut self, addr: u64) -> Self {
- self.eh_frame.section = Some(addr);
- self
- }
-
- /// Set the `.text` section base address.
- #[inline]
- pub fn set_text(mut self, addr: u64) -> Self {
- self.eh_frame_hdr.text = Some(addr);
- self.eh_frame.text = Some(addr);
- self
- }
-
- /// Set the `.got` section base address.
- #[inline]
- pub fn set_got(mut self, addr: u64) -> Self {
- self.eh_frame.data = Some(addr);
- self
- }
-}
-
-/// An iterator over CIE and FDE entries in a `.debug_frame` or `.eh_frame`
-/// section.
-///
-/// Some pointers may be encoded relative to various base addresses. Use the
-/// [`BaseAddresses`](./struct.BaseAddresses.html) parameter to provide them. By
-/// default, none are provided. If a relative pointer is encountered for a base
-/// address that is unknown, an `Err` will be returned and iteration will abort.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-///
-/// ```
-/// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindSection};
-///
-/// # fn foo() -> gimli::Result<()> {
-/// # let read_eh_frame_somehow = || unimplemented!();
-/// let eh_frame = EhFrame::new(read_eh_frame_somehow(), NativeEndian);
-///
-/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!();
-/// # let address_of_eh_frame_section_in_memory = unimplemented!();
-/// # let address_of_text_section_in_memory = unimplemented!();
-/// # let address_of_got_section_in_memory = unimplemented!();
-/// # let address_of_the_start_of_current_func = unimplemented!();
-/// // Provide base addresses for relative pointers.
-/// let bases = BaseAddresses::default()
-/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory)
-/// .set_eh_frame(address_of_eh_frame_section_in_memory)
-/// .set_text(address_of_text_section_in_memory)
-/// .set_got(address_of_got_section_in_memory);
-///
-/// let mut entries = eh_frame.entries(&bases);
-///
-/// # let do_stuff_with = |_| unimplemented!();
-/// while let Some(entry) = entries.next()? {
-/// do_stuff_with(entry)
-/// }
-/// # unreachable!()
-/// # }
-/// ```
-#[derive(Clone, Debug)]
-pub struct CfiEntriesIter<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- section: Section,
- bases: &'bases BaseAddresses,
- input: R,
-}
-
-impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- /// Advance the iterator to the next entry.
- pub fn next(&mut self) -> Result<Option<CieOrFde<'bases, Section, R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match parse_cfi_entry(self.bases, &self.section, &mut self.input) {
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- Ok(None) => {
- self.input.empty();
- Ok(None)
- }
- Ok(Some(entry)) => Ok(Some(entry)),
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<'bases, Section, R> fallible_iterator::FallibleIterator for CfiEntriesIter<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- type Item = CieOrFde<'bases, Section, R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- CfiEntriesIter::next(self)
- }
-}
-
-/// Either a `CommonInformationEntry` (CIE) or a `FrameDescriptionEntry` (FDE).
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum CieOrFde<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- /// This CFI entry is a `CommonInformationEntry`.
- Cie(CommonInformationEntry<R>),
- /// This CFI entry is a `FrameDescriptionEntry`, however fully parsing it
- /// requires parsing its CIE first, so it is left in a partially parsed
- /// state.
- Fde(PartialFrameDescriptionEntry<'bases, Section, R>),
-}
-
-fn parse_cfi_entry<'bases, Section, R>(
- bases: &'bases BaseAddresses,
- section: &Section,
- input: &mut R,
-) -> Result<Option<CieOrFde<'bases, Section, R>>>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- let (offset, length, format) = loop {
- let offset = input.offset_from(section.section());
- let (length, format) = input.read_initial_length()?;
-
- if Section::length_value_is_end_of_entries(length) {
- return Ok(None);
- }
-
- // Hack: skip zero padding inserted by buggy compilers/linkers.
- // We require that the padding is a multiple of 32-bits, otherwise
- // there is no reliable way to determine when the padding ends. This
- // should be okay since CFI entries must be aligned to the address size.
-
- if length.into_u64() != 0 || format != Format::Dwarf32 {
- break (offset, length, format);
- }
- };
-
- let mut rest = input.split(length)?;
- let cie_offset_base = rest.offset_from(section.section());
- let cie_id_or_offset = match Section::cie_offset_encoding(format) {
- CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?,
- CieOffsetEncoding::U64 => rest.read_u64()?,
- };
-
- if Section::is_cie(format, cie_id_or_offset) {
- let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?;
- Ok(Some(CieOrFde::Cie(cie)))
- } else {
- let cie_offset = R::Offset::from_u64(cie_id_or_offset)?;
- let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) {
- None => return Err(Error::OffsetOutOfBounds),
- Some(cie_offset) => cie_offset,
- };
-
- let fde = PartialFrameDescriptionEntry {
- offset,
- length,
- format,
- cie_offset: cie_offset.into(),
- rest,
- section: section.clone(),
- bases,
- };
-
- Ok(Some(CieOrFde::Fde(fde)))
- }
-}
-
-/// We support the z-style augmentation [defined by `.eh_frame`][ehframe].
-///
-/// [ehframe]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
-pub struct Augmentation {
- /// > A 'L' may be present at any position after the first character of the
- /// > string. This character may only be present if 'z' is the first character
- /// > of the string. If present, it indicates the presence of one argument in
- /// > the Augmentation Data of the CIE, and a corresponding argument in the
- /// > Augmentation Data of the FDE. The argument in the Augmentation Data of
- /// > the CIE is 1-byte and represents the pointer encoding used for the
- /// > argument in the Augmentation Data of the FDE, which is the address of a
- /// > language-specific data area (LSDA). The size of the LSDA pointer is
- /// > specified by the pointer encoding used.
- lsda: Option<constants::DwEhPe>,
-
- /// > A 'P' may be present at any position after the first character of the
- /// > string. This character may only be present if 'z' is the first character
- /// > of the string. If present, it indicates the presence of two arguments in
- /// > the Augmentation Data of the CIE. The first argument is 1-byte and
- /// > represents the pointer encoding used for the second argument, which is
- /// > the address of a personality routine handler. The size of the
- /// > personality routine pointer is specified by the pointer encoding used.
- personality: Option<(constants::DwEhPe, Pointer)>,
-
- /// > A 'R' may be present at any position after the first character of the
- /// > string. This character may only be present if 'z' is the first character
- /// > of the string. If present, The Augmentation Data shall include a 1 byte
- /// > argument that represents the pointer encoding for the address pointers
- /// > used in the FDE.
- fde_address_encoding: Option<constants::DwEhPe>,
-
- /// True if this CIE's FDEs are trampolines for signal handlers.
- is_signal_trampoline: bool,
-}
-
-impl Augmentation {
- fn parse<Section, R>(
- augmentation_str: &mut R,
- bases: &BaseAddresses,
- address_size: u8,
- section: &Section,
- input: &mut R,
- ) -> Result<Augmentation>
- where
- R: Reader,
- Section: UnwindSection<R>,
- {
- debug_assert!(
- !augmentation_str.is_empty(),
- "Augmentation::parse should only be called if we have an augmentation"
- );
-
- let mut augmentation = Augmentation::default();
-
- let mut parsed_first = false;
- let mut data = None;
-
- while !augmentation_str.is_empty() {
- let ch = augmentation_str.read_u8()?;
- match ch {
- b'z' => {
- if parsed_first {
- return Err(Error::UnknownAugmentation);
- }
-
- let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?;
- data = Some(input.split(augmentation_length)?);
- }
- b'L' => {
- let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
- let encoding = parse_pointer_encoding(rest)?;
- augmentation.lsda = Some(encoding);
- }
- b'P' => {
- let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
- let encoding = parse_pointer_encoding(rest)?;
- let parameters = PointerEncodingParameters {
- bases: &bases.eh_frame,
- func_base: None,
- address_size,
- section: section.section(),
- };
-
- let personality = parse_encoded_pointer(encoding, &parameters, rest)?;
- augmentation.personality = Some((encoding, personality));
- }
- b'R' => {
- let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
- let encoding = parse_pointer_encoding(rest)?;
- augmentation.fde_address_encoding = Some(encoding);
- }
- b'S' => augmentation.is_signal_trampoline = true,
- _ => return Err(Error::UnknownAugmentation),
- }
-
- parsed_first = true;
- }
-
- Ok(augmentation)
- }
-}
-
-/// Parsed augmentation data for a `FrameDescriptEntry`.
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-struct AugmentationData {
- lsda: Option<Pointer>,
-}
-
-impl AugmentationData {
- fn parse<R: Reader>(
- augmentation: &Augmentation,
- encoding_parameters: &PointerEncodingParameters<R>,
- input: &mut R,
- ) -> Result<AugmentationData> {
- // In theory, we should be iterating over the original augmentation
- // string, interpreting each character, and reading the appropriate bits
- // out of the augmentation data as we go. However, the only character
- // that defines augmentation data in the FDE is the 'L' character, so we
- // can just check for its presence directly.
-
- let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let rest = &mut input.split(aug_data_len)?;
- let mut augmentation_data = AugmentationData::default();
- if let Some(encoding) = augmentation.lsda {
- let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?;
- augmentation_data.lsda = Some(lsda);
- }
- Ok(augmentation_data)
- }
-}
-
-/// > A Common Information Entry holds information that is shared among many
-/// > Frame Description Entries. There is at least one CIE in every non-empty
-/// > `.debug_frame` section.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct CommonInformationEntry<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// The offset of this entry from the start of its containing section.
- offset: Offset,
-
- /// > A constant that gives the number of bytes of the CIE structure, not
- /// > including the length field itself (see Section 7.2.2). The size of the
- /// > length field plus the value of length must be an integral multiple of
- /// > the address size.
- length: Offset,
-
- format: Format,
-
- /// > A version number (see Section 7.23). This number is specific to the
- /// > call frame information and is independent of the DWARF version number.
- version: u8,
-
- /// The parsed augmentation, if any.
- augmentation: Option<Augmentation>,
-
- /// > The size of a target address in this CIE and any FDEs that use it, in
- /// > bytes. If a compilation unit exists for this frame, its address size
- /// > must match the address size here.
- address_size: u8,
-
- /// "The size of a segment selector in this CIE and any FDEs that use it, in
- /// bytes."
- segment_size: u8,
-
- /// "A constant that is factored out of all advance location instructions
- /// (see Section 6.4.2.1)."
- code_alignment_factor: u64,
-
- /// > A constant that is factored out of certain offset instructions (see
- /// > below). The resulting value is (operand * data_alignment_factor).
- data_alignment_factor: i64,
-
- /// > An unsigned LEB128 constant that indicates which column in the rule
- /// > table represents the return address of the function. Note that this
- /// > column might not correspond to an actual machine register.
- return_address_register: Register,
-
- /// > A sequence of rules that are interpreted to create the initial setting
- /// > of each column in the table.
- ///
- /// > The default rule for all columns before interpretation of the initial
- /// > instructions is the undefined rule. However, an ABI authoring body or a
- /// > compilation system authoring body may specify an alternate default
- /// > value for any or all columns.
- ///
- /// This is followed by `DW_CFA_nop` padding until the end of `length` bytes
- /// in the input.
- initial_instructions: R,
-}
-
-impl<R: Reader> CommonInformationEntry<R> {
- fn parse<Section: UnwindSection<R>>(
- bases: &BaseAddresses,
- section: &Section,
- input: &mut R,
- ) -> Result<CommonInformationEntry<R>> {
- match parse_cfi_entry(bases, section, input)? {
- Some(CieOrFde::Cie(cie)) => Ok(cie),
- Some(CieOrFde::Fde(_)) => Err(Error::NotCieId),
- None => Err(Error::NoEntryAtGivenOffset),
- }
- }
-
- fn parse_rest<Section: UnwindSection<R>>(
- offset: R::Offset,
- length: R::Offset,
- format: Format,
- bases: &BaseAddresses,
- section: &Section,
- mut rest: R,
- ) -> Result<CommonInformationEntry<R>> {
- let version = rest.read_u8()?;
-
- // Version 1 of `.debug_frame` corresponds to DWARF 2, and then for
- // DWARF 3 and 4, I think they decided to just match the standard's
- // version.
- match version {
- 1 | 3 | 4 => (),
- _ => return Err(Error::UnknownVersion(u64::from(version))),
- }
-
- let mut augmentation_string = rest.read_null_terminated_slice()?;
-
- let (address_size, segment_size) = if Section::has_address_and_segment_sizes(version) {
- let address_size = rest.read_u8()?;
- let segment_size = rest.read_u8()?;
- (address_size, segment_size)
- } else {
- (section.address_size(), section.segment_size())
- };
-
- let code_alignment_factor = rest.read_uleb128()?;
- let data_alignment_factor = rest.read_sleb128()?;
-
- let return_address_register = if version == 1 {
- Register(rest.read_u8()?.into())
- } else {
- rest.read_uleb128().and_then(Register::from_u64)?
- };
-
- let augmentation = if augmentation_string.is_empty() {
- None
- } else {
- Some(Augmentation::parse(
- &mut augmentation_string,
- bases,
- address_size,
- section,
- &mut rest,
- )?)
- };
-
- let entry = CommonInformationEntry {
- offset,
- length,
- format,
- version,
- augmentation,
- address_size,
- segment_size,
- code_alignment_factor,
- data_alignment_factor,
- return_address_register,
- initial_instructions: rest,
- };
-
- Ok(entry)
- }
-}
-
-/// # Signal Safe Methods
-///
-/// These methods are guaranteed not to allocate, acquire locks, or perform any
-/// other signal-unsafe operations.
-impl<R: Reader> CommonInformationEntry<R> {
- /// Get the offset of this entry from the start of its containing section.
- pub fn offset(&self) -> R::Offset {
- self.offset
- }
-
- /// Return the encoding parameters for this CIE.
- pub fn encoding(&self) -> Encoding {
- Encoding {
- format: self.format,
- version: u16::from(self.version),
- address_size: self.address_size,
- }
- }
-
- /// The size of addresses (in bytes) in this CIE.
- pub fn address_size(&self) -> u8 {
- self.address_size
- }
-
- /// Iterate over this CIE's initial instructions.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn instructions<'a, Section>(
- &self,
- section: &'a Section,
- bases: &'a BaseAddresses,
- ) -> CallFrameInstructionIter<'a, R>
- where
- Section: UnwindSection<R>,
- {
- CallFrameInstructionIter {
- input: self.initial_instructions.clone(),
- address_encoding: None,
- parameters: PointerEncodingParameters {
- bases: &bases.eh_frame,
- func_base: None,
- address_size: self.address_size,
- section: section.section(),
- },
- vendor: section.vendor(),
- }
- }
-
- /// > A constant that gives the number of bytes of the CIE structure, not
- /// > including the length field itself (see Section 7.2.2). The size of the
- /// > length field plus the value of length must be an integral multiple of
- /// > the address size.
- pub fn entry_len(&self) -> R::Offset {
- self.length
- }
-
- /// > A version number (see Section 7.23). This number is specific to the
- /// > call frame information and is independent of the DWARF version number.
- pub fn version(&self) -> u8 {
- self.version
- }
-
- /// Get the augmentation data, if any exists.
- ///
- /// The only augmentation understood by `gimli` is that which is defined by
- /// `.eh_frame`.
- pub fn augmentation(&self) -> Option<&Augmentation> {
- self.augmentation.as_ref()
- }
-
- /// True if this CIE's FDEs have a LSDA.
- pub fn has_lsda(&self) -> bool {
- self.augmentation.map_or(false, |a| a.lsda.is_some())
- }
-
- /// Return the encoding of the LSDA address for this CIE's FDEs.
- pub fn lsda_encoding(&self) -> Option<constants::DwEhPe> {
- self.augmentation.and_then(|a| a.lsda)
- }
-
- /// Return the encoding and address of the personality routine handler
- /// for this CIE's FDEs.
- pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> {
- self.augmentation.as_ref().and_then(|a| a.personality)
- }
-
- /// Return the address of the personality routine handler
- /// for this CIE's FDEs.
- pub fn personality(&self) -> Option<Pointer> {
- self.augmentation
- .as_ref()
- .and_then(|a| a.personality)
- .map(|(_, p)| p)
- }
-
- /// Return the encoding of the addresses for this CIE's FDEs.
- pub fn fde_address_encoding(&self) -> Option<constants::DwEhPe> {
- self.augmentation.and_then(|a| a.fde_address_encoding)
- }
-
- /// True if this CIE's FDEs are trampolines for signal handlers.
- pub fn is_signal_trampoline(&self) -> bool {
- self.augmentation.map_or(false, |a| a.is_signal_trampoline)
- }
-
- /// > A constant that is factored out of all advance location instructions
- /// > (see Section 6.4.2.1).
- pub fn code_alignment_factor(&self) -> u64 {
- self.code_alignment_factor
- }
-
- /// > A constant that is factored out of certain offset instructions (see
- /// > below). The resulting value is (operand * data_alignment_factor).
- pub fn data_alignment_factor(&self) -> i64 {
- self.data_alignment_factor
- }
-
- /// > An unsigned ... constant that indicates which column in the rule
- /// > table represents the return address of the function. Note that this
- /// > column might not correspond to an actual machine register.
- pub fn return_address_register(&self) -> Register {
- self.return_address_register
- }
-}
-
-/// A partially parsed `FrameDescriptionEntry`.
-///
-/// Fully parsing this FDE requires first parsing its CIE.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct PartialFrameDescriptionEntry<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- offset: R::Offset,
- length: R::Offset,
- format: Format,
- cie_offset: Section::Offset,
- rest: R,
- section: Section,
- bases: &'bases BaseAddresses,
-}
-
-impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R>
-where
- R: Reader,
- Section: UnwindSection<R>,
-{
- fn parse_partial(
- section: &Section,
- bases: &'bases BaseAddresses,
- input: &mut R,
- ) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> {
- match parse_cfi_entry(bases, section, input)? {
- Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer),
- Some(CieOrFde::Fde(partial)) => Ok(partial),
- None => Err(Error::NoEntryAtGivenOffset),
- }
- }
-
- /// Fully parse this FDE.
- ///
- /// You must provide a function get its associated CIE (either by parsing it
- /// on demand, or looking it up in some table mapping offsets to CIEs that
- /// you've already parsed, etc.)
- pub fn parse<F>(&self, get_cie: F) -> Result<FrameDescriptionEntry<R>>
- where
- F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
- {
- FrameDescriptionEntry::parse_rest(
- self.offset,
- self.length,
- self.format,
- self.cie_offset,
- self.rest.clone(),
- &self.section,
- self.bases,
- get_cie,
- )
- }
-
- /// Get the offset of this entry from the start of its containing section.
- pub fn offset(&self) -> R::Offset {
- self.offset
- }
-
- /// Get the offset of this FDE's CIE.
- pub fn cie_offset(&self) -> Section::Offset {
- self.cie_offset
- }
-
- /// > A constant that gives the number of bytes of the header and
- /// > instruction stream for this function, not including the length field
- /// > itself (see Section 7.2.2). The size of the length field plus the value
- /// > of length must be an integral multiple of the address size.
- pub fn entry_len(&self) -> R::Offset {
- self.length
- }
-}
-
-/// A `FrameDescriptionEntry` is a set of CFA instructions for an address range.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FrameDescriptionEntry<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// The start of this entry within its containing section.
- offset: Offset,
-
- /// > A constant that gives the number of bytes of the header and
- /// > instruction stream for this function, not including the length field
- /// > itself (see Section 7.2.2). The size of the length field plus the value
- /// > of length must be an integral multiple of the address size.
- length: Offset,
-
- format: Format,
-
- /// "A constant offset into the .debug_frame section that denotes the CIE
- /// that is associated with this FDE."
- ///
- /// This is the CIE at that offset.
- cie: CommonInformationEntry<R, Offset>,
-
- /// > The address of the first location associated with this table entry. If
- /// > the segment_size field of this FDE's CIE is non-zero, the initial
- /// > location is preceded by a segment selector of the given length.
- initial_segment: u64,
- initial_address: u64,
-
- /// "The number of bytes of program instructions described by this entry."
- address_range: u64,
-
- /// The parsed augmentation data, if we have any.
- augmentation: Option<AugmentationData>,
-
- /// "A sequence of table defining instructions that are described below."
- ///
- /// This is followed by `DW_CFA_nop` padding until `length` bytes of the
- /// input are consumed.
- instructions: R,
-}
-
-impl<R: Reader> FrameDescriptionEntry<R> {
- fn parse_rest<Section, F>(
- offset: R::Offset,
- length: R::Offset,
- format: Format,
- cie_pointer: Section::Offset,
- mut rest: R,
- section: &Section,
- bases: &BaseAddresses,
- mut get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- Section: UnwindSection<R>,
- F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
- {
- let cie = get_cie(section, bases, cie_pointer)?;
-
- let initial_segment = if cie.segment_size > 0 {
- rest.read_address(cie.segment_size)?
- } else {
- 0
- };
-
- let mut parameters = PointerEncodingParameters {
- bases: &bases.eh_frame,
- func_base: None,
- address_size: cie.address_size,
- section: section.section(),
- };
-
- let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, &parameters)?;
- parameters.func_base = Some(initial_address);
-
- let aug_data = if let Some(ref augmentation) = cie.augmentation {
- Some(AugmentationData::parse(
- augmentation,
- &parameters,
- &mut rest,
- )?)
- } else {
- None
- };
-
- let entry = FrameDescriptionEntry {
- offset,
- length,
- format,
- cie,
- initial_segment,
- initial_address,
- address_range,
- augmentation: aug_data,
- instructions: rest,
- };
-
- Ok(entry)
- }
-
- fn parse_addresses(
- input: &mut R,
- cie: &CommonInformationEntry<R>,
- parameters: &PointerEncodingParameters<R>,
- ) -> Result<(u64, u64)> {
- let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding);
- if let Some(encoding) = encoding {
- let initial_address = parse_encoded_pointer(encoding, parameters, input)?;
-
- // Ignore indirection.
- let initial_address = initial_address.pointer();
-
- // Address ranges cannot be relative to anything, so just grab the
- // data format bits from the encoding.
- let address_range = parse_encoded_pointer(encoding.format(), parameters, input)?;
- Ok((initial_address, address_range.pointer()))
- } else {
- let initial_address = input.read_address(cie.address_size)?;
- let address_range = input.read_address(cie.address_size)?;
- Ok((initial_address, address_range))
- }
- }
-
- /// Return the table of unwind information for this FDE.
- #[inline]
- pub fn rows<'a, 'ctx, Section: UnwindSection<R>, A: UnwindContextStorage<R>>(
- &self,
- section: &'a Section,
- bases: &'a BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- ) -> Result<UnwindTable<'a, 'ctx, R, A>> {
- UnwindTable::new(section, bases, ctx, self)
- }
-
- /// Find the frame unwind information for the given address.
- ///
- /// If found, the unwind information is returned along with the reset
- /// context in the form `Ok((unwind_info, context))`. If not found,
- /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or
- /// CFI evaluation fails, the error is returned.
- pub fn unwind_info_for_address<'ctx, Section: UnwindSection<R>, A: UnwindContextStorage<R>>(
- &self,
- section: &Section,
- bases: &BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- address: u64,
- ) -> Result<&'ctx UnwindTableRow<R, A>> {
- let mut table = self.rows(section, bases, ctx)?;
- while let Some(row) = table.next_row()? {
- if row.contains(address) {
- return Ok(table.ctx.row());
- }
- }
- Err(Error::NoUnwindInfoForAddress)
- }
-}
-
-/// # Signal Safe Methods
-///
-/// These methods are guaranteed not to allocate, acquire locks, or perform any
-/// other signal-unsafe operations.
-#[allow(clippy::len_without_is_empty)]
-impl<R: Reader> FrameDescriptionEntry<R> {
- /// Get the offset of this entry from the start of its containing section.
- pub fn offset(&self) -> R::Offset {
- self.offset
- }
-
- /// Get a reference to this FDE's CIE.
- pub fn cie(&self) -> &CommonInformationEntry<R> {
- &self.cie
- }
-
- /// > A constant that gives the number of bytes of the header and
- /// > instruction stream for this function, not including the length field
- /// > itself (see Section 7.2.2). The size of the length field plus the value
- /// > of length must be an integral multiple of the address size.
- pub fn entry_len(&self) -> R::Offset {
- self.length
- }
-
- /// Iterate over this FDE's instructions.
- ///
- /// Will not include the CIE's initial instructions, if you want those do
- /// `fde.cie().instructions()` first.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn instructions<'a, Section>(
- &self,
- section: &'a Section,
- bases: &'a BaseAddresses,
- ) -> CallFrameInstructionIter<'a, R>
- where
- Section: UnwindSection<R>,
- {
- CallFrameInstructionIter {
- input: self.instructions.clone(),
- address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding),
- parameters: PointerEncodingParameters {
- bases: &bases.eh_frame,
- func_base: None,
- address_size: self.cie.address_size,
- section: section.section(),
- },
- vendor: section.vendor(),
- }
- }
-
- /// The first address for which this entry has unwind information for.
- pub fn initial_address(&self) -> u64 {
- self.initial_address
- }
-
- /// The number of bytes of instructions that this entry has unwind
- /// information for.
- pub fn len(&self) -> u64 {
- self.address_range
- }
-
- /// Return `true` if the given address is within this FDE, `false`
- /// otherwise.
- ///
- /// This is equivalent to `entry.initial_address() <= address <
- /// entry.initial_address() + entry.len()`.
- pub fn contains(&self, address: u64) -> bool {
- let start = self.initial_address();
- let end = start + self.len();
- start <= address && address < end
- }
-
- /// The address of this FDE's language-specific data area (LSDA), if it has
- /// any.
- pub fn lsda(&self) -> Option<Pointer> {
- self.augmentation.as_ref().and_then(|a| a.lsda)
- }
-
- /// Return true if this FDE's function is a trampoline for a signal handler.
- #[inline]
- pub fn is_signal_trampoline(&self) -> bool {
- self.cie().is_signal_trampoline()
- }
-
- /// Return the address of the FDE's function's personality routine
- /// handler. The personality routine does language-specific clean up when
- /// unwinding the stack frames with the intent to not run them again.
- #[inline]
- pub fn personality(&self) -> Option<Pointer> {
- self.cie().personality()
- }
-}
-
-/// Specification of what storage should be used for [`UnwindContext`].
-///
-#[cfg_attr(
- feature = "read",
- doc = "
-Normally you would only need to use [`StoreOnHeap`], which places the stack
-on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`].
-"
-)]
-///
-/// If you need to avoid [`UnwindContext`] from allocating memory, e.g. for signal safety,
-/// you can provide you own storage specification:
-/// ```rust,no_run
-/// # use gimli::*;
-/// #
-/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>)
-/// # -> gimli::Result<()> {
-/// # let eh_frame: gimli::EhFrame<_> = unreachable!();
-/// # let bases = unimplemented!();
-/// #
-/// struct StoreOnStack;
-///
-/// impl<R: Reader> UnwindContextStorage<R> for StoreOnStack {
-/// type Rules = [(Register, RegisterRule<R>); 192];
-/// type Stack = [UnwindTableRow<R, Self>; 4];
-/// }
-///
-/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in();
-///
-/// // Initialize the context by evaluating the CIE's initial instruction program,
-/// // and generate the unwind table.
-/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?;
-/// while let Some(row) = table.next_row()? {
-/// // Do stuff with each row...
-/// # let _ = row;
-/// }
-/// # unreachable!()
-/// # }
-/// ```
-pub trait UnwindContextStorage<R: Reader>: Sized {
- /// The storage used for register rules in a unwind table row.
- ///
- /// Note that this is nested within the stack.
- type Rules: ArrayLike<Item = (Register, RegisterRule<R>)>;
-
- /// The storage used for unwind table row stack.
- type Stack: ArrayLike<Item = UnwindTableRow<R, Self>>;
-}
-
-#[cfg(feature = "read")]
-const MAX_RULES: usize = 192;
-#[cfg(feature = "read")]
-const MAX_UNWIND_STACK_DEPTH: usize = 4;
-
-#[cfg(feature = "read")]
-impl<R: Reader> UnwindContextStorage<R> for StoreOnHeap {
- type Rules = [(Register, RegisterRule<R>); MAX_RULES];
- type Stack = Box<[UnwindTableRow<R, Self>; MAX_UNWIND_STACK_DEPTH]>;
-}
-
-/// Common context needed when evaluating the call frame unwinding information.
-///
-/// This structure can be large so it is advisable to place it on the heap.
-/// To avoid re-allocating the context multiple times when evaluating multiple
-/// CFI programs, it can be reused.
-///
-/// ```
-/// use gimli::{UnwindContext, UnwindTable};
-///
-/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>)
-/// # -> gimli::Result<()> {
-/// # let eh_frame: gimli::EhFrame<_> = unreachable!();
-/// # let bases = unimplemented!();
-/// // An uninitialized context.
-/// let mut ctx = Box::new(UnwindContext::new());
-///
-/// // Initialize the context by evaluating the CIE's initial instruction program,
-/// // and generate the unwind table.
-/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?;
-/// while let Some(row) = table.next_row()? {
-/// // Do stuff with each row...
-/// # let _ = row;
-/// }
-/// # unreachable!()
-/// # }
-/// ```
-#[derive(Clone, PartialEq, Eq)]
-pub struct UnwindContext<R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> {
- // Stack of rows. The last row is the row currently being built by the
- // program. There is always at least one row. The vast majority of CFI
- // programs will only ever have one row on the stack.
- stack: ArrayVec<A::Stack>,
-
- // If we are evaluating an FDE's instructions, then `is_initialized` will be
- // `true`. If `initial_rule` is `Some`, then the initial register rules are either
- // all default rules or have just 1 non-default rule, stored in `initial_rule`.
- // If it's `None`, `stack[0]` will contain the initial register rules
- // described by the CIE's initial instructions. These rules are used by
- // `DW_CFA_restore`. Otherwise, when we are currently evaluating a CIE's
- // initial instructions, `is_initialized` will be `false` and initial rules
- // cannot be read.
- initial_rule: Option<(Register, RegisterRule<R>)>,
-
- is_initialized: bool,
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Debug for UnwindContext<R, S> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("UnwindContext")
- .field("stack", &self.stack)
- .field("initial_rule", &self.initial_rule)
- .field("is_initialized", &self.is_initialized)
- .finish()
- }
-}
-
-impl<R: Reader, A: UnwindContextStorage<R>> Default for UnwindContext<R, A> {
- fn default() -> Self {
- Self::new_in()
- }
-}
-
-#[cfg(feature = "read")]
-impl<R: Reader> UnwindContext<R> {
- /// Construct a new call frame unwinding context.
- pub fn new() -> Self {
- Self::new_in()
- }
-}
-
-/// # Signal Safe Methods
-///
-/// These methods are guaranteed not to allocate, acquire locks, or perform any
-/// other signal-unsafe operations, if an non-allocating storage is used.
-impl<R: Reader, A: UnwindContextStorage<R>> UnwindContext<R, A> {
- /// Construct a new call frame unwinding context.
- pub fn new_in() -> Self {
- let mut ctx = UnwindContext {
- stack: Default::default(),
- initial_rule: None,
- is_initialized: false,
- };
- ctx.reset();
- ctx
- }
-
- /// Run the CIE's initial instructions and initialize this `UnwindContext`.
- fn initialize<Section: UnwindSection<R>>(
- &mut self,
- section: &Section,
- bases: &BaseAddresses,
- cie: &CommonInformationEntry<R>,
- ) -> Result<()> {
- // Always reset because previous initialization failure may leave dirty state.
- self.reset();
-
- let mut table = UnwindTable::new_for_cie(section, bases, self, cie);
- while table.next_row()?.is_some() {}
-
- self.save_initial_rules()?;
- Ok(())
- }
-
- fn reset(&mut self) {
- self.stack.clear();
- self.stack.try_push(UnwindTableRow::default()).unwrap();
- debug_assert!(self.stack[0].is_default());
- self.initial_rule = None;
- self.is_initialized = false;
- }
-
- fn row(&self) -> &UnwindTableRow<R, A> {
- self.stack.last().unwrap()
- }
-
- fn row_mut(&mut self) -> &mut UnwindTableRow<R, A> {
- self.stack.last_mut().unwrap()
- }
-
- fn save_initial_rules(&mut self) -> Result<()> {
- debug_assert!(!self.is_initialized);
- self.initial_rule = match *self.stack.last().unwrap().registers.rules {
- // All rules are default (undefined). In this case just synthesize
- // an undefined rule.
- [] => Some((Register(0), RegisterRule::Undefined)),
- [ref rule] => Some(rule.clone()),
- _ => {
- let rules = self.stack.last().unwrap().clone();
- self.stack
- .try_insert(0, rules)
- .map_err(|_| Error::StackFull)?;
- None
- }
- };
- self.is_initialized = true;
- Ok(())
- }
-
- fn start_address(&self) -> u64 {
- self.row().start_address
- }
-
- fn set_start_address(&mut self, start_address: u64) {
- let row = self.row_mut();
- row.start_address = start_address;
- }
-
- fn set_register_rule(&mut self, register: Register, rule: RegisterRule<R>) -> Result<()> {
- let row = self.row_mut();
- row.registers.set(register, rule)
- }
-
- /// Returns `None` if we have not completed evaluation of a CIE's initial
- /// instructions.
- fn get_initial_rule(&self, register: Register) -> Option<RegisterRule<R>> {
- if !self.is_initialized {
- return None;
- }
- Some(match self.initial_rule {
- None => self.stack[0].registers.get(register),
- Some((r, ref rule)) if r == register => rule.clone(),
- _ => RegisterRule::Undefined,
- })
- }
-
- fn set_cfa(&mut self, cfa: CfaRule<R>) {
- self.row_mut().cfa = cfa;
- }
-
- fn cfa_mut(&mut self) -> &mut CfaRule<R> {
- &mut self.row_mut().cfa
- }
-
- fn push_row(&mut self) -> Result<()> {
- let new_row = self.row().clone();
- self.stack.try_push(new_row).map_err(|_| Error::StackFull)
- }
-
- fn pop_row(&mut self) -> Result<()> {
- let min_size = if self.is_initialized && self.initial_rule.is_none() {
- 2
- } else {
- 1
- };
- if self.stack.len() <= min_size {
- return Err(Error::PopWithEmptyStack);
- }
- self.stack.pop().unwrap();
- Ok(())
- }
-}
-
-/// The `UnwindTable` iteratively evaluates a `FrameDescriptionEntry`'s
-/// `CallFrameInstruction` program, yielding the each row one at a time.
-///
-/// > 6.4.1 Structure of Call Frame Information
-/// >
-/// > DWARF supports virtual unwinding by defining an architecture independent
-/// > basis for recording how procedures save and restore registers during their
-/// > lifetimes. This basis must be augmented on some machines with specific
-/// > information that is defined by an architecture specific ABI authoring
-/// > committee, a hardware vendor, or a compiler producer. The body defining a
-/// > specific augmentation is referred to below as the “augmenter.”
-/// >
-/// > Abstractly, this mechanism describes a very large table that has the
-/// > following structure:
-/// >
-/// > <table>
-/// > <tr>
-/// > <th>LOC</th><th>CFA</th><th>R0</th><th>R1</th><td>...</td><th>RN</th>
-/// > </tr>
-/// > <tr>
-/// > <th>L0</th> <td></td> <td></td> <td></td> <td></td> <td></td>
-/// > </tr>
-/// > <tr>
-/// > <th>L1</th> <td></td> <td></td> <td></td> <td></td> <td></td>
-/// > </tr>
-/// > <tr>
-/// > <td>...</td><td></td> <td></td> <td></td> <td></td> <td></td>
-/// > </tr>
-/// > <tr>
-/// > <th>LN</th> <td></td> <td></td> <td></td> <td></td> <td></td>
-/// > </tr>
-/// > </table>
-/// >
-/// > The first column indicates an address for every location that contains code
-/// > in a program. (In shared objects, this is an object-relative offset.) The
-/// > remaining columns contain virtual unwinding rules that are associated with
-/// > the indicated location.
-/// >
-/// > The CFA column defines the rule which computes the Canonical Frame Address
-/// > value; it may be either a register and a signed offset that are added
-/// > together, or a DWARF expression that is evaluated.
-/// >
-/// > The remaining columns are labeled by register number. This includes some
-/// > registers that have special designation on some architectures such as the PC
-/// > and the stack pointer register. (The actual mapping of registers for a
-/// > particular architecture is defined by the augmenter.) The register columns
-/// > contain rules that describe whether a given register has been saved and the
-/// > rule to find the value for the register in the previous frame.
-/// >
-/// > ...
-/// >
-/// > This table would be extremely large if actually constructed as
-/// > described. Most of the entries at any point in the table are identical to
-/// > the ones above them. The whole table can be represented quite compactly by
-/// > recording just the differences starting at the beginning address of each
-/// > subroutine in the program.
-#[derive(Debug)]
-pub struct UnwindTable<'a, 'ctx, R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> {
- code_alignment_factor: Wrapping<u64>,
- data_alignment_factor: Wrapping<i64>,
- next_start_address: u64,
- last_end_address: u64,
- returned_last_row: bool,
- current_row_valid: bool,
- instructions: CallFrameInstructionIter<'a, R>,
- ctx: &'ctx mut UnwindContext<R, A>,
-}
-
-/// # Signal Safe Methods
-///
-/// These methods are guaranteed not to allocate, acquire locks, or perform any
-/// other signal-unsafe operations.
-impl<'a, 'ctx, R: Reader, A: UnwindContextStorage<R>> UnwindTable<'a, 'ctx, R, A> {
- /// Construct a new `UnwindTable` for the given
- /// `FrameDescriptionEntry`'s CFI unwinding program.
- pub fn new<Section: UnwindSection<R>>(
- section: &'a Section,
- bases: &'a BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- fde: &FrameDescriptionEntry<R>,
- ) -> Result<Self> {
- ctx.initialize(section, bases, fde.cie())?;
- Ok(Self::new_for_fde(section, bases, ctx, fde))
- }
-
- fn new_for_fde<Section: UnwindSection<R>>(
- section: &'a Section,
- bases: &'a BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- fde: &FrameDescriptionEntry<R>,
- ) -> Self {
- assert!(ctx.stack.len() >= 1);
- UnwindTable {
- code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()),
- data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()),
- next_start_address: fde.initial_address(),
- last_end_address: fde.initial_address().wrapping_add(fde.len()),
- returned_last_row: false,
- current_row_valid: false,
- instructions: fde.instructions(section, bases),
- ctx,
- }
- }
-
- fn new_for_cie<Section: UnwindSection<R>>(
- section: &'a Section,
- bases: &'a BaseAddresses,
- ctx: &'ctx mut UnwindContext<R, A>,
- cie: &CommonInformationEntry<R>,
- ) -> Self {
- assert!(ctx.stack.len() >= 1);
- UnwindTable {
- code_alignment_factor: Wrapping(cie.code_alignment_factor()),
- data_alignment_factor: Wrapping(cie.data_alignment_factor()),
- next_start_address: 0,
- last_end_address: 0,
- returned_last_row: false,
- current_row_valid: false,
- instructions: cie.instructions(section, bases),
- ctx,
- }
- }
-
- /// Evaluate call frame instructions until the next row of the table is
- /// completed, and return it.
- ///
- /// Unfortunately, this cannot be used with `FallibleIterator` because of
- /// the restricted lifetime of the yielded item.
- pub fn next_row(&mut self) -> Result<Option<&UnwindTableRow<R, A>>> {
- assert!(self.ctx.stack.len() >= 1);
- self.ctx.set_start_address(self.next_start_address);
- self.current_row_valid = false;
-
- loop {
- match self.instructions.next() {
- Err(e) => return Err(e),
-
- Ok(None) => {
- if self.returned_last_row {
- return Ok(None);
- }
-
- let row = self.ctx.row_mut();
- row.end_address = self.last_end_address;
-
- self.returned_last_row = true;
- self.current_row_valid = true;
- return Ok(Some(row));
- }
-
- Ok(Some(instruction)) => {
- if self.evaluate(instruction)? {
- self.current_row_valid = true;
- return Ok(Some(self.ctx.row()));
- }
- }
- };
- }
- }
-
- /// Returns the current row with the lifetime of the context.
- pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow<R, A>> {
- if self.current_row_valid {
- Some(self.ctx.row())
- } else {
- None
- }
- }
-
- /// Evaluate one call frame instruction. Return `Ok(true)` if the row is
- /// complete, `Ok(false)` otherwise.
- fn evaluate(&mut self, instruction: CallFrameInstruction<R>) -> Result<bool> {
- use crate::CallFrameInstruction::*;
-
- match instruction {
- // Instructions that complete the current row and advance the
- // address for the next row.
- SetLoc { address } => {
- if address < self.ctx.start_address() {
- return Err(Error::InvalidAddressRange);
- }
-
- self.next_start_address = address;
- self.ctx.row_mut().end_address = self.next_start_address;
- return Ok(true);
- }
- AdvanceLoc { delta } => {
- let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor;
- self.next_start_address = (Wrapping(self.ctx.start_address()) + delta).0;
- self.ctx.row_mut().end_address = self.next_start_address;
- return Ok(true);
- }
-
- // Instructions that modify the CFA.
- DefCfa { register, offset } => {
- self.ctx.set_cfa(CfaRule::RegisterAndOffset {
- register,
- offset: offset as i64,
- });
- }
- DefCfaSf {
- register,
- factored_offset,
- } => {
- let data_align = self.data_alignment_factor;
- self.ctx.set_cfa(CfaRule::RegisterAndOffset {
- register,
- offset: (Wrapping(factored_offset) * data_align).0,
- });
- }
- DefCfaRegister { register } => {
- if let CfaRule::RegisterAndOffset {
- register: ref mut reg,
- ..
- } = *self.ctx.cfa_mut()
- {
- *reg = register;
- } else {
- return Err(Error::CfiInstructionInInvalidContext);
- }
- }
- DefCfaOffset { offset } => {
- if let CfaRule::RegisterAndOffset {
- offset: ref mut off,
- ..
- } = *self.ctx.cfa_mut()
- {
- *off = offset as i64;
- } else {
- return Err(Error::CfiInstructionInInvalidContext);
- }
- }
- DefCfaOffsetSf { factored_offset } => {
- if let CfaRule::RegisterAndOffset {
- offset: ref mut off,
- ..
- } = *self.ctx.cfa_mut()
- {
- let data_align = self.data_alignment_factor;
- *off = (Wrapping(factored_offset) * data_align).0;
- } else {
- return Err(Error::CfiInstructionInInvalidContext);
- }
- }
- DefCfaExpression { expression } => {
- self.ctx.set_cfa(CfaRule::Expression(expression));
- }
-
- // Instructions that define register rules.
- Undefined { register } => {
- self.ctx
- .set_register_rule(register, RegisterRule::Undefined)?;
- }
- SameValue { register } => {
- self.ctx
- .set_register_rule(register, RegisterRule::SameValue)?;
- }
- Offset {
- register,
- factored_offset,
- } => {
- let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
- self.ctx
- .set_register_rule(register, RegisterRule::Offset(offset.0))?;
- }
- OffsetExtendedSf {
- register,
- factored_offset,
- } => {
- let offset = Wrapping(factored_offset) * self.data_alignment_factor;
- self.ctx
- .set_register_rule(register, RegisterRule::Offset(offset.0))?;
- }
- ValOffset {
- register,
- factored_offset,
- } => {
- let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
- self.ctx
- .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
- }
- ValOffsetSf {
- register,
- factored_offset,
- } => {
- let offset = Wrapping(factored_offset) * self.data_alignment_factor;
- self.ctx
- .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
- }
- Register {
- dest_register,
- src_register,
- } => {
- self.ctx
- .set_register_rule(dest_register, RegisterRule::Register(src_register))?;
- }
- Expression {
- register,
- expression,
- } => {
- let expression = RegisterRule::Expression(expression);
- self.ctx.set_register_rule(register, expression)?;
- }
- ValExpression {
- register,
- expression,
- } => {
- let expression = RegisterRule::ValExpression(expression);
- self.ctx.set_register_rule(register, expression)?;
- }
- Restore { register } => {
- let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) {
- rule
- } else {
- // Can't restore the initial rule when we are
- // evaluating the initial rules!
- return Err(Error::CfiInstructionInInvalidContext);
- };
-
- self.ctx.set_register_rule(register, initial_rule)?;
- }
-
- // Row push and pop instructions.
- RememberState => {
- self.ctx.push_row()?;
- }
- RestoreState => {
- // Pop state while preserving current location.
- let start_address = self.ctx.start_address();
- self.ctx.pop_row()?;
- self.ctx.set_start_address(start_address);
- }
-
- // GNU Extension. Save the size somewhere so the unwinder can use
- // it when restoring IP
- ArgsSize { size } => {
- self.ctx.row_mut().saved_args_size = size;
- }
-
- // AArch64 extension.
- NegateRaState => {
- let register = crate::AArch64::RA_SIGN_STATE;
- let value = match self.ctx.row().register(register) {
- RegisterRule::Undefined => 0,
- RegisterRule::Constant(value) => value,
- _ => return Err(Error::CfiInstructionInInvalidContext),
- };
- self.ctx
- .set_register_rule(register, RegisterRule::Constant(value ^ 1))?;
- }
-
- // No operation.
- Nop => {}
- };
-
- Ok(false)
- }
-}
-
-// We tend to have very few register rules: usually only a couple. Even if we
-// have a rule for every register, on x86-64 with SSE and everything we're
-// talking about ~100 rules. So rather than keeping the rules in a hash map, or
-// a vector indexed by register number (which would lead to filling lots of
-// empty entries), we store them as a vec of (register number, register rule)
-// pairs.
-//
-// Additionally, because every register's default rule is implicitly
-// `RegisterRule::Undefined`, we never store a register's rule in this vec if it
-// is undefined and save a little bit more space and do a little fewer
-// comparisons that way.
-//
-// The maximum number of rules preallocated by libunwind is 97 for AArch64, 128
-// for ARM, and even 188 for MIPS. It is extremely unlikely to encounter this
-// many register rules in practice.
-//
-// See:
-// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-x86_64/dwarf-config.h#L36
-// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32
-// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31
-// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31
-struct RegisterRuleMap<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> {
- rules: ArrayVec<S::Rules>,
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Debug for RegisterRuleMap<R, S> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("RegisterRuleMap")
- .field("rules", &self.rules)
- .finish()
- }
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Clone for RegisterRuleMap<R, S> {
- fn clone(&self) -> Self {
- Self {
- rules: self.rules.clone(),
- }
- }
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Default for RegisterRuleMap<R, S> {
- fn default() -> Self {
- RegisterRuleMap {
- rules: Default::default(),
- }
- }
-}
-
-/// # Signal Safe Methods
-///
-/// These methods are guaranteed not to allocate, acquire locks, or perform any
-/// other signal-unsafe operations.
-impl<R: Reader, S: UnwindContextStorage<R>> RegisterRuleMap<R, S> {
- fn is_default(&self) -> bool {
- self.rules.is_empty()
- }
-
- fn get(&self, register: Register) -> RegisterRule<R> {
- self.rules
- .iter()
- .find(|rule| rule.0 == register)
- .map(|r| {
- debug_assert!(r.1.is_defined());
- r.1.clone()
- })
- .unwrap_or(RegisterRule::Undefined)
- }
-
- fn set(&mut self, register: Register, rule: RegisterRule<R>) -> Result<()> {
- if !rule.is_defined() {
- let idx = self
- .rules
- .iter()
- .enumerate()
- .find(|&(_, r)| r.0 == register)
- .map(|(i, _)| i);
- if let Some(idx) = idx {
- self.rules.swap_remove(idx);
- }
- return Ok(());
- }
-
- for &mut (reg, ref mut old_rule) in &mut *self.rules {
- debug_assert!(old_rule.is_defined());
- if reg == register {
- *old_rule = rule;
- return Ok(());
- }
- }
-
- self.rules
- .try_push((register, rule))
- .map_err(|_| Error::TooManyRegisterRules)
- }
-
- fn iter(&self) -> RegisterRuleIter<R> {
- RegisterRuleIter(self.rules.iter())
- }
-}
-
-impl<'a, R, S: UnwindContextStorage<R>> FromIterator<&'a (Register, RegisterRule<R>)>
- for RegisterRuleMap<R, S>
-where
- R: 'a + Reader,
-{
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = &'a (Register, RegisterRule<R>)>,
- {
- let iter = iter.into_iter();
- let mut rules = RegisterRuleMap::default();
- for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) {
- rules.set(reg, rule.clone()).expect(
- "This is only used in tests, impl isn't exposed publicly.
- If you trip this, fix your test",
- );
- }
- rules
- }
-}
-
-impl<R, S: UnwindContextStorage<R>> PartialEq for RegisterRuleMap<R, S>
-where
- R: Reader + PartialEq,
-{
- fn eq(&self, rhs: &Self) -> bool {
- for &(reg, ref rule) in &*self.rules {
- debug_assert!(rule.is_defined());
- if *rule != rhs.get(reg) {
- return false;
- }
- }
-
- for &(reg, ref rhs_rule) in &*rhs.rules {
- debug_assert!(rhs_rule.is_defined());
- if *rhs_rule != self.get(reg) {
- return false;
- }
- }
-
- true
- }
-}
-
-impl<R, S: UnwindContextStorage<R>> Eq for RegisterRuleMap<R, S> where R: Reader + Eq {}
-
-/// An unordered iterator for register rules.
-#[derive(Debug, Clone)]
-pub struct RegisterRuleIter<'iter, R>(::core::slice::Iter<'iter, (Register, RegisterRule<R>)>)
-where
- R: Reader;
-
-impl<'iter, R: Reader> Iterator for RegisterRuleIter<'iter, R> {
- type Item = &'iter (Register, RegisterRule<R>);
-
- fn next(&mut self) -> Option<Self::Item> {
- self.0.next()
- }
-}
-
-/// A row in the virtual unwind table that describes how to find the values of
-/// the registers in the *previous* frame for a range of PC addresses.
-#[derive(PartialEq, Eq)]
-pub struct UnwindTableRow<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> {
- start_address: u64,
- end_address: u64,
- saved_args_size: u64,
- cfa: CfaRule<R>,
- registers: RegisterRuleMap<R, S>,
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Debug for UnwindTableRow<R, S> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("UnwindTableRow")
- .field("start_address", &self.start_address)
- .field("end_address", &self.end_address)
- .field("saved_args_size", &self.saved_args_size)
- .field("cfa", &self.cfa)
- .field("registers", &self.registers)
- .finish()
- }
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Clone for UnwindTableRow<R, S> {
- fn clone(&self) -> Self {
- Self {
- start_address: self.start_address,
- end_address: self.end_address,
- saved_args_size: self.saved_args_size,
- cfa: self.cfa.clone(),
- registers: self.registers.clone(),
- }
- }
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> Default for UnwindTableRow<R, S> {
- fn default() -> Self {
- UnwindTableRow {
- start_address: 0,
- end_address: 0,
- saved_args_size: 0,
- cfa: Default::default(),
- registers: Default::default(),
- }
- }
-}
-
-impl<R: Reader, S: UnwindContextStorage<R>> UnwindTableRow<R, S> {
- fn is_default(&self) -> bool {
- self.start_address == 0
- && self.end_address == 0
- && self.cfa.is_default()
- && self.registers.is_default()
- }
-
- /// Get the starting PC address that this row applies to.
- pub fn start_address(&self) -> u64 {
- self.start_address
- }
-
- /// Get the end PC address where this row's register rules become
- /// unapplicable.
- ///
- /// In other words, this row describes how to recover the last frame's
- /// registers for all PCs where `row.start_address() <= PC <
- /// row.end_address()`. This row does NOT describe how to recover registers
- /// when `PC == row.end_address()`.
- pub fn end_address(&self) -> u64 {
- self.end_address
- }
-
- /// Return `true` if the given `address` is within this row's address range,
- /// `false` otherwise.
- pub fn contains(&self, address: u64) -> bool {
- self.start_address <= address && address < self.end_address
- }
-
- /// Returns the amount of args currently on the stack.
- ///
- /// When unwinding, if the personality function requested a change in IP,
- /// the SP needs to be adjusted by saved_args_size.
- pub fn saved_args_size(&self) -> u64 {
- self.saved_args_size
- }
-
- /// Get the canonical frame address (CFA) recovery rule for this row.
- pub fn cfa(&self) -> &CfaRule<R> {
- &self.cfa
- }
-
- /// Get the register recovery rule for the given register number.
- ///
- /// The register number mapping is architecture dependent. For example, in
- /// the x86-64 ABI the register number mapping is defined in Figure 3.36:
- ///
- /// > Figure 3.36: DWARF Register Number Mapping
- /// >
- /// > <table>
- /// > <tr><th>Register Name</th> <th>Number</th> <th>Abbreviation</th></tr>
- /// > <tr><td>General Purpose Register RAX</td> <td>0</td> <td>%rax</td></tr>
- /// > <tr><td>General Purpose Register RDX</td> <td>1</td> <td>%rdx</td></tr>
- /// > <tr><td>General Purpose Register RCX</td> <td>2</td> <td>%rcx</td></tr>
- /// > <tr><td>General Purpose Register RBX</td> <td>3</td> <td>%rbx</td></tr>
- /// > <tr><td>General Purpose Register RSI</td> <td>4</td> <td>%rsi</td></tr>
- /// > <tr><td>General Purpose Register RDI</td> <td>5</td> <td>%rdi</td></tr>
- /// > <tr><td>General Purpose Register RBP</td> <td>6</td> <td>%rbp</td></tr>
- /// > <tr><td>Stack Pointer Register RSP</td> <td>7</td> <td>%rsp</td></tr>
- /// > <tr><td>Extended Integer Registers 8-15</td> <td>8-15</td> <td>%r8-%r15</td></tr>
- /// > <tr><td>Return Address RA</td> <td>16</td> <td></td></tr>
- /// > <tr><td>Vector Registers 0–7</td> <td>17-24</td> <td>%xmm0–%xmm7</td></tr>
- /// > <tr><td>Extended Vector Registers 8–15</td> <td>25-32</td> <td>%xmm8–%xmm15</td></tr>
- /// > <tr><td>Floating Point Registers 0–7</td> <td>33-40</td> <td>%st0–%st7</td></tr>
- /// > <tr><td>MMX Registers 0–7</td> <td>41-48</td> <td>%mm0–%mm7</td></tr>
- /// > <tr><td>Flag Register</td> <td>49</td> <td>%rFLAGS</td></tr>
- /// > <tr><td>Segment Register ES</td> <td>50</td> <td>%es</td></tr>
- /// > <tr><td>Segment Register CS</td> <td>51</td> <td>%cs</td></tr>
- /// > <tr><td>Segment Register SS</td> <td>52</td> <td>%ss</td></tr>
- /// > <tr><td>Segment Register DS</td> <td>53</td> <td>%ds</td></tr>
- /// > <tr><td>Segment Register FS</td> <td>54</td> <td>%fs</td></tr>
- /// > <tr><td>Segment Register GS</td> <td>55</td> <td>%gs</td></tr>
- /// > <tr><td>Reserved</td> <td>56-57</td> <td></td></tr>
- /// > <tr><td>FS Base address</td> <td>58</td> <td>%fs.base</td></tr>
- /// > <tr><td>GS Base address</td> <td>59</td> <td>%gs.base</td></tr>
- /// > <tr><td>Reserved</td> <td>60-61</td> <td></td></tr>
- /// > <tr><td>Task Register</td> <td>62</td> <td>%tr</td></tr>
- /// > <tr><td>LDT Register</td> <td>63</td> <td>%ldtr</td></tr>
- /// > <tr><td>128-bit Media Control and Status</td> <td>64</td> <td>%mxcsr</td></tr>
- /// > <tr><td>x87 Control Word</td> <td>65</td> <td>%fcw</td></tr>
- /// > <tr><td>x87 Status Word</td> <td>66</td> <td>%fsw</td></tr>
- /// > <tr><td>Upper Vector Registers 16–31</td> <td>67-82</td> <td>%xmm16–%xmm31</td></tr>
- /// > <tr><td>Reserved</td> <td>83-117</td> <td></td></tr>
- /// > <tr><td>Vector Mask Registers 0–7</td> <td>118-125</td> <td>%k0–%k7</td></tr>
- /// > <tr><td>Reserved</td> <td>126-129</td> <td></td></tr>
- /// > </table>
- pub fn register(&self, register: Register) -> RegisterRule<R> {
- self.registers.get(register)
- }
-
- /// Iterate over all defined register `(number, rule)` pairs.
- ///
- /// The rules are not iterated in any guaranteed order. Any register that
- /// does not make an appearance in the iterator implicitly has the rule
- /// `RegisterRule::Undefined`.
- ///
- /// ```
- /// # use gimli::{EndianSlice, LittleEndian, UnwindTableRow};
- /// # fn foo<'input>(unwind_table_row: UnwindTableRow<EndianSlice<'input, LittleEndian>>) {
- /// for &(register, ref rule) in unwind_table_row.registers() {
- /// // ...
- /// # drop(register); drop(rule);
- /// }
- /// # }
- /// ```
- pub fn registers(&self) -> RegisterRuleIter<R> {
- self.registers.iter()
- }
-}
-
-/// The canonical frame address (CFA) recovery rules.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum CfaRule<R: Reader> {
- /// The CFA is given offset from the given register's value.
- RegisterAndOffset {
- /// The register containing the base value.
- register: Register,
- /// The offset from the register's base value.
- offset: i64,
- },
- /// The CFA is obtained by evaluating this `Reader` as a DWARF expression
- /// program.
- Expression(Expression<R>),
-}
-
-impl<R: Reader> Default for CfaRule<R> {
- fn default() -> Self {
- CfaRule::RegisterAndOffset {
- register: Register(0),
- offset: 0,
- }
- }
-}
-
-impl<R: Reader> CfaRule<R> {
- fn is_default(&self) -> bool {
- match *self {
- CfaRule::RegisterAndOffset { register, offset } => {
- register == Register(0) && offset == 0
- }
- _ => false,
- }
- }
-}
-
-/// An entry in the abstract CFI table that describes how to find the value of a
-/// register.
-///
-/// "The register columns contain rules that describe whether a given register
-/// has been saved and the rule to find the value for the register in the
-/// previous frame."
-#[derive(Clone, Debug, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum RegisterRule<R: Reader> {
- /// > A register that has this rule has no recoverable value in the previous
- /// > frame. (By convention, it is not preserved by a callee.)
- Undefined,
-
- /// > This register has not been modified from the previous frame. (By
- /// > convention, it is preserved by the callee, but the callee has not
- /// > modified it.)
- SameValue,
-
- /// "The previous value of this register is saved at the address CFA+N where
- /// CFA is the current CFA value and N is a signed offset."
- Offset(i64),
-
- /// "The previous value of this register is the value CFA+N where CFA is the
- /// current CFA value and N is a signed offset."
- ValOffset(i64),
-
- /// "The previous value of this register is stored in another register
- /// numbered R."
- Register(Register),
-
- /// "The previous value of this register is located at the address produced
- /// by executing the DWARF expression."
- Expression(Expression<R>),
-
- /// "The previous value of this register is the value produced by executing
- /// the DWARF expression."
- ValExpression(Expression<R>),
-
- /// "The rule is defined externally to this specification by the augmenter."
- Architectural,
-
- /// This is a pseudo-register with a constant value.
- Constant(u64),
-}
-
-impl<R: Reader> RegisterRule<R> {
- fn is_defined(&self) -> bool {
- !matches!(*self, RegisterRule::Undefined)
- }
-}
-
-/// A parsed call frame instruction.
-#[derive(Clone, Debug, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum CallFrameInstruction<R: Reader> {
- // 6.4.2.1 Row Creation Methods
- /// > 1. DW_CFA_set_loc
- /// >
- /// > The DW_CFA_set_loc instruction takes a single operand that represents
- /// > a target address. The required action is to create a new table row
- /// > using the specified address as the location. All other values in the
- /// > new row are initially identical to the current row. The new location
- /// > value is always greater than the current one. If the segment_size
- /// > field of this FDE's CIE is non- zero, the initial location is preceded
- /// > by a segment selector of the given length.
- SetLoc {
- /// The target address.
- address: u64,
- },
-
- /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and
- /// `DW_CFA_advance_loc{1,2,4}`.
- ///
- /// > 2. DW_CFA_advance_loc
- /// >
- /// > The DW_CFA_advance instruction takes a single operand (encoded with
- /// > the opcode) that represents a constant delta. The required action is
- /// > to create a new table row with a location value that is computed by
- /// > taking the current entry’s location value and adding the value of
- /// > delta * code_alignment_factor. All other values in the new row are
- /// > initially identical to the current row.
- AdvanceLoc {
- /// The delta to be added to the current address.
- delta: u32,
- },
-
- // 6.4.2.2 CFA Definition Methods
- /// > 1. DW_CFA_def_cfa
- /// >
- /// > The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands
- /// > representing a register number and a (non-factored) offset. The
- /// > required action is to define the current CFA rule to use the provided
- /// > register and offset.
- DefCfa {
- /// The target register's number.
- register: Register,
- /// The non-factored offset.
- offset: u64,
- },
-
- /// > 2. DW_CFA_def_cfa_sf
- /// >
- /// > The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned
- /// > LEB128 value representing a register number and a signed LEB128
- /// > factored offset. This instruction is identical to DW_CFA_def_cfa
- /// > except that the second operand is signed and factored. The resulting
- /// > offset is factored_offset * data_alignment_factor.
- DefCfaSf {
- /// The target register's number.
- register: Register,
- /// The factored offset.
- factored_offset: i64,
- },
-
- /// > 3. DW_CFA_def_cfa_register
- /// >
- /// > The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128
- /// > operand representing a register number. The required action is to
- /// > define the current CFA rule to use the provided register (but to keep
- /// > the old offset). This operation is valid only if the current CFA rule
- /// > is defined to use a register and offset.
- DefCfaRegister {
- /// The target register's number.
- register: Register,
- },
-
- /// > 4. DW_CFA_def_cfa_offset
- /// >
- /// > The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128
- /// > operand representing a (non-factored) offset. The required action is
- /// > to define the current CFA rule to use the provided offset (but to keep
- /// > the old register). This operation is valid only if the current CFA
- /// > rule is defined to use a register and offset.
- DefCfaOffset {
- /// The non-factored offset.
- offset: u64,
- },
-
- /// > 5. DW_CFA_def_cfa_offset_sf
- /// >
- /// > The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand
- /// > representing a factored offset. This instruction is identical to
- /// > DW_CFA_def_cfa_offset except that the operand is signed and
- /// > factored. The resulting offset is factored_offset *
- /// > data_alignment_factor. This operation is valid only if the current CFA
- /// > rule is defined to use a register and offset.
- DefCfaOffsetSf {
- /// The factored offset.
- factored_offset: i64,
- },
-
- /// > 6. DW_CFA_def_cfa_expression
- /// >
- /// > The DW_CFA_def_cfa_expression instruction takes a single operand
- /// > encoded as a DW_FORM_exprloc value representing a DWARF
- /// > expression. The required action is to establish that expression as the
- /// > means by which the current CFA is computed.
- DefCfaExpression {
- /// The DWARF expression.
- expression: Expression<R>,
- },
-
- // 6.4.2.3 Register Rule Instructions
- /// > 1. DW_CFA_undefined
- /// >
- /// > The DW_CFA_undefined instruction takes a single unsigned LEB128
- /// > operand that represents a register number. The required action is to
- /// > set the rule for the specified register to “undefined.”
- Undefined {
- /// The target register's number.
- register: Register,
- },
-
- /// > 2. DW_CFA_same_value
- /// >
- /// > The DW_CFA_same_value instruction takes a single unsigned LEB128
- /// > operand that represents a register number. The required action is to
- /// > set the rule for the specified register to “same value.”
- SameValue {
- /// The target register's number.
- register: Register,
- },
-
- /// The `Offset` instruction represents both `DW_CFA_offset` and
- /// `DW_CFA_offset_extended`.
- ///
- /// > 3. DW_CFA_offset
- /// >
- /// > The DW_CFA_offset instruction takes two operands: a register number
- /// > (encoded with the opcode) and an unsigned LEB128 constant representing
- /// > a factored offset. The required action is to change the rule for the
- /// > register indicated by the register number to be an offset(N) rule
- /// > where the value of N is factored offset * data_alignment_factor.
- Offset {
- /// The target register's number.
- register: Register,
- /// The factored offset.
- factored_offset: u64,
- },
-
- /// > 5. DW_CFA_offset_extended_sf
- /// >
- /// > The DW_CFA_offset_extended_sf instruction takes two operands: an
- /// > unsigned LEB128 value representing a register number and a signed
- /// > LEB128 factored offset. This instruction is identical to
- /// > DW_CFA_offset_extended except that the second operand is signed and
- /// > factored. The resulting offset is factored_offset *
- /// > data_alignment_factor.
- OffsetExtendedSf {
- /// The target register's number.
- register: Register,
- /// The factored offset.
- factored_offset: i64,
- },
-
- /// > 6. DW_CFA_val_offset
- /// >
- /// > The DW_CFA_val_offset instruction takes two unsigned LEB128 operands
- /// > representing a register number and a factored offset. The required
- /// > action is to change the rule for the register indicated by the
- /// > register number to be a val_offset(N) rule where the value of N is
- /// > factored_offset * data_alignment_factor.
- ValOffset {
- /// The target register's number.
- register: Register,
- /// The factored offset.
- factored_offset: u64,
- },
-
- /// > 7. DW_CFA_val_offset_sf
- /// >
- /// > The DW_CFA_val_offset_sf instruction takes two operands: an unsigned
- /// > LEB128 value representing a register number and a signed LEB128
- /// > factored offset. This instruction is identical to DW_CFA_val_offset
- /// > except that the second operand is signed and factored. The resulting
- /// > offset is factored_offset * data_alignment_factor.
- ValOffsetSf {
- /// The target register's number.
- register: Register,
- /// The factored offset.
- factored_offset: i64,
- },
-
- /// > 8. DW_CFA_register
- /// >
- /// > The DW_CFA_register instruction takes two unsigned LEB128 operands
- /// > representing register numbers. The required action is to set the rule
- /// > for the first register to be register(R) where R is the second
- /// > register.
- Register {
- /// The number of the register whose rule is being changed.
- dest_register: Register,
- /// The number of the register where the other register's value can be
- /// found.
- src_register: Register,
- },
-
- /// > 9. DW_CFA_expression
- /// >
- /// > The DW_CFA_expression instruction takes two operands: an unsigned
- /// > LEB128 value representing a register number, and a DW_FORM_block value
- /// > representing a DWARF expression. The required action is to change the
- /// > rule for the register indicated by the register number to be an
- /// > expression(E) rule where E is the DWARF expression. That is, the DWARF
- /// > expression computes the address. The value of the CFA is pushed on the
- /// > DWARF evaluation stack prior to execution of the DWARF expression.
- Expression {
- /// The target register's number.
- register: Register,
- /// The DWARF expression.
- expression: Expression<R>,
- },
-
- /// > 10. DW_CFA_val_expression
- /// >
- /// > The DW_CFA_val_expression instruction takes two operands: an unsigned
- /// > LEB128 value representing a register number, and a DW_FORM_block value
- /// > representing a DWARF expression. The required action is to change the
- /// > rule for the register indicated by the register number to be a
- /// > val_expression(E) rule where E is the DWARF expression. That is, the
- /// > DWARF expression computes the value of the given register. The value
- /// > of the CFA is pushed on the DWARF evaluation stack prior to execution
- /// > of the DWARF expression.
- ValExpression {
- /// The target register's number.
- register: Register,
- /// The DWARF expression.
- expression: Expression<R>,
- },
-
- /// The `Restore` instruction represents both `DW_CFA_restore` and
- /// `DW_CFA_restore_extended`.
- ///
- /// > 11. DW_CFA_restore
- /// >
- /// > The DW_CFA_restore instruction takes a single operand (encoded with
- /// > the opcode) that represents a register number. The required action is
- /// > to change the rule for the indicated register to the rule assigned it
- /// > by the initial_instructions in the CIE.
- Restore {
- /// The register to be reset.
- register: Register,
- },
-
- // 6.4.2.4 Row State Instructions
- /// > 1. DW_CFA_remember_state
- /// >
- /// > The DW_CFA_remember_state instruction takes no operands. The required
- /// > action is to push the set of rules for every register onto an implicit
- /// > stack.
- RememberState,
-
- /// > 2. DW_CFA_restore_state
- /// >
- /// > The DW_CFA_restore_state instruction takes no operands. The required
- /// > action is to pop the set of rules off the implicit stack and place
- /// > them in the current row.
- RestoreState,
-
- /// > DW_CFA_GNU_args_size
- /// >
- /// > GNU Extension
- /// >
- /// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand
- /// > representing an argument size. This instruction specifies the total of
- /// > the size of the arguments which have been pushed onto the stack.
- ArgsSize {
- /// The size of the arguments which have been pushed onto the stack
- size: u64,
- },
-
- /// > DW_CFA_AARCH64_negate_ra_state
- /// >
- /// > AArch64 Extension
- /// >
- /// > The DW_CFA_AARCH64_negate_ra_state operation negates bit 0 of the
- /// > RA_SIGN_STATE pseudo-register. It does not take any operands. The
- /// > DW_CFA_AARCH64_negate_ra_state must not be mixed with other DWARF Register
- /// > Rule Instructions on the RA_SIGN_STATE pseudo-register in one Common
- /// > Information Entry (CIE) and Frame Descriptor Entry (FDE) program sequence.
- NegateRaState,
-
- // 6.4.2.5 Padding Instruction
- /// > 1. DW_CFA_nop
- /// >
- /// > The DW_CFA_nop instruction has no operands and no required actions. It
- /// > is used as padding to make a CIE or FDE an appropriate size.
- Nop,
-}
-
-const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000;
-const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK;
-
-impl<R: Reader> CallFrameInstruction<R> {
- fn parse(
- input: &mut R,
- address_encoding: Option<DwEhPe>,
- parameters: &PointerEncodingParameters<R>,
- vendor: Vendor,
- ) -> Result<CallFrameInstruction<R>> {
- let instruction = input.read_u8()?;
- let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK;
-
- if high_bits == constants::DW_CFA_advance_loc.0 {
- let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK;
- return Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(delta),
- });
- }
-
- if high_bits == constants::DW_CFA_offset.0 {
- let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
- let offset = input.read_uleb128()?;
- return Ok(CallFrameInstruction::Offset {
- register,
- factored_offset: offset,
- });
- }
-
- if high_bits == constants::DW_CFA_restore.0 {
- let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
- return Ok(CallFrameInstruction::Restore { register });
- }
-
- debug_assert_eq!(high_bits, 0);
- let instruction = constants::DwCfa(instruction);
-
- match instruction {
- constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop),
-
- constants::DW_CFA_set_loc => {
- let address = if let Some(encoding) = address_encoding {
- parse_encoded_pointer(encoding, parameters, input)?.direct()?
- } else {
- input.read_address(parameters.address_size)?
- };
- Ok(CallFrameInstruction::SetLoc { address })
- }
-
- constants::DW_CFA_advance_loc1 => {
- let delta = input.read_u8()?;
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(delta),
- })
- }
-
- constants::DW_CFA_advance_loc2 => {
- let delta = input.read_u16()?;
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(delta),
- })
- }
-
- constants::DW_CFA_advance_loc4 => {
- let delta = input.read_u32()?;
- Ok(CallFrameInstruction::AdvanceLoc { delta })
- }
-
- constants::DW_CFA_offset_extended => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_uleb128()?;
- Ok(CallFrameInstruction::Offset {
- register,
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_restore_extended => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- Ok(CallFrameInstruction::Restore { register })
- }
-
- constants::DW_CFA_undefined => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- Ok(CallFrameInstruction::Undefined { register })
- }
-
- constants::DW_CFA_same_value => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- Ok(CallFrameInstruction::SameValue { register })
- }
-
- constants::DW_CFA_register => {
- let dest = input.read_uleb128().and_then(Register::from_u64)?;
- let src = input.read_uleb128().and_then(Register::from_u64)?;
- Ok(CallFrameInstruction::Register {
- dest_register: dest,
- src_register: src,
- })
- }
-
- constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState),
-
- constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState),
-
- constants::DW_CFA_def_cfa => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_uleb128()?;
- Ok(CallFrameInstruction::DefCfa { register, offset })
- }
-
- constants::DW_CFA_def_cfa_register => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- Ok(CallFrameInstruction::DefCfaRegister { register })
- }
-
- constants::DW_CFA_def_cfa_offset => {
- let offset = input.read_uleb128()?;
- Ok(CallFrameInstruction::DefCfaOffset { offset })
- }
-
- constants::DW_CFA_def_cfa_expression => {
- let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let expression = input.split(len)?;
- Ok(CallFrameInstruction::DefCfaExpression {
- expression: Expression(expression),
- })
- }
-
- constants::DW_CFA_expression => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let expression = input.split(len)?;
- Ok(CallFrameInstruction::Expression {
- register,
- expression: Expression(expression),
- })
- }
-
- constants::DW_CFA_offset_extended_sf => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_sleb128()?;
- Ok(CallFrameInstruction::OffsetExtendedSf {
- register,
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_def_cfa_sf => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_sleb128()?;
- Ok(CallFrameInstruction::DefCfaSf {
- register,
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_def_cfa_offset_sf => {
- let offset = input.read_sleb128()?;
- Ok(CallFrameInstruction::DefCfaOffsetSf {
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_val_offset => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_uleb128()?;
- Ok(CallFrameInstruction::ValOffset {
- register,
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_val_offset_sf => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let offset = input.read_sleb128()?;
- Ok(CallFrameInstruction::ValOffsetSf {
- register,
- factored_offset: offset,
- })
- }
-
- constants::DW_CFA_val_expression => {
- let register = input.read_uleb128().and_then(Register::from_u64)?;
- let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let expression = input.split(len)?;
- Ok(CallFrameInstruction::ValExpression {
- register,
- expression: Expression(expression),
- })
- }
-
- constants::DW_CFA_GNU_args_size => {
- let size = input.read_uleb128()?;
- Ok(CallFrameInstruction::ArgsSize { size })
- }
-
- constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => {
- Ok(CallFrameInstruction::NegateRaState)
- }
-
- otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
- }
- }
-}
-
-/// A lazy iterator parsing call frame instructions.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-#[derive(Clone, Debug)]
-pub struct CallFrameInstructionIter<'a, R: Reader> {
- input: R,
- address_encoding: Option<constants::DwEhPe>,
- parameters: PointerEncodingParameters<'a, R>,
- vendor: Vendor,
-}
-
-impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
- /// Parse the next call frame instruction.
- pub fn next(&mut self) -> Result<Option<CallFrameInstruction<R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match CallFrameInstruction::parse(
- &mut self.input,
- self.address_encoding,
- &self.parameters,
- self.vendor,
- ) {
- Ok(instruction) => Ok(Some(instruction)),
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> {
- type Item = CallFrameInstruction<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- CallFrameInstructionIter::next(self)
- }
-}
-
-/// Parse a `DW_EH_PE_*` pointer encoding.
-#[doc(hidden)]
-#[inline]
-fn parse_pointer_encoding<R: Reader>(input: &mut R) -> Result<constants::DwEhPe> {
- let eh_pe = input.read_u8()?;
- let eh_pe = constants::DwEhPe(eh_pe);
-
- if eh_pe.is_valid_encoding() {
- Ok(eh_pe)
- } else {
- Err(Error::UnknownPointerEncoding)
- }
-}
-
-/// A decoded pointer.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Pointer {
- /// This value is the decoded pointer value.
- Direct(u64),
-
- /// This value is *not* the pointer value, but points to the address of
- /// where the real pointer value lives. In other words, deref this pointer
- /// to get the real pointer value.
- ///
- /// Chase this pointer at your own risk: do you trust the DWARF data it came
- /// from?
- Indirect(u64),
-}
-
-impl Default for Pointer {
- #[inline]
- fn default() -> Self {
- Pointer::Direct(0)
- }
-}
-
-impl Pointer {
- #[inline]
- fn new(encoding: constants::DwEhPe, address: u64) -> Pointer {
- if encoding.is_indirect() {
- Pointer::Indirect(address)
- } else {
- Pointer::Direct(address)
- }
- }
-
- /// Return the direct pointer value.
- #[inline]
- pub fn direct(self) -> Result<u64> {
- match self {
- Pointer::Direct(p) => Ok(p),
- Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding),
- }
- }
-
- /// Return the pointer value, discarding indirectness information.
- #[inline]
- pub fn pointer(self) -> u64 {
- match self {
- Pointer::Direct(p) | Pointer::Indirect(p) => p,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-struct PointerEncodingParameters<'a, R: Reader> {
- bases: &'a SectionBaseAddresses,
- func_base: Option<u64>,
- address_size: u8,
- section: &'a R,
-}
-
-fn parse_encoded_pointer<R: Reader>(
- encoding: constants::DwEhPe,
- parameters: &PointerEncodingParameters<R>,
- input: &mut R,
-) -> Result<Pointer> {
- // TODO: check this once only in parse_pointer_encoding
- if !encoding.is_valid_encoding() {
- return Err(Error::UnknownPointerEncoding);
- }
-
- if encoding == constants::DW_EH_PE_omit {
- return Err(Error::CannotParseOmitPointerEncoding);
- }
-
- let base = match encoding.application() {
- constants::DW_EH_PE_absptr => 0,
- constants::DW_EH_PE_pcrel => {
- if let Some(section_base) = parameters.bases.section {
- let offset_from_section = input.offset_from(parameters.section);
- section_base.wrapping_add(offset_from_section.into_u64())
- } else {
- return Err(Error::PcRelativePointerButSectionBaseIsUndefined);
- }
- }
- constants::DW_EH_PE_textrel => {
- if let Some(text) = parameters.bases.text {
- text
- } else {
- return Err(Error::TextRelativePointerButTextBaseIsUndefined);
- }
- }
- constants::DW_EH_PE_datarel => {
- if let Some(data) = parameters.bases.data {
- data
- } else {
- return Err(Error::DataRelativePointerButDataBaseIsUndefined);
- }
- }
- constants::DW_EH_PE_funcrel => {
- if let Some(func) = parameters.func_base {
- func
- } else {
- return Err(Error::FuncRelativePointerInBadContext);
- }
- }
- constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding),
- _ => unreachable!(),
- };
-
- let offset = match encoding.format() {
- // Unsigned variants.
- constants::DW_EH_PE_absptr => input.read_address(parameters.address_size),
- constants::DW_EH_PE_uleb128 => input.read_uleb128(),
- constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from),
- constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from),
- constants::DW_EH_PE_udata8 => input.read_u64(),
-
- // Signed variants. Here we sign extend the values (happens by
- // default when casting a signed integer to a larger range integer
- // in Rust), return them as u64, and rely on wrapping addition to do
- // the right thing when adding these offsets to their bases.
- constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64),
- constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64),
- constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64),
- constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64),
-
- // That was all of the valid encoding formats.
- _ => unreachable!(),
- }?;
-
- Ok(Pointer::new(encoding, base.wrapping_add(offset)))
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext};
- use crate::common::Format;
- use crate::constants;
- use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian};
- use crate::read::{
- EndianSlice, Error, Expression, Pointer, ReaderOffsetId, Result, Section as ReadSection,
- };
- use crate::test_util::GimliSectionMethods;
- use alloc::boxed::Box;
- use alloc::vec::Vec;
- use core::marker::PhantomData;
- use core::mem;
- use core::u64;
- use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum};
-
- // Ensure each test tries to read the same section kind that it wrote.
- #[derive(Clone, Copy)]
- struct SectionKind<Section>(PhantomData<Section>);
-
- impl<T> SectionKind<T> {
- fn endian<'input, E>(self) -> Endian
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset<usize>,
- {
- if E::default().is_big_endian() {
- Endian::Big
- } else {
- Endian::Little
- }
- }
-
- fn section<'input, E>(self, contents: &'input [u8]) -> T
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>> + ReadSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset<usize>,
- {
- EndianSlice::new(contents, E::default()).into()
- }
- }
-
- fn debug_frame_le<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, LittleEndian>>> {
- SectionKind(PhantomData)
- }
-
- fn debug_frame_be<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, BigEndian>>> {
- SectionKind(PhantomData)
- }
-
- fn eh_frame_le<'a>() -> SectionKind<EhFrame<EndianSlice<'a, LittleEndian>>> {
- SectionKind(PhantomData)
- }
-
- fn parse_fde<Section, O, F, R>(
- section: Section,
- input: &mut R,
- get_cie: F,
- ) -> Result<FrameDescriptionEntry<R>>
- where
- R: Reader,
- Section: UnwindSection<R, Offset = O>,
- O: UnwindOffset<R::Offset>,
- F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>,
- {
- let bases = Default::default();
- match parse_cfi_entry(&bases, &section, input) {
- Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie),
- Ok(_) => Err(Error::NoEntryAtGivenOffset),
- Err(e) => Err(e),
- }
- }
-
- // Mixin methods for `Section` to help define binary test data.
-
- trait CfiSectionMethods: GimliSectionMethods {
- fn cie<'aug, 'input, E, T>(
- self,
- _kind: SectionKind<T>,
- augmentation: Option<&'aug str>,
- cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
- ) -> Self
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset;
- fn fde<'a, 'input, E, T, L>(
- self,
- _kind: SectionKind<T>,
- cie_offset: L,
- fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
- ) -> Self
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset,
- L: ToLabelOrNum<'a, u64>;
- }
-
- impl CfiSectionMethods for Section {
- fn cie<'aug, 'input, E, T>(
- self,
- _kind: SectionKind<T>,
- augmentation: Option<&'aug str>,
- cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
- ) -> Self
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset,
- {
- cie.offset = self.size() as _;
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = match cie.format {
- Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff),
- Format::Dwarf64 => {
- let section = self.D32(0xffff_ffff);
- section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff)
- }
- };
-
- let mut section = section.D8(cie.version);
-
- if let Some(augmentation) = augmentation {
- section = section.append_bytes(augmentation.as_bytes());
- }
-
- // Null terminator for augmentation string.
- let section = section.D8(0);
-
- let section = if T::has_address_and_segment_sizes(cie.version) {
- section.D8(cie.address_size).D8(cie.segment_size)
- } else {
- section
- };
-
- let section = section
- .uleb(cie.code_alignment_factor)
- .sleb(cie.data_alignment_factor)
- .uleb(cie.return_address_register.0.into())
- .append_bytes(cie.initial_instructions.slice())
- .mark(&end);
-
- cie.length = (&end - &start) as usize;
- length.set_const(cie.length as u64);
-
- section
- }
-
- fn fde<'a, 'input, E, T, L>(
- self,
- _kind: SectionKind<T>,
- cie_offset: L,
- fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
- ) -> Self
- where
- E: Endianity,
- T: UnwindSection<EndianSlice<'input, E>>,
- T::Offset: UnwindOffset,
- L: ToLabelOrNum<'a, u64>,
- {
- fde.offset = self.size() as _;
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- assert_eq!(fde.format, fde.cie.format);
-
- let section = match T::cie_offset_encoding(fde.format) {
- CieOffsetEncoding::U32 => {
- let section = self.D32(&length).mark(&start);
- match cie_offset.to_labelornum() {
- LabelOrNum::Label(ref l) => section.D32(l),
- LabelOrNum::Num(o) => section.D32(o as u32),
- }
- }
- CieOffsetEncoding::U64 => {
- let section = self.D32(0xffff_ffff);
- section.D64(&length).mark(&start).D64(cie_offset)
- }
- };
-
- let section = match fde.cie.segment_size {
- 0 => section,
- 4 => section.D32(fde.initial_segment as u32),
- 8 => section.D64(fde.initial_segment),
- x => panic!("Unsupported test segment size: {}", x),
- };
-
- let section = match fde.cie.address_size {
- 4 => section
- .D32(fde.initial_address() as u32)
- .D32(fde.len() as u32),
- 8 => section.D64(fde.initial_address()).D64(fde.len()),
- x => panic!("Unsupported address size: {}", x),
- };
-
- let section = if let Some(ref augmentation) = fde.augmentation {
- let cie_aug = fde
- .cie
- .augmentation
- .expect("FDE has augmentation, but CIE doesn't");
-
- if let Some(lsda) = augmentation.lsda {
- // We only support writing `DW_EH_PE_absptr` here.
- assert_eq!(
- cie_aug
- .lsda
- .expect("FDE has lsda, but CIE doesn't")
- .format(),
- constants::DW_EH_PE_absptr
- );
-
- // Augmentation data length
- let section = section.uleb(u64::from(fde.cie.address_size));
- match fde.cie.address_size {
- 4 => section.D32({
- let x: u64 = lsda.pointer();
- x as u32
- }),
- 8 => section.D64({
- let x: u64 = lsda.pointer();
- x
- }),
- x => panic!("Unsupported address size: {}", x),
- }
- } else {
- // Even if we don't have any augmentation data, if there is
- // an augmentation defined, we need to put the length in.
- section.uleb(0)
- }
- } else {
- section
- };
-
- let section = section.append_bytes(fde.instructions.slice()).mark(&end);
-
- fde.length = (&end - &start) as usize;
- length.set_const(fde.length as u64);
-
- section
- }
- }
-
- trait ResultExt {
- fn map_eof(self, input: &[u8]) -> Self;
- }
-
- impl<T> ResultExt for Result<T> {
- fn map_eof(self, input: &[u8]) -> Self {
- match self {
- Err(Error::UnexpectedEof(id)) => {
- let id = ReaderOffsetId(id.0 - input.as_ptr() as u64);
- Err(Error::UnexpectedEof(id))
- }
- r => r,
- }
- }
- }
-
- fn assert_parse_cie<'input, E>(
- kind: SectionKind<DebugFrame<EndianSlice<'input, E>>>,
- section: Section,
- address_size: u8,
- expected: Result<(
- EndianSlice<'input, E>,
- CommonInformationEntry<EndianSlice<'input, E>>,
- )>,
- ) where
- E: Endianity,
- {
- let section = section.get_contents().unwrap();
- let mut debug_frame = kind.section(&section);
- debug_frame.set_address_size(address_size);
- let input = &mut EndianSlice::new(&section, E::default());
- let bases = Default::default();
- let result = CommonInformationEntry::parse(&bases, &debug_frame, input);
- let result = result.map(|cie| (*input, cie)).map_eof(&section);
- assert_eq!(result, expected);
- }
-
- #[test]
- fn test_parse_cie_incomplete_length_32() {
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian()).L16(5);
- assert_parse_cie(
- kind,
- section,
- 8,
- Err(Error::UnexpectedEof(ReaderOffsetId(0))),
- );
- }
-
- #[test]
- fn test_parse_cie_incomplete_length_64() {
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .L32(0xffff_ffff)
- .L32(12345);
- assert_parse_cie(
- kind,
- section,
- 8,
- Err(Error::UnexpectedEof(ReaderOffsetId(4))),
- );
- }
-
- #[test]
- fn test_parse_cie_incomplete_id_32() {
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- // The length is not large enough to contain the ID.
- .B32(3)
- .B32(0xffff_ffff);
- assert_parse_cie(
- kind,
- section,
- 8,
- Err(Error::UnexpectedEof(ReaderOffsetId(4))),
- );
- }
-
- #[test]
- fn test_parse_cie_bad_id_32() {
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- // Initial length
- .B32(4)
- // Not the CIE Id.
- .B32(0xbad1_bad2);
- assert_parse_cie(kind, section, 8, Err(Error::NotCieId));
- }
-
- #[test]
- fn test_parse_cie_32_bad_version() {
- let mut cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 99,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 2,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
- assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99)));
- }
-
- #[test]
- fn test_parse_cie_unknown_augmentation() {
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let augmentation = Some("replicant");
- let expected_rest = [1, 2, 3];
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- // Initial length
- .L32(&length)
- .mark(&start)
- // CIE Id
- .L32(0xffff_ffff)
- // Version
- .D8(4)
- // Augmentation
- .append_bytes(augmentation.unwrap().as_bytes())
- // Null terminator
- .D8(0)
- // Extra augmented data that we can't understand.
- .L32(1)
- .L32(2)
- .L32(3)
- .L32(4)
- .L32(5)
- .L32(6)
- .mark(&end)
- .append_bytes(&expected_rest);
-
- let expected_length = (&end - &start) as u64;
- length.set_const(expected_length);
-
- assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation));
- }
-
- fn test_parse_cie(format: Format, version: u8, address_size: u8) {
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format,
- version,
- augmentation: None,
- address_size,
- segment_size: 0,
- code_alignment_factor: 16,
- data_alignment_factor: 32,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .cie(kind, None, &mut cie)
- .append_bytes(&expected_rest);
-
- assert_parse_cie(
- kind,
- section,
- address_size,
- Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)),
- );
- }
-
- #[test]
- fn test_parse_cie_32_ok() {
- test_parse_cie(Format::Dwarf32, 1, 4);
- test_parse_cie(Format::Dwarf32, 1, 8);
- test_parse_cie(Format::Dwarf32, 4, 4);
- test_parse_cie(Format::Dwarf32, 4, 8);
- }
-
- #[test]
- fn test_parse_cie_64_ok() {
- test_parse_cie(Format::Dwarf64, 1, 4);
- test_parse_cie(Format::Dwarf64, 1, 8);
- test_parse_cie(Format::Dwarf64, 4, 4);
- test_parse_cie(Format::Dwarf64, 4, 8);
- }
-
- #[test]
- fn test_parse_cie_length_too_big() {
- let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 0,
- data_alignment_factor: 0,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
-
- let mut contents = section.get_contents().unwrap();
-
- // Overwrite the length to be too big.
- contents[0] = 0;
- contents[1] = 0;
- contents[2] = 0;
- contents[3] = 255;
-
- let debug_frame = DebugFrame::new(&contents, LittleEndian);
- let bases = Default::default();
- assert_eq!(
- CommonInformationEntry::parse(
- &bases,
- &debug_frame,
- &mut EndianSlice::new(&contents, LittleEndian)
- )
- .map_eof(&contents),
- Err(Error::UnexpectedEof(ReaderOffsetId(4)))
- );
- }
-
- #[test]
- fn test_parse_fde_incomplete_length_32() {
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian()).L16(5);
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, LittleEndian);
- assert_eq!(
- parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
- Err(Error::UnexpectedEof(ReaderOffsetId(0)))
- );
- }
-
- #[test]
- fn test_parse_fde_incomplete_length_64() {
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .L32(0xffff_ffff)
- .L32(12345);
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, LittleEndian);
- assert_eq!(
- parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
- Err(Error::UnexpectedEof(ReaderOffsetId(4)))
- );
- }
-
- #[test]
- fn test_parse_fde_incomplete_cie_pointer_32() {
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- // The length is not large enough to contain the CIE pointer.
- .B32(3)
- .B32(1994);
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, BigEndian);
- assert_eq!(
- parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
- Err(Error::UnexpectedEof(ReaderOffsetId(4)))
- );
- }
-
- #[test]
- fn test_parse_fde_32_ok() {
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let cie_offset = 0xbad0_bad1;
- let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 100,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- // DWARF32 with a 64 bit address size! Holy moly!
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 3,
- data_alignment_factor: 2,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 39,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs, LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&expected_rest);
-
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, LittleEndian);
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
- Ok(cie.clone())
- };
-
- assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_fde_32_with_segment_ok() {
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let cie_offset = 0xbad0_bad1;
- let expected_instrs: Vec<_> = (0..92).map(|_| constants::DW_CFA_nop.0).collect();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 100,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 4,
- code_alignment_factor: 3,
- data_alignment_factor: 2,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0xbadb_ad11,
- initial_address: 0xfeed_beef,
- address_range: 999,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs, LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&expected_rest);
-
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, LittleEndian);
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
- Ok(cie.clone())
- };
-
- assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_fde_64_ok() {
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let cie_offset = 0xbad0_bad1;
- let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 100,
- format: Format::Dwarf64,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 3,
- data_alignment_factor: 2,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf64,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 999,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs, LittleEndian),
- };
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&expected_rest);
-
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, LittleEndian);
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
- Ok(cie.clone())
- };
-
- assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
- assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_entry_on_cie_32_ok() {
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 16,
- data_alignment_factor: 32,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&expected_instrs, BigEndian),
- };
-
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- .cie(kind, None, &mut cie)
- .append_bytes(&expected_rest);
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, BigEndian);
-
- let bases = Default::default();
- assert_eq!(
- parse_cfi_entry(&bases, &debug_frame, rest),
- Ok(Some(CieOrFde::Cie(cie)))
- );
- assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
- }
-
- #[test]
- fn test_parse_cfi_entry_on_fde_32_ok() {
- let cie_offset = 0x1234_5678;
- let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 16,
- data_alignment_factor: 32,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&[], BigEndian),
- };
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 39,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs, BigEndian),
- };
-
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&expected_rest);
-
- let section = section.get_contents().unwrap();
- let debug_frame = kind.section(&section);
- let rest = &mut EndianSlice::new(&section, BigEndian);
-
- let bases = Default::default();
- match parse_cfi_entry(&bases, &debug_frame, rest) {
- Ok(Some(CieOrFde::Fde(partial))) => {
- assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
-
- assert_eq!(partial.length, fde.length);
- assert_eq!(partial.format, fde.format);
- assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize));
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
- Ok(cie.clone())
- };
-
- assert_eq!(partial.parse(get_cie), Ok(fde));
- }
- otherwise => panic!("Unexpected result: {:#?}", otherwise),
- }
- }
-
- #[test]
- fn test_cfi_entries_iter() {
- let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
-
- let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
-
- let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect();
-
- let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie1 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 2,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian),
- };
-
- let mut cie2 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 3,
- data_alignment_factor: 2,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian),
- };
-
- let cie1_location = Label::new();
- let cie2_location = Label::new();
-
- // Write the CIEs first so that their length gets set before we clone
- // them into the FDEs and our equality assertions down the line end up
- // with all the CIEs always having he correct length.
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- .mark(&cie1_location)
- .cie(kind, None, &mut cie1)
- .mark(&cie2_location)
- .cie(kind, None, &mut cie2);
-
- let mut fde1 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie1.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 39,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs3, BigEndian),
- };
-
- let mut fde2 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie2.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: None,
- instructions: EndianSlice::new(&expected_instrs4, BigEndian),
- };
-
- let section =
- section
- .fde(kind, &cie1_location, &mut fde1)
- .fde(kind, &cie2_location, &mut fde2);
-
- section.start().set_const(0);
-
- let cie1_offset = cie1_location.value().unwrap() as usize;
- let cie2_offset = cie2_location.value().unwrap() as usize;
-
- let contents = section.get_contents().unwrap();
- let debug_frame = kind.section(&contents);
-
- let bases = Default::default();
- let mut entries = debug_frame.entries(&bases);
-
- assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone()))));
- assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone()))));
-
- match entries.next() {
- Ok(Some(CieOrFde::Fde(partial))) => {
- assert_eq!(partial.length, fde1.length);
- assert_eq!(partial.format, fde1.format);
- assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset));
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie1_offset));
- Ok(cie1.clone())
- };
- assert_eq!(partial.parse(get_cie), Ok(fde1));
- }
- otherwise => panic!("Unexpected result: {:#?}", otherwise),
- }
-
- match entries.next() {
- Ok(Some(CieOrFde::Fde(partial))) => {
- assert_eq!(partial.length, fde2.length);
- assert_eq!(partial.format, fde2.format);
- assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset));
-
- let get_cie = |_: &_, _: &_, offset| {
- assert_eq!(offset, DebugFrameOffset(cie2_offset));
- Ok(cie2.clone())
- };
- assert_eq!(partial.parse(get_cie), Ok(fde2));
- }
- otherwise => panic!("Unexpected result: {:#?}", otherwise),
- }
-
- assert_eq!(entries.next(), Ok(None));
- }
-
- #[test]
- fn test_parse_cie_from_offset() {
- let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf64,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 4,
- data_alignment_factor: 8,
- return_address_register: Register(12),
- initial_instructions: EndianSlice::new(&instrs, LittleEndian),
- };
-
- let cie_location = Label::new();
-
- let kind = debug_frame_le();
- let section = Section::with_endian(kind.endian())
- .append_bytes(&filler)
- .mark(&cie_location)
- .cie(kind, None, &mut cie)
- .append_bytes(&filler);
-
- section.start().set_const(0);
-
- let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize);
-
- let contents = section.get_contents().unwrap();
- let debug_frame = kind.section(&contents);
- let bases = Default::default();
-
- assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie));
- }
-
- fn parse_cfi_instruction<R: Reader + Default>(
- input: &mut R,
- address_size: u8,
- ) -> Result<CallFrameInstruction<R>> {
- let parameters = &PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size,
- section: &R::default(),
- };
- CallFrameInstruction::parse(input, None, parameters, Vendor::Default)
- }
-
- #[test]
- fn test_parse_cfi_instruction_advance_loc() {
- let expected_rest = [1, 2, 3, 4];
- let expected_delta = 42;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_advance_loc.0 | expected_delta)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(expected_delta),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_offset() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 3;
- let expected_offset = 1997;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_offset.0 | expected_reg)
- .uleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Offset {
- register: Register(expected_reg.into()),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_restore() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 3;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_restore.0 | expected_reg)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Restore {
- register: Register(expected_reg.into()),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_nop() {
- let expected_rest = [1, 2, 3, 4];
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_nop.0)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Nop)
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_set_loc() {
- let expected_rest = [1, 2, 3, 4];
- let expected_addr = 0xdead_beef;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_set_loc.0)
- .L64(expected_addr)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::SetLoc {
- address: expected_addr,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_set_loc_encoding() {
- let text_base = 0xfeed_face;
- let addr_offset = 0xbeef;
- let expected_addr = text_base + addr_offset;
- let expected_rest = [1, 2, 3, 4];
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_set_loc.0)
- .L64(addr_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- let parameters = &PointerEncodingParameters {
- bases: &BaseAddresses::default().set_text(text_base).eh_frame,
- func_base: None,
- address_size: 8,
- section: &EndianSlice::new(&[], LittleEndian),
- };
- assert_eq!(
- CallFrameInstruction::parse(
- input,
- Some(constants::DW_EH_PE_textrel),
- parameters,
- Vendor::Default
- ),
- Ok(CallFrameInstruction::SetLoc {
- address: expected_addr,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_advance_loc1() {
- let expected_rest = [1, 2, 3, 4];
- let expected_delta = 8;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(expected_delta)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(expected_delta),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_advance_loc2() {
- let expected_rest = [1, 2, 3, 4];
- let expected_delta = 500;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_advance_loc2.0)
- .L16(expected_delta)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(expected_delta),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_advance_loc4() {
- let expected_rest = [1, 2, 3, 4];
- let expected_delta = 1 << 20;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_advance_loc4.0)
- .L32(expected_delta)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::AdvanceLoc {
- delta: expected_delta,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_offset_extended() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 7;
- let expected_offset = 33;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_offset_extended.0)
- .uleb(expected_reg.into())
- .uleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Offset {
- register: Register(expected_reg),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_restore_extended() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 7;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_restore_extended.0)
- .uleb(expected_reg.into())
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Restore {
- register: Register(expected_reg),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_undefined() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 7;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_undefined.0)
- .uleb(expected_reg.into())
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Undefined {
- register: Register(expected_reg),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_same_value() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 7;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_same_value.0)
- .uleb(expected_reg.into())
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::SameValue {
- register: Register(expected_reg),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_register() {
- let expected_rest = [1, 2, 3, 4];
- let expected_dest_reg = 7;
- let expected_src_reg = 8;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_register.0)
- .uleb(expected_dest_reg.into())
- .uleb(expected_src_reg.into())
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Register {
- dest_register: Register(expected_dest_reg),
- src_register: Register(expected_src_reg),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_remember_state() {
- let expected_rest = [1, 2, 3, 4];
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_remember_state.0)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::RememberState)
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_restore_state() {
- let expected_rest = [1, 2, 3, 4];
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_restore_state.0)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::RestoreState)
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 2;
- let expected_offset = 0;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa.0)
- .uleb(expected_reg.into())
- .uleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfa {
- register: Register(expected_reg),
- offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa_register() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 2;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa_register.0)
- .uleb(expected_reg.into())
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfaRegister {
- register: Register(expected_reg),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa_offset() {
- let expected_rest = [1, 2, 3, 4];
- let expected_offset = 23;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa_offset.0)
- .uleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfaOffset {
- offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa_expression() {
- let expected_rest = [1, 2, 3, 4];
- let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa_expression.0)
- .D8(&length)
- .mark(&start)
- .append_bytes(&expected_expr)
- .mark(&end)
- .append_bytes(&expected_rest);
-
- length.set_const((&end - &start) as u64);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
-
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfaExpression {
- expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_expression() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 99;
- let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_expression.0)
- .uleb(expected_reg.into())
- .D8(&length)
- .mark(&start)
- .append_bytes(&expected_expr)
- .mark(&end)
- .append_bytes(&expected_rest);
-
- length.set_const((&end - &start) as u64);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
-
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::Expression {
- register: Register(expected_reg),
- expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_offset_extended_sf() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 7;
- let expected_offset = -33;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_offset_extended_sf.0)
- .uleb(expected_reg.into())
- .sleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::OffsetExtendedSf {
- register: Register(expected_reg),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa_sf() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 2;
- let expected_offset = -9999;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa_sf.0)
- .uleb(expected_reg.into())
- .sleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfaSf {
- register: Register(expected_reg),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_def_cfa_offset_sf() {
- let expected_rest = [1, 2, 3, 4];
- let expected_offset = -123;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_def_cfa_offset_sf.0)
- .sleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::DefCfaOffsetSf {
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_val_offset() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 50;
- let expected_offset = 23;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_val_offset.0)
- .uleb(expected_reg.into())
- .uleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::ValOffset {
- register: Register(expected_reg),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_val_offset_sf() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 50;
- let expected_offset = -23;
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_val_offset_sf.0)
- .uleb(expected_reg.into())
- .sleb(expected_offset)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::ValOffsetSf {
- register: Register(expected_reg),
- factored_offset: expected_offset,
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_val_expression() {
- let expected_rest = [1, 2, 3, 4];
- let expected_reg = 50;
- let expected_expr = [2, 2, 1, 1, 5, 5];
-
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_val_expression.0)
- .uleb(expected_reg.into())
- .D8(&length)
- .mark(&start)
- .append_bytes(&expected_expr)
- .mark(&end)
- .append_bytes(&expected_rest);
-
- length.set_const((&end - &start) as u64);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
-
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Ok(CallFrameInstruction::ValExpression {
- register: Register(expected_reg),
- expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)),
- })
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_negate_ra_state() {
- let expected_rest = [1, 2, 3, 4];
- let section = Section::with_endian(Endian::Little)
- .D8(constants::DW_CFA_AARCH64_negate_ra_state.0)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- let parameters = &PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 8,
- section: &EndianSlice::default(),
- };
- assert_eq!(
- CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64),
- Ok(CallFrameInstruction::NegateRaState)
- );
- assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_cfi_instruction_unknown_instruction() {
- let expected_rest = [1, 2, 3, 4];
- let unknown_instr = constants::DwCfa(0b0011_1111);
- let section = Section::with_endian(Endian::Little)
- .D8(unknown_instr.0)
- .append_bytes(&expected_rest);
- let contents = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&contents, LittleEndian);
- assert_eq!(
- parse_cfi_instruction(input, 8),
- Err(Error::UnknownCallFrameInstruction(unknown_instr))
- );
- }
-
- #[test]
- fn test_call_frame_instruction_iter_ok() {
- let expected_reg = 50;
- let expected_expr = [2, 2, 1, 1, 5, 5];
- let expected_delta = 230;
-
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = Section::with_endian(Endian::Big)
- .D8(constants::DW_CFA_val_expression.0)
- .uleb(expected_reg.into())
- .D8(&length)
- .mark(&start)
- .append_bytes(&expected_expr)
- .mark(&end)
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(expected_delta);
-
- length.set_const((&end - &start) as u64);
- let contents = section.get_contents().unwrap();
- let input = EndianSlice::new(&contents, BigEndian);
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 8,
- section: &EndianSlice::default(),
- };
- let mut iter = CallFrameInstructionIter {
- input,
- address_encoding: None,
- parameters,
- vendor: Vendor::Default,
- };
-
- assert_eq!(
- iter.next(),
- Ok(Some(CallFrameInstruction::ValExpression {
- register: Register(expected_reg),
- expression: Expression(EndianSlice::new(&expected_expr, BigEndian)),
- }))
- );
-
- assert_eq!(
- iter.next(),
- Ok(Some(CallFrameInstruction::AdvanceLoc {
- delta: u32::from(expected_delta),
- }))
- );
-
- assert_eq!(iter.next(), Ok(None));
- }
-
- #[test]
- fn test_call_frame_instruction_iter_err() {
- // DW_CFA_advance_loc1 without an operand.
- let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0);
-
- let contents = section.get_contents().unwrap();
- let input = EndianSlice::new(&contents, BigEndian);
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 8,
- section: &EndianSlice::default(),
- };
- let mut iter = CallFrameInstructionIter {
- input,
- address_encoding: None,
- parameters,
- vendor: Vendor::Default,
- };
-
- assert_eq!(
- iter.next().map_eof(&contents),
- Err(Error::UnexpectedEof(ReaderOffsetId(1)))
- );
- assert_eq!(iter.next(), Ok(None));
- }
-
- fn assert_eval<'a, I>(
- mut initial_ctx: UnwindContext<EndianSlice<'a, LittleEndian>>,
- expected_ctx: UnwindContext<EndianSlice<'a, LittleEndian>>,
- cie: CommonInformationEntry<EndianSlice<'a, LittleEndian>>,
- fde: Option<FrameDescriptionEntry<EndianSlice<'a, LittleEndian>>>,
- instructions: I,
- ) where
- I: AsRef<
- [(
- Result<bool>,
- CallFrameInstruction<EndianSlice<'a, LittleEndian>>,
- )],
- >,
- {
- {
- let section = &DebugFrame::from(EndianSlice::default());
- let bases = &BaseAddresses::default();
- let mut table = match fde {
- Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde),
- None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie),
- };
- for &(ref expected_result, ref instruction) in instructions.as_ref() {
- assert_eq!(*expected_result, table.evaluate(instruction.clone()));
- }
- }
-
- assert_eq!(expected_ctx, initial_ctx);
- }
-
- fn make_test_cie<'a>() -> CommonInformationEntry<EndianSlice<'a, LittleEndian>> {
- CommonInformationEntry {
- offset: 0,
- format: Format::Dwarf64,
- length: 0,
- return_address_register: Register(0),
- version: 4,
- address_size: mem::size_of::<usize>() as u8,
- initial_instructions: EndianSlice::new(&[], LittleEndian),
- augmentation: None,
- segment_size: 0,
- data_alignment_factor: 2,
- code_alignment_factor: 3,
- }
- }
-
- #[test]
- fn test_eval_set_loc() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected.row_mut().end_address = 42;
- let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_set_loc_backwards() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.row_mut().start_address = 999;
- let expected = ctx.clone();
- let instructions = [(
- Err(Error::InvalidAddressRange),
- CallFrameInstruction::SetLoc { address: 42 },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_advance_loc() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.row_mut().start_address = 3;
- let mut expected = ctx.clone();
- expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor;
- let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_advance_loc_overflow() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.row_mut().start_address = u64::MAX;
- let mut expected = ctx.clone();
- expected.row_mut().end_address = 42 * cie.code_alignment_factor - 1;
- let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 42 })];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(42),
- offset: 36,
- });
- let instructions = [(
- Ok(false),
- CallFrameInstruction::DefCfa {
- register: Register(42),
- offset: 36,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_sf() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(42),
- offset: 36 * cie.data_alignment_factor as i64,
- });
- let instructions = [(
- Ok(false),
- CallFrameInstruction::DefCfaSf {
- register: Register(42),
- factored_offset: 36,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_register() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(3),
- offset: 8,
- });
- let mut expected = ctx.clone();
- expected.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(42),
- offset: 8,
- });
- let instructions = [(
- Ok(false),
- CallFrameInstruction::DefCfaRegister {
- register: Register(42),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_register_invalid_context() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new(
- &[],
- LittleEndian,
- ))));
- let expected = ctx.clone();
- let instructions = [(
- Err(Error::CfiInstructionInInvalidContext),
- CallFrameInstruction::DefCfaRegister {
- register: Register(42),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_offset() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(3),
- offset: 8,
- });
- let mut expected = ctx.clone();
- expected.set_cfa(CfaRule::RegisterAndOffset {
- register: Register(3),
- offset: 42,
- });
- let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_offset_invalid_context() {
- let cie = make_test_cie();
- let mut ctx = UnwindContext::new();
- ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new(
- &[],
- LittleEndian,
- ))));
- let expected = ctx.clone();
- let instructions = [(
- Err(Error::CfiInstructionInInvalidContext),
- CallFrameInstruction::DefCfaOffset { offset: 1993 },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_def_cfa_expression() {
- let expr = [1, 2, 3, 4];
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected.set_cfa(CfaRule::Expression(Expression(EndianSlice::new(
- &expr,
- LittleEndian,
- ))));
- let instructions = [(
- Ok(false),
- CallFrameInstruction::DefCfaExpression {
- expression: Expression(EndianSlice::new(&expr, LittleEndian)),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_undefined() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(Register(5), RegisterRule::Undefined)
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::Undefined {
- register: Register(5),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_same_value() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(Register(0), RegisterRule::SameValue)
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::SameValue {
- register: Register(0),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_offset() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(2),
- RegisterRule::Offset(3 * cie.data_alignment_factor),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::Offset {
- register: Register(2),
- factored_offset: 3,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_offset_extended_sf() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(4),
- RegisterRule::Offset(-3 * cie.data_alignment_factor),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::OffsetExtendedSf {
- register: Register(4),
- factored_offset: -3,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_val_offset() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(5),
- RegisterRule::ValOffset(7 * cie.data_alignment_factor),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::ValOffset {
- register: Register(5),
- factored_offset: 7,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_val_offset_sf() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(5),
- RegisterRule::ValOffset(-7 * cie.data_alignment_factor),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::ValOffsetSf {
- register: Register(5),
- factored_offset: -7,
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_expression() {
- let expr = [1, 2, 3, 4];
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(9),
- RegisterRule::Expression(Expression(EndianSlice::new(&expr, LittleEndian))),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::Expression {
- register: Register(9),
- expression: Expression(EndianSlice::new(&expr, LittleEndian)),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_val_expression() {
- let expr = [1, 2, 3, 4];
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- Register(9),
- RegisterRule::ValExpression(Expression(EndianSlice::new(&expr, LittleEndian))),
- )
- .unwrap();
- let instructions = [(
- Ok(false),
- CallFrameInstruction::ValExpression {
- register: Register(9),
- expression: Expression(EndianSlice::new(&expr, LittleEndian)),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_restore() {
- let cie = make_test_cie();
- let fde = FrameDescriptionEntry {
- offset: 0,
- format: Format::Dwarf64,
- length: 0,
- address_range: 0,
- augmentation: None,
- initial_address: 0,
- initial_segment: 0,
- cie: cie.clone(),
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let mut ctx = UnwindContext::new();
- ctx.set_register_rule(Register(0), RegisterRule::Offset(1))
- .unwrap();
- ctx.save_initial_rules().unwrap();
- let expected = ctx.clone();
- ctx.set_register_rule(Register(0), RegisterRule::Offset(2))
- .unwrap();
-
- let instructions = [(
- Ok(false),
- CallFrameInstruction::Restore {
- register: Register(0),
- },
- )];
- assert_eval(ctx, expected, cie, Some(fde), instructions);
- }
-
- #[test]
- fn test_eval_restore_havent_saved_initial_context() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let expected = ctx.clone();
- let instructions = [(
- Err(Error::CfiInstructionInInvalidContext),
- CallFrameInstruction::Restore {
- register: Register(0),
- },
- )];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_remember_state() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected.push_row().unwrap();
- let instructions = [(Ok(false), CallFrameInstruction::RememberState)];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_restore_state() {
- let cie = make_test_cie();
-
- let mut ctx = UnwindContext::new();
- ctx.set_start_address(1);
- ctx.set_register_rule(Register(0), RegisterRule::SameValue)
- .unwrap();
- let mut expected = ctx.clone();
- ctx.push_row().unwrap();
- ctx.set_start_address(2);
- ctx.set_register_rule(Register(0), RegisterRule::Offset(16))
- .unwrap();
-
- // Restore state should preserve current location.
- expected.set_start_address(2);
-
- let instructions = [
- // First one pops just fine.
- (Ok(false), CallFrameInstruction::RestoreState),
- // Second pop would try to pop out of bounds.
- (
- Err(Error::PopWithEmptyStack),
- CallFrameInstruction::RestoreState,
- ),
- ];
-
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_negate_ra_state() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1))
- .unwrap();
- let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)];
- assert_eval(ctx, expected, cie, None, instructions);
-
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0))
- .unwrap();
- let instructions = [
- (Ok(false), CallFrameInstruction::NegateRaState),
- (Ok(false), CallFrameInstruction::NegateRaState),
- ];
- assert_eval(ctx, expected, cie, None, instructions);
-
- // NegateRaState can't be used with other instructions.
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let mut expected = ctx.clone();
- expected
- .set_register_rule(
- crate::AArch64::RA_SIGN_STATE,
- RegisterRule::Offset(cie.data_alignment_factor as i64),
- )
- .unwrap();
- let instructions = [
- (
- Ok(false),
- CallFrameInstruction::Offset {
- register: crate::AArch64::RA_SIGN_STATE,
- factored_offset: 1,
- },
- ),
- (
- Err(Error::CfiInstructionInInvalidContext),
- CallFrameInstruction::NegateRaState,
- ),
- ];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_eval_nop() {
- let cie = make_test_cie();
- let ctx = UnwindContext::new();
- let expected = ctx.clone();
- let instructions = [(Ok(false), CallFrameInstruction::Nop)];
- assert_eval(ctx, expected, cie, None, instructions);
- }
-
- #[test]
- fn test_unwind_table_cie_no_rule() {
- let initial_instructions = Section::with_endian(Endian::Little)
- // The CFA is -12 from register 4.
- .D8(constants::DW_CFA_def_cfa_sf.0)
- .uleb(4)
- .sleb(-12)
- .append_repeated(constants::DW_CFA_nop.0, 4);
- let initial_instructions = initial_instructions.get_contents().unwrap();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
- };
-
- let instructions = Section::with_endian(Endian::Little)
- // A bunch of nop padding.
- .append_repeated(constants::DW_CFA_nop.0, 8);
- let instructions = instructions.get_contents().unwrap();
-
- let fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0,
- address_range: 100,
- augmentation: None,
- instructions: EndianSlice::new(&instructions, LittleEndian),
- };
-
- let section = &DebugFrame::from(EndianSlice::default());
- let bases = &BaseAddresses::default();
- let mut ctx = Box::new(UnwindContext::new());
-
- let mut table = fde
- .rows(section, bases, &mut ctx)
- .expect("Should run initial program OK");
- assert!(table.ctx.is_initialized);
- let expected_initial_rule = (Register(0), RegisterRule::Undefined);
- assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
-
- {
- let row = table.next_row().expect("Should evaluate first row OK");
- let expected = UnwindTableRow {
- start_address: 0,
- end_address: 100,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [].iter().collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- // All done!
- assert_eq!(Ok(None), table.next_row());
- assert_eq!(Ok(None), table.next_row());
- }
-
- #[test]
- fn test_unwind_table_cie_single_rule() {
- let initial_instructions = Section::with_endian(Endian::Little)
- // The CFA is -12 from register 4.
- .D8(constants::DW_CFA_def_cfa_sf.0)
- .uleb(4)
- .sleb(-12)
- // Register 3 is 4 from the CFA.
- .D8(constants::DW_CFA_offset.0 | 3)
- .uleb(4)
- .append_repeated(constants::DW_CFA_nop.0, 4);
- let initial_instructions = initial_instructions.get_contents().unwrap();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
- };
-
- let instructions = Section::with_endian(Endian::Little)
- // A bunch of nop padding.
- .append_repeated(constants::DW_CFA_nop.0, 8);
- let instructions = instructions.get_contents().unwrap();
-
- let fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0,
- address_range: 100,
- augmentation: None,
- instructions: EndianSlice::new(&instructions, LittleEndian),
- };
-
- let section = &DebugFrame::from(EndianSlice::default());
- let bases = &BaseAddresses::default();
- let mut ctx = Box::new(UnwindContext::new());
-
- let mut table = fde
- .rows(section, bases, &mut ctx)
- .expect("Should run initial program OK");
- assert!(table.ctx.is_initialized);
- let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
- assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
-
- {
- let row = table.next_row().expect("Should evaluate first row OK");
- let expected = UnwindTableRow {
- start_address: 0,
- end_address: 100,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- // All done!
- assert_eq!(Ok(None), table.next_row());
- assert_eq!(Ok(None), table.next_row());
- }
-
- #[test]
- fn test_unwind_table_cie_invalid_rule() {
- let initial_instructions1 = Section::with_endian(Endian::Little)
- // Test that stack length is reset.
- .D8(constants::DW_CFA_remember_state.0)
- // Test that stack value is reset (different register from that used later).
- .D8(constants::DW_CFA_offset.0 | 4)
- .uleb(8)
- // Invalid due to missing operands.
- .D8(constants::DW_CFA_offset.0);
- let initial_instructions1 = initial_instructions1.get_contents().unwrap();
-
- let cie1 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian),
- };
-
- let initial_instructions2 = Section::with_endian(Endian::Little)
- // Register 3 is 4 from the CFA.
- .D8(constants::DW_CFA_offset.0 | 3)
- .uleb(4)
- .append_repeated(constants::DW_CFA_nop.0, 4);
- let initial_instructions2 = initial_instructions2.get_contents().unwrap();
-
- let cie2 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian),
- };
-
- let fde1 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie1.clone(),
- initial_segment: 0,
- initial_address: 0,
- address_range: 100,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let fde2 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie2.clone(),
- initial_segment: 0,
- initial_address: 0,
- address_range: 100,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let section = &DebugFrame::from(EndianSlice::default());
- let bases = &BaseAddresses::default();
- let mut ctx = Box::new(UnwindContext::new());
-
- let table = fde1
- .rows(section, bases, &mut ctx)
- .map_eof(&initial_instructions1);
- assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4))));
- assert!(!ctx.is_initialized);
- assert_eq!(ctx.stack.len(), 2);
- assert_eq!(ctx.initial_rule, None);
-
- let _table = fde2
- .rows(section, bases, &mut ctx)
- .expect("Should run initial program OK");
- assert!(ctx.is_initialized);
- assert_eq!(ctx.stack.len(), 1);
- let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
- assert_eq!(ctx.initial_rule, Some(expected_initial_rule));
- }
-
- #[test]
- fn test_unwind_table_next_row() {
- let initial_instructions = Section::with_endian(Endian::Little)
- // The CFA is -12 from register 4.
- .D8(constants::DW_CFA_def_cfa_sf.0)
- .uleb(4)
- .sleb(-12)
- // Register 0 is 8 from the CFA.
- .D8(constants::DW_CFA_offset.0 | 0)
- .uleb(8)
- // Register 3 is 4 from the CFA.
- .D8(constants::DW_CFA_offset.0 | 3)
- .uleb(4)
- .append_repeated(constants::DW_CFA_nop.0, 4);
- let initial_instructions = initial_instructions.get_contents().unwrap();
-
- let cie = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
- };
-
- let instructions = Section::with_endian(Endian::Little)
- // Initial instructions form a row, advance the address by 1.
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(1)
- // Register 0 is -16 from the CFA.
- .D8(constants::DW_CFA_offset_extended_sf.0)
- .uleb(0)
- .sleb(-16)
- // Finish this row, advance the address by 32.
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(32)
- // Register 3 is -4 from the CFA.
- .D8(constants::DW_CFA_offset_extended_sf.0)
- .uleb(3)
- .sleb(-4)
- // Finish this row, advance the address by 64.
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(64)
- // Register 5 is 4 from the CFA.
- .D8(constants::DW_CFA_offset.0 | 5)
- .uleb(4)
- // A bunch of nop padding.
- .append_repeated(constants::DW_CFA_nop.0, 8);
- let instructions = instructions.get_contents().unwrap();
-
- let fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0,
- address_range: 100,
- augmentation: None,
- instructions: EndianSlice::new(&instructions, LittleEndian),
- };
-
- let section = &DebugFrame::from(EndianSlice::default());
- let bases = &BaseAddresses::default();
- let mut ctx = Box::new(UnwindContext::new());
-
- let mut table = fde
- .rows(section, bases, &mut ctx)
- .expect("Should run initial program OK");
- assert!(table.ctx.is_initialized);
- assert!(table.ctx.initial_rule.is_none());
- let expected_initial_rules: RegisterRuleMap<_> = [
- (Register(0), RegisterRule::Offset(8)),
- (Register(3), RegisterRule::Offset(4)),
- ]
- .iter()
- .collect();
- assert_eq!(table.ctx.stack[0].registers, expected_initial_rules);
-
- {
- let row = table.next_row().expect("Should evaluate first row OK");
- let expected = UnwindTableRow {
- start_address: 0,
- end_address: 1,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [
- (Register(0), RegisterRule::Offset(8)),
- (Register(3), RegisterRule::Offset(4)),
- ]
- .iter()
- .collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- {
- let row = table.next_row().expect("Should evaluate second row OK");
- let expected = UnwindTableRow {
- start_address: 1,
- end_address: 33,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [
- (Register(0), RegisterRule::Offset(-16)),
- (Register(3), RegisterRule::Offset(4)),
- ]
- .iter()
- .collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- {
- let row = table.next_row().expect("Should evaluate third row OK");
- let expected = UnwindTableRow {
- start_address: 33,
- end_address: 97,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [
- (Register(0), RegisterRule::Offset(-16)),
- (Register(3), RegisterRule::Offset(-4)),
- ]
- .iter()
- .collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- {
- let row = table.next_row().expect("Should evaluate fourth row OK");
- let expected = UnwindTableRow {
- start_address: 97,
- end_address: 100,
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [
- (Register(0), RegisterRule::Offset(-16)),
- (Register(3), RegisterRule::Offset(-4)),
- (Register(5), RegisterRule::Offset(4)),
- ]
- .iter()
- .collect(),
- };
- assert_eq!(Some(&expected), row);
- }
-
- // All done!
- assert_eq!(Ok(None), table.next_row());
- assert_eq!(Ok(None), table.next_row());
- }
-
- #[test]
- fn test_unwind_info_for_address_ok() {
- let instrs1 = Section::with_endian(Endian::Big)
- // The CFA is -12 from register 4.
- .D8(constants::DW_CFA_def_cfa_sf.0)
- .uleb(4)
- .sleb(-12);
- let instrs1 = instrs1.get_contents().unwrap();
-
- let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
-
- let instrs3 = Section::with_endian(Endian::Big)
- // Initial instructions form a row, advance the address by 100.
- .D8(constants::DW_CFA_advance_loc1.0)
- .D8(100)
- // Register 0 is -16 from the CFA.
- .D8(constants::DW_CFA_offset_extended_sf.0)
- .uleb(0)
- .sleb(-16);
- let instrs3 = instrs3.get_contents().unwrap();
-
- let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
-
- let mut cie1 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 8,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(3),
- initial_instructions: EndianSlice::new(&instrs1, BigEndian),
- };
-
- let mut cie2 = CommonInformationEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- version: 4,
- augmentation: None,
- address_size: 4,
- segment_size: 0,
- code_alignment_factor: 1,
- data_alignment_factor: 1,
- return_address_register: Register(1),
- initial_instructions: EndianSlice::new(&instrs2, BigEndian),
- };
-
- let cie1_location = Label::new();
- let cie2_location = Label::new();
-
- // Write the CIEs first so that their length gets set before we clone
- // them into the FDEs and our equality assertions down the line end up
- // with all the CIEs always having he correct length.
- let kind = debug_frame_be();
- let section = Section::with_endian(kind.endian())
- .mark(&cie1_location)
- .cie(kind, None, &mut cie1)
- .mark(&cie2_location)
- .cie(kind, None, &mut cie2);
-
- let mut fde1 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie1.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 200,
- augmentation: None,
- instructions: EndianSlice::new(&instrs3, BigEndian),
- };
-
- let mut fde2 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie2.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: None,
- instructions: EndianSlice::new(&instrs4, BigEndian),
- };
-
- let section =
- section
- .fde(kind, &cie1_location, &mut fde1)
- .fde(kind, &cie2_location, &mut fde2);
- section.start().set_const(0);
-
- let contents = section.get_contents().unwrap();
- let debug_frame = kind.section(&contents);
-
- // Get the second row of the unwind table in `instrs3`.
- let bases = Default::default();
- let mut ctx = Box::new(UnwindContext::new());
- let result = debug_frame.unwind_info_for_address(
- &bases,
- &mut ctx,
- 0xfeed_beef + 150,
- DebugFrame::cie_from_offset,
- );
- assert!(result.is_ok());
- let unwind_info = result.unwrap();
-
- assert_eq!(
- *unwind_info,
- UnwindTableRow {
- start_address: fde1.initial_address() + 100,
- end_address: fde1.initial_address() + fde1.len(),
- saved_args_size: 0,
- cfa: CfaRule::RegisterAndOffset {
- register: Register(4),
- offset: -12,
- },
- registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(),
- }
- );
- }
-
- #[test]
- fn test_unwind_info_for_address_not_found() {
- let debug_frame = DebugFrame::new(&[], NativeEndian);
- let bases = Default::default();
- let mut ctx = Box::new(UnwindContext::new());
- let result = debug_frame.unwind_info_for_address(
- &bases,
- &mut ctx,
- 0xbadb_ad99,
- DebugFrame::cie_from_offset,
- );
- assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
- }
-
- #[test]
- fn test_eh_frame_hdr_unknown_version() {
- let bases = BaseAddresses::default();
- let buf = &[42];
- let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8);
- assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::UnknownVersion(42));
- }
-
- #[test]
- fn test_eh_frame_hdr_omit_ehptr() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0xff)
- .L8(0x03)
- .L8(0x0b)
- .L32(2)
- .L32(10)
- .L32(1)
- .L32(20)
- .L32(2)
- .L32(0);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding);
- }
-
- #[test]
- fn test_eh_frame_hdr_omit_count() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x0b)
- .L8(0xff)
- .L8(0x0b)
- .L32(0x12345);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_ok());
- let result = result.unwrap();
- assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
- assert!(result.table().is_none());
- }
-
- #[test]
- fn test_eh_frame_hdr_omit_table() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x0b)
- .L8(0x03)
- .L8(0xff)
- .L32(0x12345)
- .L32(2);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_ok());
- let result = result.unwrap();
- assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
- assert!(result.table().is_none());
- }
-
- #[test]
- fn test_eh_frame_hdr_varlen_table() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x0b)
- .L8(0x03)
- .L8(0x01)
- .L32(0x12345)
- .L32(2);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_ok());
- let result = result.unwrap();
- assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
- let table = result.table();
- assert!(table.is_some());
- let table = table.unwrap();
- assert_eq!(
- table.lookup(0, &bases),
- Err(Error::VariableLengthSearchTable)
- );
- }
-
- #[test]
- fn test_eh_frame_hdr_indirect_length() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x0b)
- .L8(0x83)
- .L8(0x0b)
- .L32(0x12345)
- .L32(2);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding);
- }
-
- #[test]
- fn test_eh_frame_hdr_indirect_ptrs() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x8b)
- .L8(0x03)
- .L8(0x8b)
- .L32(0x12345)
- .L32(2)
- .L32(10)
- .L32(1)
- .L32(20)
- .L32(2);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_ok());
- let result = result.unwrap();
- assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345));
- let table = result.table();
- assert!(table.is_some());
- let table = table.unwrap();
- assert_eq!(
- table.lookup(0, &bases),
- Err(Error::UnsupportedPointerEncoding)
- );
- }
-
- #[test]
- fn test_eh_frame_hdr_good() {
- let section = Section::with_endian(Endian::Little)
- .L8(1)
- .L8(0x0b)
- .L8(0x03)
- .L8(0x0b)
- .L32(0x12345)
- .L32(2)
- .L32(10)
- .L32(1)
- .L32(20)
- .L32(2);
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(result.is_ok());
- let result = result.unwrap();
- assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
- let table = result.table();
- assert!(table.is_some());
- let table = table.unwrap();
- assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1)));
- assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1)));
- assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1)));
- assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1)));
- assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1)));
- assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2)));
- assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2)));
- assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2)));
- }
-
- #[test]
- fn test_eh_frame_fde_for_address_good() {
- // First, setup eh_frame
- // Write the CIE first so that its length gets set before we clone it
- // into the FDE.
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
-
- let start_of_cie = Label::new();
- let end_of_cie = Label::new();
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .append_repeated(0, 16)
- .mark(&start_of_cie)
- .cie(kind, None, &mut cie)
- .mark(&end_of_cie);
-
- let mut fde1 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 9,
- address_range: 4,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
- let mut fde2 = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 20,
- address_range: 8,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let start_of_fde1 = Label::new();
- let start_of_fde2 = Label::new();
-
- let section = section
- // +4 for the FDE length before the CIE offset.
- .mark(&start_of_fde1)
- .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1)
- .mark(&start_of_fde2)
- .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2);
-
- section.start().set_const(0);
- let section = section.get_contents().unwrap();
- let eh_frame = kind.section(&section);
-
- // Setup eh_frame_hdr
- let section = Section::with_endian(kind.endian())
- .L8(1)
- .L8(0x0b)
- .L8(0x03)
- .L8(0x0b)
- .L32(0x12345)
- .L32(2)
- .L32(10)
- .L32(0x12345 + start_of_fde1.value().unwrap() as u32)
- .L32(20)
- .L32(0x12345 + start_of_fde2.value().unwrap() as u32);
-
- let section = section.get_contents().unwrap();
- let bases = BaseAddresses::default();
- let eh_frame_hdr = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
- assert!(eh_frame_hdr.is_ok());
- let eh_frame_hdr = eh_frame_hdr.unwrap();
-
- let table = eh_frame_hdr.table();
- assert!(table.is_some());
- let table = table.unwrap();
-
- let bases = Default::default();
- let mut iter = table.iter(&bases);
- assert_eq!(
- iter.next(),
- Ok(Some((
- Pointer::Direct(10),
- Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64)
- )))
- );
- assert_eq!(
- iter.next(),
- Ok(Some((
- Pointer::Direct(20),
- Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64)
- )))
- );
- assert_eq!(iter.next(), Ok(None));
-
- assert_eq!(
- table.iter(&bases).nth(0),
- Ok(Some((
- Pointer::Direct(10),
- Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64)
- )))
- );
-
- assert_eq!(
- table.iter(&bases).nth(1),
- Ok(Some((
- Pointer::Direct(20),
- Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64)
- )))
- );
- assert_eq!(table.iter(&bases).nth(2), Ok(None));
-
- let f = |_: &_, _: &_, o: EhFrameOffset| {
- assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
- Ok(cie.clone())
- };
- assert_eq!(
- table.fde_for_address(&eh_frame, &bases, 9, f),
- Ok(fde1.clone())
- );
- assert_eq!(
- table.fde_for_address(&eh_frame, &bases, 10, f),
- Ok(fde1.clone())
- );
- assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1));
- assert_eq!(
- table.fde_for_address(&eh_frame, &bases, 19, f),
- Err(Error::NoUnwindInfoForAddress)
- );
- assert_eq!(
- table.fde_for_address(&eh_frame, &bases, 20, f),
- Ok(fde2.clone())
- );
- assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2));
- assert_eq!(
- table.fde_for_address(&eh_frame, &bases, 100_000, f),
- Err(Error::NoUnwindInfoForAddress)
- );
- }
-
- #[test]
- fn test_eh_frame_stops_at_zero_length() {
- let section = Section::with_endian(Endian::Little).L32(0);
- let section = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&section, LittleEndian);
- let bases = Default::default();
-
- assert_eq!(
- parse_cfi_entry(&bases, &EhFrame::new(&*section, LittleEndian), rest),
- Ok(None)
- );
-
- assert_eq!(
- EhFrame::new(&section, LittleEndian).cie_from_offset(&bases, EhFrameOffset(0)),
- Err(Error::NoEntryAtGivenOffset)
- );
- }
-
- fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result<usize> {
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf64,
- cie: make_test_cie(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 39,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .append_bytes(&buf)
- .fde(kind, cie_offset as u64, &mut fde)
- .append_bytes(&buf);
-
- let section = section.get_contents().unwrap();
- let eh_frame = kind.section(&section);
- let input = &mut EndianSlice::new(&section[buf.len()..], LittleEndian);
-
- let bases = Default::default();
- match parse_cfi_entry(&bases, &eh_frame, input) {
- Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0),
- Err(e) => Err(e),
- otherwise => panic!("Unexpected result: {:#?}", otherwise),
- }
- }
-
- #[test]
- fn test_eh_frame_resolve_cie_offset_ok() {
- let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- let cie_offset = 2;
- // + 4 for size of length field
- assert_eq!(
- resolve_cie_offset(&buf, buf.len() + 4 - cie_offset),
- Ok(cie_offset)
- );
- }
-
- #[test]
- fn test_eh_frame_resolve_cie_offset_out_of_bounds() {
- let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- assert_eq!(
- resolve_cie_offset(&buf, buf.len() + 4 + 2),
- Err(Error::OffsetOutOfBounds)
- );
- }
-
- #[test]
- fn test_eh_frame_resolve_cie_offset_underflow() {
- let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- assert_eq!(
- resolve_cie_offset(&buf, ::core::usize::MAX),
- Err(Error::OffsetOutOfBounds)
- );
- }
-
- #[test]
- fn test_eh_frame_fde_ok() {
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
-
- let start_of_cie = Label::new();
- let end_of_cie = Label::new();
-
- // Write the CIE first so that its length gets set before we clone it
- // into the FDE.
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .append_repeated(0, 16)
- .mark(&start_of_cie)
- .cie(kind, None, &mut cie)
- .mark(&end_of_cie);
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 999,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let section = section
- // +4 for the FDE length before the CIE offset.
- .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde);
-
- section.start().set_const(0);
- let section = section.get_contents().unwrap();
- let eh_frame = kind.section(&section);
- let section = EndianSlice::new(&section, LittleEndian);
-
- let mut offset = None;
- match parse_fde(
- eh_frame,
- &mut section.range_from(end_of_cie.value().unwrap() as usize..),
- |_, _, o| {
- offset = Some(o);
- assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
- Ok(cie.clone())
- },
- ) {
- Ok(actual) => assert_eq!(actual, fde),
- otherwise => panic!("Unexpected result {:?}", otherwise),
- }
- assert!(offset.is_some());
- }
-
- #[test]
- fn test_eh_frame_fde_out_of_bounds() {
- let mut cie = make_test_cie();
- cie.version = 1;
-
- let end_of_cie = Label::new();
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf64,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_beef,
- address_range: 999,
- augmentation: None,
- instructions: EndianSlice::new(&[], LittleEndian),
- };
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .cie(kind, None, &mut cie)
- .mark(&end_of_cie)
- .fde(kind, 99_999_999_999_999, &mut fde);
-
- section.start().set_const(0);
- let section = section.get_contents().unwrap();
- let eh_frame = kind.section(&section);
- let section = EndianSlice::new(&section, LittleEndian);
-
- let result = parse_fde(
- eh_frame,
- &mut section.range_from(end_of_cie.value().unwrap() as usize..),
- UnwindSection::cie_from_offset,
- );
- assert_eq!(result, Err(Error::OffsetOutOfBounds));
- }
-
- #[test]
- fn test_augmentation_parse_not_z_augmentation() {
- let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian);
- let bases = Default::default();
- let address_size = 8;
- let section = EhFrame::new(&[], NativeEndian);
- let input = &mut EndianSlice::new(&[], NativeEndian);
- assert_eq!(
- Augmentation::parse(augmentation, &bases, address_size, &section, input),
- Err(Error::UnknownAugmentation)
- );
- }
-
- #[test]
- fn test_augmentation_parse_just_signal_trampoline() {
- let aug_str = &mut EndianSlice::new(b"S", LittleEndian);
- let bases = Default::default();
- let address_size = 8;
- let section = EhFrame::new(&[], LittleEndian);
- let input = &mut EndianSlice::new(&[], LittleEndian);
-
- let mut augmentation = Augmentation::default();
- augmentation.is_signal_trampoline = true;
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- }
-
- #[test]
- fn test_augmentation_parse_unknown_part_of_z_augmentation() {
- // The 'Z' character is not defined by the z-style augmentation.
- let bases = Default::default();
- let address_size = 8;
- let section = Section::with_endian(Endian::Little)
- .uleb(4)
- .append_repeated(4, 4)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian);
- assert_eq!(
- Augmentation::parse(augmentation, &bases, address_size, &section, input),
- Err(Error::UnknownAugmentation)
- );
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_augmentation_parse_L() {
- let bases = Default::default();
- let address_size = 8;
- let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let section = Section::with_endian(Endian::Little)
- .uleb(1)
- .D8(constants::DW_EH_PE_uleb128.0)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let aug_str = &mut EndianSlice::new(b"zL", LittleEndian);
-
- let mut augmentation = Augmentation::default();
- augmentation.lsda = Some(constants::DW_EH_PE_uleb128);
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_augmentation_parse_P() {
- let bases = Default::default();
- let address_size = 8;
- let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let section = Section::with_endian(Endian::Little)
- .uleb(9)
- .D8(constants::DW_EH_PE_udata8.0)
- .L64(0xf00d_f00d)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let aug_str = &mut EndianSlice::new(b"zP", LittleEndian);
-
- let mut augmentation = Augmentation::default();
- augmentation.personality = Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d)));
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_augmentation_parse_R() {
- let bases = Default::default();
- let address_size = 8;
- let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let section = Section::with_endian(Endian::Little)
- .uleb(1)
- .D8(constants::DW_EH_PE_udata4.0)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let aug_str = &mut EndianSlice::new(b"zR", LittleEndian);
-
- let mut augmentation = Augmentation::default();
- augmentation.fde_address_encoding = Some(constants::DW_EH_PE_udata4);
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_augmentation_parse_S() {
- let bases = Default::default();
- let address_size = 8;
- let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let section = Section::with_endian(Endian::Little)
- .uleb(0)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let aug_str = &mut EndianSlice::new(b"zS", LittleEndian);
-
- let mut augmentation = Augmentation::default();
- augmentation.is_signal_trampoline = true;
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_augmentation_parse_all() {
- let bases = Default::default();
- let address_size = 8;
- let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
-
- let section = Section::with_endian(Endian::Little)
- .uleb(1 + 9 + 1)
- // L
- .D8(constants::DW_EH_PE_uleb128.0)
- // P
- .D8(constants::DW_EH_PE_udata8.0)
- .L64(0x1bad_f00d)
- // R
- .D8(constants::DW_EH_PE_uleb128.0)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = EhFrame::new(&section, LittleEndian);
- let input = &mut section.section().clone();
- let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian);
-
- let augmentation = Augmentation {
- lsda: Some(constants::DW_EH_PE_uleb128),
- personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))),
- fde_address_encoding: Some(constants::DW_EH_PE_uleb128),
- is_signal_trampoline: true,
- };
-
- assert_eq!(
- Augmentation::parse(aug_str, &bases, address_size, &section, input),
- Ok(augmentation)
- );
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_eh_frame_fde_no_augmentation() {
- let instrs = [1, 2, 3, 4];
- let cie_offset = 1;
-
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: None,
- instructions: EndianSlice::new(&instrs, LittleEndian),
- };
-
- let rest = [1, 2, 3, 4];
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = kind.section(&section);
- let input = &mut section.section().clone();
-
- let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
- assert_eq!(result, Ok(fde));
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_eh_frame_fde_empty_augmentation() {
- let instrs = [1, 2, 3, 4];
- let cie_offset = 1;
-
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
- cie.augmentation = Some(Augmentation::default());
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: Some(AugmentationData::default()),
- instructions: EndianSlice::new(&instrs, LittleEndian),
- };
-
- let rest = [1, 2, 3, 4];
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = kind.section(&section);
- let input = &mut section.section().clone();
-
- let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
- assert_eq!(result, Ok(fde));
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_eh_frame_fde_lsda_augmentation() {
- let instrs = [1, 2, 3, 4];
- let cie_offset = 1;
-
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
- cie.augmentation = Some(Augmentation::default());
- cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr);
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: Some(AugmentationData {
- lsda: Some(Pointer::Direct(0x1122_3344)),
- }),
- instructions: EndianSlice::new(&instrs, LittleEndian),
- };
-
- let rest = [1, 2, 3, 4];
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = kind.section(&section);
- let input = &mut section.section().clone();
-
- let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
- assert_eq!(result, Ok(fde));
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_eh_frame_fde_lsda_function_relative() {
- let instrs = [1, 2, 3, 4];
- let cie_offset = 1;
-
- let mut cie = make_test_cie();
- cie.format = Format::Dwarf32;
- cie.version = 1;
- cie.augmentation = Some(Augmentation::default());
- cie.augmentation.as_mut().unwrap().lsda = Some(constants::DwEhPe(
- constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_absptr.0,
- ));
-
- let mut fde = FrameDescriptionEntry {
- offset: 0,
- length: 0,
- format: Format::Dwarf32,
- cie: cie.clone(),
- initial_segment: 0,
- initial_address: 0xfeed_face,
- address_range: 9000,
- augmentation: Some(AugmentationData {
- lsda: Some(Pointer::Direct(0xbeef)),
- }),
- instructions: EndianSlice::new(&instrs, LittleEndian),
- };
-
- let rest = [1, 2, 3, 4];
-
- let kind = eh_frame_le();
- let section = Section::with_endian(kind.endian())
- .append_repeated(10, 10)
- .fde(kind, cie_offset, &mut fde)
- .append_bytes(&rest)
- .get_contents()
- .unwrap();
- let section = kind.section(&section);
- let input = &mut section.section().range_from(10..);
-
- // Adjust the FDE's augmentation to be relative to the function.
- fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef));
-
- let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
- assert_eq!(result, Ok(fde));
- assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
- }
-
- #[test]
- fn test_eh_frame_cie_personality_function_relative_bad_context() {
- let instrs = [1, 2, 3, 4];
-
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let aug_len = Label::new();
- let aug_start = Label::new();
- let aug_end = Label::new();
-
- let section = Section::with_endian(Endian::Little)
- // Length
- .L32(&length)
- .mark(&start)
- // CIE ID
- .L32(0)
- // Version
- .D8(1)
- // Augmentation
- .append_bytes(b"zP\0")
- // Code alignment factor
- .uleb(1)
- // Data alignment factor
- .sleb(1)
- // Return address register
- .uleb(1)
- // Augmentation data length. This is a uleb, be we rely on the value
- // being less than 2^7 and therefore a valid uleb (can't use Label
- // with uleb).
- .D8(&aug_len)
- .mark(&aug_start)
- // Augmentation data. Personality encoding and then encoded pointer.
- .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0)
- .uleb(1)
- .mark(&aug_end)
- // Initial instructions
- .append_bytes(&instrs)
- .mark(&end);
-
- length.set_const((&end - &start) as u64);
- aug_len.set_const((&aug_end - &aug_start) as u64);
-
- let section = section.get_contents().unwrap();
- let section = EhFrame::new(&section, LittleEndian);
-
- let bases = BaseAddresses::default();
- let mut iter = section.entries(&bases);
- assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext));
- }
-
- #[test]
- fn register_rule_map_eq() {
- // Different order, but still equal.
- let map1: RegisterRuleMap<EndianSlice<LittleEndian>> = [
- (Register(0), RegisterRule::SameValue),
- (Register(3), RegisterRule::Offset(1)),
- ]
- .iter()
- .collect();
- let map2: RegisterRuleMap<EndianSlice<LittleEndian>> = [
- (Register(3), RegisterRule::Offset(1)),
- (Register(0), RegisterRule::SameValue),
- ]
- .iter()
- .collect();
- assert_eq!(map1, map2);
- assert_eq!(map2, map1);
-
- // Not equal.
- let map3: RegisterRuleMap<EndianSlice<LittleEndian>> = [
- (Register(0), RegisterRule::SameValue),
- (Register(2), RegisterRule::Offset(1)),
- ]
- .iter()
- .collect();
- let map4: RegisterRuleMap<EndianSlice<LittleEndian>> = [
- (Register(3), RegisterRule::Offset(1)),
- (Register(0), RegisterRule::SameValue),
- ]
- .iter()
- .collect();
- assert!(map3 != map4);
- assert!(map4 != map3);
-
- // One has undefined explicitly set, other implicitly has undefined.
- let mut map5 = RegisterRuleMap::<EndianSlice<LittleEndian>>::default();
- map5.set(Register(0), RegisterRule::SameValue).unwrap();
- map5.set(Register(0), RegisterRule::Undefined).unwrap();
- let map6 = RegisterRuleMap::<EndianSlice<LittleEndian>>::default();
- assert_eq!(map5, map6);
- assert_eq!(map6, map5);
- }
-
- #[test]
- fn iter_register_rules() {
- let mut row = UnwindTableRow::<EndianSlice<LittleEndian>>::default();
- row.registers = [
- (Register(0), RegisterRule::SameValue),
- (Register(1), RegisterRule::Offset(1)),
- (Register(2), RegisterRule::ValOffset(2)),
- ]
- .iter()
- .collect();
-
- let mut found0 = false;
- let mut found1 = false;
- let mut found2 = false;
-
- for &(register, ref rule) in row.registers() {
- match register.0 {
- 0 => {
- assert_eq!(found0, false);
- found0 = true;
- assert_eq!(*rule, RegisterRule::SameValue);
- }
- 1 => {
- assert_eq!(found1, false);
- found1 = true;
- assert_eq!(*rule, RegisterRule::Offset(1));
- }
- 2 => {
- assert_eq!(found2, false);
- found2 = true;
- assert_eq!(*rule, RegisterRule::ValOffset(2));
- }
- x => panic!("Unexpected register rule: ({}, {:?})", x, rule),
- }
- }
-
- assert_eq!(found0, true);
- assert_eq!(found1, true);
- assert_eq!(found2, true);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn size_of_unwind_ctx() {
- use core::mem;
- let size = mem::size_of::<UnwindContext<EndianSlice<NativeEndian>>>();
- let max_size = 30968;
- if size > max_size {
- assert_eq!(size, max_size);
- }
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn size_of_register_rule_map() {
- use core::mem;
- let size = mem::size_of::<RegisterRuleMap<EndianSlice<NativeEndian>>>();
- let max_size = 6152;
- if size > max_size {
- assert_eq!(size, max_size);
- }
- }
-
- #[test]
- fn test_parse_pointer_encoding_ok() {
- use crate::endianity::NativeEndian;
- let expected =
- constants::DwEhPe(constants::DW_EH_PE_uleb128.0 | constants::DW_EH_PE_pcrel.0);
- let input = [expected.0, 1, 2, 3, 4];
- let input = &mut EndianSlice::new(&input, NativeEndian);
- assert_eq!(parse_pointer_encoding(input), Ok(expected));
- assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian));
- }
-
- #[test]
- fn test_parse_pointer_encoding_bad_encoding() {
- use crate::endianity::NativeEndian;
- let expected =
- constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0);
- let input = [expected.0, 1, 2, 3, 4];
- let input = &mut EndianSlice::new(&input, NativeEndian);
- assert_eq!(
- Err(Error::UnknownPointerEncoding),
- parse_pointer_encoding(input)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_absptr() {
- let encoding = constants::DW_EH_PE_absptr;
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L32(0xf00d_f00d)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0xf00d_f00d))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_pcrel() {
- let encoding = constants::DW_EH_PE_pcrel;
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .append_repeated(0, 0x10)
- .L32(0x1)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input.range_from(0x10..);
-
- let parameters = PointerEncodingParameters {
- bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame,
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x111))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_pcrel_undefined() {
- let encoding = constants::DW_EH_PE_pcrel;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::PcRelativePointerButSectionBaseIsUndefined)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_textrel() {
- let encoding = constants::DW_EH_PE_textrel;
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L32(0x1)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &BaseAddresses::default().set_text(0x10).eh_frame,
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x11))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_textrel_undefined() {
- let encoding = constants::DW_EH_PE_textrel;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::TextRelativePointerButTextBaseIsUndefined)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_datarel() {
- let encoding = constants::DW_EH_PE_datarel;
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L32(0x1)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &BaseAddresses::default().set_got(0x10).eh_frame,
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x11))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_datarel_undefined() {
- let encoding = constants::DW_EH_PE_datarel;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::DataRelativePointerButDataBaseIsUndefined)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_funcrel() {
- let encoding = constants::DW_EH_PE_funcrel;
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L32(0x1)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: Some(0x10),
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x11))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_funcrel_undefined() {
- let encoding = constants::DW_EH_PE_funcrel;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::FuncRelativePointerInBadContext)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_uleb128() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_uleb128.0);
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .uleb(0x12_3456)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x12_3456))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_udata2() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata2.0);
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L16(0x1234)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x1234))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_udata4() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata4.0);
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L32(0x1234_5678)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x1234_5678))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_udata8() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata8.0);
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .L64(0x1234_5678_1234_5678)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x1234_5678_1234_5678))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_sleb128() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_textrel.0 | constants::DW_EH_PE_sleb128.0);
- let expected_rest = [1, 2, 3, 4];
-
- let input = Section::with_endian(Endian::Little)
- .sleb(-0x1111)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame,
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(0x1111_0000))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_sdata2() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata2.0);
- let expected_rest = [1, 2, 3, 4];
- let expected = 0x111 as i16;
-
- let input = Section::with_endian(Endian::Little)
- .L16(expected as u16)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(expected as u64))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_sdata4() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata4.0);
- let expected_rest = [1, 2, 3, 4];
- let expected = 0x111_1111 as i32;
-
- let input = Section::with_endian(Endian::Little)
- .L32(expected as u32)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(expected as u64))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_sdata8() {
- let encoding =
- constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata8.0);
- let expected_rest = [1, 2, 3, 4];
- let expected = -0x11_1111_1222_2222 as i64;
-
- let input = Section::with_endian(Endian::Little)
- .L64(expected as u64)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Direct(expected as u64))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_encoded_pointer_omit() {
- let encoding = constants::DW_EH_PE_omit;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::CannotParseOmitPointerEncoding)
- );
- assert_eq!(rest, input);
- }
-
- #[test]
- fn test_parse_encoded_pointer_bad_encoding() {
- let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1);
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::UnknownPointerEncoding)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_aligned() {
- // FIXME: support this encoding!
-
- let encoding = constants::DW_EH_PE_aligned;
-
- let input = Section::with_endian(Endian::Little).L32(0x1);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Err(Error::UnsupportedPointerEncoding)
- );
- }
-
- #[test]
- fn test_parse_encoded_pointer_indirect() {
- let expected_rest = [1, 2, 3, 4];
- let encoding = constants::DW_EH_PE_indirect;
-
- let input = Section::with_endian(Endian::Little)
- .L32(0x1234_5678)
- .append_bytes(&expected_rest);
- let input = input.get_contents().unwrap();
- let input = EndianSlice::new(&input, LittleEndian);
- let mut rest = input;
-
- let parameters = PointerEncodingParameters {
- bases: &SectionBaseAddresses::default(),
- func_base: None,
- address_size: 4,
- section: &input,
- };
- assert_eq!(
- parse_encoded_pointer(encoding, &parameters, &mut rest),
- Ok(Pointer::Indirect(0x1234_5678))
- );
- assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
- }
-}
diff --git a/vendor/gimli/src/read/dwarf.rs b/vendor/gimli/src/read/dwarf.rs
deleted file mode 100644
index 2f8dcb3..0000000
--- a/vendor/gimli/src/read/dwarf.rs
+++ /dev/null
@@ -1,1210 +0,0 @@
-use alloc::string::String;
-use alloc::sync::Arc;
-
-use crate::common::{
- DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase,
- DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
- DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwarfFileType, DwoId, Encoding,
- LocationListsOffset, RangeListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset,
-};
-use crate::constants;
-use crate::read::{
- Abbreviations, AbbreviationsCache, AbbreviationsCacheStrategy, AttributeValue, DebugAbbrev,
- DebugAddr, DebugAranges, DebugCuIndex, DebugInfo, DebugInfoUnitHeadersIter, DebugLine,
- DebugLineStr, DebugLoc, DebugLocLists, DebugRngLists, DebugStr, DebugStrOffsets, DebugTuIndex,
- DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw,
- EntriesTree, Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists,
- RawLocListIter, RawRngListIter, Reader, ReaderOffset, ReaderOffsetId, Result, RngListIter,
- Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, UnitOffset, UnitType,
-};
-
-/// All of the commonly used DWARF sections, and other common information.
-#[derive(Debug, Default)]
-pub struct Dwarf<R> {
- /// The `.debug_abbrev` section.
- pub debug_abbrev: DebugAbbrev<R>,
-
- /// The `.debug_addr` section.
- pub debug_addr: DebugAddr<R>,
-
- /// The `.debug_aranges` section.
- pub debug_aranges: DebugAranges<R>,
-
- /// The `.debug_info` section.
- pub debug_info: DebugInfo<R>,
-
- /// The `.debug_line` section.
- pub debug_line: DebugLine<R>,
-
- /// The `.debug_line_str` section.
- pub debug_line_str: DebugLineStr<R>,
-
- /// The `.debug_str` section.
- pub debug_str: DebugStr<R>,
-
- /// The `.debug_str_offsets` section.
- pub debug_str_offsets: DebugStrOffsets<R>,
-
- /// The `.debug_types` section.
- pub debug_types: DebugTypes<R>,
-
- /// The location lists in the `.debug_loc` and `.debug_loclists` sections.
- pub locations: LocationLists<R>,
-
- /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections.
- pub ranges: RangeLists<R>,
-
- /// The type of this file.
- pub file_type: DwarfFileType,
-
- /// The DWARF sections for a supplementary object file.
- pub sup: Option<Arc<Dwarf<R>>>,
-
- /// A cache of previously parsed abbreviations for units in this file.
- pub abbreviations_cache: AbbreviationsCache,
-}
-
-impl<T> Dwarf<T> {
- /// Try to load the DWARF sections using the given loader function.
- ///
- /// `section` loads a DWARF section from the object file.
- /// It should return an empty section if the section does not exist.
- ///
- /// `section` may either directly return a `Reader` instance (such as
- /// `EndianSlice`), or it may return some other type and then convert
- /// that type into a `Reader` using `Dwarf::borrow`.
- ///
- /// After loading, the user should set the `file_type` field and
- /// call `load_sup` if required.
- pub fn load<F, E>(mut section: F) -> core::result::Result<Self, E>
- where
- F: FnMut(SectionId) -> core::result::Result<T, E>,
- {
- // Section types are inferred.
- let debug_loc = Section::load(&mut section)?;
- let debug_loclists = Section::load(&mut section)?;
- let debug_ranges = Section::load(&mut section)?;
- let debug_rnglists = Section::load(&mut section)?;
- Ok(Dwarf {
- debug_abbrev: Section::load(&mut section)?,
- debug_addr: Section::load(&mut section)?,
- debug_aranges: Section::load(&mut section)?,
- debug_info: Section::load(&mut section)?,
- debug_line: Section::load(&mut section)?,
- debug_line_str: Section::load(&mut section)?,
- debug_str: Section::load(&mut section)?,
- debug_str_offsets: Section::load(&mut section)?,
- debug_types: Section::load(&mut section)?,
- locations: LocationLists::new(debug_loc, debug_loclists),
- ranges: RangeLists::new(debug_ranges, debug_rnglists),
- file_type: DwarfFileType::Main,
- sup: None,
- abbreviations_cache: AbbreviationsCache::new(),
- })
- }
-
- /// Load the DWARF sections from the supplementary object file.
- ///
- /// `section` operates the same as for `load`.
- ///
- /// Sets `self.sup`, replacing any previous value.
- pub fn load_sup<F, E>(&mut self, section: F) -> core::result::Result<(), E>
- where
- F: FnMut(SectionId) -> core::result::Result<T, E>,
- {
- self.sup = Some(Arc::new(Self::load(section)?));
- Ok(())
- }
-
- /// Create a `Dwarf` structure that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// It can be useful to load DWARF sections into owned data structures,
- /// such as `Vec`. However, we do not implement the `Reader` trait
- /// for `Vec`, because it would be very inefficient, but this trait
- /// is required for all of the methods that parse the DWARF data.
- /// So we first load the DWARF sections into `Vec`s, and then use
- /// `borrow` to create `Reader`s that reference the data.
- ///
- /// ```rust,no_run
- /// # fn example() -> Result<(), gimli::Error> {
- /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() };
- /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() };
- /// // Read the DWARF sections into `Vec`s with whatever object loader you're using.
- /// let mut owned_dwarf: gimli::Dwarf<Vec<u8>> = gimli::Dwarf::load(loader)?;
- /// owned_dwarf.load_sup(sup_loader)?;
- /// // Create references to the DWARF sections.
- /// let dwarf = owned_dwarf.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// # unreachable!()
- /// # }
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R>
- where
- F: FnMut(&'a T) -> R,
- {
- Dwarf {
- debug_abbrev: self.debug_abbrev.borrow(&mut borrow),
- debug_addr: self.debug_addr.borrow(&mut borrow),
- debug_aranges: self.debug_aranges.borrow(&mut borrow),
- debug_info: self.debug_info.borrow(&mut borrow),
- debug_line: self.debug_line.borrow(&mut borrow),
- debug_line_str: self.debug_line_str.borrow(&mut borrow),
- debug_str: self.debug_str.borrow(&mut borrow),
- debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow),
- debug_types: self.debug_types.borrow(&mut borrow),
- locations: self.locations.borrow(&mut borrow),
- ranges: self.ranges.borrow(&mut borrow),
- file_type: self.file_type,
- sup: self.sup().map(|sup| Arc::new(sup.borrow(borrow))),
- abbreviations_cache: AbbreviationsCache::new(),
- }
- }
-
- /// Return a reference to the DWARF sections for supplementary object file.
- pub fn sup(&self) -> Option<&Dwarf<T>> {
- self.sup.as_ref().map(Arc::as_ref)
- }
-}
-
-impl<R: Reader> Dwarf<R> {
- /// Parse abbreviations and store them in the cache.
- ///
- /// This will iterate over the units in `self.debug_info` to determine the
- /// abbreviations offsets.
- ///
- /// Errors during parsing abbreviations are also stored in the cache.
- /// Errors during iterating over the units are ignored.
- pub fn populate_abbreviations_cache(&mut self, strategy: AbbreviationsCacheStrategy) {
- self.abbreviations_cache
- .populate(strategy, &self.debug_abbrev, self.debug_info.units());
- }
-
- /// Iterate the unit headers in the `.debug_info` section.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- #[inline]
- pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
- self.debug_info.units()
- }
-
- /// Construct a new `Unit` from the given unit header.
- #[inline]
- pub fn unit(&self, header: UnitHeader<R>) -> Result<Unit<R>> {
- Unit::new(self, header)
- }
-
- /// Iterate the type-unit headers in the `.debug_types` section.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- #[inline]
- pub fn type_units(&self) -> DebugTypesUnitHeadersIter<R> {
- self.debug_types.units()
- }
-
- /// Parse the abbreviations for a compilation unit.
- #[inline]
- pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Arc<Abbreviations>> {
- self.abbreviations_cache
- .get(&self.debug_abbrev, unit.debug_abbrev_offset())
- }
-
- /// Return the string offset at the given index.
- #[inline]
- pub fn string_offset(
- &self,
- unit: &Unit<R>,
- index: DebugStrOffsetsIndex<R::Offset>,
- ) -> Result<DebugStrOffset<R::Offset>> {
- self.debug_str_offsets
- .get_str_offset(unit.header.format(), unit.str_offsets_base, index)
- }
-
- /// Return the string at the given offset in `.debug_str`.
- #[inline]
- pub fn string(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
- self.debug_str.get_str(offset)
- }
-
- /// Return the string at the given offset in `.debug_line_str`.
- #[inline]
- pub fn line_string(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
- self.debug_line_str.get_str(offset)
- }
-
- /// Return an attribute value as a string slice.
- ///
- /// If the attribute value is one of:
- ///
- /// - an inline `DW_FORM_string` string
- /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section
- /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary
- /// object file
- /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str`
- /// section
- /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit
- ///
- /// then return the attribute's string value. Returns an error if the attribute
- /// value does not have a string form, or if a string form has an invalid value.
- pub fn attr_string(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<R> {
- match attr {
- AttributeValue::String(string) => Ok(string),
- AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset),
- AttributeValue::DebugStrRefSup(offset) => {
- if let Some(sup) = self.sup() {
- sup.debug_str.get_str(offset)
- } else {
- Err(Error::ExpectedStringAttributeValue)
- }
- }
- AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset),
- AttributeValue::DebugStrOffsetsIndex(index) => {
- let offset = self.debug_str_offsets.get_str_offset(
- unit.header.format(),
- unit.str_offsets_base,
- index,
- )?;
- self.debug_str.get_str(offset)
- }
- _ => Err(Error::ExpectedStringAttributeValue),
- }
- }
-
- /// Return the address at the given index.
- pub fn address(&self, unit: &Unit<R>, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
- self.debug_addr
- .get_address(unit.encoding().address_size, unit.addr_base, index)
- }
-
- /// Try to return an attribute value as an address.
- ///
- /// If the attribute value is one of:
- ///
- /// - a `DW_FORM_addr`
- /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit
- ///
- /// then return the address.
- /// Returns `None` for other forms.
- pub fn attr_address(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<Option<u64>> {
- match attr {
- AttributeValue::Addr(addr) => Ok(Some(addr)),
- AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some),
- _ => Ok(None),
- }
- }
-
- /// Return the range list offset for the given raw offset.
- ///
- /// This handles adding `DW_AT_GNU_ranges_base` if required.
- pub fn ranges_offset_from_raw(
- &self,
- unit: &Unit<R>,
- offset: RawRangeListsOffset<R::Offset>,
- ) -> RangeListsOffset<R::Offset> {
- if self.file_type == DwarfFileType::Dwo && unit.header.version() < 5 {
- RangeListsOffset(offset.0.wrapping_add(unit.rnglists_base.0))
- } else {
- RangeListsOffset(offset.0)
- }
- }
-
- /// Return the range list offset at the given index.
- pub fn ranges_offset(
- &self,
- unit: &Unit<R>,
- index: DebugRngListsIndex<R::Offset>,
- ) -> Result<RangeListsOffset<R::Offset>> {
- self.ranges
- .get_offset(unit.encoding(), unit.rnglists_base, index)
- }
-
- /// Iterate over the `RangeListEntry`s starting at the given offset.
- pub fn ranges(
- &self,
- unit: &Unit<R>,
- offset: RangeListsOffset<R::Offset>,
- ) -> Result<RngListIter<R>> {
- self.ranges.ranges(
- offset,
- unit.encoding(),
- unit.low_pc,
- &self.debug_addr,
- unit.addr_base,
- )
- }
-
- /// Iterate over the `RawRngListEntry`ies starting at the given offset.
- pub fn raw_ranges(
- &self,
- unit: &Unit<R>,
- offset: RangeListsOffset<R::Offset>,
- ) -> Result<RawRngListIter<R>> {
- self.ranges.raw_ranges(offset, unit.encoding())
- }
-
- /// Try to return an attribute value as a range list offset.
- ///
- /// If the attribute value is one of:
- ///
- /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections
- /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit
- ///
- /// then return the range list offset of the range list.
- /// Returns `None` for other forms.
- pub fn attr_ranges_offset(
- &self,
- unit: &Unit<R>,
- attr: AttributeValue<R>,
- ) -> Result<Option<RangeListsOffset<R::Offset>>> {
- match attr {
- AttributeValue::RangeListsRef(offset) => {
- Ok(Some(self.ranges_offset_from_raw(unit, offset)))
- }
- AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some),
- _ => Ok(None),
- }
- }
-
- /// Try to return an attribute value as a range list entry iterator.
- ///
- /// If the attribute value is one of:
- ///
- /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections
- /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit
- ///
- /// then return an iterator over the entries in the range list.
- /// Returns `None` for other forms.
- pub fn attr_ranges(
- &self,
- unit: &Unit<R>,
- attr: AttributeValue<R>,
- ) -> Result<Option<RngListIter<R>>> {
- match self.attr_ranges_offset(unit, attr)? {
- Some(offset) => Ok(Some(self.ranges(unit, offset)?)),
- None => Ok(None),
- }
- }
-
- /// Return an iterator for the address ranges of a `DebuggingInformationEntry`.
- ///
- /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`.
- pub fn die_ranges(
- &self,
- unit: &Unit<R>,
- entry: &DebuggingInformationEntry<R>,
- ) -> Result<RangeIter<R>> {
- let mut low_pc = None;
- let mut high_pc = None;
- let mut size = None;
- let mut attrs = entry.attrs();
- while let Some(attr) = attrs.next()? {
- match attr.name() {
- constants::DW_AT_low_pc => {
- low_pc = Some(
- self.attr_address(unit, attr.value())?
- .ok_or(Error::UnsupportedAttributeForm)?,
- );
- }
- constants::DW_AT_high_pc => match attr.value() {
- AttributeValue::Udata(val) => size = Some(val),
- attr => {
- high_pc = Some(
- self.attr_address(unit, attr)?
- .ok_or(Error::UnsupportedAttributeForm)?,
- );
- }
- },
- constants::DW_AT_ranges => {
- if let Some(list) = self.attr_ranges(unit, attr.value())? {
- return Ok(RangeIter(RangeIterInner::List(list)));
- }
- }
- _ => {}
- }
- }
- let range = low_pc.and_then(|begin| {
- let end = size.map(|size| begin + size).or(high_pc);
- // TODO: perhaps return an error if `end` is `None`
- end.map(|end| Range { begin, end })
- });
- Ok(RangeIter(RangeIterInner::Single(range)))
- }
-
- /// Return an iterator for the address ranges of a `Unit`.
- ///
- /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the
- /// root `DebuggingInformationEntry`.
- pub fn unit_ranges(&self, unit: &Unit<R>) -> Result<RangeIter<R>> {
- let mut cursor = unit.header.entries(&unit.abbreviations);
- cursor.next_dfs()?;
- let root = cursor.current().ok_or(Error::MissingUnitDie)?;
- self.die_ranges(unit, root)
- }
-
- /// Return the location list offset at the given index.
- pub fn locations_offset(
- &self,
- unit: &Unit<R>,
- index: DebugLocListsIndex<R::Offset>,
- ) -> Result<LocationListsOffset<R::Offset>> {
- self.locations
- .get_offset(unit.encoding(), unit.loclists_base, index)
- }
-
- /// Iterate over the `LocationListEntry`s starting at the given offset.
- pub fn locations(
- &self,
- unit: &Unit<R>,
- offset: LocationListsOffset<R::Offset>,
- ) -> Result<LocListIter<R>> {
- match self.file_type {
- DwarfFileType::Main => self.locations.locations(
- offset,
- unit.encoding(),
- unit.low_pc,
- &self.debug_addr,
- unit.addr_base,
- ),
- DwarfFileType::Dwo => self.locations.locations_dwo(
- offset,
- unit.encoding(),
- unit.low_pc,
- &self.debug_addr,
- unit.addr_base,
- ),
- }
- }
-
- /// Iterate over the raw `LocationListEntry`s starting at the given offset.
- pub fn raw_locations(
- &self,
- unit: &Unit<R>,
- offset: LocationListsOffset<R::Offset>,
- ) -> Result<RawLocListIter<R>> {
- match self.file_type {
- DwarfFileType::Main => self.locations.raw_locations(offset, unit.encoding()),
- DwarfFileType::Dwo => self.locations.raw_locations_dwo(offset, unit.encoding()),
- }
- }
-
- /// Try to return an attribute value as a location list offset.
- ///
- /// If the attribute value is one of:
- ///
- /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections
- /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit
- ///
- /// then return the location list offset of the location list.
- /// Returns `None` for other forms.
- pub fn attr_locations_offset(
- &self,
- unit: &Unit<R>,
- attr: AttributeValue<R>,
- ) -> Result<Option<LocationListsOffset<R::Offset>>> {
- match attr {
- AttributeValue::LocationListsRef(offset) => Ok(Some(offset)),
- AttributeValue::DebugLocListsIndex(index) => {
- self.locations_offset(unit, index).map(Some)
- }
- _ => Ok(None),
- }
- }
-
- /// Try to return an attribute value as a location list entry iterator.
- ///
- /// If the attribute value is one of:
- ///
- /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections
- /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit
- ///
- /// then return an iterator over the entries in the location list.
- /// Returns `None` for other forms.
- pub fn attr_locations(
- &self,
- unit: &Unit<R>,
- attr: AttributeValue<R>,
- ) -> Result<Option<LocListIter<R>>> {
- match self.attr_locations_offset(unit, attr)? {
- Some(offset) => Ok(Some(self.locations(unit, offset)?)),
- None => Ok(None),
- }
- }
-
- /// Call `Reader::lookup_offset_id` for each section, and return the first match.
- ///
- /// The first element of the tuple is `true` for supplementary sections.
- pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> {
- None.or_else(|| self.debug_abbrev.lookup_offset_id(id))
- .or_else(|| self.debug_addr.lookup_offset_id(id))
- .or_else(|| self.debug_aranges.lookup_offset_id(id))
- .or_else(|| self.debug_info.lookup_offset_id(id))
- .or_else(|| self.debug_line.lookup_offset_id(id))
- .or_else(|| self.debug_line_str.lookup_offset_id(id))
- .or_else(|| self.debug_str.lookup_offset_id(id))
- .or_else(|| self.debug_str_offsets.lookup_offset_id(id))
- .or_else(|| self.debug_types.lookup_offset_id(id))
- .or_else(|| self.locations.lookup_offset_id(id))
- .or_else(|| self.ranges.lookup_offset_id(id))
- .map(|(id, offset)| (false, id, offset))
- .or_else(|| {
- self.sup()
- .and_then(|sup| sup.lookup_offset_id(id))
- .map(|(_, id, offset)| (true, id, offset))
- })
- }
-
- /// Returns a string representation of the given error.
- ///
- /// This uses information from the DWARF sections to provide more information in some cases.
- pub fn format_error(&self, err: Error) -> String {
- #[allow(clippy::single_match)]
- match err {
- Error::UnexpectedEof(id) => match self.lookup_offset_id(id) {
- Some((sup, section, offset)) => {
- return format!(
- "{} at {}{}+0x{:x}",
- err,
- section.name(),
- if sup { "(sup)" } else { "" },
- offset.into_u64(),
- );
- }
- None => {}
- },
- _ => {}
- }
- err.description().into()
- }
-}
-
-impl<R: Clone> Dwarf<R> {
- /// Assuming `self` was loaded from a .dwo, take the appropriate
- /// sections from `parent` (which contains the skeleton unit for this
- /// dwo) such as `.debug_addr` and merge them into this `Dwarf`.
- pub fn make_dwo(&mut self, parent: &Dwarf<R>) {
- self.file_type = DwarfFileType::Dwo;
- // These sections are always taken from the parent file and not the dwo.
- self.debug_addr = parent.debug_addr.clone();
- // .debug_rnglists comes from the DWO, .debug_ranges comes from the
- // parent file.
- self.ranges
- .set_debug_ranges(parent.ranges.debug_ranges().clone());
- self.sup = parent.sup.clone();
- }
-}
-
-/// The sections from a `.dwp` file.
-#[derive(Debug)]
-pub struct DwarfPackage<R: Reader> {
- /// The compilation unit index in the `.debug_cu_index` section.
- pub cu_index: UnitIndex<R>,
-
- /// The type unit index in the `.debug_tu_index` section.
- pub tu_index: UnitIndex<R>,
-
- /// The `.debug_abbrev.dwo` section.
- pub debug_abbrev: DebugAbbrev<R>,
-
- /// The `.debug_info.dwo` section.
- pub debug_info: DebugInfo<R>,
-
- /// The `.debug_line.dwo` section.
- pub debug_line: DebugLine<R>,
-
- /// The `.debug_str.dwo` section.
- pub debug_str: DebugStr<R>,
-
- /// The `.debug_str_offsets.dwo` section.
- pub debug_str_offsets: DebugStrOffsets<R>,
-
- /// The `.debug_loc.dwo` section.
- ///
- /// Only present when using GNU split-dwarf extension to DWARF 4.
- pub debug_loc: DebugLoc<R>,
-
- /// The `.debug_loclists.dwo` section.
- pub debug_loclists: DebugLocLists<R>,
-
- /// The `.debug_rnglists.dwo` section.
- pub debug_rnglists: DebugRngLists<R>,
-
- /// The `.debug_types.dwo` section.
- ///
- /// Only present when using GNU split-dwarf extension to DWARF 4.
- pub debug_types: DebugTypes<R>,
-
- /// An empty section.
- ///
- /// Used when creating `Dwarf<R>`.
- pub empty: R,
-}
-
-impl<R: Reader> DwarfPackage<R> {
- /// Try to load the `.dwp` sections using the given loader function.
- ///
- /// `section` loads a DWARF section from the object file.
- /// It should return an empty section if the section does not exist.
- pub fn load<F, E>(mut section: F, empty: R) -> core::result::Result<Self, E>
- where
- F: FnMut(SectionId) -> core::result::Result<R, E>,
- E: From<Error>,
- {
- Ok(DwarfPackage {
- cu_index: DebugCuIndex::load(&mut section)?.index()?,
- tu_index: DebugTuIndex::load(&mut section)?.index()?,
- // Section types are inferred.
- debug_abbrev: Section::load(&mut section)?,
- debug_info: Section::load(&mut section)?,
- debug_line: Section::load(&mut section)?,
- debug_str: Section::load(&mut section)?,
- debug_str_offsets: Section::load(&mut section)?,
- debug_loc: Section::load(&mut section)?,
- debug_loclists: Section::load(&mut section)?,
- debug_rnglists: Section::load(&mut section)?,
- debug_types: Section::load(&mut section)?,
- empty,
- })
- }
-
- /// Find the compilation unit with the given DWO identifier and return its section
- /// contributions.
- pub fn find_cu(&self, id: DwoId, parent: &Dwarf<R>) -> Result<Option<Dwarf<R>>> {
- let row = match self.cu_index.find(id.0) {
- Some(row) => row,
- None => return Ok(None),
- };
- self.cu_sections(row, parent).map(Some)
- }
-
- /// Find the type unit with the given type signature and return its section
- /// contributions.
- pub fn find_tu(
- &self,
- signature: DebugTypeSignature,
- parent: &Dwarf<R>,
- ) -> Result<Option<Dwarf<R>>> {
- let row = match self.tu_index.find(signature.0) {
- Some(row) => row,
- None => return Ok(None),
- };
- self.tu_sections(row, parent).map(Some)
- }
-
- /// Return the section contributions of the compilation unit at the given index.
- ///
- /// The index must be in the range `1..cu_index.unit_count`.
- ///
- /// This function should only be needed by low level parsers.
- pub fn cu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> {
- self.sections(self.cu_index.sections(index)?, parent)
- }
-
- /// Return the section contributions of the compilation unit at the given index.
- ///
- /// The index must be in the range `1..tu_index.unit_count`.
- ///
- /// This function should only be needed by low level parsers.
- pub fn tu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> {
- self.sections(self.tu_index.sections(index)?, parent)
- }
-
- /// Return the section contributions of a unit.
- ///
- /// This function should only be needed by low level parsers.
- pub fn sections(
- &self,
- sections: UnitIndexSectionIterator<R>,
- parent: &Dwarf<R>,
- ) -> Result<Dwarf<R>> {
- let mut abbrev_offset = 0;
- let mut abbrev_size = 0;
- let mut info_offset = 0;
- let mut info_size = 0;
- let mut line_offset = 0;
- let mut line_size = 0;
- let mut loc_offset = 0;
- let mut loc_size = 0;
- let mut loclists_offset = 0;
- let mut loclists_size = 0;
- let mut str_offsets_offset = 0;
- let mut str_offsets_size = 0;
- let mut rnglists_offset = 0;
- let mut rnglists_size = 0;
- let mut types_offset = 0;
- let mut types_size = 0;
- for section in sections {
- match section.section {
- SectionId::DebugAbbrev => {
- abbrev_offset = section.offset;
- abbrev_size = section.size;
- }
- SectionId::DebugInfo => {
- info_offset = section.offset;
- info_size = section.size;
- }
- SectionId::DebugLine => {
- line_offset = section.offset;
- line_size = section.size;
- }
- SectionId::DebugLoc => {
- loc_offset = section.offset;
- loc_size = section.size;
- }
- SectionId::DebugLocLists => {
- loclists_offset = section.offset;
- loclists_size = section.size;
- }
- SectionId::DebugStrOffsets => {
- str_offsets_offset = section.offset;
- str_offsets_size = section.size;
- }
- SectionId::DebugRngLists => {
- rnglists_offset = section.offset;
- rnglists_size = section.size;
- }
- SectionId::DebugTypes => {
- types_offset = section.offset;
- types_size = section.size;
- }
- SectionId::DebugMacro | SectionId::DebugMacinfo => {
- // These are valid but we can't parse these yet.
- }
- _ => return Err(Error::UnknownIndexSection),
- }
- }
-
- let debug_abbrev = self.debug_abbrev.dwp_range(abbrev_offset, abbrev_size)?;
- let debug_info = self.debug_info.dwp_range(info_offset, info_size)?;
- let debug_line = self.debug_line.dwp_range(line_offset, line_size)?;
- let debug_loc = self.debug_loc.dwp_range(loc_offset, loc_size)?;
- let debug_loclists = self
- .debug_loclists
- .dwp_range(loclists_offset, loclists_size)?;
- let debug_str_offsets = self
- .debug_str_offsets
- .dwp_range(str_offsets_offset, str_offsets_size)?;
- let debug_rnglists = self
- .debug_rnglists
- .dwp_range(rnglists_offset, rnglists_size)?;
- let debug_types = self.debug_types.dwp_range(types_offset, types_size)?;
-
- let debug_str = self.debug_str.clone();
-
- let debug_addr = parent.debug_addr.clone();
- let debug_ranges = parent.ranges.debug_ranges().clone();
-
- let debug_aranges = self.empty.clone().into();
- let debug_line_str = self.empty.clone().into();
-
- Ok(Dwarf {
- debug_abbrev,
- debug_addr,
- debug_aranges,
- debug_info,
- debug_line,
- debug_line_str,
- debug_str,
- debug_str_offsets,
- debug_types,
- locations: LocationLists::new(debug_loc, debug_loclists),
- ranges: RangeLists::new(debug_ranges, debug_rnglists),
- file_type: DwarfFileType::Dwo,
- sup: parent.sup.clone(),
- abbreviations_cache: AbbreviationsCache::new(),
- })
- }
-}
-
-/// All of the commonly used information for a unit in the `.debug_info` or `.debug_types`
-/// sections.
-#[derive(Debug)]
-pub struct Unit<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// The header of the unit.
- pub header: UnitHeader<R, Offset>,
-
- /// The parsed abbreviations for the unit.
- pub abbreviations: Arc<Abbreviations>,
-
- /// The `DW_AT_name` attribute of the unit.
- pub name: Option<R>,
-
- /// The `DW_AT_comp_dir` attribute of the unit.
- pub comp_dir: Option<R>,
-
- /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0.
- pub low_pc: u64,
-
- /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0.
- pub str_offsets_base: DebugStrOffsetsBase<Offset>,
-
- /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0.
- pub addr_base: DebugAddrBase<Offset>,
-
- /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0.
- pub loclists_base: DebugLocListsBase<Offset>,
-
- /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0.
- pub rnglists_base: DebugRngListsBase<Offset>,
-
- /// The line number program of the unit.
- pub line_program: Option<IncompleteLineProgram<R, Offset>>,
-
- /// The DWO ID of a skeleton unit or split compilation unit.
- pub dwo_id: Option<DwoId>,
-}
-
-impl<R: Reader> Unit<R> {
- /// Construct a new `Unit` from the given unit header.
- #[inline]
- pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> {
- let abbreviations = dwarf.abbreviations(&header)?;
- Self::new_with_abbreviations(dwarf, header, abbreviations)
- }
-
- /// Construct a new `Unit` from the given unit header and abbreviations.
- ///
- /// The abbreviations for this call can be obtained using `dwarf.abbreviations(&header)`.
- /// The caller may implement caching to reuse the `Abbreviations` across units with the
- /// same `header.debug_abbrev_offset()` value.
- #[inline]
- pub fn new_with_abbreviations(
- dwarf: &Dwarf<R>,
- header: UnitHeader<R>,
- abbreviations: Arc<Abbreviations>,
- ) -> Result<Self> {
- let mut unit = Unit {
- abbreviations,
- name: None,
- comp_dir: None,
- low_pc: 0,
- str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file(
- header.encoding(),
- dwarf.file_type,
- ),
- // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided.
- addr_base: DebugAddrBase(R::Offset::from_u8(0)),
- loclists_base: DebugLocListsBase::default_for_encoding_and_file(
- header.encoding(),
- dwarf.file_type,
- ),
- rnglists_base: DebugRngListsBase::default_for_encoding_and_file(
- header.encoding(),
- dwarf.file_type,
- ),
- line_program: None,
- dwo_id: match header.type_() {
- UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => Some(dwo_id),
- _ => None,
- },
- header,
- };
- let mut name = None;
- let mut comp_dir = None;
- let mut line_program_offset = None;
- let mut low_pc_attr = None;
-
- {
- let mut cursor = unit.header.entries(&unit.abbreviations);
- cursor.next_dfs()?;
- let root = cursor.current().ok_or(Error::MissingUnitDie)?;
- let mut attrs = root.attrs();
- while let Some(attr) = attrs.next()? {
- match attr.name() {
- constants::DW_AT_name => {
- name = Some(attr.value());
- }
- constants::DW_AT_comp_dir => {
- comp_dir = Some(attr.value());
- }
- constants::DW_AT_low_pc => {
- low_pc_attr = Some(attr.value());
- }
- constants::DW_AT_stmt_list => {
- if let AttributeValue::DebugLineRef(offset) = attr.value() {
- line_program_offset = Some(offset);
- }
- }
- constants::DW_AT_str_offsets_base => {
- if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() {
- unit.str_offsets_base = base;
- }
- }
- constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
- if let AttributeValue::DebugAddrBase(base) = attr.value() {
- unit.addr_base = base;
- }
- }
- constants::DW_AT_loclists_base => {
- if let AttributeValue::DebugLocListsBase(base) = attr.value() {
- unit.loclists_base = base;
- }
- }
- constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
- if let AttributeValue::DebugRngListsBase(base) = attr.value() {
- unit.rnglists_base = base;
- }
- }
- constants::DW_AT_GNU_dwo_id => {
- if unit.dwo_id.is_none() {
- if let AttributeValue::DwoId(dwo_id) = attr.value() {
- unit.dwo_id = Some(dwo_id);
- }
- }
- }
- _ => {}
- }
- }
- }
-
- unit.name = match name {
- Some(val) => dwarf.attr_string(&unit, val).ok(),
- None => None,
- };
- unit.comp_dir = match comp_dir {
- Some(val) => dwarf.attr_string(&unit, val).ok(),
- None => None,
- };
- unit.line_program = match line_program_offset {
- Some(offset) => Some(dwarf.debug_line.program(
- offset,
- unit.header.address_size(),
- unit.comp_dir.clone(),
- unit.name.clone(),
- )?),
- None => None,
- };
- if let Some(low_pc_attr) = low_pc_attr {
- if let Some(addr) = dwarf.attr_address(&unit, low_pc_attr)? {
- unit.low_pc = addr;
- }
- }
- Ok(unit)
- }
-
- /// Return the encoding parameters for this unit.
- #[inline]
- pub fn encoding(&self) -> Encoding {
- self.header.encoding()
- }
-
- /// Read the `DebuggingInformationEntry` at the given offset.
- pub fn entry(&self, offset: UnitOffset<R::Offset>) -> Result<DebuggingInformationEntry<R>> {
- self.header.entry(&self.abbreviations, offset)
- }
-
- /// Navigate this unit's `DebuggingInformationEntry`s.
- #[inline]
- pub fn entries(&self) -> EntriesCursor<R> {
- self.header.entries(&self.abbreviations)
- }
-
- /// Navigate this unit's `DebuggingInformationEntry`s
- /// starting at the given offset.
- #[inline]
- pub fn entries_at_offset(&self, offset: UnitOffset<R::Offset>) -> Result<EntriesCursor<R>> {
- self.header.entries_at_offset(&self.abbreviations, offset)
- }
-
- /// Navigate this unit's `DebuggingInformationEntry`s as a tree
- /// starting at the given offset.
- #[inline]
- pub fn entries_tree(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesTree<R>> {
- self.header.entries_tree(&self.abbreviations, offset)
- }
-
- /// Read the raw data that defines the Debugging Information Entries.
- #[inline]
- pub fn entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>> {
- self.header.entries_raw(&self.abbreviations, offset)
- }
-
- /// Copy attributes that are subject to relocation from another unit. This is intended
- /// to be used to copy attributes from a skeleton compilation unit to the corresponding
- /// split compilation unit.
- pub fn copy_relocated_attributes(&mut self, other: &Unit<R>) {
- self.low_pc = other.low_pc;
- self.addr_base = other.addr_base;
- if self.header.version() < 5 {
- self.rnglists_base = other.rnglists_base;
- }
- }
-
- /// Find the dwo name (if any) for this unit, automatically handling the differences
- /// between the standardized DWARF 5 split DWARF format and the pre-DWARF 5 GNU
- /// extension.
- ///
- /// The returned value is relative to this unit's `comp_dir`.
- pub fn dwo_name(&self) -> Result<Option<AttributeValue<R>>> {
- let mut entries = self.entries();
- if let None = entries.next_entry()? {
- return Ok(None);
- }
-
- let entry = entries.current().unwrap();
- if self.header.version() < 5 {
- entry.attr_value(constants::DW_AT_GNU_dwo_name)
- } else {
- entry.attr_value(constants::DW_AT_dwo_name)
- }
- }
-}
-
-impl<T: ReaderOffset> UnitSectionOffset<T> {
- /// Convert an offset to be relative to the start of the given unit,
- /// instead of relative to the start of the section.
- /// Returns `None` if the offset is not within the unit entries.
- pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>>
- where
- R: Reader<Offset = T>,
- {
- let (offset, unit_offset) = match (self, unit.header.offset()) {
- (
- UnitSectionOffset::DebugInfoOffset(offset),
- UnitSectionOffset::DebugInfoOffset(unit_offset),
- ) => (offset.0, unit_offset.0),
- (
- UnitSectionOffset::DebugTypesOffset(offset),
- UnitSectionOffset::DebugTypesOffset(unit_offset),
- ) => (offset.0, unit_offset.0),
- _ => return None,
- };
- let offset = match offset.checked_sub(unit_offset) {
- Some(offset) => UnitOffset(offset),
- None => return None,
- };
- if !unit.header.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 compilation unit.
- ///
- /// Does not check that the offset is valid.
- pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T>
- where
- R: Reader<Offset = T>,
- {
- match unit.header.offset() {
- UnitSectionOffset::DebugInfoOffset(unit_offset) => {
- DebugInfoOffset(unit_offset.0 + self.0).into()
- }
- UnitSectionOffset::DebugTypesOffset(unit_offset) => {
- DebugTypesOffset(unit_offset.0 + self.0).into()
- }
- }
- }
-}
-
-/// An iterator for the address ranges of a `DebuggingInformationEntry`.
-///
-/// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`.
-#[derive(Debug)]
-pub struct RangeIter<R: Reader>(RangeIterInner<R>);
-
-#[derive(Debug)]
-enum RangeIterInner<R: Reader> {
- Single(Option<Range>),
- List(RngListIter<R>),
-}
-
-impl<R: Reader> Default for RangeIter<R> {
- fn default() -> Self {
- RangeIter(RangeIterInner::Single(None))
- }
-}
-
-impl<R: Reader> RangeIter<R> {
- /// Advance the iterator to the next range.
- pub fn next(&mut self) -> Result<Option<Range>> {
- match self.0 {
- RangeIterInner::Single(ref mut range) => Ok(range.take()),
- RangeIterInner::List(ref mut list) => list.next(),
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for RangeIter<R> {
- type Item = Range;
- type Error = Error;
-
- #[inline]
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- RangeIter::next(self)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::read::EndianSlice;
- use crate::{Endianity, LittleEndian};
-
- /// Ensure that `Dwarf<R>` is covariant wrt R.
- #[test]
- fn test_dwarf_variance() {
- /// This only needs to compile.
- fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf<EndianSlice<'a, E>>) -> Dwarf<EndianSlice<'b, E>> {
- x
- }
- }
-
- /// Ensure that `Unit<R>` is covariant wrt R.
- #[test]
- fn test_dwarf_unit_variance() {
- /// This only needs to compile.
- fn _f<'a: 'b, 'b, E: Endianity>(x: Unit<EndianSlice<'a, E>>) -> Unit<EndianSlice<'b, E>> {
- x
- }
- }
-
- #[test]
- fn test_send() {
- fn assert_is_send<T: Send>() {}
- assert_is_send::<Dwarf<EndianSlice<LittleEndian>>>();
- assert_is_send::<Unit<EndianSlice<LittleEndian>>>();
- }
-
- #[test]
- fn test_format_error() {
- let mut owned_dwarf = Dwarf::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap();
- owned_dwarf
- .load_sup(|_| -> Result<_> { Ok(vec![1, 2]) })
- .unwrap();
- let dwarf = owned_dwarf.borrow(|section| EndianSlice::new(&section, LittleEndian));
-
- match dwarf.debug_str.get_str(DebugStrOffset(1)) {
- Ok(r) => panic!("Unexpected str {:?}", r),
- Err(e) => {
- assert_eq!(
- dwarf.format_error(e),
- "Hit the end of input before it was expected at .debug_str+0x1"
- );
- }
- }
- match dwarf.sup().unwrap().debug_str.get_str(DebugStrOffset(1)) {
- Ok(r) => panic!("Unexpected str {:?}", r),
- Err(e) => {
- assert_eq!(
- dwarf.format_error(e),
- "Hit the end of input before it was expected at .debug_str(sup)+0x1"
- );
- }
- }
- assert_eq!(dwarf.format_error(Error::Io), Error::Io.description());
- }
-}
diff --git a/vendor/gimli/src/read/endian_reader.rs b/vendor/gimli/src/read/endian_reader.rs
deleted file mode 100644
index 8852b38..0000000
--- a/vendor/gimli/src/read/endian_reader.rs
+++ /dev/null
@@ -1,639 +0,0 @@
-//! Defining custom `Reader`s quickly.
-
-use alloc::borrow::Cow;
-use alloc::rc::Rc;
-use alloc::string::String;
-use alloc::sync::Arc;
-use core::fmt::Debug;
-use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
-use core::slice;
-use core::str;
-use stable_deref_trait::CloneStableDeref;
-
-use crate::endianity::Endianity;
-use crate::read::{Error, Reader, ReaderOffsetId, Result};
-
-/// A reference counted, non-thread-safe slice of bytes and associated
-/// endianity.
-///
-/// ```
-/// # #[cfg(feature = "std")] {
-/// use std::rc::Rc;
-///
-/// let buf = Rc::from(&[1, 2, 3, 4][..]);
-/// let reader = gimli::EndianRcSlice::new(buf, gimli::NativeEndian);
-/// # let _ = reader;
-/// # }
-/// ```
-pub type EndianRcSlice<Endian> = EndianReader<Endian, Rc<[u8]>>;
-
-/// An atomically reference counted, thread-safe slice of bytes and associated
-/// endianity.
-///
-/// ```
-/// # #[cfg(feature = "std")] {
-/// use std::sync::Arc;
-///
-/// let buf = Arc::from(&[1, 2, 3, 4][..]);
-/// let reader = gimli::EndianArcSlice::new(buf, gimli::NativeEndian);
-/// # let _ = reader;
-/// # }
-/// ```
-pub type EndianArcSlice<Endian> = EndianReader<Endian, Arc<[u8]>>;
-
-/// An easy way to define a custom `Reader` implementation with a reference to a
-/// generic buffer of bytes and an associated endianity.
-///
-/// Note that the whole original buffer is kept alive in memory even if there is
-/// only one reader that references only a handful of bytes from that original
-/// buffer. That is, `EndianReader` will not do any copying, moving, or
-/// compacting in order to free up unused regions of the original buffer. If you
-/// require this kind of behavior, it is up to you to implement `Reader`
-/// directly by-hand.
-///
-/// # Example
-///
-/// Say you have an `mmap`ed file that you want to serve as a `gimli::Reader`.
-/// You can wrap that `mmap`ed file up in a `MmapFile` type and use
-/// `EndianReader<Rc<MmapFile>>` or `EndianReader<Arc<MmapFile>>` as readers as
-/// long as `MmapFile` dereferences to the underlying `[u8]` data.
-///
-/// ```
-/// use std::io;
-/// use std::ops::Deref;
-/// use std::path::Path;
-/// use std::slice;
-/// use std::sync::Arc;
-///
-/// /// A type that represents an `mmap`ed file.
-/// #[derive(Debug)]
-/// pub struct MmapFile {
-/// ptr: *const u8,
-/// len: usize,
-/// }
-///
-/// impl MmapFile {
-/// pub fn new(path: &Path) -> io::Result<MmapFile> {
-/// // Call `mmap` and check for errors and all that...
-/// # unimplemented!()
-/// }
-/// }
-///
-/// impl Drop for MmapFile {
-/// fn drop(&mut self) {
-/// // Call `munmap` to clean up after ourselves...
-/// # unimplemented!()
-/// }
-/// }
-///
-/// // And `MmapFile` can deref to a slice of the `mmap`ed region of memory.
-/// impl Deref for MmapFile {
-/// type Target = [u8];
-/// fn deref(&self) -> &[u8] {
-/// unsafe {
-/// slice::from_raw_parts(self.ptr, self.len)
-/// }
-/// }
-/// }
-///
-/// /// A type that represents a shared `mmap`ed file.
-/// #[derive(Debug, Clone)]
-/// pub struct ArcMmapFile(Arc<MmapFile>);
-///
-/// // And `ArcMmapFile` can deref to a slice of the `mmap`ed region of memory.
-/// impl Deref for ArcMmapFile {
-/// type Target = [u8];
-/// fn deref(&self) -> &[u8] {
-/// &self.0
-/// }
-/// }
-///
-/// // These are both valid for any `Rc` or `Arc`.
-/// unsafe impl gimli::StableDeref for ArcMmapFile {}
-/// unsafe impl gimli::CloneStableDeref for ArcMmapFile {}
-///
-/// /// A `gimli::Reader` that is backed by an `mmap`ed file!
-/// pub type MmapFileReader<Endian> = gimli::EndianReader<Endian, ArcMmapFile>;
-/// # fn test(_: &MmapFileReader<gimli::NativeEndian>) { }
-/// ```
-#[derive(Debug, Clone, Copy, Hash)]
-pub struct EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- range: SubRange<T>,
- endian: Endian,
-}
-
-impl<Endian, T1, T2> PartialEq<EndianReader<Endian, T2>> for EndianReader<Endian, T1>
-where
- Endian: Endianity,
- T1: CloneStableDeref<Target = [u8]> + Debug,
- T2: CloneStableDeref<Target = [u8]> + Debug,
-{
- fn eq(&self, rhs: &EndianReader<Endian, T2>) -> bool {
- self.bytes() == rhs.bytes()
- }
-}
-
-impl<Endian, T> Eq for EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
-}
-
-// This is separated out from `EndianReader` so that we can avoid running afoul
-// of borrowck. We need to `read_slice(&mut self, ...) -> &[u8]` and then call
-// `self.endian.read_whatever` on the result. The problem is that the returned
-// slice keeps the `&mut self` borrow active, so we wouldn't be able to access
-// `self.endian`. Splitting the sub-range out from the endian lets us work
-// around this, making it so that only the `self.range` borrow is held active,
-// not all of `self`.
-//
-// This also serves to encapsulate the unsafe code concerning `CloneStableDeref`.
-// The `bytes` member is held so that the bytes live long enough, and the
-// `CloneStableDeref` ensures these bytes never move. The `ptr` and `len`
-// members point inside `bytes`, and are updated during read operations.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-struct SubRange<T>
-where
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- bytes: T,
- ptr: *const u8,
- len: usize,
-}
-
-unsafe impl<T> Send for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Send {}
-
-unsafe impl<T> Sync for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Sync {}
-
-impl<T> SubRange<T>
-where
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- #[inline]
- fn new(bytes: T) -> Self {
- let ptr = bytes.as_ptr();
- let len = bytes.len();
- SubRange { bytes, ptr, len }
- }
-
- #[inline]
- fn bytes(&self) -> &[u8] {
- // Safe because `T` implements `CloneStableDeref`, `bytes` can't be modified,
- // and all operations that modify `ptr` and `len` ensure they stay in range.
- unsafe { slice::from_raw_parts(self.ptr, self.len) }
- }
-
- #[inline]
- fn len(&self) -> usize {
- self.len
- }
-
- #[inline]
- fn truncate(&mut self, len: usize) {
- assert!(len <= self.len);
- self.len = len;
- }
-
- #[inline]
- fn skip(&mut self, len: usize) {
- assert!(len <= self.len);
- self.ptr = unsafe { self.ptr.add(len) };
- self.len -= len;
- }
-
- #[inline]
- fn read_slice(&mut self, len: usize) -> Option<&[u8]> {
- if self.len() < len {
- None
- } else {
- // Same as for `bytes()`.
- let bytes = unsafe { slice::from_raw_parts(self.ptr, len) };
- self.skip(len);
- Some(bytes)
- }
- }
-}
-
-impl<Endian, T> EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- /// Construct a new `EndianReader` with the given bytes.
- #[inline]
- pub fn new(bytes: T, endian: Endian) -> EndianReader<Endian, T> {
- EndianReader {
- range: SubRange::new(bytes),
- endian,
- }
- }
-
- /// Return a reference to the raw bytes underlying this reader.
- #[inline]
- pub fn bytes(&self) -> &[u8] {
- self.range.bytes()
- }
-}
-
-/// # Range Methods
-///
-/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
-/// implement `Index<Range<usize>>` to return a new `EndianReader` the way we
-/// would like to. Instead, we abandon fancy indexing operators and have these
-/// plain old methods.
-impl<Endian, T> EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- /// Take the given `start..end` range of the underlying buffer and return a
- /// new `EndianReader`.
- ///
- /// ```
- /// # #[cfg(feature = "std")] {
- /// use gimli::{EndianReader, LittleEndian};
- /// use std::sync::Arc;
- ///
- /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]);
- /// let reader = EndianReader::new(buf.clone(), LittleEndian);
- /// assert_eq!(reader.range(1..3),
- /// EndianReader::new(&buf[1..3], LittleEndian));
- /// # }
- /// ```
- ///
- /// # Panics
- ///
- /// Panics if the range is out of bounds.
- pub fn range(&self, idx: Range<usize>) -> EndianReader<Endian, T> {
- let mut r = self.clone();
- r.range.skip(idx.start);
- r.range.truncate(idx.len());
- r
- }
-
- /// Take the given `start..` range of the underlying buffer and return a new
- /// `EndianReader`.
- ///
- /// ```
- /// # #[cfg(feature = "std")] {
- /// use gimli::{EndianReader, LittleEndian};
- /// use std::sync::Arc;
- ///
- /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]);
- /// let reader = EndianReader::new(buf.clone(), LittleEndian);
- /// assert_eq!(reader.range_from(2..),
- /// EndianReader::new(&buf[2..], LittleEndian));
- /// # }
- /// ```
- ///
- /// # Panics
- ///
- /// Panics if the range is out of bounds.
- pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianReader<Endian, T> {
- let mut r = self.clone();
- r.range.skip(idx.start);
- r
- }
-
- /// Take the given `..end` range of the underlying buffer and return a new
- /// `EndianReader`.
- ///
- /// ```
- /// # #[cfg(feature = "std")] {
- /// use gimli::{EndianReader, LittleEndian};
- /// use std::sync::Arc;
- ///
- /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]);
- /// let reader = EndianReader::new(buf.clone(), LittleEndian);
- /// assert_eq!(reader.range_to(..3),
- /// EndianReader::new(&buf[..3], LittleEndian));
- /// # }
- /// ```
- ///
- /// # Panics
- ///
- /// Panics if the range is out of bounds.
- pub fn range_to(&self, idx: RangeTo<usize>) -> EndianReader<Endian, T> {
- let mut r = self.clone();
- r.range.truncate(idx.end);
- r
- }
-}
-
-impl<Endian, T> Index<usize> for EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- type Output = u8;
- fn index(&self, idx: usize) -> &Self::Output {
- &self.bytes()[idx]
- }
-}
-
-impl<Endian, T> Index<RangeFrom<usize>> for EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- type Output = [u8];
- fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
- &self.bytes()[idx]
- }
-}
-
-impl<Endian, T> Deref for EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- type Target = [u8];
- fn deref(&self) -> &Self::Target {
- self.bytes()
- }
-}
-
-impl<Endian, T> Reader for EndianReader<Endian, T>
-where
- Endian: Endianity,
- T: CloneStableDeref<Target = [u8]> + Debug,
-{
- type Endian = Endian;
- type Offset = usize;
-
- #[inline]
- fn endian(&self) -> Endian {
- self.endian
- }
-
- #[inline]
- fn len(&self) -> usize {
- self.range.len()
- }
-
- #[inline]
- fn empty(&mut self) {
- self.range.truncate(0);
- }
-
- #[inline]
- fn truncate(&mut self, len: usize) -> Result<()> {
- if self.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- self.range.truncate(len);
- Ok(())
- }
- }
-
- #[inline]
- fn offset_from(&self, base: &EndianReader<Endian, T>) -> usize {
- let base_ptr = base.bytes().as_ptr() as *const u8 as usize;
- let ptr = self.bytes().as_ptr() as *const u8 as usize;
- debug_assert!(base_ptr <= ptr);
- debug_assert!(ptr + self.bytes().len() <= base_ptr + base.bytes().len());
- ptr - base_ptr
- }
-
- #[inline]
- fn offset_id(&self) -> ReaderOffsetId {
- ReaderOffsetId(self.bytes().as_ptr() as u64)
- }
-
- #[inline]
- fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
- let id = id.0;
- let self_id = self.bytes().as_ptr() as u64;
- let self_len = self.bytes().len() as u64;
- if id >= self_id && id <= self_id + self_len {
- Some((id - self_id) as usize)
- } else {
- None
- }
- }
-
- #[inline]
- fn find(&self, byte: u8) -> Result<usize> {
- self.bytes()
- .iter()
- .position(|x| *x == byte)
- .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
- }
-
- #[inline]
- fn skip(&mut self, len: usize) -> Result<()> {
- if self.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- self.range.skip(len);
- Ok(())
- }
- }
-
- #[inline]
- fn split(&mut self, len: usize) -> Result<Self> {
- if self.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- let mut r = self.clone();
- r.range.truncate(len);
- self.range.skip(len);
- Ok(r)
- }
- }
-
- #[inline]
- fn to_slice(&self) -> Result<Cow<[u8]>> {
- Ok(self.bytes().into())
- }
-
- #[inline]
- fn to_string(&self) -> Result<Cow<str>> {
- match str::from_utf8(self.bytes()) {
- Ok(s) => Ok(s.into()),
- _ => Err(Error::BadUtf8),
- }
- }
-
- #[inline]
- fn to_string_lossy(&self) -> Result<Cow<str>> {
- Ok(String::from_utf8_lossy(self.bytes()))
- }
-
- #[inline]
- fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
- match self.range.read_slice(buf.len()) {
- Some(slice) => {
- buf.copy_from_slice(slice);
- Ok(())
- }
- None => Err(Error::UnexpectedEof(self.offset_id())),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::endianity::NativeEndian;
- use crate::read::Reader;
-
- fn native_reader<T: CloneStableDeref<Target = [u8]> + Debug>(
- bytes: T,
- ) -> EndianReader<NativeEndian, T> {
- EndianReader::new(bytes, NativeEndian)
- }
-
- const BUF: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
-
- #[test]
- fn test_reader_split() {
- let mut reader = native_reader(BUF);
- let left = reader.split(3).unwrap();
- assert_eq!(left, native_reader(&BUF[..3]));
- assert_eq!(reader, native_reader(&BUF[3..]));
- }
-
- #[test]
- fn test_reader_split_out_of_bounds() {
- let mut reader = native_reader(BUF);
- assert!(reader.split(30).is_err());
- }
-
- #[test]
- fn bytes_and_len_and_range_and_eq() {
- let reader = native_reader(BUF);
- assert_eq!(reader.len(), BUF.len());
- assert_eq!(reader.bytes(), BUF);
- assert_eq!(reader, native_reader(BUF));
-
- let range = reader.range(2..8);
- let buf_range = &BUF[2..8];
- assert_eq!(range.len(), buf_range.len());
- assert_eq!(range.bytes(), buf_range);
- assert_ne!(range, native_reader(BUF));
- assert_eq!(range, native_reader(buf_range));
-
- let range_from = range.range_from(1..);
- let buf_range_from = &buf_range[1..];
- assert_eq!(range_from.len(), buf_range_from.len());
- assert_eq!(range_from.bytes(), buf_range_from);
- assert_ne!(range_from, native_reader(BUF));
- assert_eq!(range_from, native_reader(buf_range_from));
-
- let range_to = range_from.range_to(..4);
- let buf_range_to = &buf_range_from[..4];
- assert_eq!(range_to.len(), buf_range_to.len());
- assert_eq!(range_to.bytes(), buf_range_to);
- assert_ne!(range_to, native_reader(BUF));
- assert_eq!(range_to, native_reader(buf_range_to));
- }
-
- #[test]
- fn find() {
- let mut reader = native_reader(BUF);
- reader.skip(2).unwrap();
- assert_eq!(
- reader.find(5),
- Ok(BUF[2..].iter().position(|x| *x == 5).unwrap())
- );
- }
-
- #[test]
- fn indexing() {
- let mut reader = native_reader(BUF);
- reader.skip(2).unwrap();
- assert_eq!(reader[0], BUF[2]);
- }
-
- #[test]
- #[should_panic]
- fn indexing_out_of_bounds() {
- let mut reader = native_reader(BUF);
- reader.skip(2).unwrap();
- let _ = reader[900];
- }
-
- #[test]
- fn endian() {
- let reader = native_reader(BUF);
- assert_eq!(reader.endian(), NativeEndian);
- }
-
- #[test]
- fn empty() {
- let mut reader = native_reader(BUF);
- assert!(!reader.is_empty());
- reader.empty();
- assert!(reader.is_empty());
- assert!(reader.bytes().is_empty());
- }
-
- #[test]
- fn truncate() {
- let reader = native_reader(BUF);
- let mut reader = reader.range(2..8);
- reader.truncate(2).unwrap();
- assert_eq!(reader.bytes(), &BUF[2..4]);
- }
-
- #[test]
- fn offset_from() {
- let reader = native_reader(BUF);
- let sub = reader.range(2..8);
- assert_eq!(sub.offset_from(&reader), 2);
- }
-
- #[test]
- fn skip() {
- let mut reader = native_reader(BUF);
- reader.skip(2).unwrap();
- assert_eq!(reader.bytes(), &BUF[2..]);
- }
-
- #[test]
- fn to_slice() {
- assert_eq!(
- native_reader(BUF).range(2..5).to_slice(),
- Ok(Cow::from(&BUF[2..5]))
- );
- }
-
- #[test]
- fn to_string_ok() {
- let buf = b"hello, world!";
- let reader = native_reader(&buf[..]);
- let reader = reader.range_from(7..);
- assert_eq!(reader.to_string(), Ok(Cow::from("world!")));
- }
-
- // The rocket emoji (🚀 = [0xf0, 0x9f, 0x9a, 0x80]) but rotated left by one
- // to make it invalid UTF-8.
- const BAD_UTF8: &[u8] = &[0x9f, 0x9a, 0x80, 0xf0];
-
- #[test]
- fn to_string_err() {
- let reader = native_reader(BAD_UTF8);
- assert!(reader.to_string().is_err());
- }
-
- #[test]
- fn to_string_lossy() {
- let reader = native_reader(BAD_UTF8);
- assert_eq!(reader.to_string_lossy(), Ok(Cow::from("����")));
- }
-
- #[test]
- fn read_u8_array() {
- let mut reader = native_reader(BAD_UTF8);
- reader.skip(1).unwrap();
- let arr: [u8; 2] = reader.read_u8_array().unwrap();
- assert_eq!(arr, &BAD_UTF8[1..3]);
- assert_eq!(reader.bytes(), &BAD_UTF8[3..]);
- }
-}
diff --git a/vendor/gimli/src/read/endian_slice.rs b/vendor/gimli/src/read/endian_slice.rs
deleted file mode 100644
index 0db28da..0000000
--- a/vendor/gimli/src/read/endian_slice.rs
+++ /dev/null
@@ -1,360 +0,0 @@
-//! Working with byte slices that have an associated endianity.
-
-#[cfg(feature = "read")]
-use alloc::borrow::Cow;
-#[cfg(feature = "read")]
-use alloc::string::String;
-use core::fmt;
-use core::ops::{Deref, Range, RangeFrom, RangeTo};
-use core::str;
-
-use crate::endianity::Endianity;
-use crate::read::{Error, Reader, ReaderOffsetId, Result};
-
-/// A `&[u8]` slice with endianity metadata.
-///
-/// This implements the `Reader` trait, which is used for all reading of DWARF sections.
-#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct EndianSlice<'input, Endian>
-where
- Endian: Endianity,
-{
- slice: &'input [u8],
- endian: Endian,
-}
-
-impl<'input, Endian> EndianSlice<'input, Endian>
-where
- Endian: Endianity,
-{
- /// Construct a new `EndianSlice` with the given slice and endianity.
- #[inline]
- pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> {
- EndianSlice { slice, endian }
- }
-
- /// Return a reference to the raw slice.
- #[inline]
- #[doc(hidden)]
- #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")]
- pub fn buf(&self) -> &'input [u8] {
- self.slice
- }
-
- /// Return a reference to the raw slice.
- #[inline]
- pub fn slice(&self) -> &'input [u8] {
- self.slice
- }
-
- /// Split the slice in two at the given index, resulting in the tuple where
- /// the first item has range [0, idx), and the second has range [idx,
- /// len). Panics if the index is out of bounds.
- #[inline]
- pub fn split_at(
- &self,
- idx: usize,
- ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) {
- (self.range_to(..idx), self.range_from(idx..))
- }
-
- /// Find the first occurrence of a byte in the slice, and return its index.
- #[inline]
- pub fn find(&self, byte: u8) -> Option<usize> {
- self.slice.iter().position(|ch| *ch == byte)
- }
-
- /// Return the offset of the start of the slice relative to the start
- /// of the given slice.
- #[inline]
- pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize {
- let base_ptr = base.slice.as_ptr() as *const u8 as usize;
- let ptr = self.slice.as_ptr() as *const u8 as usize;
- debug_assert!(base_ptr <= ptr);
- debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len());
- ptr - base_ptr
- }
-
- /// Converts the slice to a string using `str::from_utf8`.
- ///
- /// Returns an error if the slice contains invalid characters.
- #[inline]
- pub fn to_string(&self) -> Result<&'input str> {
- str::from_utf8(self.slice).map_err(|_| Error::BadUtf8)
- }
-
- /// Converts the slice to a string, including invalid characters,
- /// using `String::from_utf8_lossy`.
- #[cfg(feature = "read")]
- #[inline]
- pub fn to_string_lossy(&self) -> Cow<'input, str> {
- String::from_utf8_lossy(self.slice)
- }
-
- #[inline]
- fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> {
- if self.slice.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- let val = &self.slice[..len];
- self.slice = &self.slice[len..];
- Ok(val)
- }
- }
-}
-
-/// # Range Methods
-///
-/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
-/// implement `Index<Range<usize>>` to return a new `EndianSlice` the way we would
-/// like to. Instead, we abandon fancy indexing operators and have these plain
-/// old methods.
-impl<'input, Endian> EndianSlice<'input, Endian>
-where
- Endian: Endianity,
-{
- /// Take the given `start..end` range of the underlying slice and return a
- /// new `EndianSlice`.
- ///
- /// ```
- /// use gimli::{EndianSlice, LittleEndian};
- ///
- /// let slice = &[0x01, 0x02, 0x03, 0x04];
- /// let endian_slice = EndianSlice::new(slice, LittleEndian);
- /// assert_eq!(endian_slice.range(1..3),
- /// EndianSlice::new(&slice[1..3], LittleEndian));
- /// ```
- pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> {
- EndianSlice {
- slice: &self.slice[idx],
- endian: self.endian,
- }
- }
-
- /// Take the given `start..` range of the underlying slice and return a new
- /// `EndianSlice`.
- ///
- /// ```
- /// use gimli::{EndianSlice, LittleEndian};
- ///
- /// let slice = &[0x01, 0x02, 0x03, 0x04];
- /// let endian_slice = EndianSlice::new(slice, LittleEndian);
- /// assert_eq!(endian_slice.range_from(2..),
- /// EndianSlice::new(&slice[2..], LittleEndian));
- /// ```
- pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> {
- EndianSlice {
- slice: &self.slice[idx],
- endian: self.endian,
- }
- }
-
- /// Take the given `..end` range of the underlying slice and return a new
- /// `EndianSlice`.
- ///
- /// ```
- /// use gimli::{EndianSlice, LittleEndian};
- ///
- /// let slice = &[0x01, 0x02, 0x03, 0x04];
- /// let endian_slice = EndianSlice::new(slice, LittleEndian);
- /// assert_eq!(endian_slice.range_to(..3),
- /// EndianSlice::new(&slice[..3], LittleEndian));
- /// ```
- pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> {
- EndianSlice {
- slice: &self.slice[idx],
- endian: self.endian,
- }
- }
-}
-
-impl<'input, Endian> Deref for EndianSlice<'input, Endian>
-where
- Endian: Endianity,
-{
- type Target = [u8];
- fn deref(&self) -> &Self::Target {
- self.slice
- }
-}
-
-impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
- fmt.debug_tuple("EndianSlice")
- .field(&self.endian)
- .field(&DebugBytes(self.slice))
- .finish()
- }
-}
-
-struct DebugBytes<'input>(&'input [u8]);
-
-impl<'input> core::fmt::Debug for DebugBytes<'input> {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
- let mut list = fmt.debug_list();
- list.entries(self.0.iter().take(8).copied().map(DebugByte));
- if self.0.len() > 8 {
- list.entry(&DebugLen(self.0.len()));
- }
- list.finish()
- }
-}
-
-struct DebugByte(u8);
-
-impl fmt::Debug for DebugByte {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(fmt, "0x{:02x}", self.0)
- }
-}
-
-struct DebugLen(usize);
-
-impl fmt::Debug for DebugLen {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(fmt, "...; {}", self.0)
- }
-}
-
-impl<'input, Endian> Reader for EndianSlice<'input, Endian>
-where
- Endian: Endianity,
-{
- type Endian = Endian;
- type Offset = usize;
-
- #[inline]
- fn endian(&self) -> Endian {
- self.endian
- }
-
- #[inline]
- fn len(&self) -> usize {
- self.slice.len()
- }
-
- #[inline]
- fn is_empty(&self) -> bool {
- self.slice.is_empty()
- }
-
- #[inline]
- fn empty(&mut self) {
- self.slice = &[];
- }
-
- #[inline]
- fn truncate(&mut self, len: usize) -> Result<()> {
- if self.slice.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- self.slice = &self.slice[..len];
- Ok(())
- }
- }
-
- #[inline]
- fn offset_from(&self, base: &Self) -> usize {
- self.offset_from(*base)
- }
-
- #[inline]
- fn offset_id(&self) -> ReaderOffsetId {
- ReaderOffsetId(self.slice.as_ptr() as u64)
- }
-
- #[inline]
- fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
- let id = id.0;
- let self_id = self.slice.as_ptr() as u64;
- let self_len = self.slice.len() as u64;
- if id >= self_id && id <= self_id + self_len {
- Some((id - self_id) as usize)
- } else {
- None
- }
- }
-
- #[inline]
- fn find(&self, byte: u8) -> Result<usize> {
- self.find(byte)
- .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
- }
-
- #[inline]
- fn skip(&mut self, len: usize) -> Result<()> {
- if self.slice.len() < len {
- Err(Error::UnexpectedEof(self.offset_id()))
- } else {
- self.slice = &self.slice[len..];
- Ok(())
- }
- }
-
- #[inline]
- fn split(&mut self, len: usize) -> Result<Self> {
- let slice = self.read_slice(len)?;
- Ok(EndianSlice::new(slice, self.endian))
- }
-
- #[cfg(not(feature = "read"))]
- fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
- super::reader::seal_if_no_alloc::Sealed
- }
-
- #[cfg(feature = "read")]
- #[inline]
- fn to_slice(&self) -> Result<Cow<[u8]>> {
- Ok(self.slice.into())
- }
-
- #[cfg(feature = "read")]
- #[inline]
- fn to_string(&self) -> Result<Cow<str>> {
- match str::from_utf8(self.slice) {
- Ok(s) => Ok(s.into()),
- _ => Err(Error::BadUtf8),
- }
- }
-
- #[cfg(feature = "read")]
- #[inline]
- fn to_string_lossy(&self) -> Result<Cow<str>> {
- Ok(String::from_utf8_lossy(self.slice))
- }
-
- #[inline]
- fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
- let slice = self.read_slice(buf.len())?;
- buf.copy_from_slice(slice);
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::endianity::NativeEndian;
-
- #[test]
- fn test_endian_slice_split_at() {
- let endian = NativeEndian;
- let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
- let eb = EndianSlice::new(slice, endian);
- assert_eq!(
- eb.split_at(3),
- (
- EndianSlice::new(&slice[..3], endian),
- EndianSlice::new(&slice[3..], endian)
- )
- );
- }
-
- #[test]
- #[should_panic]
- fn test_endian_slice_split_at_out_of_bounds() {
- let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
- let eb = EndianSlice::new(slice, NativeEndian);
- eb.split_at(30);
- }
-}
diff --git a/vendor/gimli/src/read/index.rs b/vendor/gimli/src/read/index.rs
deleted file mode 100644
index 129eb2f..0000000
--- a/vendor/gimli/src/read/index.rs
+++ /dev/null
@@ -1,535 +0,0 @@
-use core::slice;
-
-use crate::common::SectionId;
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section};
-
-/// The data in the `.debug_cu_index` section of a `.dwp` file.
-///
-/// This section contains the compilation unit index.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugCuIndex<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugCuIndex<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugCuIndex` instance from the data in the `.debug_cu_index`
- /// section.
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugCuIndex<R> {
- fn id() -> SectionId {
- SectionId::DebugCuIndex
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugCuIndex<R> {
- fn from(section: R) -> Self {
- DebugCuIndex { section }
- }
-}
-
-impl<R: Reader> DebugCuIndex<R> {
- /// Parse the index header.
- pub fn index(self) -> Result<UnitIndex<R>> {
- UnitIndex::parse(self.section)
- }
-}
-
-/// The data in the `.debug_tu_index` section of a `.dwp` file.
-///
-/// This section contains the type unit index.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugTuIndex<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index`
- /// section.
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugTuIndex<R> {
- fn id() -> SectionId {
- SectionId::DebugTuIndex
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugTuIndex<R> {
- fn from(section: R) -> Self {
- DebugTuIndex { section }
- }
-}
-
-impl<R: Reader> DebugTuIndex<R> {
- /// Parse the index header.
- pub fn index(self) -> Result<UnitIndex<R>> {
- UnitIndex::parse(self.section)
- }
-}
-
-const SECTION_COUNT_MAX: u8 = 8;
-
-/// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`.
-#[derive(Debug, Clone)]
-pub struct UnitIndex<R: Reader> {
- version: u16,
- section_count: u32,
- unit_count: u32,
- slot_count: u32,
- hash_ids: R,
- hash_rows: R,
- // Only `section_count` values are valid.
- sections: [SectionId; SECTION_COUNT_MAX as usize],
- offsets: R,
- sizes: R,
-}
-
-impl<R: Reader> UnitIndex<R> {
- fn parse(mut input: R) -> Result<UnitIndex<R>> {
- if input.is_empty() {
- return Ok(UnitIndex {
- version: 5,
- section_count: 0,
- unit_count: 0,
- slot_count: 0,
- hash_ids: input.clone(),
- hash_rows: input.clone(),
- sections: [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize],
- offsets: input.clone(),
- sizes: input.clone(),
- });
- }
-
- // GNU split-dwarf extension to DWARF 4 uses a 32-bit version,
- // but DWARF 5 uses a 16-bit version followed by 16-bit padding.
- let mut original_input = input.clone();
- let version;
- if input.read_u32()? == 2 {
- version = 2
- } else {
- version = original_input.read_u16()?;
- if version != 5 {
- return Err(Error::UnknownVersion(version.into()));
- }
- }
-
- let section_count = input.read_u32()?;
- let unit_count = input.read_u32()?;
- let slot_count = input.read_u32()?;
- if slot_count == 0 || slot_count & (slot_count - 1) != 0 || slot_count <= unit_count {
- return Err(Error::InvalidIndexSlotCount);
- }
-
- let hash_ids = input.split(R::Offset::from_u64(u64::from(slot_count) * 8)?)?;
- let hash_rows = input.split(R::Offset::from_u64(u64::from(slot_count) * 4)?)?;
-
- let mut sections = [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize];
- if section_count > SECTION_COUNT_MAX.into() {
- return Err(Error::InvalidIndexSectionCount);
- }
- for i in 0..section_count {
- let section = input.read_u32()?;
- sections[i as usize] = if version == 2 {
- match constants::DwSectV2(section) {
- constants::DW_SECT_V2_INFO => SectionId::DebugInfo,
- constants::DW_SECT_V2_TYPES => SectionId::DebugTypes,
- constants::DW_SECT_V2_ABBREV => SectionId::DebugAbbrev,
- constants::DW_SECT_V2_LINE => SectionId::DebugLine,
- constants::DW_SECT_V2_LOC => SectionId::DebugLoc,
- constants::DW_SECT_V2_STR_OFFSETS => SectionId::DebugStrOffsets,
- constants::DW_SECT_V2_MACINFO => SectionId::DebugMacinfo,
- constants::DW_SECT_V2_MACRO => SectionId::DebugMacro,
- _ => return Err(Error::UnknownIndexSection),
- }
- } else {
- match constants::DwSect(section) {
- constants::DW_SECT_INFO => SectionId::DebugInfo,
- constants::DW_SECT_ABBREV => SectionId::DebugAbbrev,
- constants::DW_SECT_LINE => SectionId::DebugLine,
- constants::DW_SECT_LOCLISTS => SectionId::DebugLocLists,
- constants::DW_SECT_STR_OFFSETS => SectionId::DebugStrOffsets,
- constants::DW_SECT_MACRO => SectionId::DebugMacro,
- constants::DW_SECT_RNGLISTS => SectionId::DebugRngLists,
- _ => return Err(Error::UnknownIndexSection),
- }
- };
- }
-
- let offsets = input.split(R::Offset::from_u64(
- u64::from(unit_count) * u64::from(section_count) * 4,
- )?)?;
- let sizes = input.split(R::Offset::from_u64(
- u64::from(unit_count) * u64::from(section_count) * 4,
- )?)?;
-
- Ok(UnitIndex {
- version,
- section_count,
- unit_count,
- slot_count,
- hash_ids,
- hash_rows,
- sections,
- offsets,
- sizes,
- })
- }
-
- /// Find `id` in the index hash table, and return the row index.
- ///
- /// `id` may be a compilation unit ID if this index is from `.debug_cu_index`,
- /// or a type signature if this index is from `.debug_tu_index`.
- pub fn find(&self, id: u64) -> Option<u32> {
- if self.slot_count == 0 {
- return None;
- }
- let mask = u64::from(self.slot_count - 1);
- let mut hash1 = id & mask;
- let hash2 = ((id >> 32) & mask) | 1;
- for _ in 0..self.slot_count {
- // The length of these arrays was validated in `UnitIndex::parse`.
- let mut hash_ids = self.hash_ids.clone();
- hash_ids.skip(R::Offset::from_u64(hash1 * 8).ok()?).ok()?;
- let hash_id = hash_ids.read_u64().ok()?;
- if hash_id == id {
- let mut hash_rows = self.hash_rows.clone();
- hash_rows.skip(R::Offset::from_u64(hash1 * 4).ok()?).ok()?;
- let hash_row = hash_rows.read_u32().ok()?;
- return Some(hash_row);
- }
- if hash_id == 0 {
- return None;
- }
- hash1 = (hash1 + hash2) & mask;
- }
- None
- }
-
- /// Return the section offsets and sizes for the given row index.
- pub fn sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>> {
- if row == 0 {
- return Err(Error::InvalidIndexRow);
- }
- row -= 1;
- if row >= self.unit_count {
- return Err(Error::InvalidIndexRow);
- }
- let mut offsets = self.offsets.clone();
- offsets.skip(R::Offset::from_u64(
- u64::from(row) * u64::from(self.section_count) * 4,
- )?)?;
- let mut sizes = self.sizes.clone();
- sizes.skip(R::Offset::from_u64(
- u64::from(row) * u64::from(self.section_count) * 4,
- )?)?;
- Ok(UnitIndexSectionIterator {
- sections: self.sections[..self.section_count as usize].iter(),
- offsets,
- sizes,
- })
- }
-
- /// Return the version.
- pub fn version(&self) -> u16 {
- self.version
- }
-
- /// Return the number of sections.
- pub fn section_count(&self) -> u32 {
- self.section_count
- }
-
- /// Return the number of units.
- pub fn unit_count(&self) -> u32 {
- self.unit_count
- }
-
- /// Return the number of slots.
- pub fn slot_count(&self) -> u32 {
- self.slot_count
- }
-}
-
-/// An iterator over the section offsets and sizes for a row in a `UnitIndex`.
-#[derive(Debug, Clone)]
-pub struct UnitIndexSectionIterator<'index, R: Reader> {
- sections: slice::Iter<'index, SectionId>,
- offsets: R,
- sizes: R,
-}
-
-impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> {
- type Item = UnitIndexSection;
-
- fn next(&mut self) -> Option<UnitIndexSection> {
- let section = *self.sections.next()?;
- // The length of these arrays was validated in `UnitIndex::parse`.
- let offset = self.offsets.read_u32().ok()?;
- let size = self.sizes.read_u32().ok()?;
- Some(UnitIndexSection {
- section,
- offset,
- size,
- })
- }
-}
-
-/// Information about a unit's contribution to a section in a `.dwp` file.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct UnitIndexSection {
- /// The section kind.
- pub section: SectionId,
- /// The base offset of the unit's contribution to the section.
- pub offset: u32,
- /// The size of the unit's contribution to the section.
- pub size: u32,
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::endianity::BigEndian;
- use test_assembler::{Endian, Section};
-
- #[test]
- fn test_empty() {
- let buf = EndianSlice::new(&[], BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert!(index.find(0).is_none());
- }
-
- #[test]
- fn test_version_2() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D32(2).D32(0).D32(0).D32(1)
- // Slots.
- .D64(0).D32(0);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert_eq!(index.version, 2);
- }
-
- #[test]
- fn test_version_5() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D16(5).D16(0).D32(0).D32(0).D32(1)
- // Slots.
- .D64(0).D32(0);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert_eq!(index.version, 5);
- }
-
- #[test]
- fn test_version_5_invalid() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D32(5).D32(0).D32(0).D32(1)
- // Slots.
- .D64(0).D32(0);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- assert!(UnitIndex::parse(buf).is_err());
- }
-
- #[test]
- fn test_version_2_sections() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D32(2).D32(8).D32(1).D32(2)
- // Slots.
- .D64(0).D64(0).D32(0).D32(0)
- // Sections.
- .D32(constants::DW_SECT_V2_INFO.0)
- .D32(constants::DW_SECT_V2_TYPES.0)
- .D32(constants::DW_SECT_V2_ABBREV.0)
- .D32(constants::DW_SECT_V2_LINE.0)
- .D32(constants::DW_SECT_V2_LOC.0)
- .D32(constants::DW_SECT_V2_STR_OFFSETS.0)
- .D32(constants::DW_SECT_V2_MACINFO.0)
- .D32(constants::DW_SECT_V2_MACRO.0)
- // Offsets.
- .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18)
- // Sizes.
- .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27).D32(28);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert_eq!(index.section_count, 8);
- assert_eq!(
- index.sections,
- [
- SectionId::DebugInfo,
- SectionId::DebugTypes,
- SectionId::DebugAbbrev,
- SectionId::DebugLine,
- SectionId::DebugLoc,
- SectionId::DebugStrOffsets,
- SectionId::DebugMacinfo,
- SectionId::DebugMacro,
- ]
- );
- #[rustfmt::skip]
- let expect = [
- UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
- UnitIndexSection { section: SectionId::DebugTypes, offset: 12, size: 22 },
- UnitIndexSection { section: SectionId::DebugAbbrev, offset: 13, size: 23 },
- UnitIndexSection { section: SectionId::DebugLine, offset: 14, size: 24 },
- UnitIndexSection { section: SectionId::DebugLoc, offset: 15, size: 25 },
- UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 16, size: 26 },
- UnitIndexSection { section: SectionId::DebugMacinfo, offset: 17, size: 27 },
- UnitIndexSection { section: SectionId::DebugMacro, offset: 18, size: 28 },
- ];
- let mut sections = index.sections(1).unwrap();
- for section in &expect {
- assert_eq!(*section, sections.next().unwrap());
- }
- assert!(sections.next().is_none());
- }
-
- #[test]
- fn test_version_5_sections() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D16(5).D16(0).D32(7).D32(1).D32(2)
- // Slots.
- .D64(0).D64(0).D32(0).D32(0)
- // Sections.
- .D32(constants::DW_SECT_INFO.0)
- .D32(constants::DW_SECT_ABBREV.0)
- .D32(constants::DW_SECT_LINE.0)
- .D32(constants::DW_SECT_LOCLISTS.0)
- .D32(constants::DW_SECT_STR_OFFSETS.0)
- .D32(constants::DW_SECT_MACRO.0)
- .D32(constants::DW_SECT_RNGLISTS.0)
- // Offsets.
- .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17)
- // Sizes.
- .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert_eq!(index.section_count, 7);
- assert_eq!(
- index.sections[..7],
- [
- SectionId::DebugInfo,
- SectionId::DebugAbbrev,
- SectionId::DebugLine,
- SectionId::DebugLocLists,
- SectionId::DebugStrOffsets,
- SectionId::DebugMacro,
- SectionId::DebugRngLists,
- ]
- );
- #[rustfmt::skip]
- let expect = [
- UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
- UnitIndexSection { section: SectionId::DebugAbbrev, offset: 12, size: 22 },
- UnitIndexSection { section: SectionId::DebugLine, offset: 13, size: 23 },
- UnitIndexSection { section: SectionId::DebugLocLists, offset: 14, size: 24 },
- UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 15, size: 25 },
- UnitIndexSection { section: SectionId::DebugMacro, offset: 16, size: 26 },
- UnitIndexSection { section: SectionId::DebugRngLists, offset: 17, size: 27 },
- ];
- let mut sections = index.sections(1).unwrap();
- for section in &expect {
- assert_eq!(*section, sections.next().unwrap());
- }
- assert!(sections.next().is_none());
-
- assert!(index.sections(0).is_err());
- assert!(index.sections(2).is_err());
- }
-
- #[test]
- fn test_hash() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D16(5).D16(0).D32(2).D32(3).D32(4)
- // Slots.
- .D64(0xffff_fff2_ffff_fff1)
- .D64(0xffff_fff0_ffff_fff1)
- .D64(0xffff_fff1_ffff_fff1)
- .D64(0)
- .D32(3).D32(1).D32(2).D32(0)
- // Sections.
- .D32(constants::DW_SECT_INFO.0)
- .D32(constants::DW_SECT_ABBREV.0)
- // Offsets.
- .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0)
- // Sizes.
- .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0);
- let buf = section.get_contents().unwrap();
- let buf = EndianSlice::new(&buf, BigEndian);
- let index = UnitIndex::parse(buf).unwrap();
- assert_eq!(index.version(), 5);
- assert_eq!(index.slot_count(), 4);
- assert_eq!(index.unit_count(), 3);
- assert_eq!(index.section_count(), 2);
- assert_eq!(index.find(0xffff_fff0_ffff_fff1), Some(1));
- assert_eq!(index.find(0xffff_fff1_ffff_fff1), Some(2));
- assert_eq!(index.find(0xffff_fff2_ffff_fff1), Some(3));
- assert_eq!(index.find(0xffff_fff3_ffff_fff1), None);
- }
-
- #[test]
- fn test_cu_index() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D16(5).D16(0).D32(0).D32(0).D32(1)
- // Slots.
- .D64(0).D32(0);
- let buf = section.get_contents().unwrap();
- let cu_index = DebugCuIndex::new(&buf, BigEndian);
- let index = cu_index.index().unwrap();
- assert_eq!(index.version, 5);
- }
-
- #[test]
- fn test_tu_index() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Big)
- // Header.
- .D16(5).D16(0).D32(0).D32(0).D32(1)
- // Slots.
- .D64(0).D32(0);
- let buf = section.get_contents().unwrap();
- let tu_index = DebugTuIndex::new(&buf, BigEndian);
- let index = tu_index.index().unwrap();
- assert_eq!(index.version, 5);
- }
-}
diff --git a/vendor/gimli/src/read/line.rs b/vendor/gimli/src/read/line.rs
deleted file mode 100644
index 47eae92..0000000
--- a/vendor/gimli/src/read/line.rs
+++ /dev/null
@@ -1,3130 +0,0 @@
-use alloc::vec::Vec;
-use core::fmt;
-use core::num::{NonZeroU64, Wrapping};
-use core::result;
-
-use crate::common::{
- DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format,
- LineEncoding, SectionId,
-};
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::{AttributeValue, EndianSlice, Error, Reader, ReaderOffset, Result, Section};
-
-/// The `DebugLine` struct contains the source location to instruction mapping
-/// found in the `.debug_line` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugLine<R> {
- debug_line_section: R,
-}
-
-impl<'input, Endian> DebugLine<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugLine` instance from the data in the `.debug_line`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_line` 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::{DebugLine, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_line_section_somehow = || &buf;
- /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_line_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_line_section, endian))
- }
-}
-
-impl<R: Reader> DebugLine<R> {
- /// Parse the line number program whose header is at the given `offset` in the
- /// `.debug_line` section.
- ///
- /// The `address_size` must match the compilation unit that the lines apply to.
- /// The `comp_dir` should be from the `DW_AT_comp_dir` attribute of the compilation
- /// unit. The `comp_name` should be from the `DW_AT_name` attribute of the
- /// compilation unit.
- ///
- /// ```rust,no_run
- /// use gimli::{DebugLine, DebugLineOffset, IncompleteLineProgram, EndianSlice, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_line_section_somehow = || &buf;
- /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian);
- ///
- /// // In a real example, we'd grab the offset via a compilation unit
- /// // entry's `DW_AT_stmt_list` attribute, and the address size from that
- /// // unit directly.
- /// let offset = DebugLineOffset(0);
- /// let address_size = 8;
- ///
- /// let program = debug_line.program(offset, address_size, None, None)
- /// .expect("should have found a header at that offset, and parsed it OK");
- /// ```
- pub fn program(
- &self,
- offset: DebugLineOffset<R::Offset>,
- address_size: u8,
- comp_dir: Option<R>,
- comp_name: Option<R>,
- ) -> Result<IncompleteLineProgram<R>> {
- let input = &mut self.debug_line_section.clone();
- input.skip(offset.0)?;
- let header = LineProgramHeader::parse(input, offset, address_size, comp_dir, comp_name)?;
- let program = IncompleteLineProgram { header };
- Ok(program)
- }
-}
-
-impl<T> DebugLine<T> {
- /// Create a `DebugLine` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugLine<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLine<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.debug_line_section).into()
- }
-}
-
-impl<R> Section<R> for DebugLine<R> {
- fn id() -> SectionId {
- SectionId::DebugLine
- }
-
- fn reader(&self) -> &R {
- &self.debug_line_section
- }
-}
-
-impl<R> From<R> for DebugLine<R> {
- fn from(debug_line_section: R) -> Self {
- DebugLine { debug_line_section }
- }
-}
-
-/// Deprecated. `LineNumberProgram` has been renamed to `LineProgram`.
-#[deprecated(note = "LineNumberProgram has been renamed to LineProgram, use that instead.")]
-pub type LineNumberProgram<R, Offset> = dyn LineProgram<R, Offset>;
-
-/// A `LineProgram` provides access to a `LineProgramHeader` and
-/// a way to add files to the files table if necessary. Gimli consumers should
-/// never need to use or see this trait.
-pub trait LineProgram<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Get a reference to the held `LineProgramHeader`.
- fn header(&self) -> &LineProgramHeader<R, Offset>;
- /// Add a file to the file table if necessary.
- fn add_file(&mut self, file: FileEntry<R, Offset>);
-}
-
-impl<R, Offset> LineProgram<R, Offset> for IncompleteLineProgram<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn header(&self) -> &LineProgramHeader<R, Offset> {
- &self.header
- }
- fn add_file(&mut self, file: FileEntry<R, Offset>) {
- self.header.file_names.push(file);
- }
-}
-
-impl<'program, R, Offset> LineProgram<R, Offset> for &'program CompleteLineProgram<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn header(&self) -> &LineProgramHeader<R, Offset> {
- &self.header
- }
- fn add_file(&mut self, _: FileEntry<R, Offset>) {
- // Nop. Our file table is already complete.
- }
-}
-
-/// Deprecated. `StateMachine` has been renamed to `LineRows`.
-#[deprecated(note = "StateMachine has been renamed to LineRows, use that instead.")]
-pub type StateMachine<R, Program, Offset> = LineRows<R, Program, Offset>;
-
-/// Executes a `LineProgram` to iterate over the rows in the matrix of line number information.
-///
-/// "The hypothetical machine used by a consumer of the line number information
-/// to expand the byte-coded instruction stream into a matrix of line number
-/// information." -- Section 6.2.1
-#[derive(Debug, Clone)]
-pub struct LineRows<R, Program, Offset = <R as Reader>::Offset>
-where
- Program: LineProgram<R, Offset>,
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- program: Program,
- row: LineRow,
- instructions: LineInstructions<R>,
-}
-
-type OneShotLineRows<R, Offset = <R as Reader>::Offset> =
- LineRows<R, IncompleteLineProgram<R, Offset>, Offset>;
-
-type ResumedLineRows<'program, R, Offset = <R as Reader>::Offset> =
- LineRows<R, &'program CompleteLineProgram<R, Offset>, Offset>;
-
-impl<R, Program, Offset> LineRows<R, Program, Offset>
-where
- Program: LineProgram<R, Offset>,
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn new(program: IncompleteLineProgram<R, Offset>) -> OneShotLineRows<R, Offset> {
- let row = LineRow::new(program.header());
- let instructions = LineInstructions {
- input: program.header().program_buf.clone(),
- };
- LineRows {
- program,
- row,
- instructions,
- }
- }
-
- fn resume<'program>(
- program: &'program CompleteLineProgram<R, Offset>,
- sequence: &LineSequence<R>,
- ) -> ResumedLineRows<'program, R, Offset> {
- let row = LineRow::new(program.header());
- let instructions = sequence.instructions.clone();
- LineRows {
- program,
- row,
- instructions,
- }
- }
-
- /// Get a reference to the header for this state machine's line number
- /// program.
- #[inline]
- pub fn header(&self) -> &LineProgramHeader<R, Offset> {
- self.program.header()
- }
-
- /// Parse and execute the next instructions in the line number program until
- /// another row in the line number matrix is computed.
- ///
- /// The freshly computed row is returned as `Ok(Some((header, row)))`.
- /// If the matrix is complete, and there are no more new rows in the line
- /// number matrix, then `Ok(None)` is returned. If there was an error parsing
- /// an instruction, then `Err(e)` is returned.
- ///
- /// Unfortunately, the references mean that this cannot be a
- /// `FallibleIterator`.
- pub fn next_row(&mut self) -> Result<Option<(&LineProgramHeader<R, Offset>, &LineRow)>> {
- // Perform any reset that was required after copying the previous row.
- self.row.reset(self.program.header());
-
- loop {
- // Split the borrow here, rather than calling `self.header()`.
- match self.instructions.next_instruction(self.program.header()) {
- Err(err) => return Err(err),
- Ok(None) => return Ok(None),
- Ok(Some(instruction)) => {
- if self.row.execute(instruction, &mut self.program) {
- if self.row.tombstone {
- // Perform any reset that was required for the tombstone row.
- // Normally this is done when `next_row` is called again, but for
- // tombstones we loop immediately.
- self.row.reset(self.program.header());
- } else {
- return Ok(Some((self.header(), &self.row)));
- }
- }
- // Fall through, parse the next instruction, and see if that
- // yields a row.
- }
- }
- }
- }
-}
-
-/// Deprecated. `Opcode` has been renamed to `LineInstruction`.
-#[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")]
-pub type Opcode<R> = LineInstruction<R, <R as Reader>::Offset>;
-
-/// A parsed line number program instruction.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum LineInstruction<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// > ### 6.2.5.1 Special Opcodes
- /// >
- /// > Each ubyte special opcode has the following effect on the state machine:
- /// >
- /// > 1. Add a signed integer to the line register.
- /// >
- /// > 2. Modify the operation pointer by incrementing the address and
- /// > op_index registers as described below.
- /// >
- /// > 3. Append a row to the matrix using the current values of the state
- /// > machine registers.
- /// >
- /// > 4. Set the basic_block register to “false.”
- /// >
- /// > 5. Set the prologue_end register to “false.”
- /// >
- /// > 6. Set the epilogue_begin register to “false.”
- /// >
- /// > 7. Set the discriminator register to 0.
- /// >
- /// > All of the special opcodes do those same seven things; they differ from
- /// > one another only in what values they add to the line, address and
- /// > op_index registers.
- Special(u8),
-
- /// "[`LineInstruction::Copy`] appends a row to the matrix using the current
- /// values of the state machine registers. Then it sets the discriminator
- /// register to 0, and sets the basic_block, prologue_end and epilogue_begin
- /// registers to “false.”"
- Copy,
-
- /// "The DW_LNS_advance_pc opcode takes a single unsigned LEB128 operand as
- /// the operation advance and modifies the address and op_index registers
- /// [the same as `LineInstruction::Special`]"
- AdvancePc(u64),
-
- /// "The DW_LNS_advance_line opcode takes a single signed LEB128 operand and
- /// adds that value to the line register of the state machine."
- AdvanceLine(i64),
-
- /// "The DW_LNS_set_file opcode takes a single unsigned LEB128 operand and
- /// stores it in the file register of the state machine."
- SetFile(u64),
-
- /// "The DW_LNS_set_column opcode takes a single unsigned LEB128 operand and
- /// stores it in the column register of the state machine."
- SetColumn(u64),
-
- /// "The DW_LNS_negate_stmt opcode takes no operands. It sets the is_stmt
- /// register of the state machine to the logical negation of its current
- /// value."
- NegateStatement,
-
- /// "The DW_LNS_set_basic_block opcode takes no operands. It sets the
- /// basic_block register of the state machine to “true.”"
- SetBasicBlock,
-
- /// > The DW_LNS_const_add_pc opcode takes no operands. It advances the
- /// > address and op_index registers by the increments corresponding to
- /// > special opcode 255.
- /// >
- /// > When the line number program needs to advance the address by a small
- /// > amount, it can use a single special opcode, which occupies a single
- /// > byte. When it needs to advance the address by up to twice the range of
- /// > the last special opcode, it can use DW_LNS_const_add_pc followed by a
- /// > special opcode, for a total of two bytes. Only if it needs to advance
- /// > the address by more than twice that range will it need to use both
- /// > DW_LNS_advance_pc and a special opcode, requiring three or more bytes.
- ConstAddPc,
-
- /// > The DW_LNS_fixed_advance_pc opcode takes a single uhalf (unencoded)
- /// > operand and adds it to the address register of the state machine and
- /// > sets the op_index register to 0. This is the only standard opcode whose
- /// > operand is not a variable length number. It also does not multiply the
- /// > operand by the minimum_instruction_length field of the header.
- FixedAddPc(u16),
-
- /// "[`LineInstruction::SetPrologueEnd`] sets the prologue_end register to “true”."
- SetPrologueEnd,
-
- /// "[`LineInstruction::SetEpilogueBegin`] sets the epilogue_begin register to
- /// “true”."
- SetEpilogueBegin,
-
- /// "The DW_LNS_set_isa opcode takes a single unsigned LEB128 operand and
- /// stores that value in the isa register of the state machine."
- SetIsa(u64),
-
- /// An unknown standard opcode with zero operands.
- UnknownStandard0(constants::DwLns),
-
- /// An unknown standard opcode with one operand.
- UnknownStandard1(constants::DwLns, u64),
-
- /// An unknown standard opcode with multiple operands.
- UnknownStandardN(constants::DwLns, R),
-
- /// > [`LineInstruction::EndSequence`] sets the end_sequence register of the state
- /// > machine to “true” and appends a row to the matrix using the current
- /// > values of the state-machine registers. Then it resets the registers to
- /// > the initial values specified above (see Section 6.2.2). Every line
- /// > number program sequence must end with a DW_LNE_end_sequence instruction
- /// > which creates a row whose address is that of the byte after the last
- /// > target machine instruction of the sequence.
- EndSequence,
-
- /// > The DW_LNE_set_address opcode takes a single relocatable address as an
- /// > operand. The size of the operand is the size of an address on the target
- /// > machine. It sets the address register to the value given by the
- /// > relocatable address and sets the op_index register to 0.
- /// >
- /// > All of the other line number program opcodes that affect the address
- /// > register add a delta to it. This instruction stores a relocatable value
- /// > into it instead.
- SetAddress(u64),
-
- /// Defines a new source file in the line number program and appends it to
- /// the line number program header's list of source files.
- DefineFile(FileEntry<R, Offset>),
-
- /// "The DW_LNE_set_discriminator opcode takes a single parameter, an
- /// unsigned LEB128 integer. It sets the discriminator register to the new
- /// value."
- SetDiscriminator(u64),
-
- /// An unknown extended opcode and the slice of its unparsed operands.
- UnknownExtended(constants::DwLne, R),
-}
-
-impl<R, Offset> LineInstruction<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn parse<'header>(
- header: &'header LineProgramHeader<R>,
- input: &mut R,
- ) -> Result<LineInstruction<R>>
- where
- R: 'header,
- {
- let opcode = input.read_u8()?;
- if opcode == 0 {
- let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let mut instr_rest = input.split(length)?;
- let opcode = instr_rest.read_u8()?;
-
- match constants::DwLne(opcode) {
- constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence),
-
- constants::DW_LNE_set_address => {
- let address = instr_rest.read_address(header.address_size())?;
- Ok(LineInstruction::SetAddress(address))
- }
-
- constants::DW_LNE_define_file => {
- if header.version() <= 4 {
- let path_name = instr_rest.read_null_terminated_slice()?;
- let entry = FileEntry::parse(&mut instr_rest, path_name)?;
- Ok(LineInstruction::DefineFile(entry))
- } else {
- Ok(LineInstruction::UnknownExtended(
- constants::DW_LNE_define_file,
- instr_rest,
- ))
- }
- }
-
- constants::DW_LNE_set_discriminator => {
- let discriminator = instr_rest.read_uleb128()?;
- Ok(LineInstruction::SetDiscriminator(discriminator))
- }
-
- otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)),
- }
- } else if opcode >= header.opcode_base {
- Ok(LineInstruction::Special(opcode))
- } else {
- match constants::DwLns(opcode) {
- constants::DW_LNS_copy => Ok(LineInstruction::Copy),
-
- constants::DW_LNS_advance_pc => {
- let advance = input.read_uleb128()?;
- Ok(LineInstruction::AdvancePc(advance))
- }
-
- constants::DW_LNS_advance_line => {
- let increment = input.read_sleb128()?;
- Ok(LineInstruction::AdvanceLine(increment))
- }
-
- constants::DW_LNS_set_file => {
- let file = input.read_uleb128()?;
- Ok(LineInstruction::SetFile(file))
- }
-
- constants::DW_LNS_set_column => {
- let column = input.read_uleb128()?;
- Ok(LineInstruction::SetColumn(column))
- }
-
- constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement),
-
- constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock),
-
- constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc),
-
- constants::DW_LNS_fixed_advance_pc => {
- let advance = input.read_u16()?;
- Ok(LineInstruction::FixedAddPc(advance))
- }
-
- constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd),
-
- constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin),
-
- constants::DW_LNS_set_isa => {
- let isa = input.read_uleb128()?;
- Ok(LineInstruction::SetIsa(isa))
- }
-
- otherwise => {
- let mut opcode_lengths = header.standard_opcode_lengths().clone();
- opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?;
- let num_args = opcode_lengths.read_u8()? as usize;
- match num_args {
- 0 => Ok(LineInstruction::UnknownStandard0(otherwise)),
- 1 => {
- let arg = input.read_uleb128()?;
- Ok(LineInstruction::UnknownStandard1(otherwise, arg))
- }
- _ => {
- let mut args = input.clone();
- for _ in 0..num_args {
- input.read_uleb128()?;
- }
- let len = input.offset_from(&args);
- args.truncate(len)?;
- Ok(LineInstruction::UnknownStandardN(otherwise, args))
- }
- }
- }
- }
- }
- }
-}
-
-impl<R, Offset> fmt::Display for LineInstruction<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
- match *self {
- LineInstruction::Special(opcode) => write!(f, "Special opcode {}", opcode),
- LineInstruction::Copy => write!(f, "{}", constants::DW_LNS_copy),
- LineInstruction::AdvancePc(advance) => {
- write!(f, "{} by {}", constants::DW_LNS_advance_pc, advance)
- }
- LineInstruction::AdvanceLine(increment) => {
- write!(f, "{} by {}", constants::DW_LNS_advance_line, increment)
- }
- LineInstruction::SetFile(file) => {
- write!(f, "{} to {}", constants::DW_LNS_set_file, file)
- }
- LineInstruction::SetColumn(column) => {
- write!(f, "{} to {}", constants::DW_LNS_set_column, column)
- }
- LineInstruction::NegateStatement => write!(f, "{}", constants::DW_LNS_negate_stmt),
- LineInstruction::SetBasicBlock => write!(f, "{}", constants::DW_LNS_set_basic_block),
- LineInstruction::ConstAddPc => write!(f, "{}", constants::DW_LNS_const_add_pc),
- LineInstruction::FixedAddPc(advance) => {
- write!(f, "{} by {}", constants::DW_LNS_fixed_advance_pc, advance)
- }
- LineInstruction::SetPrologueEnd => write!(f, "{}", constants::DW_LNS_set_prologue_end),
- LineInstruction::SetEpilogueBegin => {
- write!(f, "{}", constants::DW_LNS_set_epilogue_begin)
- }
- LineInstruction::SetIsa(isa) => write!(f, "{} to {}", constants::DW_LNS_set_isa, isa),
- LineInstruction::UnknownStandard0(opcode) => write!(f, "Unknown {}", opcode),
- LineInstruction::UnknownStandard1(opcode, arg) => {
- write!(f, "Unknown {} with operand {}", opcode, arg)
- }
- LineInstruction::UnknownStandardN(opcode, ref args) => {
- write!(f, "Unknown {} with operands {:?}", opcode, args)
- }
- LineInstruction::EndSequence => write!(f, "{}", constants::DW_LNE_end_sequence),
- LineInstruction::SetAddress(address) => {
- write!(f, "{} to {}", constants::DW_LNE_set_address, address)
- }
- LineInstruction::DefineFile(_) => write!(f, "{}", constants::DW_LNE_define_file),
- LineInstruction::SetDiscriminator(discr) => {
- write!(f, "{} to {}", constants::DW_LNE_set_discriminator, discr)
- }
- LineInstruction::UnknownExtended(opcode, _) => write!(f, "Unknown {}", opcode),
- }
- }
-}
-
-/// Deprecated. `OpcodesIter` has been renamed to `LineInstructions`.
-#[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")]
-pub type OpcodesIter<R> = LineInstructions<R>;
-
-/// An iterator yielding parsed instructions.
-///
-/// See
-/// [`LineProgramHeader::instructions`](./struct.LineProgramHeader.html#method.instructions)
-/// for more details.
-#[derive(Clone, Debug)]
-pub struct LineInstructions<R: Reader> {
- input: R,
-}
-
-impl<R: Reader> LineInstructions<R> {
- fn remove_trailing(&self, other: &LineInstructions<R>) -> Result<LineInstructions<R>> {
- let offset = other.input.offset_from(&self.input);
- let mut input = self.input.clone();
- input.truncate(offset)?;
- Ok(LineInstructions { input })
- }
-}
-
-impl<R: Reader> LineInstructions<R> {
- /// Advance the iterator and return the next instruction.
- ///
- /// Returns the newly parsed instruction as `Ok(Some(instruction))`. Returns
- /// `Ok(None)` when iteration is complete and all instructions have already been
- /// parsed and yielded. If an error occurs while parsing the next attribute,
- /// then this error is returned as `Err(e)`, and all subsequent calls return
- /// `Ok(None)`.
- ///
- /// Unfortunately, the `header` parameter means that this cannot be a
- /// `FallibleIterator`.
- #[inline(always)]
- pub fn next_instruction(
- &mut self,
- header: &LineProgramHeader<R>,
- ) -> Result<Option<LineInstruction<R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match LineInstruction::parse(header, &mut self.input) {
- Ok(instruction) => Ok(Some(instruction)),
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-/// Deprecated. `LineNumberRow` has been renamed to `LineRow`.
-#[deprecated(note = "LineNumberRow has been renamed to LineRow, use that instead.")]
-pub type LineNumberRow = LineRow;
-
-/// A row in the line number program's resulting matrix.
-///
-/// Each row is a copy of the registers of the state machine, as defined in section 6.2.2.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct LineRow {
- tombstone: bool,
- address: Wrapping<u64>,
- op_index: Wrapping<u64>,
- file: u64,
- line: Wrapping<u64>,
- column: u64,
- is_stmt: bool,
- basic_block: bool,
- end_sequence: bool,
- prologue_end: bool,
- epilogue_begin: bool,
- isa: u64,
- discriminator: u64,
-}
-
-impl LineRow {
- /// Create a line number row in the initial state for the given program.
- pub fn new<R: Reader>(header: &LineProgramHeader<R>) -> Self {
- LineRow {
- // "At the beginning of each sequence within a line number program, the
- // state of the registers is:" -- Section 6.2.2
- tombstone: false,
- address: Wrapping(0),
- op_index: Wrapping(0),
- file: 1,
- line: Wrapping(1),
- column: 0,
- // "determined by default_is_stmt in the line number program header"
- is_stmt: header.line_encoding.default_is_stmt,
- basic_block: false,
- end_sequence: false,
- prologue_end: false,
- epilogue_begin: false,
- // "The isa value 0 specifies that the instruction set is the
- // architecturally determined default instruction set. This may be fixed
- // by the ABI, or it may be specified by other means, for example, by
- // the object file description."
- isa: 0,
- discriminator: 0,
- }
- }
-
- /// "The program-counter value corresponding to a machine instruction
- /// generated by the compiler."
- #[inline]
- pub fn address(&self) -> u64 {
- self.address.0
- }
-
- /// > An unsigned integer representing the index of an operation within a VLIW
- /// > instruction. The index of the first operation is 0. For non-VLIW
- /// > architectures, this register will always be 0.
- /// >
- /// > The address and op_index registers, taken together, form an operation
- /// > pointer that can reference any individual operation with the
- /// > instruction stream.
- #[inline]
- pub fn op_index(&self) -> u64 {
- self.op_index.0
- }
-
- /// "An unsigned integer indicating the identity of the source file
- /// corresponding to a machine instruction."
- #[inline]
- pub fn file_index(&self) -> u64 {
- self.file
- }
-
- /// The source file corresponding to the current machine instruction.
- #[inline]
- pub fn file<'header, R: Reader>(
- &self,
- header: &'header LineProgramHeader<R>,
- ) -> Option<&'header FileEntry<R>> {
- header.file(self.file)
- }
-
- /// "An unsigned integer indicating a source line number. Lines are numbered
- /// beginning at 1. The compiler may emit the value 0 in cases where an
- /// instruction cannot be attributed to any source line."
- /// Line number values of 0 are represented as `None`.
- #[inline]
- pub fn line(&self) -> Option<NonZeroU64> {
- NonZeroU64::new(self.line.0)
- }
-
- /// "An unsigned integer indicating a column number within a source
- /// line. Columns are numbered beginning at 1. The value 0 is reserved to
- /// indicate that a statement begins at the “left edge” of the line."
- #[inline]
- pub fn column(&self) -> ColumnType {
- NonZeroU64::new(self.column)
- .map(ColumnType::Column)
- .unwrap_or(ColumnType::LeftEdge)
- }
-
- /// "A boolean indicating that the current instruction is a recommended
- /// breakpoint location. A recommended breakpoint location is intended to
- /// “represent” a line, a statement and/or a semantically distinct subpart
- /// of a statement."
- #[inline]
- pub fn is_stmt(&self) -> bool {
- self.is_stmt
- }
-
- /// "A boolean indicating that the current instruction is the beginning of a
- /// basic block."
- #[inline]
- pub fn basic_block(&self) -> bool {
- self.basic_block
- }
-
- /// "A boolean indicating that the current address is that of the first byte
- /// after the end of a sequence of target machine instructions. end_sequence
- /// terminates a sequence of lines; therefore other information in the same
- /// row is not meaningful."
- #[inline]
- pub fn end_sequence(&self) -> bool {
- self.end_sequence
- }
-
- /// "A boolean indicating that the current address is one (of possibly many)
- /// where execution should be suspended for an entry breakpoint of a
- /// function."
- #[inline]
- pub fn prologue_end(&self) -> bool {
- self.prologue_end
- }
-
- /// "A boolean indicating that the current address is one (of possibly many)
- /// where execution should be suspended for an exit breakpoint of a
- /// function."
- #[inline]
- pub fn epilogue_begin(&self) -> bool {
- self.epilogue_begin
- }
-
- /// Tag for the current instruction set architecture.
- ///
- /// > An unsigned integer whose value encodes the applicable instruction set
- /// > architecture for the current instruction.
- /// >
- /// > The encoding of instruction sets should be shared by all users of a
- /// > given architecture. It is recommended that this encoding be defined by
- /// > the ABI authoring committee for each architecture.
- #[inline]
- pub fn isa(&self) -> u64 {
- self.isa
- }
-
- /// "An unsigned integer identifying the block to which the current
- /// instruction belongs. Discriminator values are assigned arbitrarily by
- /// the DWARF producer and serve to distinguish among multiple blocks that
- /// may all be associated with the same source file, line, and column. Where
- /// only one block exists for a given source position, the discriminator
- /// value should be zero."
- #[inline]
- pub fn discriminator(&self) -> u64 {
- self.discriminator
- }
-
- /// Execute the given instruction, and return true if a new row in the
- /// line number matrix needs to be generated.
- ///
- /// Unknown opcodes are treated as no-ops.
- #[inline]
- pub fn execute<R, Program>(
- &mut self,
- instruction: LineInstruction<R>,
- program: &mut Program,
- ) -> bool
- where
- Program: LineProgram<R>,
- R: Reader,
- {
- match instruction {
- LineInstruction::Special(opcode) => {
- self.exec_special_opcode(opcode, program.header());
- true
- }
-
- LineInstruction::Copy => true,
-
- LineInstruction::AdvancePc(operation_advance) => {
- self.apply_operation_advance(operation_advance, program.header());
- false
- }
-
- LineInstruction::AdvanceLine(line_increment) => {
- self.apply_line_advance(line_increment);
- false
- }
-
- LineInstruction::SetFile(file) => {
- self.file = file;
- false
- }
-
- LineInstruction::SetColumn(column) => {
- self.column = column;
- false
- }
-
- LineInstruction::NegateStatement => {
- self.is_stmt = !self.is_stmt;
- false
- }
-
- LineInstruction::SetBasicBlock => {
- self.basic_block = true;
- false
- }
-
- LineInstruction::ConstAddPc => {
- let adjusted = self.adjust_opcode(255, program.header());
- let operation_advance = adjusted / program.header().line_encoding.line_range;
- self.apply_operation_advance(u64::from(operation_advance), program.header());
- false
- }
-
- LineInstruction::FixedAddPc(operand) => {
- self.address += Wrapping(u64::from(operand));
- self.op_index.0 = 0;
- false
- }
-
- LineInstruction::SetPrologueEnd => {
- self.prologue_end = true;
- false
- }
-
- LineInstruction::SetEpilogueBegin => {
- self.epilogue_begin = true;
- false
- }
-
- LineInstruction::SetIsa(isa) => {
- self.isa = isa;
- false
- }
-
- LineInstruction::EndSequence => {
- self.end_sequence = true;
- true
- }
-
- LineInstruction::SetAddress(address) => {
- let tombstone_address = !0 >> (64 - program.header().encoding.address_size * 8);
- self.tombstone = address == tombstone_address;
- self.address.0 = address;
- self.op_index.0 = 0;
- false
- }
-
- LineInstruction::DefineFile(entry) => {
- program.add_file(entry);
- false
- }
-
- LineInstruction::SetDiscriminator(discriminator) => {
- self.discriminator = discriminator;
- false
- }
-
- // Compatibility with future opcodes.
- LineInstruction::UnknownStandard0(_)
- | LineInstruction::UnknownStandard1(_, _)
- | LineInstruction::UnknownStandardN(_, _)
- | LineInstruction::UnknownExtended(_, _) => false,
- }
- }
-
- /// Perform any reset that was required after copying the previous row.
- #[inline]
- pub fn reset<R: Reader>(&mut self, header: &LineProgramHeader<R>) {
- if self.end_sequence {
- // Previous instruction was EndSequence, so reset everything
- // as specified in Section 6.2.5.3.
- *self = Self::new(header);
- } else {
- // Previous instruction was one of:
- // - Special - specified in Section 6.2.5.1, steps 4-7
- // - Copy - specified in Section 6.2.5.2
- // The reset behaviour is the same in both cases.
- self.discriminator = 0;
- self.basic_block = false;
- self.prologue_end = false;
- self.epilogue_begin = false;
- }
- }
-
- /// Step 1 of section 6.2.5.1
- fn apply_line_advance(&mut self, line_increment: i64) {
- if line_increment < 0 {
- let decrement = -line_increment as u64;
- if decrement <= self.line.0 {
- self.line.0 -= decrement;
- } else {
- self.line.0 = 0;
- }
- } else {
- self.line += Wrapping(line_increment as u64);
- }
- }
-
- /// Step 2 of section 6.2.5.1
- fn apply_operation_advance<R: Reader>(
- &mut self,
- operation_advance: u64,
- header: &LineProgramHeader<R>,
- ) {
- let operation_advance = Wrapping(operation_advance);
-
- let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length);
- let minimum_instruction_length = Wrapping(minimum_instruction_length);
-
- let maximum_operations_per_instruction =
- u64::from(header.line_encoding.maximum_operations_per_instruction);
- let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction);
-
- if maximum_operations_per_instruction.0 == 1 {
- self.address += minimum_instruction_length * operation_advance;
- self.op_index.0 = 0;
- } else {
- let op_index_with_advance = self.op_index + operation_advance;
- self.address += minimum_instruction_length
- * (op_index_with_advance / maximum_operations_per_instruction);
- self.op_index = op_index_with_advance % maximum_operations_per_instruction;
- }
- }
-
- #[inline]
- fn adjust_opcode<R: Reader>(&self, opcode: u8, header: &LineProgramHeader<R>) -> u8 {
- opcode - header.opcode_base
- }
-
- /// Section 6.2.5.1
- fn exec_special_opcode<R: Reader>(&mut self, opcode: u8, header: &LineProgramHeader<R>) {
- let adjusted_opcode = self.adjust_opcode(opcode, header);
-
- let line_range = header.line_encoding.line_range;
- let line_advance = adjusted_opcode % line_range;
- let operation_advance = adjusted_opcode / line_range;
-
- // Step 1
- let line_base = i64::from(header.line_encoding.line_base);
- self.apply_line_advance(line_base + i64::from(line_advance));
-
- // Step 2
- self.apply_operation_advance(u64::from(operation_advance), header);
- }
-}
-
-/// The type of column that a row is referring to.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum ColumnType {
- /// The `LeftEdge` means that the statement begins at the start of the new
- /// line.
- LeftEdge,
- /// A column number, whose range begins at 1.
- Column(NonZeroU64),
-}
-
-/// Deprecated. `LineNumberSequence` has been renamed to `LineSequence`.
-#[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")]
-pub type LineNumberSequence<R> = LineSequence<R>;
-
-/// A sequence within a line number program. A sequence, as defined in section
-/// 6.2.5 of the standard, is a linear subset of a line number program within
-/// which addresses are monotonically increasing.
-#[derive(Clone, Debug)]
-pub struct LineSequence<R: Reader> {
- /// The first address that is covered by this sequence within the line number
- /// program.
- pub start: u64,
- /// The first address that is *not* covered by this sequence within the line
- /// number program.
- pub end: u64,
- instructions: LineInstructions<R>,
-}
-
-/// Deprecated. `LineNumberProgramHeader` has been renamed to `LineProgramHeader`.
-#[deprecated(
- note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead."
-)]
-pub type LineNumberProgramHeader<R, Offset> = LineProgramHeader<R, Offset>;
-
-/// A header for a line number program in the `.debug_line` section, as defined
-/// in section 6.2.4 of the standard.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct LineProgramHeader<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- encoding: Encoding,
- offset: DebugLineOffset<Offset>,
- unit_length: Offset,
-
- header_length: Offset,
-
- line_encoding: LineEncoding,
-
- /// "The number assigned to the first special opcode."
- opcode_base: u8,
-
- /// "This array specifies the number of LEB128 operands for each of the
- /// standard opcodes. The first element of the array corresponds to the
- /// opcode whose value is 1, and the last element corresponds to the opcode
- /// whose value is `opcode_base - 1`."
- standard_opcode_lengths: R,
-
- /// "A sequence of directory entry format descriptions."
- directory_entry_format: Vec<FileEntryFormat>,
-
- /// > Entries in this sequence describe each path that was searched for
- /// > included source files in this compilation. (The paths include those
- /// > directories specified explicitly by the user for the compiler to search
- /// > and those the compiler searches without explicit direction.) Each path
- /// > entry is either a full path name or is relative to the current directory
- /// > of the compilation.
- /// >
- /// > The last entry is followed by a single null byte.
- include_directories: Vec<AttributeValue<R, Offset>>,
-
- /// "A sequence of file entry format descriptions."
- file_name_entry_format: Vec<FileEntryFormat>,
-
- /// "Entries in this sequence describe source files that contribute to the
- /// line number information for this compilation unit or is used in other
- /// contexts."
- file_names: Vec<FileEntry<R, Offset>>,
-
- /// The encoded line program instructions.
- program_buf: R,
-
- /// The current directory of the compilation.
- comp_dir: Option<R>,
-
- /// The primary source file.
- comp_file: Option<FileEntry<R, Offset>>,
-}
-
-impl<R, Offset> LineProgramHeader<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Return the offset of the line number program header in the `.debug_line` section.
- pub fn offset(&self) -> DebugLineOffset<R::Offset> {
- self.offset
- }
-
- /// Return the length of the line number program and header, not including
- /// the length of the encoded length itself.
- pub fn unit_length(&self) -> R::Offset {
- self.unit_length
- }
-
- /// Return the encoding parameters for this header's line program.
- pub fn encoding(&self) -> Encoding {
- self.encoding
- }
-
- /// Get the version of this header's line program.
- pub fn version(&self) -> u16 {
- self.encoding.version
- }
-
- /// Get the length of the encoded line number program header, not including
- /// the length of the encoded length itself.
- pub fn header_length(&self) -> R::Offset {
- self.header_length
- }
-
- /// Get the size in bytes of a target machine address.
- pub fn address_size(&self) -> u8 {
- self.encoding.address_size
- }
-
- /// Whether this line program is encoded in 64- or 32-bit DWARF.
- pub fn format(&self) -> Format {
- self.encoding.format
- }
-
- /// Get the line encoding parameters for this header's line program.
- pub fn line_encoding(&self) -> LineEncoding {
- self.line_encoding
- }
-
- /// Get the minimum instruction length any instruction in this header's line
- /// program may have.
- pub fn minimum_instruction_length(&self) -> u8 {
- self.line_encoding.minimum_instruction_length
- }
-
- /// Get the maximum number of operations each instruction in this header's
- /// line program may have.
- pub fn maximum_operations_per_instruction(&self) -> u8 {
- self.line_encoding.maximum_operations_per_instruction
- }
-
- /// Get the default value of the `is_stmt` register for this header's line
- /// program.
- pub fn default_is_stmt(&self) -> bool {
- self.line_encoding.default_is_stmt
- }
-
- /// Get the line base for this header's line program.
- pub fn line_base(&self) -> i8 {
- self.line_encoding.line_base
- }
-
- /// Get the line range for this header's line program.
- pub fn line_range(&self) -> u8 {
- self.line_encoding.line_range
- }
-
- /// Get opcode base for this header's line program.
- pub fn opcode_base(&self) -> u8 {
- self.opcode_base
- }
-
- /// An array of `u8` that specifies the number of LEB128 operands for
- /// each of the standard opcodes.
- pub fn standard_opcode_lengths(&self) -> &R {
- &self.standard_opcode_lengths
- }
-
- /// Get the format of a directory entry.
- pub fn directory_entry_format(&self) -> &[FileEntryFormat] {
- &self.directory_entry_format[..]
- }
-
- /// Get the set of include directories for this header's line program.
- ///
- /// For DWARF version <= 4, the compilation's current directory is not included
- /// in the return value, but is implicitly considered to be in the set per spec.
- pub fn include_directories(&self) -> &[AttributeValue<R, Offset>] {
- &self.include_directories[..]
- }
-
- /// The include directory with the given directory index.
- ///
- /// A directory index of 0 corresponds to the compilation unit directory.
- pub fn directory(&self, directory: u64) -> Option<AttributeValue<R, Offset>> {
- if self.encoding.version <= 4 {
- if directory == 0 {
- self.comp_dir.clone().map(AttributeValue::String)
- } else {
- let directory = directory as usize - 1;
- self.include_directories.get(directory).cloned()
- }
- } else {
- self.include_directories.get(directory as usize).cloned()
- }
- }
-
- /// Get the format of a file name entry.
- pub fn file_name_entry_format(&self) -> &[FileEntryFormat] {
- &self.file_name_entry_format[..]
- }
-
- /// Return true if the file entries may have valid timestamps.
- ///
- /// Only returns false if we definitely know that all timestamp fields
- /// are invalid.
- pub fn file_has_timestamp(&self) -> bool {
- self.encoding.version <= 4
- || self
- .file_name_entry_format
- .iter()
- .any(|x| x.content_type == constants::DW_LNCT_timestamp)
- }
-
- /// Return true if the file entries may have valid sizes.
- ///
- /// Only returns false if we definitely know that all size fields
- /// are invalid.
- pub fn file_has_size(&self) -> bool {
- self.encoding.version <= 4
- || self
- .file_name_entry_format
- .iter()
- .any(|x| x.content_type == constants::DW_LNCT_size)
- }
-
- /// Return true if the file name entry format contains an MD5 field.
- pub fn file_has_md5(&self) -> bool {
- self.file_name_entry_format
- .iter()
- .any(|x| x.content_type == constants::DW_LNCT_MD5)
- }
-
- /// Get the list of source files that appear in this header's line program.
- pub fn file_names(&self) -> &[FileEntry<R, Offset>] {
- &self.file_names[..]
- }
-
- /// The source file with the given file index.
- ///
- /// A file index of 0 corresponds to the compilation unit file.
- /// Note that a file index of 0 is invalid for DWARF version <= 4,
- /// but we support it anyway.
- pub fn file(&self, file: u64) -> Option<&FileEntry<R, Offset>> {
- if self.encoding.version <= 4 {
- if file == 0 {
- self.comp_file.as_ref()
- } else {
- let file = file as usize - 1;
- self.file_names.get(file)
- }
- } else {
- self.file_names.get(file as usize)
- }
- }
-
- /// Get the raw, un-parsed `EndianSlice` containing this header's line number
- /// program.
- ///
- /// ```
- /// # fn foo() {
- /// use gimli::{LineProgramHeader, EndianSlice, NativeEndian};
- ///
- /// fn get_line_number_program_header<'a>() -> LineProgramHeader<EndianSlice<'a, NativeEndian>> {
- /// // Get a line number program header from some offset in a
- /// // `.debug_line` section...
- /// # unimplemented!()
- /// }
- ///
- /// let header = get_line_number_program_header();
- /// let raw_program = header.raw_program_buf();
- /// println!("The length of the raw program in bytes is {}", raw_program.len());
- /// # }
- /// ```
- pub fn raw_program_buf(&self) -> R {
- self.program_buf.clone()
- }
-
- /// Iterate over the instructions in this header's line number program, parsing
- /// them as we go.
- pub fn instructions(&self) -> LineInstructions<R> {
- LineInstructions {
- input: self.program_buf.clone(),
- }
- }
-
- fn parse(
- input: &mut R,
- offset: DebugLineOffset<Offset>,
- mut address_size: u8,
- mut comp_dir: Option<R>,
- comp_name: Option<R>,
- ) -> Result<LineProgramHeader<R, Offset>> {
- let (unit_length, format) = input.read_initial_length()?;
- let rest = &mut input.split(unit_length)?;
-
- let version = rest.read_u16()?;
- if version < 2 || version > 5 {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
-
- if version >= 5 {
- address_size = rest.read_u8()?;
- let segment_selector_size = rest.read_u8()?;
- if segment_selector_size != 0 {
- return Err(Error::UnsupportedSegmentSize);
- }
- }
-
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
-
- let header_length = rest.read_length(format)?;
-
- let mut program_buf = rest.clone();
- program_buf.skip(header_length)?;
- rest.truncate(header_length)?;
-
- let minimum_instruction_length = rest.read_u8()?;
- if minimum_instruction_length == 0 {
- return Err(Error::MinimumInstructionLengthZero);
- }
-
- // This field did not exist before DWARF 4, but is specified to be 1 for
- // non-VLIW architectures, which makes it a no-op.
- let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 };
- if maximum_operations_per_instruction == 0 {
- return Err(Error::MaximumOperationsPerInstructionZero);
- }
-
- let default_is_stmt = rest.read_u8()? != 0;
- let line_base = rest.read_i8()?;
- let line_range = rest.read_u8()?;
- if line_range == 0 {
- return Err(Error::LineRangeZero);
- }
- let line_encoding = LineEncoding {
- minimum_instruction_length,
- maximum_operations_per_instruction,
- default_is_stmt,
- line_base,
- line_range,
- };
-
- let opcode_base = rest.read_u8()?;
- if opcode_base == 0 {
- return Err(Error::OpcodeBaseZero);
- }
-
- let standard_opcode_count = R::Offset::from_u8(opcode_base - 1);
- let standard_opcode_lengths = rest.split(standard_opcode_count)?;
-
- let directory_entry_format;
- let mut include_directories = Vec::new();
- if version <= 4 {
- directory_entry_format = Vec::new();
- loop {
- let directory = rest.read_null_terminated_slice()?;
- if directory.is_empty() {
- break;
- }
- include_directories.push(AttributeValue::String(directory));
- }
- } else {
- comp_dir = None;
- directory_entry_format = FileEntryFormat::parse(rest)?;
- let count = rest.read_uleb128()?;
- for _ in 0..count {
- include_directories.push(parse_directory_v5(
- rest,
- encoding,
- &directory_entry_format,
- )?);
- }
- }
-
- let comp_file;
- let file_name_entry_format;
- let mut file_names = Vec::new();
- if version <= 4 {
- comp_file = comp_name.map(|name| FileEntry {
- path_name: AttributeValue::String(name),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- });
-
- file_name_entry_format = Vec::new();
- loop {
- let path_name = rest.read_null_terminated_slice()?;
- if path_name.is_empty() {
- break;
- }
- file_names.push(FileEntry::parse(rest, path_name)?);
- }
- } else {
- comp_file = None;
- file_name_entry_format = FileEntryFormat::parse(rest)?;
- let count = rest.read_uleb128()?;
- for _ in 0..count {
- file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?);
- }
- }
-
- let header = LineProgramHeader {
- encoding,
- offset,
- unit_length,
- header_length,
- line_encoding,
- opcode_base,
- standard_opcode_lengths,
- directory_entry_format,
- include_directories,
- file_name_entry_format,
- file_names,
- program_buf,
- comp_dir,
- comp_file,
- };
- Ok(header)
- }
-}
-
-/// Deprecated. `IncompleteLineNumberProgram` has been renamed to `IncompleteLineProgram`.
-#[deprecated(
- note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead."
-)]
-pub type IncompleteLineNumberProgram<R, Offset> = IncompleteLineProgram<R, Offset>;
-
-/// A line number program that has not been run to completion.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct IncompleteLineProgram<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- header: LineProgramHeader<R, Offset>,
-}
-
-impl<R, Offset> IncompleteLineProgram<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Retrieve the `LineProgramHeader` for this program.
- pub fn header(&self) -> &LineProgramHeader<R, Offset> {
- &self.header
- }
-
- /// Construct a new `LineRows` for executing this program to iterate
- /// over rows in the line information matrix.
- pub fn rows(self) -> OneShotLineRows<R, Offset> {
- OneShotLineRows::new(self)
- }
-
- /// Execute the line number program, completing the `IncompleteLineProgram`
- /// into a `CompleteLineProgram` and producing an array of sequences within
- /// the line number program that can later be used with
- /// `CompleteLineProgram::resume_from`.
- ///
- /// ```
- /// # fn foo() {
- /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian};
- ///
- /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> {
- /// // Get a line number program from some offset in a
- /// // `.debug_line` section...
- /// # unimplemented!()
- /// }
- ///
- /// let program = get_line_number_program();
- /// let (program, sequences) = program.sequences().unwrap();
- /// println!("There are {} sequences in this line number program", sequences.len());
- /// # }
- /// ```
- #[allow(clippy::type_complexity)]
- pub fn sequences(self) -> Result<(CompleteLineProgram<R, Offset>, Vec<LineSequence<R>>)> {
- let mut sequences = Vec::new();
- let mut rows = self.rows();
- let mut instructions = rows.instructions.clone();
- let mut sequence_start_addr = None;
- loop {
- let sequence_end_addr;
- if rows.next_row()?.is_none() {
- break;
- }
-
- let row = &rows.row;
- if row.end_sequence() {
- sequence_end_addr = row.address();
- } else if sequence_start_addr.is_none() {
- sequence_start_addr = Some(row.address());
- continue;
- } else {
- continue;
- }
-
- // We just finished a sequence.
- sequences.push(LineSequence {
- // In theory one could have multiple DW_LNE_end_sequence instructions
- // in a row.
- start: sequence_start_addr.unwrap_or(0),
- end: sequence_end_addr,
- instructions: instructions.remove_trailing(&rows.instructions)?,
- });
- sequence_start_addr = None;
- instructions = rows.instructions.clone();
- }
-
- let program = CompleteLineProgram {
- header: rows.program.header,
- };
- Ok((program, sequences))
- }
-}
-
-/// Deprecated. `CompleteLineNumberProgram` has been renamed to `CompleteLineProgram`.
-#[deprecated(
- note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead."
-)]
-pub type CompleteLineNumberProgram<R, Offset> = CompleteLineProgram<R, Offset>;
-
-/// A line number program that has previously been run to completion.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct CompleteLineProgram<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- header: LineProgramHeader<R, Offset>,
-}
-
-impl<R, Offset> CompleteLineProgram<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Retrieve the `LineProgramHeader` for this program.
- pub fn header(&self) -> &LineProgramHeader<R, Offset> {
- &self.header
- }
-
- /// Construct a new `LineRows` for executing the subset of the line
- /// number program identified by 'sequence' and generating the line information
- /// matrix.
- ///
- /// ```
- /// # fn foo() {
- /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian};
- ///
- /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> {
- /// // Get a line number program from some offset in a
- /// // `.debug_line` section...
- /// # unimplemented!()
- /// }
- ///
- /// let program = get_line_number_program();
- /// let (program, sequences) = program.sequences().unwrap();
- /// for sequence in &sequences {
- /// let mut sm = program.resume_from(sequence);
- /// }
- /// # }
- /// ```
- pub fn resume_from<'program>(
- &'program self,
- sequence: &LineSequence<R>,
- ) -> ResumedLineRows<'program, R, Offset> {
- ResumedLineRows::resume(self, sequence)
- }
-}
-
-/// An entry in the `LineProgramHeader`'s `file_names` set.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct FileEntry<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- path_name: AttributeValue<R, Offset>,
- directory_index: u64,
- timestamp: u64,
- size: u64,
- md5: [u8; 16],
-}
-
-impl<R, Offset> FileEntry<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- // version 2-4
- fn parse(input: &mut R, path_name: R) -> Result<FileEntry<R, Offset>> {
- let directory_index = input.read_uleb128()?;
- let timestamp = input.read_uleb128()?;
- let size = input.read_uleb128()?;
-
- let entry = FileEntry {
- path_name: AttributeValue::String(path_name),
- directory_index,
- timestamp,
- size,
- md5: [0; 16],
- };
-
- Ok(entry)
- }
-
- /// > A slice containing the full or relative path name of
- /// > a source file. If the entry contains a file name or a relative path
- /// > name, the file is located relative to either the compilation directory
- /// > (as specified by the DW_AT_comp_dir attribute given in the compilation
- /// > unit) or one of the directories in the include_directories section.
- pub fn path_name(&self) -> AttributeValue<R, Offset> {
- self.path_name.clone()
- }
-
- /// > An unsigned LEB128 number representing the directory index of the
- /// > directory in which the file was found.
- /// >
- /// > ...
- /// >
- /// > The directory index represents an entry in the include_directories
- /// > section of the line number program header. The index is 0 if the file
- /// > was found in the current directory of the compilation, 1 if it was found
- /// > in the first directory in the include_directories section, and so
- /// > on. The directory index is ignored for file names that represent full
- /// > path names.
- pub fn directory_index(&self) -> u64 {
- self.directory_index
- }
-
- /// Get this file's directory.
- ///
- /// A directory index of 0 corresponds to the compilation unit directory.
- pub fn directory(&self, header: &LineProgramHeader<R>) -> Option<AttributeValue<R, Offset>> {
- header.directory(self.directory_index)
- }
-
- /// The implementation-defined time of last modification of the file,
- /// or 0 if not available.
- pub fn timestamp(&self) -> u64 {
- self.timestamp
- }
-
- /// "An unsigned LEB128 number representing the time of last modification of
- /// the file, or 0 if not available."
- // Terminology changed in DWARF version 5.
- #[doc(hidden)]
- pub fn last_modification(&self) -> u64 {
- self.timestamp
- }
-
- /// The size of the file in bytes, or 0 if not available.
- pub fn size(&self) -> u64 {
- self.size
- }
-
- /// "An unsigned LEB128 number representing the length in bytes of the file,
- /// or 0 if not available."
- // Terminology changed in DWARF version 5.
- #[doc(hidden)]
- pub fn length(&self) -> u64 {
- self.size
- }
-
- /// A 16-byte MD5 digest of the file contents.
- ///
- /// Only valid if `LineProgramHeader::file_has_md5` returns `true`.
- pub fn md5(&self) -> &[u8; 16] {
- &self.md5
- }
-}
-
-/// The format of a component of an include directory or file name entry.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct FileEntryFormat {
- /// The type of information that is represented by the component.
- pub content_type: constants::DwLnct,
-
- /// The encoding form of the component value.
- pub form: constants::DwForm,
-}
-
-impl FileEntryFormat {
- fn parse<R: Reader>(input: &mut R) -> Result<Vec<FileEntryFormat>> {
- let format_count = input.read_u8()? as usize;
- let mut format = Vec::with_capacity(format_count);
- let mut path_count = 0;
- for _ in 0..format_count {
- let content_type = input.read_uleb128()?;
- let content_type = if content_type > u64::from(u16::max_value()) {
- constants::DwLnct(u16::max_value())
- } else {
- constants::DwLnct(content_type as u16)
- };
- if content_type == constants::DW_LNCT_path {
- path_count += 1;
- }
-
- let form = constants::DwForm(input.read_uleb128_u16()?);
-
- format.push(FileEntryFormat { content_type, form });
- }
- if path_count != 1 {
- return Err(Error::MissingFileEntryFormatPath);
- }
- Ok(format)
- }
-}
-
-fn parse_directory_v5<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- formats: &[FileEntryFormat],
-) -> Result<AttributeValue<R>> {
- let mut path_name = None;
-
- for format in formats {
- let value = parse_attribute(input, encoding, format.form)?;
- if format.content_type == constants::DW_LNCT_path {
- path_name = Some(value);
- }
- }
-
- Ok(path_name.unwrap())
-}
-
-fn parse_file_v5<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- formats: &[FileEntryFormat],
-) -> Result<FileEntry<R>> {
- let mut path_name = None;
- let mut directory_index = 0;
- let mut timestamp = 0;
- let mut size = 0;
- let mut md5 = [0; 16];
-
- for format in formats {
- let value = parse_attribute(input, encoding, format.form)?;
- match format.content_type {
- constants::DW_LNCT_path => path_name = Some(value),
- constants::DW_LNCT_directory_index => {
- if let Some(value) = value.udata_value() {
- directory_index = value;
- }
- }
- constants::DW_LNCT_timestamp => {
- if let Some(value) = value.udata_value() {
- timestamp = value;
- }
- }
- constants::DW_LNCT_size => {
- if let Some(value) = value.udata_value() {
- size = value;
- }
- }
- constants::DW_LNCT_MD5 => {
- if let AttributeValue::Block(mut value) = value {
- if value.len().into_u64() == 16 {
- md5 = value.read_u8_array()?;
- }
- }
- }
- // Ignore unknown content types.
- _ => {}
- }
- }
-
- Ok(FileEntry {
- path_name: path_name.unwrap(),
- directory_index,
- timestamp,
- size,
- md5,
- })
-}
-
-// TODO: this should be shared with unit::parse_attribute(), but that is hard to do.
-fn parse_attribute<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- form: constants::DwForm,
-) -> Result<AttributeValue<R>> {
- Ok(match form {
- constants::DW_FORM_block1 => {
- let len = input.read_u8().map(R::Offset::from_u8)?;
- let block = input.split(len)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block2 => {
- let len = input.read_u16().map(R::Offset::from_u16)?;
- let block = input.split(len)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block4 => {
- let len = input.read_u32().map(R::Offset::from_u32)?;
- let block = input.split(len)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block => {
- let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- let block = input.split(len)?;
- 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 => {
- let data = input.read_u32()?;
- AttributeValue::Data4(data)
- }
- constants::DW_FORM_data8 => {
- 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_flag => {
- let present = input.read_u8()?;
- AttributeValue::Flag(present != 0)
- }
- constants::DW_FORM_sec_offset => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::SecOffset(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_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))
- }
- _ => {
- return Err(Error::UnknownForm);
- }
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::constants;
- use crate::endianity::LittleEndian;
- use crate::read::{EndianSlice, Error};
- use crate::test_util::GimliSectionMethods;
- use core::u64;
- use core::u8;
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- #[test]
- fn test_parse_debug_line_32_ok() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 62.
- 0x3e, 0x00, 0x00, 0x00,
- // Version.
- 0x04, 0x00,
- // Header length = 40.
- 0x28, 0x00, 0x00, 0x00,
- // Minimum instruction length.
- 0x01,
- // Maximum operations per byte.
- 0x01,
- // Default is_stmt.
- 0x01,
- // Line base.
- 0x00,
- // Line range.
- 0x01,
- // Opcode base.
- 0x03,
- // Standard opcode lengths for opcodes 1 .. opcode base - 1.
- 0x01, 0x02,
- // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
- 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
- // File names
- // foo.rs
- 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
- 0x00,
- 0x00,
- 0x00,
- // bar.h
- 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
- 0x01,
- 0x00,
- 0x00,
- // End file names.
- 0x00,
-
- // Dummy line program data.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next line program.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
- let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian);
- let comp_name = EndianSlice::new(b"/comp_name", LittleEndian);
-
- let header =
- LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name))
- .expect("should parse header ok");
-
- assert_eq!(
- *rest,
- EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
- );
-
- assert_eq!(header.offset, DebugLineOffset(0));
- assert_eq!(header.version(), 4);
- assert_eq!(header.minimum_instruction_length(), 1);
- assert_eq!(header.maximum_operations_per_instruction(), 1);
- assert_eq!(header.default_is_stmt(), true);
- assert_eq!(header.line_base(), 0);
- assert_eq!(header.line_range(), 1);
- assert_eq!(header.opcode_base(), 3);
- assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir)));
- assert_eq!(
- header.file(0).unwrap().path_name,
- AttributeValue::String(comp_name)
- );
-
- let expected_lengths = [1, 2];
- assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths);
-
- let expected_include_directories = [
- AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)),
- AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)),
- ];
- assert_eq!(header.include_directories(), &expected_include_directories);
-
- let expected_file_names = [
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- },
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)),
- directory_index: 1,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- },
- ];
- assert_eq!(&*header.file_names(), &expected_file_names);
- }
-
- #[test]
- fn test_parse_debug_line_header_length_too_short() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 62.
- 0x3e, 0x00, 0x00, 0x00,
- // Version.
- 0x04, 0x00,
- // Header length = 20. TOO SHORT!!!
- 0x15, 0x00, 0x00, 0x00,
- // Minimum instruction length.
- 0x01,
- // Maximum operations per byte.
- 0x01,
- // Default is_stmt.
- 0x01,
- // Line base.
- 0x00,
- // Line range.
- 0x01,
- // Opcode base.
- 0x03,
- // Standard opcode lengths for opcodes 1 .. opcode base - 1.
- 0x01, 0x02,
- // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
- 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
- // File names
- // foo.rs
- 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
- 0x00,
- 0x00,
- 0x00,
- // bar.h
- 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
- 0x01,
- 0x00,
- 0x00,
- // End file names.
- 0x00,
-
- // Dummy line program data.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next line program.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
-
- match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
- Err(Error::UnexpectedEof(_)) => return,
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_parse_debug_line_unit_length_too_short() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length = 40. TOO SHORT!!!
- 0x28, 0x00, 0x00, 0x00,
- // Version.
- 0x04, 0x00,
- // Header length = 40.
- 0x28, 0x00, 0x00, 0x00,
- // Minimum instruction length.
- 0x01,
- // Maximum operations per byte.
- 0x01,
- // Default is_stmt.
- 0x01,
- // Line base.
- 0x00,
- // Line range.
- 0x01,
- // Opcode base.
- 0x03,
- // Standard opcode lengths for opcodes 1 .. opcode base - 1.
- 0x01, 0x02,
- // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
- 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
- // File names
- // foo.rs
- 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
- 0x00,
- 0x00,
- 0x00,
- // bar.h
- 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
- 0x01,
- 0x00,
- 0x00,
- // End file names.
- 0x00,
-
- // Dummy line program data.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- // Dummy next line program.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
-
- match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
- Err(Error::UnexpectedEof(_)) => return,
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- const OPCODE_BASE: u8 = 13;
- const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1];
-
- fn make_test_header(
- buf: EndianSlice<LittleEndian>,
- ) -> LineProgramHeader<EndianSlice<LittleEndian>> {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 8,
- };
- let line_encoding = LineEncoding {
- line_base: -3,
- line_range: 12,
- ..Default::default()
- };
- LineProgramHeader {
- encoding,
- offset: DebugLineOffset(0),
- unit_length: 1,
- header_length: 1,
- line_encoding,
- opcode_base: OPCODE_BASE,
- standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian),
- file_names: vec![
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- },
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- },
- ],
- include_directories: vec![],
- directory_entry_format: vec![],
- file_name_entry_format: vec![],
- program_buf: buf,
- comp_dir: None,
- comp_file: None,
- }
- }
-
- fn make_test_program(
- buf: EndianSlice<LittleEndian>,
- ) -> IncompleteLineProgram<EndianSlice<LittleEndian>> {
- IncompleteLineProgram {
- header: make_test_header(buf),
- }
- }
-
- #[test]
- fn test_parse_special_opcodes() {
- for i in OPCODE_BASE..u8::MAX {
- let input = [i, 0, 0, 0];
- let input = EndianSlice::new(&input, LittleEndian);
- let header = make_test_header(input);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(*rest, *input.range_from(1..));
- assert_eq!(opcode, LineInstruction::Special(i));
- }
- }
-
- #[test]
- fn test_parse_standard_opcodes() {
- fn test<Operands>(
- raw: constants::DwLns,
- operands: Operands,
- expected: LineInstruction<EndianSlice<LittleEndian>>,
- ) where
- Operands: AsRef<[u8]>,
- {
- let mut input = Vec::new();
- input.push(raw.0);
- input.extend_from_slice(operands.as_ref());
-
- let expected_rest = [0, 1, 2, 3, 4];
- input.extend_from_slice(&expected_rest);
-
- let input = EndianSlice::new(&*input, LittleEndian);
- let header = make_test_header(input);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(opcode, expected);
- assert_eq!(*rest, expected_rest);
- }
-
- test(constants::DW_LNS_copy, [], LineInstruction::Copy);
- test(
- constants::DW_LNS_advance_pc,
- [42],
- LineInstruction::AdvancePc(42),
- );
- test(
- constants::DW_LNS_advance_line,
- [9],
- LineInstruction::AdvanceLine(9),
- );
- test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7));
- test(
- constants::DW_LNS_set_column,
- [1],
- LineInstruction::SetColumn(1),
- );
- test(
- constants::DW_LNS_negate_stmt,
- [],
- LineInstruction::NegateStatement,
- );
- test(
- constants::DW_LNS_set_basic_block,
- [],
- LineInstruction::SetBasicBlock,
- );
- test(
- constants::DW_LNS_const_add_pc,
- [],
- LineInstruction::ConstAddPc,
- );
- test(
- constants::DW_LNS_fixed_advance_pc,
- [42, 0],
- LineInstruction::FixedAddPc(42),
- );
- test(
- constants::DW_LNS_set_prologue_end,
- [],
- LineInstruction::SetPrologueEnd,
- );
- test(
- constants::DW_LNS_set_isa,
- [57 + 0x80, 100],
- LineInstruction::SetIsa(12857),
- );
- }
-
- #[test]
- fn test_parse_unknown_standard_opcode_no_args() {
- let input = [OPCODE_BASE, 1, 2, 3];
- let input = EndianSlice::new(&input, LittleEndian);
- let mut standard_opcode_lengths = Vec::new();
- let mut header = make_test_header(input);
- standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
- standard_opcode_lengths.push(0);
- header.opcode_base += 1;
- header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(
- opcode,
- LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE))
- );
- assert_eq!(*rest, *input.range_from(1..));
- }
-
- #[test]
- fn test_parse_unknown_standard_opcode_one_arg() {
- let input = [OPCODE_BASE, 1, 2, 3];
- let input = EndianSlice::new(&input, LittleEndian);
- let mut standard_opcode_lengths = Vec::new();
- let mut header = make_test_header(input);
- standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
- standard_opcode_lengths.push(1);
- header.opcode_base += 1;
- header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(
- opcode,
- LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1)
- );
- assert_eq!(*rest, *input.range_from(2..));
- }
-
- #[test]
- fn test_parse_unknown_standard_opcode_many_args() {
- let input = [OPCODE_BASE, 1, 2, 3];
- let input = EndianSlice::new(&input, LittleEndian);
- let args = input.range_from(1..);
- let mut standard_opcode_lengths = Vec::new();
- let mut header = make_test_header(input);
- standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
- standard_opcode_lengths.push(3);
- header.opcode_base += 1;
- header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(
- opcode,
- LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args)
- );
- assert_eq!(*rest, []);
- }
-
- #[test]
- fn test_parse_extended_opcodes() {
- fn test<Operands>(
- raw: constants::DwLne,
- operands: Operands,
- expected: LineInstruction<EndianSlice<LittleEndian>>,
- ) where
- Operands: AsRef<[u8]>,
- {
- let mut input = Vec::new();
- input.push(0);
-
- let operands = operands.as_ref();
- input.push(1 + operands.len() as u8);
-
- input.push(raw.0);
- input.extend_from_slice(operands);
-
- let expected_rest = [0, 1, 2, 3, 4];
- input.extend_from_slice(&expected_rest);
-
- let input = EndianSlice::new(&input, LittleEndian);
- let header = make_test_header(input);
-
- let mut rest = input;
- let opcode =
- LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
-
- assert_eq!(opcode, expected);
- assert_eq!(*rest, expected_rest);
- }
-
- test(
- constants::DW_LNE_end_sequence,
- [],
- LineInstruction::EndSequence,
- );
- test(
- constants::DW_LNE_set_address,
- [1, 2, 3, 4, 5, 6, 7, 8],
- LineInstruction::SetAddress(578_437_695_752_307_201),
- );
- test(
- constants::DW_LNE_set_discriminator,
- [42],
- LineInstruction::SetDiscriminator(42),
- );
-
- let mut file = Vec::new();
- // "foo.c"
- let path_name = [b'f', b'o', b'o', b'.', b'c', 0];
- file.extend_from_slice(&path_name);
- // Directory index.
- file.push(0);
- // Last modification of file.
- file.push(1);
- // Size of file.
- file.push(2);
-
- test(
- constants::DW_LNE_define_file,
- file,
- LineInstruction::DefineFile(FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
- directory_index: 0,
- timestamp: 1,
- size: 2,
- md5: [0; 16],
- }),
- );
-
- // Unknown extended opcode.
- let operands = [1, 2, 3, 4, 5, 6];
- let opcode = constants::DwLne(99);
- test(
- opcode,
- operands,
- LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)),
- );
- }
-
- #[test]
- fn test_file_entry_directory() {
- let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0];
-
- let mut file = FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)),
- directory_index: 1,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- };
-
- let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian));
- header.include_directories.push(dir);
-
- assert_eq!(file.directory(&header), Some(dir));
-
- // Now test the compilation's current directory.
- file.directory_index = 0;
- assert_eq!(file.directory(&header), None);
- }
-
- fn assert_exec_opcode<'input>(
- header: LineProgramHeader<EndianSlice<'input, LittleEndian>>,
- mut registers: LineRow,
- opcode: LineInstruction<EndianSlice<'input, LittleEndian>>,
- expected_registers: LineRow,
- expect_new_row: bool,
- ) {
- let mut program = IncompleteLineProgram { header };
- let is_new_row = registers.execute(opcode, &mut program);
-
- assert_eq!(is_new_row, expect_new_row);
- assert_eq!(registers, expected_registers);
- }
-
- #[test]
- fn test_exec_special_noop() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::Special(16);
- let expected_registers = initial_registers;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_negative_line_advance() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.line.0 = 10;
-
- let opcode = LineInstruction::Special(13);
-
- let mut expected_registers = initial_registers;
- expected_registers.line.0 -= 3;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_positive_line_advance() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let initial_registers = LineRow::new(&header);
-
- let opcode = LineInstruction::Special(19);
-
- let mut expected_registers = initial_registers;
- expected_registers.line.0 += 3;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_positive_address_advance() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let initial_registers = LineRow::new(&header);
-
- let opcode = LineInstruction::Special(52);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 3;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_positive_address_and_line_advance() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let initial_registers = LineRow::new(&header);
-
- let opcode = LineInstruction::Special(55);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 3;
- expected_registers.line.0 += 3;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_positive_address_and_negative_line_advance() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.line.0 = 10;
-
- let opcode = LineInstruction::Special(49);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 3;
- expected_registers.line.0 -= 3;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_special_line_underflow() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.line.0 = 2;
-
- // -3 line advance.
- let opcode = LineInstruction::Special(13);
-
- let mut expected_registers = initial_registers;
- // Clamp at 0. No idea if this is the best way to handle this situation
- // or not...
- expected_registers.line.0 = 0;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_copy() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.address.0 = 1337;
- initial_registers.line.0 = 42;
-
- let opcode = LineInstruction::Copy;
-
- let expected_registers = initial_registers;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_advance_pc() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::AdvancePc(42);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 42;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_advance_pc_overflow() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let opcode = LineInstruction::AdvancePc(42);
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.address.0 = u64::MAX;
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 = 41;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_advance_line() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::AdvanceLine(42);
-
- let mut expected_registers = initial_registers;
- expected_registers.line.0 += 42;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_advance_line_overflow() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let opcode = LineInstruction::AdvanceLine(42);
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.line.0 = u64::MAX;
-
- let mut expected_registers = initial_registers;
- expected_registers.line.0 = 41;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_set_file_in_bounds() {
- for file_idx in 1..3 {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetFile(file_idx);
-
- let mut expected_registers = initial_registers;
- expected_registers.file = file_idx;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
- }
-
- #[test]
- fn test_exec_set_file_out_of_bounds() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetFile(100);
-
- // The spec doesn't say anything about rejecting input programs
- // that set the file register out of bounds of the actual number
- // of files that have been defined. Instead, we cross our
- // fingers and hope that one gets defined before
- // `LineRow::file` gets called and handle the error at
- // that time if need be.
- let mut expected_registers = initial_registers;
- expected_registers.file = 100;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_file_entry_file_index_out_of_bounds() {
- // These indices are 1-based, so 0 is invalid. 100 is way more than the
- // number of files defined in the header.
- let out_of_bounds_indices = [0, 100];
-
- for file_idx in &out_of_bounds_indices[..] {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let mut row = LineRow::new(&header);
-
- row.file = *file_idx;
-
- assert_eq!(row.file(&header), None);
- }
- }
-
- #[test]
- fn test_file_entry_file_index_in_bounds() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let mut row = LineRow::new(&header);
-
- row.file = 2;
-
- assert_eq!(row.file(&header), Some(&header.file_names()[1]));
- }
-
- #[test]
- fn test_exec_set_column() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetColumn(42);
-
- let mut expected_registers = initial_registers;
- expected_registers.column = 42;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_negate_statement() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::NegateStatement;
-
- let mut expected_registers = initial_registers;
- expected_registers.is_stmt = !initial_registers.is_stmt;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_set_basic_block() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.basic_block = false;
-
- let opcode = LineInstruction::SetBasicBlock;
-
- let mut expected_registers = initial_registers;
- expected_registers.basic_block = true;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_const_add_pc() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::ConstAddPc;
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 20;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_fixed_add_pc() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.op_index.0 = 1;
-
- let opcode = LineInstruction::FixedAddPc(10);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 += 10;
- expected_registers.op_index.0 = 0;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_set_prologue_end() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
-
- let mut initial_registers = LineRow::new(&header);
- initial_registers.prologue_end = false;
-
- let opcode = LineInstruction::SetPrologueEnd;
-
- let mut expected_registers = initial_registers;
- expected_registers.prologue_end = true;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_set_isa() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetIsa(1993);
-
- let mut expected_registers = initial_registers;
- expected_registers.isa = 1993;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_unknown_standard_0() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111));
- let expected_registers = initial_registers;
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_unknown_standard_1() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2);
- let expected_registers = initial_registers;
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_unknown_standard_n() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::UnknownStandardN(
- constants::DwLns(111),
- EndianSlice::new(&[2, 2, 2], LittleEndian),
- );
- let expected_registers = initial_registers;
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_end_sequence() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::EndSequence;
-
- let mut expected_registers = initial_registers;
- expected_registers.end_sequence = true;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
- }
-
- #[test]
- fn test_exec_set_address() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetAddress(3030);
-
- let mut expected_registers = initial_registers;
- expected_registers.address.0 = 3030;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_set_address_tombstone() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetAddress(!0);
-
- let mut expected_registers = initial_registers;
- expected_registers.tombstone = true;
- expected_registers.address.0 = !0;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_define_file() {
- let mut program = make_test_program(EndianSlice::new(&[], LittleEndian));
- let mut row = LineRow::new(program.header());
-
- let file = FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [0; 16],
- };
-
- let opcode = LineInstruction::DefineFile(file);
- let is_new_row = row.execute(opcode, &mut program);
-
- assert_eq!(is_new_row, false);
- assert_eq!(Some(&file), program.header().file_names.last());
- }
-
- #[test]
- fn test_exec_set_discriminator() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::SetDiscriminator(9);
-
- let mut expected_registers = initial_registers;
- expected_registers.discriminator = 9;
-
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- #[test]
- fn test_exec_unknown_extended() {
- let header = make_test_header(EndianSlice::new(&[], LittleEndian));
- let initial_registers = LineRow::new(&header);
- let opcode = LineInstruction::UnknownExtended(
- constants::DwLne(74),
- EndianSlice::new(&[], LittleEndian),
- );
- let expected_registers = initial_registers;
- assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
- }
-
- /// Ensure that `LineRows<R,P>` is covariant wrt R.
- /// This only needs to compile.
- #[allow(dead_code, unreachable_code, unused_variables)]
- fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8])
- where
- 'a: 'b,
- {
- let a: &OneShotLineRows<EndianSlice<'a, LittleEndian>> = unimplemented!();
- let _: &OneShotLineRows<EndianSlice<'b, LittleEndian>> = a;
- }
-
- #[test]
- fn test_parse_debug_line_v5_ok() {
- let expected_lengths = &[1, 2];
- let expected_program = &[0, 1, 2, 3, 4];
- let expected_rest = &[5, 6, 7, 8, 9];
- let expected_include_directories = [
- AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)),
- AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)),
- ];
- let expected_file_names = [
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)),
- directory_index: 0,
- timestamp: 0,
- size: 0,
- md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
- },
- FileEntry {
- path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)),
- directory_index: 1,
- timestamp: 0,
- size: 0,
- md5: [
- 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
- ],
- },
- ];
-
- for format in vec![Format::Dwarf32, Format::Dwarf64] {
- let length = Label::new();
- let header_length = Label::new();
- let start = Label::new();
- let header_start = Label::new();
- let end = Label::new();
- let header_end = Label::new();
- let section = Section::with_endian(Endian::Little)
- .initial_length(format, &length, &start)
- .D16(5)
- // Address size.
- .D8(4)
- // Segment selector size.
- .D8(0)
- .word_label(format.word_size(), &header_length)
- .mark(&header_start)
- // Minimum instruction length.
- .D8(1)
- // Maximum operations per byte.
- .D8(1)
- // Default is_stmt.
- .D8(1)
- // Line base.
- .D8(0)
- // Line range.
- .D8(1)
- // Opcode base.
- .D8(expected_lengths.len() as u8 + 1)
- // Standard opcode lengths for opcodes 1 .. opcode base - 1.
- .append_bytes(expected_lengths)
- // Directory entry format count.
- .D8(1)
- .uleb(constants::DW_LNCT_path.0 as u64)
- .uleb(constants::DW_FORM_string.0 as u64)
- // Directory count.
- .D8(2)
- .append_bytes(b"dir1\0")
- .append_bytes(b"dir2\0")
- // File entry format count.
- .D8(3)
- .uleb(constants::DW_LNCT_path.0 as u64)
- .uleb(constants::DW_FORM_string.0 as u64)
- .uleb(constants::DW_LNCT_directory_index.0 as u64)
- .uleb(constants::DW_FORM_data1.0 as u64)
- .uleb(constants::DW_LNCT_MD5.0 as u64)
- .uleb(constants::DW_FORM_data16.0 as u64)
- // File count.
- .D8(2)
- .append_bytes(b"file1\0")
- .D8(0)
- .append_bytes(&expected_file_names[0].md5)
- .append_bytes(b"file2\0")
- .D8(1)
- .append_bytes(&expected_file_names[1].md5)
- .mark(&header_end)
- // Dummy line program data.
- .append_bytes(expected_program)
- .mark(&end)
- // Dummy trailing data.
- .append_bytes(expected_rest);
- length.set_const((&end - &start) as u64);
- header_length.set_const((&header_end - &header_start) as u64);
- let section = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&section, LittleEndian);
-
- let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None)
- .expect("should parse header ok");
-
- assert_eq!(header.raw_program_buf().slice(), expected_program);
- assert_eq!(input.slice(), expected_rest);
-
- assert_eq!(header.offset, DebugLineOffset(0));
- assert_eq!(header.version(), 5);
- assert_eq!(header.address_size(), 4);
- assert_eq!(header.minimum_instruction_length(), 1);
- assert_eq!(header.maximum_operations_per_instruction(), 1);
- assert_eq!(header.default_is_stmt(), true);
- assert_eq!(header.line_base(), 0);
- assert_eq!(header.line_range(), 1);
- assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1);
- assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths);
- assert_eq!(
- header.directory_entry_format(),
- &[FileEntryFormat {
- content_type: constants::DW_LNCT_path,
- form: constants::DW_FORM_string,
- }]
- );
- assert_eq!(header.include_directories(), expected_include_directories);
- assert_eq!(header.directory(0), Some(expected_include_directories[0]));
- assert_eq!(
- header.file_name_entry_format(),
- &[
- FileEntryFormat {
- content_type: constants::DW_LNCT_path,
- form: constants::DW_FORM_string,
- },
- FileEntryFormat {
- content_type: constants::DW_LNCT_directory_index,
- form: constants::DW_FORM_data1,
- },
- FileEntryFormat {
- content_type: constants::DW_LNCT_MD5,
- form: constants::DW_FORM_data16,
- }
- ]
- );
- assert_eq!(header.file_names(), expected_file_names);
- assert_eq!(header.file(0), Some(&expected_file_names[0]));
- }
- }
-
- #[test]
- fn test_sequences() {
- #[rustfmt::skip]
- let buf = [
- // 32-bit length
- 94, 0x00, 0x00, 0x00,
- // Version.
- 0x04, 0x00,
- // Header length = 40.
- 0x28, 0x00, 0x00, 0x00,
- // Minimum instruction length.
- 0x01,
- // Maximum operations per byte.
- 0x01,
- // Default is_stmt.
- 0x01,
- // Line base.
- 0x00,
- // Line range.
- 0x01,
- // Opcode base.
- 0x03,
- // Standard opcode lengths for opcodes 1 .. opcode base - 1.
- 0x01, 0x02,
- // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
- 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
- // File names
- // foo.rs
- 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
- 0x00,
- 0x00,
- 0x00,
- // bar.h
- 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
- 0x01,
- 0x00,
- 0x00,
- // End file names.
- 0x00,
-
- 0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 1,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 2,
- 0, 1, constants::DW_LNE_end_sequence.0,
-
- // Tombstone
- 0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 1,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 2,
- 0, 1, constants::DW_LNE_end_sequence.0,
-
- 0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 1,
- constants::DW_LNS_copy.0,
- constants::DW_LNS_advance_pc.0, 2,
- 0, 1, constants::DW_LNE_end_sequence.0,
- ];
- assert_eq!(buf[0] as usize, buf.len() - 4);
-
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None)
- .expect("should parse header ok");
- let program = IncompleteLineProgram { header };
-
- let sequences = program.sequences().unwrap().1;
- assert_eq!(sequences.len(), 2);
- assert_eq!(sequences[0].start, 1);
- assert_eq!(sequences[0].end, 4);
- assert_eq!(sequences[1].start, 11);
- assert_eq!(sequences[1].end, 14);
- }
-}
diff --git a/vendor/gimli/src/read/lists.rs b/vendor/gimli/src/read/lists.rs
deleted file mode 100644
index 898a757..0000000
--- a/vendor/gimli/src/read/lists.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use crate::common::{Encoding, Format};
-use crate::read::{Error, Reader, Result};
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct ListsHeader {
- encoding: Encoding,
- #[allow(dead_code)]
- offset_entry_count: u32,
-}
-
-impl Default for ListsHeader {
- fn default() -> Self {
- ListsHeader {
- encoding: Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 0,
- },
- offset_entry_count: 0,
- }
- }
-}
-
-impl ListsHeader {
- /// Return the serialized size of the table header.
- #[allow(dead_code)]
- #[inline]
- fn size(self) -> u8 {
- // initial_length + version + address_size + segment_selector_size + offset_entry_count
- ListsHeader::size_for_encoding(self.encoding)
- }
-
- /// Return the serialized size of the table header.
- #[inline]
- pub(crate) fn size_for_encoding(encoding: Encoding) -> u8 {
- // initial_length + version + address_size + segment_selector_size + offset_entry_count
- encoding.format.initial_length_size() + 2 + 1 + 1 + 4
- }
-}
-
-// TODO: add an iterator over headers in the appropriate sections section
-#[allow(dead_code)]
-fn parse_header<R: Reader>(input: &mut R) -> Result<ListsHeader> {
- let (length, format) = input.read_initial_length()?;
- input.truncate(length)?;
-
- let version = input.read_u16()?;
- if version != 5 {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
-
- let address_size = input.read_u8()?;
- let segment_selector_size = input.read_u8()?;
- if segment_selector_size != 0 {
- return Err(Error::UnsupportedSegmentSize);
- }
- let offset_entry_count = input.read_u32()?;
-
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
- Ok(ListsHeader {
- encoding,
- offset_entry_count,
- })
-}
diff --git a/vendor/gimli/src/read/loclists.rs b/vendor/gimli/src/read/loclists.rs
deleted file mode 100644
index 5cba675..0000000
--- a/vendor/gimli/src/read/loclists.rs
+++ /dev/null
@@ -1,1627 +0,0 @@
-use crate::common::{
- DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding,
- LocationListsOffset, SectionId,
-};
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::{
- lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader,
- ReaderOffset, ReaderOffsetId, Result, Section,
-};
-
-/// The raw contents of the `.debug_loc` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugLoc<R> {
- pub(crate) section: R,
-}
-
-impl<'input, Endian> DebugLoc<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugLoc` instance from the data in the `.debug_loc`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_loc` 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::{DebugLoc, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_loc_section_somehow = || &buf;
- /// let debug_loc = DebugLoc::new(read_debug_loc_section_somehow(), LittleEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugLoc<R> {
- fn id() -> SectionId {
- SectionId::DebugLoc
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugLoc<R> {
- fn from(section: R) -> Self {
- DebugLoc { section }
- }
-}
-
-/// The `DebugLocLists` struct represents the DWARF data
-/// found in the `.debug_loclists` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugLocLists<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugLocLists<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugLocLists` instance from the data in the `.debug_loclists`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_loclists` 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::{DebugLocLists, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_loclists_section_somehow = || &buf;
- /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugLocLists<R> {
- fn id() -> SectionId {
- SectionId::DebugLocLists
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugLocLists<R> {
- fn from(section: R) -> Self {
- DebugLocLists { section }
- }
-}
-
-pub(crate) type LocListsHeader = ListsHeader;
-
-impl<Offset> DebugLocListsBase<Offset>
-where
- Offset: ReaderOffset,
-{
- /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base
- /// for the given `Encoding` and `DwarfFileType`.
- pub fn default_for_encoding_and_file(
- encoding: Encoding,
- file_type: DwarfFileType,
- ) -> DebugLocListsBase<Offset> {
- if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
- // In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is
- // only a single unit in the file) but we must skip past the header, which the attribute
- // would normally do for us.
- DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding)))
- } else {
- DebugLocListsBase(Offset::from_u8(0))
- }
- }
-}
-
-/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct LocationLists<R> {
- debug_loc: DebugLoc<R>,
- debug_loclists: DebugLocLists<R>,
-}
-
-impl<R> LocationLists<R> {
- /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and
- /// `.debug_loclists` sections.
- pub fn new(debug_loc: DebugLoc<R>, debug_loclists: DebugLocLists<R>) -> LocationLists<R> {
- LocationLists {
- debug_loc,
- debug_loclists,
- }
- }
-}
-
-impl<T> LocationLists<T> {
- /// Create a `LocationLists` that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::LocationLists<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists<R>
- where
- F: FnMut(&'a T) -> R,
- {
- LocationLists {
- debug_loc: borrow(&self.debug_loc.section).into(),
- debug_loclists: borrow(&self.debug_loclists.section).into(),
- }
- }
-}
-
-impl<R: Reader> LocationLists<R> {
- /// Iterate over the `LocationListEntry`s starting at the given offset.
- ///
- /// The `unit_encoding` must match the compilation unit that the
- /// offset was contained in.
- ///
- /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the
- /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location
- /// list.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn locations(
- &self,
- offset: LocationListsOffset<R::Offset>,
- unit_encoding: Encoding,
- base_address: u64,
- debug_addr: &DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
- ) -> Result<LocListIter<R>> {
- Ok(LocListIter::new(
- self.raw_locations(offset, unit_encoding)?,
- base_address,
- debug_addr.clone(),
- debug_addr_base,
- ))
- }
-
- /// Similar to `locations`, but with special handling for .dwo files.
- /// This should only been used when this `LocationLists` was loaded from a
- /// .dwo file.
- pub fn locations_dwo(
- &self,
- offset: LocationListsOffset<R::Offset>,
- unit_encoding: Encoding,
- base_address: u64,
- debug_addr: &DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
- ) -> Result<LocListIter<R>> {
- Ok(LocListIter::new(
- self.raw_locations_dwo(offset, unit_encoding)?,
- base_address,
- debug_addr.clone(),
- debug_addr_base,
- ))
- }
-
- /// Iterate over the raw `LocationListEntry`s starting at the given offset.
- ///
- /// The `unit_encoding` must match the compilation unit that the
- /// offset was contained in.
- ///
- /// This iterator does not perform any processing of the location entries,
- /// such as handling base addresses.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn raw_locations(
- &self,
- offset: LocationListsOffset<R::Offset>,
- unit_encoding: Encoding,
- ) -> Result<RawLocListIter<R>> {
- let (mut input, format) = if unit_encoding.version <= 4 {
- (self.debug_loc.section.clone(), LocListsFormat::Bare)
- } else {
- (self.debug_loclists.section.clone(), LocListsFormat::Lle)
- };
- input.skip(offset.0)?;
- Ok(RawLocListIter::new(input, unit_encoding, format))
- }
-
- /// Similar to `raw_locations`, but with special handling for .dwo files.
- /// This should only been used when this `LocationLists` was loaded from a
- /// .dwo file.
- pub fn raw_locations_dwo(
- &self,
- offset: LocationListsOffset<R::Offset>,
- unit_encoding: Encoding,
- ) -> Result<RawLocListIter<R>> {
- let mut input = if unit_encoding.version <= 4 {
- // In the GNU split dwarf extension the locations are present in the
- // .debug_loc section but are encoded with the DW_LLE values used
- // for the DWARF 5 .debug_loclists section.
- self.debug_loc.section.clone()
- } else {
- self.debug_loclists.section.clone()
- };
- input.skip(offset.0)?;
- Ok(RawLocListIter::new(
- input,
- unit_encoding,
- LocListsFormat::Lle,
- ))
- }
-
- /// Returns the `.debug_loclists` offset at the given `base` and `index`.
- ///
- /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE.
- /// This is an offset that points to the first entry following the header.
- ///
- /// The `index` is the value of a `DW_FORM_loclistx` attribute.
- pub fn get_offset(
- &self,
- unit_encoding: Encoding,
- base: DebugLocListsBase<R::Offset>,
- index: DebugLocListsIndex<R::Offset>,
- ) -> Result<LocationListsOffset<R::Offset>> {
- let format = unit_encoding.format;
- let input = &mut self.debug_loclists.section.clone();
- input.skip(base.0)?;
- input.skip(R::Offset::from_u64(
- index.0.into_u64() * u64::from(format.word_size()),
- )?)?;
- input
- .read_offset(format)
- .map(|x| LocationListsOffset(base.0 + x))
- }
-
- /// Call `Reader::lookup_offset_id` for each section, and return the first match.
- pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> {
- self.debug_loc
- .lookup_offset_id(id)
- .or_else(|| self.debug_loclists.lookup_offset_id(id))
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum LocListsFormat {
- /// The bare location list format used before DWARF 5.
- Bare,
- /// The DW_LLE encoded range list format used in DWARF 5 and the non-standard GNU
- /// split dwarf extension.
- Lle,
-}
-
-/// A raw iterator over a location list.
-///
-/// This iterator does not perform any processing of the location entries,
-/// such as handling base addresses.
-#[derive(Debug)]
-pub struct RawLocListIter<R: Reader> {
- input: R,
- encoding: Encoding,
- format: LocListsFormat,
-}
-
-/// A raw entry in .debug_loclists.
-#[derive(Clone, Debug)]
-pub enum RawLocListEntry<R: Reader> {
- /// A location from DWARF version <= 4.
- AddressOrOffsetPair {
- /// Start of range. May be an address or an offset.
- begin: u64,
- /// End of range. May be an address or an offset.
- end: u64,
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_base_address
- BaseAddress {
- /// base address
- addr: u64,
- },
- /// DW_LLE_base_addressx
- BaseAddressx {
- /// base address
- addr: DebugAddrIndex<R::Offset>,
- },
- /// DW_LLE_startx_endx
- StartxEndx {
- /// start of range
- begin: DebugAddrIndex<R::Offset>,
- /// end of range
- end: DebugAddrIndex<R::Offset>,
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_startx_length
- StartxLength {
- /// start of range
- begin: DebugAddrIndex<R::Offset>,
- /// length of range
- length: u64,
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_offset_pair
- OffsetPair {
- /// start of range
- begin: u64,
- /// end of range
- end: u64,
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_default_location
- DefaultLocation {
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_start_end
- StartEnd {
- /// start of range
- begin: u64,
- /// end of range
- end: u64,
- /// expression
- data: Expression<R>,
- },
- /// DW_LLE_start_length
- StartLength {
- /// start of range
- begin: u64,
- /// length of range
- length: u64,
- /// expression
- data: Expression<R>,
- },
-}
-
-fn parse_data<R: Reader>(input: &mut R, encoding: Encoding) -> Result<Expression<R>> {
- if encoding.version >= 5 {
- let len = R::Offset::from_u64(input.read_uleb128()?)?;
- Ok(Expression(input.split(len)?))
- } else {
- // In the GNU split-dwarf extension this is a fixed 2 byte value.
- let len = R::Offset::from_u16(input.read_u16()?);
- Ok(Expression(input.split(len)?))
- }
-}
-
-impl<R: Reader> RawLocListEntry<R> {
- /// Parse a location list entry from `.debug_loclists`
- fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result<Option<Self>> {
- Ok(match format {
- LocListsFormat::Bare => {
- let range = RawRange::parse(input, encoding.address_size)?;
- if range.is_end() {
- None
- } else if range.is_base_address(encoding.address_size) {
- Some(RawLocListEntry::BaseAddress { addr: range.end })
- } else {
- let len = R::Offset::from_u16(input.read_u16()?);
- let data = Expression(input.split(len)?);
- Some(RawLocListEntry::AddressOrOffsetPair {
- begin: range.begin,
- end: range.end,
- data,
- })
- }
- }
- LocListsFormat::Lle => match constants::DwLle(input.read_u8()?) {
- constants::DW_LLE_end_of_list => None,
- constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx {
- addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- }),
- constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx {
- begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- data: parse_data(input, encoding)?,
- }),
- constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength {
- begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- length: if encoding.version >= 5 {
- input.read_uleb128()?
- } else {
- // In the GNU split-dwarf extension this is a fixed 4 byte value.
- input.read_u32()? as u64
- },
- data: parse_data(input, encoding)?,
- }),
- constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair {
- begin: input.read_uleb128()?,
- end: input.read_uleb128()?,
- data: parse_data(input, encoding)?,
- }),
- constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation {
- data: parse_data(input, encoding)?,
- }),
- constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress {
- addr: input.read_address(encoding.address_size)?,
- }),
- constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd {
- begin: input.read_address(encoding.address_size)?,
- end: input.read_address(encoding.address_size)?,
- data: parse_data(input, encoding)?,
- }),
- constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength {
- begin: input.read_address(encoding.address_size)?,
- length: input.read_uleb128()?,
- data: parse_data(input, encoding)?,
- }),
- _ => {
- return Err(Error::InvalidAddressRange);
- }
- },
- })
- }
-}
-
-impl<R: Reader> RawLocListIter<R> {
- /// Construct a `RawLocListIter`.
- fn new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter<R> {
- RawLocListIter {
- input,
- encoding,
- format,
- }
- }
-
- /// Advance the iterator to the next location.
- pub fn next(&mut self) -> Result<Option<RawLocListEntry<R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match RawLocListEntry::parse(&mut self.input, self.encoding, self.format) {
- Ok(entry) => {
- if entry.is_none() {
- self.input.empty();
- }
- Ok(entry)
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for RawLocListIter<R> {
- type Item = RawLocListEntry<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- RawLocListIter::next(self)
- }
-}
-
-/// An iterator over a location list.
-///
-/// This iterator internally handles processing of base address selection entries
-/// and list end entries. Thus, it only returns location entries that are valid
-/// and already adjusted for the base address.
-#[derive(Debug)]
-pub struct LocListIter<R: Reader> {
- raw: RawLocListIter<R>,
- base_address: u64,
- debug_addr: DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
-}
-
-impl<R: Reader> LocListIter<R> {
- /// Construct a `LocListIter`.
- fn new(
- raw: RawLocListIter<R>,
- base_address: u64,
- debug_addr: DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
- ) -> LocListIter<R> {
- LocListIter {
- raw,
- base_address,
- debug_addr,
- debug_addr_base,
- }
- }
-
- #[inline]
- fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
- self.debug_addr
- .get_address(self.raw.encoding.address_size, self.debug_addr_base, index)
- }
-
- /// Advance the iterator to the next location.
- pub fn next(&mut self) -> Result<Option<LocationListEntry<R>>> {
- loop {
- let raw_loc = match self.raw.next()? {
- Some(loc) => loc,
- None => return Ok(None),
- };
-
- let loc = self.convert_raw(raw_loc)?;
- if loc.is_some() {
- return Ok(loc);
- }
- }
- }
-
- /// Return the next raw location.
- ///
- /// The raw location should be passed to `convert_raw`.
- #[doc(hidden)]
- pub fn next_raw(&mut self) -> Result<Option<RawLocListEntry<R>>> {
- self.raw.next()
- }
-
- /// Convert a raw location into a location, and update the state of the iterator.
- ///
- /// The raw location should have been obtained from `next_raw`.
- #[doc(hidden)]
- pub fn convert_raw(
- &mut self,
- raw_loc: RawLocListEntry<R>,
- ) -> Result<Option<LocationListEntry<R>>> {
- let mask = !0 >> (64 - self.raw.encoding.address_size * 8);
- let tombstone = if self.raw.encoding.version <= 4 {
- mask - 1
- } else {
- mask
- };
-
- let (range, data) = match raw_loc {
- RawLocListEntry::BaseAddress { addr } => {
- self.base_address = addr;
- return Ok(None);
- }
- RawLocListEntry::BaseAddressx { addr } => {
- self.base_address = self.get_address(addr)?;
- return Ok(None);
- }
- RawLocListEntry::StartxEndx { begin, end, data } => {
- let begin = self.get_address(begin)?;
- let end = self.get_address(end)?;
- (Range { begin, end }, data)
- }
- RawLocListEntry::StartxLength {
- begin,
- length,
- data,
- } => {
- let begin = self.get_address(begin)?;
- let end = begin.wrapping_add(length) & mask;
- (Range { begin, end }, data)
- }
- RawLocListEntry::DefaultLocation { data } => (
- Range {
- begin: 0,
- end: u64::max_value(),
- },
- data,
- ),
- RawLocListEntry::AddressOrOffsetPair { begin, end, data }
- | RawLocListEntry::OffsetPair { begin, end, data } => {
- if self.base_address == tombstone {
- return Ok(None);
- }
- let mut range = Range { begin, end };
- range.add_base_address(self.base_address, self.raw.encoding.address_size);
- (range, data)
- }
- RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data),
- RawLocListEntry::StartLength {
- begin,
- length,
- data,
- } => {
- let end = begin.wrapping_add(length) & mask;
- (Range { begin, end }, data)
- }
- };
-
- if range.begin == tombstone {
- return Ok(None);
- }
-
- if range.begin > range.end {
- self.raw.input.empty();
- return Err(Error::InvalidLocationAddressRange);
- }
-
- Ok(Some(LocationListEntry { range, data }))
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for LocListIter<R> {
- type Item = LocationListEntry<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- LocListIter::next(self)
- }
-}
-
-/// A location list entry from the `.debug_loc` or `.debug_loclists` sections.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct LocationListEntry<R: Reader> {
- /// The address range that this location is valid for.
- pub range: Range,
-
- /// The data containing a single location description.
- pub data: Expression<R>,
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::common::Format;
- use crate::endianity::LittleEndian;
- use crate::read::{EndianSlice, Range};
- use crate::test_util::GimliSectionMethods;
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- #[test]
- fn test_loclists_32() {
- let tombstone = !0u32;
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
-
- let section = Section::with_endian(Endian::Little)
- .L32(0x0300_0000)
- .L32(0x0301_0300)
- .L32(0x0301_0400)
- .L32(0x0301_0500)
- .L32(tombstone)
- .L32(0x0301_0600);
- let buf = section.get_contents().unwrap();
- let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
-
- let start = Label::new();
- let first = Label::new();
- let size = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // Header
- .mark(&start)
- .L32(&size)
- .L16(encoding.version)
- .L8(encoding.address_size)
- .L8(0)
- .L32(0)
- .mark(&first)
- // OffsetPair
- .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
- // A base address selection followed by an OffsetPair.
- .L8(6).L32(0x0200_0000)
- .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
- // An empty OffsetPair followed by a normal OffsetPair.
- .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
- .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
- // A StartEnd
- .L8(7).L32(0x201_0a00).L32(0x201_0b00).uleb(4).L32(6)
- // A StartLength
- .L8(8).L32(0x201_0c00).uleb(0x100).uleb(4).L32(7)
- // An OffsetPair that starts at 0.
- .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
- // An OffsetPair that ends at -1.
- .L8(6).L32(0)
- .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
- // A DefaultLocation
- .L8(5).uleb(4).L32(10)
- // A BaseAddressx + OffsetPair
- .L8(1).uleb(0)
- .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
- // A StartxEndx
- .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
- // A StartxLength
- .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
-
- // Tombstone entries, all of which should be ignored.
- // A BaseAddressx that is a tombstone.
- .L8(1).uleb(4)
- .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20)
- // A BaseAddress that is a tombstone.
- .L8(6).L32(tombstone)
- .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21)
- // A StartxEndx that is a tombstone.
- .L8(2).uleb(4).uleb(5).uleb(4).L32(22)
- // A StartxLength that is a tombstone.
- .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23)
- // A StartEnd that is a tombstone.
- .L8(7).L32(tombstone).L32(0x201_1500).uleb(4).L32(24)
- // A StartLength that is a tombstone.
- .L8(8).L32(tombstone).uleb(0x100).uleb(4).L32(25)
- // A StartEnd (not ignored)
- .L8(7).L32(0x201_1600).L32(0x201_1700).uleb(4).L32(26)
-
- // A range end.
- .L8(0)
- // Some extra data.
- .L32(0xffff_ffff);
- size.set_const((&section.here() - &start - 4) as u64);
-
- let buf = section.get_contents().unwrap();
- let debug_loc = DebugLoc::new(&[], LittleEndian);
- let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let offset = LocationListsOffset((&first - &start) as usize);
- let mut locations = loclists
- .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- },
- data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A base address selection followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- },
- data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // An empty location range followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- },
- data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
- }))
- );
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- },
- data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0a00,
- end: 0x0201_0b00,
- },
- data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0c00,
- end: 0x0201_0d00,
- },
- data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that starts at 0.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- },
- data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that ends at -1.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- },
- data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A DefaultLocation.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0,
- end: u64::max_value(),
- },
- data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A BaseAddressx + OffsetPair
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0100,
- end: 0x0301_0200,
- },
- data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartxEndx
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0300,
- end: 0x0301_0400,
- },
- data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartxLength
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0500,
- end: 0x0301_0600,
- },
- data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartEnd location following the tombstones
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_1600,
- end: 0x0201_1700,
- },
- data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location list end.
- assert_eq!(locations.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut locations = loclists
- .locations(
- LocationListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Ok(None));
- }
-
- #[test]
- fn test_loclists_64() {
- let tombstone = !0u64;
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
-
- let section = Section::with_endian(Endian::Little)
- .L64(0x0300_0000)
- .L64(0x0301_0300)
- .L64(0x0301_0400)
- .L64(0x0301_0500)
- .L64(tombstone)
- .L64(0x0301_0600);
- let buf = section.get_contents().unwrap();
- let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
-
- let start = Label::new();
- let first = Label::new();
- let size = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // Header
- .mark(&start)
- .L32(0xffff_ffff)
- .L64(&size)
- .L16(encoding.version)
- .L8(encoding.address_size)
- .L8(0)
- .L32(0)
- .mark(&first)
- // OffsetPair
- .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
- // A base address selection followed by an OffsetPair.
- .L8(6).L64(0x0200_0000)
- .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
- // An empty OffsetPair followed by a normal OffsetPair.
- .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
- .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
- // A StartEnd
- .L8(7).L64(0x201_0a00).L64(0x201_0b00).uleb(4).L32(6)
- // A StartLength
- .L8(8).L64(0x201_0c00).uleb(0x100).uleb(4).L32(7)
- // An OffsetPair that starts at 0.
- .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
- // An OffsetPair that ends at -1.
- .L8(6).L64(0)
- .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
- // A DefaultLocation
- .L8(5).uleb(4).L32(10)
- // A BaseAddressx + OffsetPair
- .L8(1).uleb(0)
- .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
- // A StartxEndx
- .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
- // A StartxLength
- .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
-
- // Tombstone entries, all of which should be ignored.
- // A BaseAddressx that is a tombstone.
- .L8(1).uleb(4)
- .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20)
- // A BaseAddress that is a tombstone.
- .L8(6).L64(tombstone)
- .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21)
- // A StartxEndx that is a tombstone.
- .L8(2).uleb(4).uleb(5).uleb(4).L32(22)
- // A StartxLength that is a tombstone.
- .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23)
- // A StartEnd that is a tombstone.
- .L8(7).L64(tombstone).L64(0x201_1500).uleb(4).L32(24)
- // A StartLength that is a tombstone.
- .L8(8).L64(tombstone).uleb(0x100).uleb(4).L32(25)
- // A StartEnd (not ignored)
- .L8(7).L64(0x201_1600).L64(0x201_1700).uleb(4).L32(26)
-
- // A range end.
- .L8(0)
- // Some extra data.
- .L32(0xffff_ffff);
- size.set_const((&section.here() - &start - 12) as u64);
-
- let buf = section.get_contents().unwrap();
- let debug_loc = DebugLoc::new(&[], LittleEndian);
- let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let offset = LocationListsOffset((&first - &start) as usize);
- let mut locations = loclists
- .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- },
- data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A base address selection followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- },
- data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // An empty location range followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- },
- data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
- }))
- );
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- },
- data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0a00,
- end: 0x0201_0b00,
- },
- data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0c00,
- end: 0x0201_0d00,
- },
- data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that starts at 0.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- },
- data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that ends at -1.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- },
- data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A DefaultLocation.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0,
- end: u64::max_value(),
- },
- data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A BaseAddressx + OffsetPair
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0100,
- end: 0x0301_0200,
- },
- data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartxEndx
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0300,
- end: 0x0301_0400,
- },
- data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartxLength
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0301_0500,
- end: 0x0301_0600,
- },
- data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A StartEnd location following the tombstones
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_1600,
- end: 0x0201_1700,
- },
- data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location list end.
- assert_eq!(locations.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut locations = loclists
- .locations(
- LocationListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Ok(None));
- }
-
- #[test]
- fn test_location_list_32() {
- let tombstone = !0u32 - 1;
- let start = Label::new();
- let first = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // A location before the offset.
- .mark(&start)
- .L32(0x10000).L32(0x10100).L16(4).L32(1)
- .mark(&first)
- // A normal location.
- .L32(0x10200).L32(0x10300).L16(4).L32(2)
- // A base address selection followed by a normal location.
- .L32(0xffff_ffff).L32(0x0200_0000)
- .L32(0x10400).L32(0x10500).L16(4).L32(3)
- // An empty location range followed by a normal location.
- .L32(0x10600).L32(0x10600).L16(4).L32(4)
- .L32(0x10800).L32(0x10900).L16(4).L32(5)
- // A location range that starts at 0.
- .L32(0).L32(1).L16(4).L32(6)
- // A location range that ends at -1.
- .L32(0xffff_ffff).L32(0x0000_0000)
- .L32(0).L32(0xffff_ffff).L16(4).L32(7)
- // A normal location with tombstone.
- .L32(tombstone).L32(tombstone).L16(4).L32(8)
- // A base address selection with tombstone followed by a normal location.
- .L32(0xffff_ffff).L32(tombstone)
- .L32(0x10a00).L32(0x10b00).L16(4).L32(9)
- // A location list end.
- .L32(0).L32(0)
- // Some extra data.
- .L32(0);
-
- let buf = section.get_contents().unwrap();
- let debug_loc = DebugLoc::new(&buf, LittleEndian);
- let debug_loclists = DebugLocLists::new(&[], LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let offset = LocationListsOffset((&first - &start) as usize);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut locations = loclists
- .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- },
- data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A base address selection followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- },
- data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // An empty location range followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- },
- data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
- }))
- );
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- },
- data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that starts at 0.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- },
- data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that ends at -1.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- },
- data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location list end.
- assert_eq!(locations.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut locations = loclists
- .locations(
- LocationListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Ok(None));
- }
-
- #[test]
- fn test_location_list_64() {
- let tombstone = !0u64 - 1;
- let start = Label::new();
- let first = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // A location before the offset.
- .mark(&start)
- .L64(0x10000).L64(0x10100).L16(4).L32(1)
- .mark(&first)
- // A normal location.
- .L64(0x10200).L64(0x10300).L16(4).L32(2)
- // A base address selection followed by a normal location.
- .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000)
- .L64(0x10400).L64(0x10500).L16(4).L32(3)
- // An empty location range followed by a normal location.
- .L64(0x10600).L64(0x10600).L16(4).L32(4)
- .L64(0x10800).L64(0x10900).L16(4).L32(5)
- // A location range that starts at 0.
- .L64(0).L64(1).L16(4).L32(6)
- // A location range that ends at -1.
- .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000)
- .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7)
- // A normal location with tombstone.
- .L64(tombstone).L64(tombstone).L16(4).L32(8)
- // A base address selection with tombstone followed by a normal location.
- .L64(0xffff_ffff_ffff_ffff).L64(tombstone)
- .L64(0x10a00).L64(0x10b00).L16(4).L32(9)
- // A location list end.
- .L64(0).L64(0)
- // Some extra data.
- .L64(0);
-
- let buf = section.get_contents().unwrap();
- let debug_loc = DebugLoc::new(&buf, LittleEndian);
- let debug_loclists = DebugLocLists::new(&[], LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let offset = LocationListsOffset((&first - &start) as usize);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- };
- let mut locations = loclists
- .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- },
- data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A base address selection followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- },
- data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // An empty location range followed by a normal location.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- },
- data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
- }))
- );
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- },
- data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that starts at 0.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- },
- data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location range that ends at -1.
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0,
- end: 0xffff_ffff_ffff_ffff,
- },
- data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
- }))
- );
-
- // A location list end.
- assert_eq!(locations.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut locations = loclists
- .locations(
- LocationListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Ok(None));
- }
-
- #[test]
- fn test_locations_invalid() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // An invalid location range.
- .L32(0x20000).L32(0x10000).L16(4).L32(1)
- // An invalid range after wrapping.
- .L32(0x20000).L32(0xff01_0000).L16(4).L32(2);
-
- let buf = section.get_contents().unwrap();
- let debug_loc = DebugLoc::new(&buf, LittleEndian);
- let debug_loclists = DebugLocLists::new(&[], LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
-
- // An invalid location range.
- let mut locations = loclists
- .locations(
- LocationListsOffset(0x0),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
-
- // An invalid location range after wrapping.
- let mut locations = loclists
- .locations(
- LocationListsOffset(14),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
-
- // An invalid offset.
- match loclists.locations(
- LocationListsOffset(buf.len() + 1),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- ) {
- Err(Error::UnexpectedEof(_)) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_get_offset() {
- for format in vec![Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version: 5,
- address_size: 4,
- };
-
- let zero = Label::new();
- let length = Label::new();
- let start = Label::new();
- let first = Label::new();
- let end = Label::new();
- let mut section = Section::with_endian(Endian::Little)
- .mark(&zero)
- .initial_length(format, &length, &start)
- .D16(encoding.version)
- .D8(encoding.address_size)
- .D8(0)
- .D32(20)
- .mark(&first);
- for i in 0..20 {
- section = section.word(format.word_size(), 1000 + i);
- }
- section = section.mark(&end);
- length.set_const((&end - &start) as u64);
- let section = section.get_contents().unwrap();
-
- let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian));
- let debug_loclists = DebugLocLists::from(EndianSlice::new(&section, LittleEndian));
- let locations = LocationLists::new(debug_loc, debug_loclists);
-
- let base = DebugLocListsBase((&first - &zero) as usize);
- assert_eq!(
- locations.get_offset(encoding, base, DebugLocListsIndex(0)),
- Ok(LocationListsOffset(base.0 + 1000))
- );
- assert_eq!(
- locations.get_offset(encoding, base, DebugLocListsIndex(19)),
- Ok(LocationListsOffset(base.0 + 1019))
- );
- }
- }
-
- #[test]
- fn test_loclists_gnu_v4_split_dwarf() {
- #[rustfmt::skip]
- let buf = [
- 0x03, // DW_LLE_startx_length
- 0x00, // ULEB encoded b7
- 0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8
- 0x03, 0x00, // Fixed two byte length of the location
- 0x11, 0x00, // DW_OP_constu 0
- 0x9f, // DW_OP_stack_value
- // Padding data
- //0x99, 0x99, 0x99, 0x99
- ];
- let data_buf = [0x11, 0x00, 0x9f];
- let expected_data = EndianSlice::new(&data_buf, LittleEndian);
- let debug_loc = DebugLoc::new(&buf, LittleEndian);
- let debug_loclists = DebugLocLists::new(&[], LittleEndian);
- let loclists = LocationLists::new(debug_loc, debug_loclists);
- let debug_addr =
- &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
-
- // An invalid location range.
- let mut locations = loclists
- .locations_dwo(
- LocationListsOffset(0x0),
- encoding,
- 0,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(
- locations.next(),
- Ok(Some(LocationListEntry {
- range: Range {
- begin: 0x0403_0201,
- end: 0x0403_0209
- },
- data: Expression(expected_data),
- }))
- );
- }
-}
diff --git a/vendor/gimli/src/read/lookup.rs b/vendor/gimli/src/read/lookup.rs
deleted file mode 100644
index 1d082f2..0000000
--- a/vendor/gimli/src/read/lookup.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use core::marker::PhantomData;
-
-use crate::common::{DebugInfoOffset, Format};
-use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset};
-
-// The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have
-// similar structures. They consist of a header with metadata and an offset into the
-// .debug_info section for the entire compilation unit, and a series
-// of following entries that list addresses (for .debug_aranges) or names
-// (for .debug_pubnames and .debug_pubtypes) that are covered.
-//
-// Because these three tables all have similar structures, we abstract out some of
-// the parsing mechanics.
-
-pub trait LookupParser<R: Reader> {
- /// The type of the produced header.
- type Header;
- /// The type of the produced entry.
- type Entry;
-
- /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries
- /// corresponding to this header (without the header itself), and the parsed representation of
- /// the header itself.
- fn parse_header(input: &mut R) -> Result<(R, Self::Header)>;
-
- /// Parse a single entry from `input`. Returns either a parsed representation of the entry
- /// or None if `input` is exhausted.
- fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>;
-}
-
-#[derive(Clone, Debug)]
-pub struct DebugLookup<R, Parser>
-where
- R: Reader,
- Parser: LookupParser<R>,
-{
- input_buffer: R,
- phantom: PhantomData<Parser>,
-}
-
-impl<R, Parser> From<R> for DebugLookup<R, Parser>
-where
- R: Reader,
- Parser: LookupParser<R>,
-{
- fn from(input_buffer: R) -> Self {
- DebugLookup {
- input_buffer,
- phantom: PhantomData,
- }
- }
-}
-
-impl<R, Parser> DebugLookup<R, Parser>
-where
- R: Reader,
- Parser: LookupParser<R>,
-{
- pub fn items(&self) -> LookupEntryIter<R, Parser> {
- LookupEntryIter {
- current_set: None,
- remaining_input: self.input_buffer.clone(),
- }
- }
-
- pub fn reader(&self) -> &R {
- &self.input_buffer
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct LookupEntryIter<R, Parser>
-where
- R: Reader,
- Parser: LookupParser<R>,
-{
- current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end.
- remaining_input: R,
-}
-
-impl<R, Parser> LookupEntryIter<R, Parser>
-where
- R: Reader,
- Parser: LookupParser<R>,
-{
- /// Advance the iterator and return the next entry.
- ///
- /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns
- /// `Ok(None)` when iteration is complete and all entries have already been
- /// parsed and yielded. If an error occurs while parsing the next entry,
- /// then this error is returned as `Err(e)`, and all subsequent calls return
- /// `Ok(None)`.
- ///
- /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn next(&mut self) -> Result<Option<Parser::Entry>> {
- loop {
- if let Some((ref mut input, ref header)) = self.current_set {
- if !input.is_empty() {
- match Parser::parse_entry(input, header) {
- Ok(Some(entry)) => return Ok(Some(entry)),
- Ok(None) => {}
- Err(e) => {
- input.empty();
- self.remaining_input.empty();
- return Err(e);
- }
- }
- }
- }
- if self.remaining_input.is_empty() {
- self.current_set = None;
- return Ok(None);
- }
- match Parser::parse_header(&mut self.remaining_input) {
- Ok(set) => {
- self.current_set = Some(set);
- }
- Err(e) => {
- self.current_set = None;
- self.remaining_input.empty();
- return Err(e);
- }
- }
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct PubStuffHeader<T = usize> {
- format: Format,
- length: T,
- version: u16,
- unit_offset: DebugInfoOffset<T>,
- unit_length: T,
-}
-
-pub trait PubStuffEntry<R: Reader> {
- fn new(
- die_offset: UnitOffset<R::Offset>,
- name: R,
- unit_header_offset: DebugInfoOffset<R::Offset>,
- ) -> Self;
-}
-
-#[derive(Clone, Debug)]
-pub struct PubStuffParser<R, Entry>
-where
- R: Reader,
- Entry: PubStuffEntry<R>,
-{
- // This struct is never instantiated.
- phantom: PhantomData<(R, Entry)>,
-}
-
-impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
-where
- R: Reader,
- Entry: PubStuffEntry<R>,
-{
- type Header = PubStuffHeader<R::Offset>;
- type Entry = Entry;
-
- /// Parse an pubthings set header. Returns a tuple of the
- /// pubthings to be parsed for this set, and the newly created PubThingHeader struct.
- fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
- let (length, format) = input.read_initial_length()?;
- let mut rest = input.split(length)?;
-
- let version = rest.read_u16()?;
- if version != 2 {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
-
- let unit_offset = parse_debug_info_offset(&mut rest, format)?;
- let unit_length = rest.read_length(format)?;
-
- let header = PubStuffHeader {
- format,
- length,
- version,
- unit_offset,
- unit_length,
- };
- Ok((rest, header))
- }
-
- /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing.
- fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
- let offset = input.read_offset(header.format)?;
- if offset.into_u64() == 0 {
- input.empty();
- Ok(None)
- } else {
- let name = input.read_null_terminated_slice()?;
- Ok(Some(Self::Entry::new(
- UnitOffset(offset),
- name,
- header.unit_offset,
- )))
- }
- }
-}
diff --git a/vendor/gimli/src/read/mod.rs b/vendor/gimli/src/read/mod.rs
deleted file mode 100644
index 2ad7f6a..0000000
--- a/vendor/gimli/src/read/mod.rs
+++ /dev/null
@@ -1,827 +0,0 @@
-//! Read DWARF debugging information.
-//!
-//! * [Example Usage](#example-usage)
-//! * [API Structure](#api-structure)
-//! * [Using with `FallibleIterator`](#using-with-fallibleiterator)
-//!
-//! ## Example Usage
-//!
-//! Print out all of the functions in the debuggee program:
-//!
-//! ```rust,no_run
-//! # fn example() -> Result<(), gimli::Error> {
-//! # type R = gimli::EndianSlice<'static, gimli::LittleEndian>;
-//! # let get_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() };
-//! # let get_sup_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() };
-//! // Read the DWARF sections with whatever object loader you're using.
-//! // These closures should return a `Reader` instance (e.g. `EndianSlice`).
-//! let loader = |section: gimli::SectionId| { get_file_section_reader(section.name()) };
-//! let sup_loader = |section: gimli::SectionId| { get_sup_file_section_reader(section.name()) };
-//! let mut dwarf = gimli::Dwarf::load(loader)?;
-//! dwarf.load_sup(sup_loader)?;
-//!
-//! // Iterate over all compilation units.
-//! let mut iter = dwarf.units();
-//! while let Some(header) = iter.next()? {
-//! // Parse the abbreviations and other information for this compilation unit.
-//! let unit = dwarf.unit(header)?;
-//!
-//! // Iterate over all of this compilation unit's entries.
-//! let mut entries = unit.entries();
-//! while let Some((_, entry)) = entries.next_dfs()? {
-//! // If we find an entry for a function, print it.
-//! if entry.tag() == gimli::DW_TAG_subprogram {
-//! println!("Found a function: {:?}", entry);
-//! }
-//! }
-//! }
-//! # unreachable!()
-//! # }
-//! ```
-//!
-//! Full example programs:
-//!
-//! * [A simple parser](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/simple.rs)
-//!
-//! * [A `dwarfdump`
-//! clone](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarfdump.rs)
-//!
-//! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line)
-//!
-//! * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into
-//! code generation by making debugging information readable
-//!
-//! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the
-//! compilers used to create each compilation unit within a shared library or
-//! executable (via `DW_AT_producer`)
-//!
-//! * [`dwarf-validate`](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarf-validate.rs),
-//! a program to validate the integrity of some DWARF and its references
-//! between sections and compilation units.
-//!
-//! ## API Structure
-//!
-//! * Basic familiarity with DWARF is assumed.
-//!
-//! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF
-//! sections. It has methods that simplify access to debugging data that spans
-//! multiple sections. Use of this type is optional, but recommended.
-//!
-//! * Each section gets its own type. Consider these types the entry points to
-//! the library:
-//!
-//! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section.
-//!
-//! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section.
-//!
-//! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges`
-//! section.
-//!
-//! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section.
-//!
-//! * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section.
-//!
-//! * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section.
-//!
-//! * [`DebugLineStr`](./struct.DebugLineStr.html): The `.debug_line_str` section.
-//!
-//! * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section.
-//!
-//! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section.
-//!
-//! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames`
-//! section.
-//!
-//! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes`
-//! section.
-//!
-//! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section.
-//!
-//! * [`DebugRngLists`](./struct.DebugRngLists.html): The `.debug_rnglists` section.
-//!
-//! * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section.
-//!
-//! * [`DebugStrOffsets`](./struct.DebugStrOffsets.html): The `.debug_str_offsets` section.
-//!
-//! * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section.
-//!
-//! * [`DebugCuIndex`](./struct.DebugCuIndex.html): The `.debug_cu_index` section.
-//!
-//! * [`DebugTuIndex`](./struct.DebugTuIndex.html): The `.debug_tu_index` section.
-//!
-//! * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section.
-//!
-//! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section.
-//!
-//! * Each section type exposes methods for accessing the debugging data encoded
-//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html)
-//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for
-//! iterating over the compilation units defined within it.
-//!
-//! * Offsets into a section are strongly typed: an offset into `.debug_info` is
-//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be
-//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because
-//! `DebugLine` represents the `.debug_line` section. There are similar types
-//! for offsets relative to a compilation unit rather than a section.
-//!
-//! ## Using with `FallibleIterator`
-//!
-//! The standard library's `Iterator` trait and related APIs do not play well
-//! with iterators where the `next` operation is fallible. One can make the
-//! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the
-//! provided methods cannot gracefully handle the case when an `Err` is
-//! returned.
-//!
-//! This situation led to the
-//! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's
-//! existence. You can read more of the rationale for its existence in its
-//! docs. The crate provides the helpers you have come to expect (eg `map`,
-//! `filter`, etc) for iterators that can fail.
-//!
-//! `gimli`'s many lazy parsing iterators are a perfect match for the
-//! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not
-//! done eagerly. Parse errors later in the input might only be discovered after
-//! having iterated through many items.
-//!
-//! To use `gimli` iterators with `FallibleIterator`, import the crate and trait
-//! into your code:
-//!
-//! ```
-//! # #[cfg(feature = "fallible-iterator")]
-//! # fn foo() {
-//! // Use the `FallibleIterator` trait so its methods are in scope!
-//! use fallible_iterator::FallibleIterator;
-//! use gimli::{DebugAranges, EndianSlice, LittleEndian};
-//!
-//! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianSlice<LittleEndian>>)
-//! -> gimli::Result<u64>
-//! {
-//! // `DebugAranges::headers` returns a `FallibleIterator`!
-//! aranges.headers()
-//! // `flat_map` is provided by `FallibleIterator`!
-//! .flat_map(|header| Ok(header.entries()))
-//! // `map` is provided by `FallibleIterator`!
-//! .map(|arange| Ok(arange.length()))
-//! // `fold` is provided by `FallibleIterator`!
-//! .fold(0, |sum, len| Ok(sum + len))
-//! }
-//! # }
-//! # fn main() {}
-//! ```
-
-use core::fmt::{self, Debug};
-use core::result;
-#[cfg(feature = "std")]
-use std::{error, io};
-
-use crate::common::{Register, SectionId};
-use crate::constants;
-
-mod util;
-pub use util::*;
-
-mod addr;
-pub use self::addr::*;
-
-mod cfi;
-pub use self::cfi::*;
-
-#[cfg(feature = "read")]
-mod dwarf;
-#[cfg(feature = "read")]
-pub use self::dwarf::*;
-
-mod endian_slice;
-pub use self::endian_slice::*;
-
-#[cfg(feature = "endian-reader")]
-mod endian_reader;
-#[cfg(feature = "endian-reader")]
-pub use self::endian_reader::*;
-
-mod reader;
-pub use self::reader::*;
-
-#[cfg(feature = "read")]
-mod abbrev;
-#[cfg(feature = "read")]
-pub use self::abbrev::*;
-
-mod aranges;
-pub use self::aranges::*;
-
-mod index;
-pub use self::index::*;
-
-#[cfg(feature = "read")]
-mod line;
-#[cfg(feature = "read")]
-pub use self::line::*;
-
-mod lists;
-
-mod loclists;
-pub use self::loclists::*;
-
-#[cfg(feature = "read")]
-mod lookup;
-
-mod op;
-pub use self::op::*;
-
-#[cfg(feature = "read")]
-mod pubnames;
-#[cfg(feature = "read")]
-pub use self::pubnames::*;
-
-#[cfg(feature = "read")]
-mod pubtypes;
-#[cfg(feature = "read")]
-pub use self::pubtypes::*;
-
-mod rnglists;
-pub use self::rnglists::*;
-
-mod str;
-pub use self::str::*;
-
-/// An offset into the current compilation or type unit.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
-pub struct UnitOffset<T = usize>(pub T);
-
-#[cfg(feature = "read")]
-mod unit;
-#[cfg(feature = "read")]
-pub use self::unit::*;
-
-mod value;
-pub use self::value::*;
-
-/// Indicates that storage should be allocated on heap.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct StoreOnHeap;
-
-/// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across
-/// `gimli` versions, we export this type alias.
-#[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")]
-pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>;
-
-/// An error that occurred when parsing.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Error {
- /// An I/O error occurred while reading.
- Io,
- /// Found a PC relative pointer, but the section base is undefined.
- PcRelativePointerButSectionBaseIsUndefined,
- /// Found a `.text` relative pointer, but the `.text` base is undefined.
- TextRelativePointerButTextBaseIsUndefined,
- /// Found a data relative pointer, but the data base is undefined.
- DataRelativePointerButDataBaseIsUndefined,
- /// Found a function relative pointer in a context that does not have a
- /// function base.
- FuncRelativePointerInBadContext,
- /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding.
- CannotParseOmitPointerEncoding,
- /// An error parsing an unsigned LEB128 value.
- BadUnsignedLeb128,
- /// An error parsing a signed LEB128 value.
- BadSignedLeb128,
- /// An abbreviation declared that its tag is zero, but zero is reserved for
- /// null records.
- AbbreviationTagZero,
- /// An attribute specification declared that its form is zero, but zero is
- /// reserved for null records.
- AttributeFormZero,
- /// The abbreviation's has-children byte was not one of
- /// `DW_CHILDREN_{yes,no}`.
- BadHasChildren,
- /// The specified length is impossible.
- BadLength,
- /// Found an unknown `DW_FORM_*` type.
- UnknownForm,
- /// Expected a zero, found something else.
- ExpectedZero,
- /// Found an abbreviation code that has already been used.
- DuplicateAbbreviationCode,
- /// Found a duplicate arange.
- DuplicateArange,
- /// Found an unknown reserved length value.
- UnknownReservedLength,
- /// Found an unknown DWARF version.
- UnknownVersion(u64),
- /// Found a record with an unknown abbreviation code.
- UnknownAbbreviation,
- /// Hit the end of input before it was expected.
- UnexpectedEof(ReaderOffsetId),
- /// Read a null entry before it was expected.
- UnexpectedNull,
- /// Found an unknown standard opcode.
- UnknownStandardOpcode(constants::DwLns),
- /// Found an unknown extended opcode.
- UnknownExtendedOpcode(constants::DwLne),
- /// The specified address size is not supported.
- UnsupportedAddressSize(u8),
- /// The specified offset size is not supported.
- UnsupportedOffsetSize(u8),
- /// The specified field size is not supported.
- UnsupportedFieldSize(u8),
- /// The minimum instruction length must not be zero.
- MinimumInstructionLengthZero,
- /// The maximum operations per instruction must not be zero.
- MaximumOperationsPerInstructionZero,
- /// The line range must not be zero.
- LineRangeZero,
- /// The opcode base must not be zero.
- OpcodeBaseZero,
- /// Found an invalid UTF-8 string.
- BadUtf8,
- /// Expected to find the CIE ID, but found something else.
- NotCieId,
- /// Expected to find a pointer to a CIE, but found the CIE ID instead.
- NotCiePointer,
- /// Expected to find a pointer to an FDE, but found a CIE instead.
- NotFdePointer,
- /// Invalid branch target for a DW_OP_bra or DW_OP_skip.
- BadBranchTarget(u64),
- /// DW_OP_push_object_address used but no address passed in.
- InvalidPushObjectAddress,
- /// Not enough items on the stack when evaluating an expression.
- NotEnoughStackItems,
- /// Too many iterations to compute the expression.
- TooManyIterations,
- /// An unrecognized operation was found while parsing a DWARF
- /// expression.
- InvalidExpression(constants::DwOp),
- /// An unsupported operation was found while evaluating a DWARF expression.
- UnsupportedEvaluation,
- /// The expression had a piece followed by an expression
- /// terminator without a piece.
- InvalidPiece,
- /// An expression-terminating operation was followed by something
- /// other than the end of the expression or a piece operation.
- InvalidExpressionTerminator(u64),
- /// Division or modulus by zero when evaluating an expression.
- DivisionByZero,
- /// An expression operation used mismatching types.
- TypeMismatch,
- /// An expression operation required an integral type but saw a
- /// floating point type.
- IntegralTypeRequired,
- /// An expression operation used types that are not supported.
- UnsupportedTypeOperation,
- /// The shift value in an expression must be a non-negative integer.
- InvalidShiftExpression,
- /// An unknown DW_CFA_* instruction.
- UnknownCallFrameInstruction(constants::DwCfa),
- /// The end of an address range was before the beginning.
- InvalidAddressRange,
- /// The end offset of a loc list entry was before the beginning.
- InvalidLocationAddressRange,
- /// Encountered a call frame instruction in a context in which it is not
- /// valid.
- CfiInstructionInInvalidContext,
- /// When evaluating call frame instructions, found a `DW_CFA_restore_state`
- /// stack pop instruction, but the stack was empty, and had nothing to pop.
- PopWithEmptyStack,
- /// Do not have unwind info for the given address.
- NoUnwindInfoForAddress,
- /// An offset value was larger than the maximum supported value.
- UnsupportedOffset,
- /// The given pointer encoding is either unknown or invalid.
- UnknownPointerEncoding,
- /// Did not find an entry at the given offset.
- NoEntryAtGivenOffset,
- /// The given offset is out of bounds.
- OffsetOutOfBounds,
- /// Found an unknown CFI augmentation.
- UnknownAugmentation,
- /// We do not support the given pointer encoding yet.
- UnsupportedPointerEncoding,
- /// Registers larger than `u16` are not supported.
- UnsupportedRegister(u64),
- /// The CFI program defined more register rules than we have storage for.
- TooManyRegisterRules,
- /// Attempted to push onto the CFI or evaluation stack, but it was already
- /// at full capacity.
- StackFull,
- /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded,
- /// which makes binary search impossible.
- VariableLengthSearchTable,
- /// The `DW_UT_*` value for this unit is not supported yet.
- UnsupportedUnitType,
- /// Ranges using AddressIndex are not supported yet.
- UnsupportedAddressIndex,
- /// Nonzero segment selector sizes aren't supported yet.
- UnsupportedSegmentSize,
- /// A compilation unit or type unit is missing its top level DIE.
- MissingUnitDie,
- /// A DIE attribute used an unsupported form.
- UnsupportedAttributeForm,
- /// Missing DW_LNCT_path in file entry format.
- MissingFileEntryFormatPath,
- /// Expected an attribute value to be a string form.
- ExpectedStringAttributeValue,
- /// `DW_FORM_implicit_const` used in an invalid context.
- InvalidImplicitConst,
- /// Invalid section count in `.dwp` index.
- InvalidIndexSectionCount,
- /// Invalid slot count in `.dwp` index.
- InvalidIndexSlotCount,
- /// Invalid hash row in `.dwp` index.
- InvalidIndexRow,
- /// Unknown section type in `.dwp` index.
- UnknownIndexSection,
-}
-
-impl fmt::Display for Error {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> {
- write!(f, "{}", self.description())
- }
-}
-
-impl Error {
- /// A short description of the error.
- pub fn description(&self) -> &str {
- match *self {
- Error::Io => "An I/O error occurred while reading.",
- Error::PcRelativePointerButSectionBaseIsUndefined => {
- "Found a PC relative pointer, but the section base is undefined."
- }
- Error::TextRelativePointerButTextBaseIsUndefined => {
- "Found a `.text` relative pointer, but the `.text` base is undefined."
- }
- Error::DataRelativePointerButDataBaseIsUndefined => {
- "Found a data relative pointer, but the data base is undefined."
- }
- Error::FuncRelativePointerInBadContext => {
- "Found a function relative pointer in a context that does not have a function base."
- }
- Error::CannotParseOmitPointerEncoding => {
- "Cannot parse a pointer with a `DW_EH_PE_omit` encoding."
- }
- Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value",
- Error::BadSignedLeb128 => "An error parsing a signed LEB128 value",
- Error::AbbreviationTagZero => {
- "An abbreviation declared that its tag is zero,
- but zero is reserved for null records"
- }
- Error::AttributeFormZero => {
- "An attribute specification declared that its form is zero,
- but zero is reserved for null records"
- }
- Error::BadHasChildren => {
- "The abbreviation's has-children byte was not one of
- `DW_CHILDREN_{yes,no}`"
- }
- Error::BadLength => "The specified length is impossible",
- Error::UnknownForm => "Found an unknown `DW_FORM_*` type",
- Error::ExpectedZero => "Expected a zero, found something else",
- Error::DuplicateAbbreviationCode => {
- "Found an abbreviation code that has already been used"
- }
- Error::DuplicateArange => "Found a duplicate arange",
- Error::UnknownReservedLength => "Found an unknown reserved length value",
- Error::UnknownVersion(_) => "Found an unknown DWARF version",
- Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code",
- Error::UnexpectedEof(_) => "Hit the end of input before it was expected",
- Error::UnexpectedNull => "Read a null entry before it was expected.",
- Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode",
- Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode",
- Error::UnsupportedAddressSize(_) => "The specified address size is not supported",
- Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported",
- Error::UnsupportedFieldSize(_) => "The specified field size is not supported",
- Error::MinimumInstructionLengthZero => {
- "The minimum instruction length must not be zero."
- }
- Error::MaximumOperationsPerInstructionZero => {
- "The maximum operations per instruction must not be zero."
- }
- Error::LineRangeZero => "The line range must not be zero.",
- Error::OpcodeBaseZero => "The opcode base must not be zero.",
- Error::BadUtf8 => "Found an invalid UTF-8 string.",
- Error::NotCieId => "Expected to find the CIE ID, but found something else.",
- Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.",
- Error::NotFdePointer => {
- "Expected to find an FDE pointer, but found a CIE pointer instead."
- }
- Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression",
- Error::InvalidPushObjectAddress => {
- "DW_OP_push_object_address used but no object address given"
- }
- Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression",
- Error::TooManyIterations => "Too many iterations to evaluate DWARF expression",
- Error::InvalidExpression(_) => "Invalid opcode in DWARF expression",
- Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression",
- Error::InvalidPiece => {
- "DWARF expression has piece followed by non-piece expression at end"
- }
- Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece",
- Error::DivisionByZero => "Division or modulus by zero when evaluating expression",
- Error::TypeMismatch => "Type mismatch when evaluating expression",
- Error::IntegralTypeRequired => "Integral type expected when evaluating expression",
- Error::UnsupportedTypeOperation => {
- "An expression operation used types that are not supported"
- }
- Error::InvalidShiftExpression => {
- "The shift value in an expression must be a non-negative integer."
- }
- Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion",
- Error::InvalidAddressRange => {
- "The end of an address range must not be before the beginning."
- }
- Error::InvalidLocationAddressRange => {
- "The end offset of a location list entry must not be before the beginning."
- }
- Error::CfiInstructionInInvalidContext => {
- "Encountered a call frame instruction in a context in which it is not valid."
- }
- Error::PopWithEmptyStack => {
- "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \
- instruction, but the stack was empty, and had nothing to pop."
- }
- Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.",
- Error::UnsupportedOffset => {
- "An offset value was larger than the maximum supported value."
- }
- Error::UnknownPointerEncoding => {
- "The given pointer encoding is either unknown or invalid."
- }
- Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.",
- Error::OffsetOutOfBounds => "The given offset is out of bounds.",
- Error::UnknownAugmentation => "Found an unknown CFI augmentation.",
- Error::UnsupportedPointerEncoding => {
- "We do not support the given pointer encoding yet."
- }
- Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.",
- Error::TooManyRegisterRules => {
- "The CFI program defined more register rules than we have storage for."
- }
- Error::StackFull => {
- "Attempted to push onto the CFI stack, but it was already at full capacity."
- }
- Error::VariableLengthSearchTable => {
- "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \
- which makes binary search impossible."
- }
- Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet",
- Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet",
- Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet",
- Error::MissingUnitDie => {
- "A compilation unit or type unit is missing its top level DIE."
- }
- Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.",
- Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.",
- Error::ExpectedStringAttributeValue => {
- "Expected an attribute value to be a string form."
- }
- Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.",
- Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.",
- Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.",
- Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.",
- Error::UnknownIndexSection => "Unknown section type in `.dwp` index.",
- }
- }
-}
-
-#[cfg(feature = "std")]
-impl error::Error for Error {}
-
-#[cfg(feature = "std")]
-impl From<io::Error> for Error {
- fn from(_: io::Error) -> Self {
- Error::Io
- }
-}
-
-/// The result of a parse.
-pub type Result<T> = result::Result<T, Error>;
-
-/// A convenience trait for loading DWARF sections from object files. To be
-/// used like:
-///
-/// ```
-/// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section};
-///
-/// let buf = [0x00, 0x01, 0x02, 0x03];
-/// let reader = EndianSlice::new(&buf, LittleEndian);
-/// let loader = |name| -> Result<_, ()> { Ok(reader) };
-///
-/// let debug_info: DebugInfo<_> = Section::load(loader).unwrap();
-/// ```
-pub trait Section<R>: From<R> {
- /// Returns the section id for this type.
- fn id() -> SectionId;
-
- /// Returns the ELF section name for this type.
- fn section_name() -> &'static str {
- Self::id().name()
- }
-
- /// Returns the ELF section name (if any) for this type when used in a dwo
- /// file.
- fn dwo_section_name() -> Option<&'static str> {
- Self::id().dwo_name()
- }
-
- /// Returns the XCOFF section name (if any) for this type when used in a XCOFF
- /// file.
- fn xcoff_section_name() -> Option<&'static str> {
- Self::id().xcoff_name()
- }
-
- /// Try to load the section using the given loader function.
- fn load<F, E>(f: F) -> core::result::Result<Self, E>
- where
- F: FnOnce(SectionId) -> core::result::Result<R, E>,
- {
- f(Self::id()).map(From::from)
- }
-
- /// Returns the `Reader` for this section.
- fn reader(&self) -> &R
- where
- R: Reader;
-
- /// Returns the subrange of the section that is the contribution of
- /// a unit in a `.dwp` file.
- fn dwp_range(&self, offset: u32, size: u32) -> Result<Self>
- where
- R: Reader,
- {
- let mut data = self.reader().clone();
- data.skip(R::Offset::from_u32(offset))?;
- data.truncate(R::Offset::from_u32(size))?;
- Ok(data.into())
- }
-
- /// Returns the `Reader` for this section.
- fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)>
- where
- R: Reader,
- {
- self.reader()
- .lookup_offset_id(id)
- .map(|offset| (Self::id(), offset))
- }
-}
-
-impl Register {
- pub(crate) fn from_u64(x: u64) -> Result<Register> {
- let y = x as u16;
- if u64::from(y) == x {
- Ok(Register(y))
- } else {
- Err(Error::UnsupportedRegister(x))
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::common::Format;
- use crate::endianity::LittleEndian;
- use test_assembler::{Endian, Section};
-
- #[test]
- fn test_parse_initial_length_32_ok() {
- let section = Section::with_endian(Endian::Little).L32(0x7856_3412);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_initial_length() {
- Ok((length, format)) => {
- assert_eq!(input.len(), 0);
- assert_eq!(format, Format::Dwarf32);
- assert_eq!(0x7856_3412, length);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_parse_initial_length_64_ok() {
- let section = Section::with_endian(Endian::Little)
- // Dwarf_64_INITIAL_UNIT_LENGTH
- .L32(0xffff_ffff)
- // Actual length
- .L64(0xffde_bc9a_7856_3412);
- let buf = section.get_contents().unwrap();
- let input = &mut EndianSlice::new(&buf, LittleEndian);
-
- #[cfg(target_pointer_width = "64")]
- match input.read_initial_length() {
- Ok((length, format)) => {
- assert_eq!(input.len(), 0);
- assert_eq!(format, Format::Dwarf64);
- assert_eq!(0xffde_bc9a_7856_3412, length);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
-
- #[cfg(target_pointer_width = "32")]
- match input.read_initial_length() {
- Err(Error::UnsupportedOffset) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_initial_length_unknown_reserved_value() {
- let section = Section::with_endian(Endian::Little).L32(0xffff_fffe);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_initial_length() {
- Err(Error::UnknownReservedLength) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_initial_length_incomplete() {
- let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes.
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_initial_length() {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_initial_length_64_incomplete() {
- let section = Section::with_endian(Endian::Little)
- // Dwarf_64_INITIAL_UNIT_LENGTH
- .L32(0xffff_ffff)
- // Actual length is not long enough.
- .L32(0x7856_3412);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_initial_length() {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_offset_32() {
- let section = Section::with_endian(Endian::Little).L32(0x0123_4567);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_offset(Format::Dwarf32) {
- Ok(val) => {
- assert_eq!(input.len(), 0);
- assert_eq!(val, 0x0123_4567);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_offset_64_small() {
- let section = Section::with_endian(Endian::Little).L64(0x0123_4567);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_offset(Format::Dwarf64) {
- Ok(val) => {
- assert_eq!(input.len(), 0);
- assert_eq!(val, 0x0123_4567);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_offset_64_large() {
- let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_offset(Format::Dwarf64) {
- Ok(val) => {
- assert_eq!(input.len(), 0);
- assert_eq!(val, 0x0123_4567_89ab_cdef);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- #[cfg(target_pointer_width = "32")]
- fn test_parse_offset_64_large() {
- let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
- let buf = section.get_contents().unwrap();
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- match input.read_offset(Format::Dwarf64) {
- Err(Error::UnsupportedOffset) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-}
diff --git a/vendor/gimli/src/read/op.rs b/vendor/gimli/src/read/op.rs
deleted file mode 100644
index 4cb681e..0000000
--- a/vendor/gimli/src/read/op.rs
+++ /dev/null
@@ -1,4140 +0,0 @@
-//! Functions for parsing and evaluating DWARF expressions.
-
-#[cfg(feature = "read")]
-use alloc::vec::Vec;
-use core::mem;
-
-use super::util::{ArrayLike, ArrayVec};
-use crate::common::{DebugAddrIndex, DebugInfoOffset, Encoding, Register};
-use crate::constants;
-use crate::read::{Error, Reader, ReaderOffset, Result, StoreOnHeap, UnitOffset, Value, ValueType};
-
-/// A reference to a DIE, either relative to the current CU or
-/// relative to the section.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum DieReference<T = usize> {
- /// A CU-relative reference.
- UnitRef(UnitOffset<T>),
- /// A section-relative reference.
- DebugInfoRef(DebugInfoOffset<T>),
-}
-
-/// A single decoded DWARF expression operation.
-///
-/// DWARF expression evaluation is done in two parts: first the raw
-/// bytes of the next part of the expression are decoded; and then the
-/// decoded operation is evaluated. This approach lets other
-/// consumers inspect the DWARF expression without reimplementing the
-/// decoding operation.
-///
-/// Multiple DWARF opcodes may decode into a single `Operation`. For
-/// example, both `DW_OP_deref` and `DW_OP_xderef` are represented
-/// using `Operation::Deref`.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Operation<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Dereference the topmost value of the stack.
- Deref {
- /// The DIE of the base type or 0 to indicate the generic type
- base_type: UnitOffset<Offset>,
- /// The size of the data to dereference.
- size: u8,
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- },
- /// Drop an item from the stack.
- Drop,
- /// Pick an item from the stack and push it on top of the stack.
- /// This operation handles `DW_OP_pick`, `DW_OP_dup`, and
- /// `DW_OP_over`.
- Pick {
- /// The index, from the top of the stack, of the item to copy.
- index: u8,
- },
- /// Swap the top two stack items.
- Swap,
- /// Rotate the top three stack items.
- Rot,
- /// Take the absolute value of the top of the stack.
- Abs,
- /// Bitwise `and` of the top two values on the stack.
- And,
- /// Divide the top two values on the stack.
- Div,
- /// Subtract the top two values on the stack.
- Minus,
- /// Modulus of the top two values on the stack.
- Mod,
- /// Multiply the top two values on the stack.
- Mul,
- /// Negate the top of the stack.
- Neg,
- /// Bitwise `not` of the top of the stack.
- Not,
- /// Bitwise `or` of the top two values on the stack.
- Or,
- /// Add the top two values on the stack.
- Plus,
- /// Add a constant to the topmost value on the stack.
- PlusConstant {
- /// The value to add.
- value: u64,
- },
- /// Logical left shift of the 2nd value on the stack by the number
- /// of bits given by the topmost value on the stack.
- Shl,
- /// Right shift of the 2nd value on the stack by the number of
- /// bits given by the topmost value on the stack.
- Shr,
- /// Arithmetic left shift of the 2nd value on the stack by the
- /// number of bits given by the topmost value on the stack.
- Shra,
- /// Bitwise `xor` of the top two values on the stack.
- Xor,
- /// Branch to the target location if the top of stack is nonzero.
- Bra {
- /// The relative offset to the target bytecode.
- target: i16,
- },
- /// Compare the top two stack values for equality.
- Eq,
- /// Compare the top two stack values using `>=`.
- Ge,
- /// Compare the top two stack values using `>`.
- Gt,
- /// Compare the top two stack values using `<=`.
- Le,
- /// Compare the top two stack values using `<`.
- Lt,
- /// Compare the top two stack values using `!=`.
- Ne,
- /// Unconditional branch to the target location.
- Skip {
- /// The relative offset to the target bytecode.
- target: i16,
- },
- /// Push an unsigned constant value on the stack. This handles multiple
- /// DWARF opcodes.
- UnsignedConstant {
- /// The value to push.
- value: u64,
- },
- /// Push a signed constant value on the stack. This handles multiple
- /// DWARF opcodes.
- SignedConstant {
- /// The value to push.
- value: i64,
- },
- /// Indicate that this piece's location is in the given register.
- ///
- /// Completes the piece or expression.
- Register {
- /// The register number.
- register: Register,
- },
- /// Find the value of the given register, add the offset, and then
- /// push the resulting sum on the stack.
- RegisterOffset {
- /// The register number.
- register: Register,
- /// The offset to add.
- offset: i64,
- /// The DIE of the base type or 0 to indicate the generic type
- base_type: UnitOffset<Offset>,
- },
- /// Compute the frame base (using `DW_AT_frame_base`), add the
- /// given offset, and then push the resulting sum on the stack.
- FrameOffset {
- /// The offset to add.
- offset: i64,
- },
- /// No operation.
- Nop,
- /// Push the object address on the stack.
- PushObjectAddress,
- /// Evaluate a DWARF expression as a subroutine. The expression
- /// comes from the `DW_AT_location` attribute of the indicated
- /// DIE.
- Call {
- /// The DIE to use.
- offset: DieReference<Offset>,
- },
- /// Compute the address of a thread-local variable and push it on
- /// the stack.
- TLS,
- /// Compute the call frame CFA and push it on the stack.
- CallFrameCFA,
- /// Terminate a piece.
- Piece {
- /// The size of this piece in bits.
- size_in_bits: u64,
- /// The bit offset of this piece. If `None`, then this piece
- /// was specified using `DW_OP_piece` and should start at the
- /// next byte boundary.
- bit_offset: Option<u64>,
- },
- /// The object has no location, but has a known constant value.
- ///
- /// Represents `DW_OP_implicit_value`.
- /// Completes the piece or expression.
- ImplicitValue {
- /// The implicit value to use.
- data: R,
- },
- /// The object has no location, but its value is at the top of the stack.
- ///
- /// Represents `DW_OP_stack_value`.
- /// Completes the piece or expression.
- StackValue,
- /// The object is a pointer to a value which has no actual location,
- /// such as an implicit value or a stack value.
- ///
- /// Represents `DW_OP_implicit_pointer`.
- /// Completes the piece or expression.
- ImplicitPointer {
- /// The `.debug_info` offset of the value that this is an implicit pointer into.
- value: DebugInfoOffset<Offset>,
- /// The byte offset into the value that the implicit pointer points to.
- byte_offset: i64,
- },
- /// Evaluate an expression at the entry to the current subprogram, and push it on the stack.
- ///
- /// Represents `DW_OP_entry_value`.
- EntryValue {
- /// The expression to be evaluated.
- expression: R,
- },
- /// This represents a parameter that was optimized out.
- ///
- /// The offset points to the definition of the parameter, and is
- /// matched to the `DW_TAG_GNU_call_site_parameter` in the caller that also
- /// points to the same definition of the parameter.
- ///
- /// Represents `DW_OP_GNU_parameter_ref`.
- ParameterRef {
- /// The DIE to use.
- offset: UnitOffset<Offset>,
- },
- /// Relocate the address if needed, and push it on the stack.
- ///
- /// Represents `DW_OP_addr`.
- Address {
- /// The offset to add.
- address: u64,
- },
- /// Read the address at the given index in `.debug_addr, relocate the address if needed,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_addrx`.
- AddressIndex {
- /// The index of the address in `.debug_addr`.
- index: DebugAddrIndex<Offset>,
- },
- /// Read the address at the given index in `.debug_addr, and push it on the stack.
- /// Do not relocate the address.
- ///
- /// Represents `DW_OP_constx`.
- ConstantIndex {
- /// The index of the address in `.debug_addr`.
- index: DebugAddrIndex<Offset>,
- },
- /// Interpret the value bytes as a constant of a given type, and push it on the stack.
- ///
- /// Represents `DW_OP_const_type`.
- TypedLiteral {
- /// The DIE of the base type.
- base_type: UnitOffset<Offset>,
- /// The value bytes.
- value: R,
- },
- /// Pop the top stack entry, convert it to a different type, and push it on the stack.
- ///
- /// Represents `DW_OP_convert`.
- Convert {
- /// The DIE of the base type.
- base_type: UnitOffset<Offset>,
- },
- /// Pop the top stack entry, reinterpret the bits in its value as a different type,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_reinterpret`.
- Reinterpret {
- /// The DIE of the base type.
- base_type: UnitOffset<Offset>,
- },
- /// The index of a local in the currently executing function.
- ///
- /// Represents `DW_OP_WASM_location 0x00`.
- /// Completes the piece or expression.
- WasmLocal {
- /// The index of the local.
- index: u32,
- },
- /// The index of a global.
- ///
- /// Represents `DW_OP_WASM_location 0x01` or `DW_OP_WASM_location 0x03`.
- /// Completes the piece or expression.
- WasmGlobal {
- /// The index of the global.
- index: u32,
- },
- /// The index of an item on the operand stack.
- ///
- /// Represents `DW_OP_WASM_location 0x02`.
- /// Completes the piece or expression.
- WasmStack {
- /// The index of the stack item. 0 is the bottom of the operand stack.
- index: u32,
- },
-}
-
-#[derive(Debug)]
-enum OperationEvaluationResult<R: Reader> {
- Piece,
- Incomplete,
- Complete { location: Location<R> },
- Waiting(EvaluationWaiting<R>, EvaluationResult<R>),
-}
-
-/// A single location of a piece of the result of a DWARF expression.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Location<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// The piece is empty. Ordinarily this means the piece has been
- /// optimized away.
- Empty,
- /// The piece is found in a register.
- Register {
- /// The register number.
- register: Register,
- },
- /// The piece is found in memory.
- Address {
- /// The address.
- address: u64,
- },
- /// The piece has no location but its value is known.
- Value {
- /// The value.
- value: Value,
- },
- /// The piece is represented by some constant bytes.
- Bytes {
- /// The value.
- value: R,
- },
- /// The piece is a pointer to a value which has no actual location.
- ImplicitPointer {
- /// The `.debug_info` offset of the value that this is an implicit pointer into.
- value: DebugInfoOffset<Offset>,
- /// The byte offset into the value that the implicit pointer points to.
- byte_offset: i64,
- },
-}
-
-impl<R, Offset> Location<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Return true if the piece is empty.
- pub fn is_empty(&self) -> bool {
- matches!(*self, Location::Empty)
- }
-}
-
-/// The description of a single piece of the result of a DWARF
-/// expression.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Piece<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// If given, the size of the piece in bits. If `None`, there
- /// must be only one piece whose size is all of the object.
- pub size_in_bits: Option<u64>,
- /// If given, the bit offset of the piece within the location.
- /// If the location is a `Location::Register` or `Location::Value`,
- /// then this offset is from the least significant bit end of
- /// the register or value.
- /// If the location is a `Location::Address` then the offset uses
- /// the bit numbering and direction conventions of the language
- /// and target system.
- ///
- /// If `None`, the piece starts at the location. If the
- /// location is a register whose size is larger than the piece,
- /// then placement within the register is defined by the ABI.
- pub bit_offset: Option<u64>,
- /// Where this piece is to be found.
- pub location: Location<R, Offset>,
-}
-
-// A helper function to handle branch offsets.
-fn compute_pc<R: Reader>(pc: &R, bytecode: &R, offset: i16) -> Result<R> {
- let pc_offset = pc.offset_from(bytecode);
- let new_pc_offset = pc_offset.wrapping_add(R::Offset::from_i16(offset));
- if new_pc_offset > bytecode.len() {
- Err(Error::BadBranchTarget(new_pc_offset.into_u64()))
- } else {
- let mut new_pc = bytecode.clone();
- new_pc.skip(new_pc_offset)?;
- Ok(new_pc)
- }
-}
-
-fn generic_type<O: ReaderOffset>() -> UnitOffset<O> {
- UnitOffset(O::from_u64(0).unwrap())
-}
-
-impl<R, Offset> Operation<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Parse a single DWARF expression operation.
- ///
- /// This is useful when examining a DWARF expression for reasons other
- /// than direct evaluation.
- ///
- /// `bytes` points to a the operation to decode. It should point into
- /// the same array as `bytecode`, which should be the entire
- /// expression.
- pub fn parse(bytes: &mut R, encoding: Encoding) -> Result<Operation<R, Offset>> {
- let opcode = bytes.read_u8()?;
- let name = constants::DwOp(opcode);
- match name {
- constants::DW_OP_addr => {
- let address = bytes.read_address(encoding.address_size)?;
- Ok(Operation::Address { address })
- }
- constants::DW_OP_deref => Ok(Operation::Deref {
- base_type: generic_type(),
- size: encoding.address_size,
- space: false,
- }),
- constants::DW_OP_const1u => {
- let value = bytes.read_u8()?;
- Ok(Operation::UnsignedConstant {
- value: u64::from(value),
- })
- }
- constants::DW_OP_const1s => {
- let value = bytes.read_i8()?;
- Ok(Operation::SignedConstant {
- value: i64::from(value),
- })
- }
- constants::DW_OP_const2u => {
- let value = bytes.read_u16()?;
- Ok(Operation::UnsignedConstant {
- value: u64::from(value),
- })
- }
- constants::DW_OP_const2s => {
- let value = bytes.read_i16()?;
- Ok(Operation::SignedConstant {
- value: i64::from(value),
- })
- }
- constants::DW_OP_const4u => {
- let value = bytes.read_u32()?;
- Ok(Operation::UnsignedConstant {
- value: u64::from(value),
- })
- }
- constants::DW_OP_const4s => {
- let value = bytes.read_i32()?;
- Ok(Operation::SignedConstant {
- value: i64::from(value),
- })
- }
- constants::DW_OP_const8u => {
- let value = bytes.read_u64()?;
- Ok(Operation::UnsignedConstant { value })
- }
- constants::DW_OP_const8s => {
- let value = bytes.read_i64()?;
- Ok(Operation::SignedConstant { value })
- }
- constants::DW_OP_constu => {
- let value = bytes.read_uleb128()?;
- Ok(Operation::UnsignedConstant { value })
- }
- constants::DW_OP_consts => {
- let value = bytes.read_sleb128()?;
- Ok(Operation::SignedConstant { value })
- }
- constants::DW_OP_dup => Ok(Operation::Pick { index: 0 }),
- constants::DW_OP_drop => Ok(Operation::Drop),
- constants::DW_OP_over => Ok(Operation::Pick { index: 1 }),
- constants::DW_OP_pick => {
- let value = bytes.read_u8()?;
- Ok(Operation::Pick { index: value })
- }
- constants::DW_OP_swap => Ok(Operation::Swap),
- constants::DW_OP_rot => Ok(Operation::Rot),
- constants::DW_OP_xderef => Ok(Operation::Deref {
- base_type: generic_type(),
- size: encoding.address_size,
- space: true,
- }),
- constants::DW_OP_abs => Ok(Operation::Abs),
- constants::DW_OP_and => Ok(Operation::And),
- constants::DW_OP_div => Ok(Operation::Div),
- constants::DW_OP_minus => Ok(Operation::Minus),
- constants::DW_OP_mod => Ok(Operation::Mod),
- constants::DW_OP_mul => Ok(Operation::Mul),
- constants::DW_OP_neg => Ok(Operation::Neg),
- constants::DW_OP_not => Ok(Operation::Not),
- constants::DW_OP_or => Ok(Operation::Or),
- constants::DW_OP_plus => Ok(Operation::Plus),
- constants::DW_OP_plus_uconst => {
- let value = bytes.read_uleb128()?;
- Ok(Operation::PlusConstant { value })
- }
- constants::DW_OP_shl => Ok(Operation::Shl),
- constants::DW_OP_shr => Ok(Operation::Shr),
- constants::DW_OP_shra => Ok(Operation::Shra),
- constants::DW_OP_xor => Ok(Operation::Xor),
- constants::DW_OP_bra => {
- let target = bytes.read_i16()?;
- Ok(Operation::Bra { target })
- }
- constants::DW_OP_eq => Ok(Operation::Eq),
- constants::DW_OP_ge => Ok(Operation::Ge),
- constants::DW_OP_gt => Ok(Operation::Gt),
- constants::DW_OP_le => Ok(Operation::Le),
- constants::DW_OP_lt => Ok(Operation::Lt),
- constants::DW_OP_ne => Ok(Operation::Ne),
- constants::DW_OP_skip => {
- let target = bytes.read_i16()?;
- Ok(Operation::Skip { target })
- }
- constants::DW_OP_lit0
- | constants::DW_OP_lit1
- | constants::DW_OP_lit2
- | constants::DW_OP_lit3
- | constants::DW_OP_lit4
- | constants::DW_OP_lit5
- | constants::DW_OP_lit6
- | constants::DW_OP_lit7
- | constants::DW_OP_lit8
- | constants::DW_OP_lit9
- | constants::DW_OP_lit10
- | constants::DW_OP_lit11
- | constants::DW_OP_lit12
- | constants::DW_OP_lit13
- | constants::DW_OP_lit14
- | constants::DW_OP_lit15
- | constants::DW_OP_lit16
- | constants::DW_OP_lit17
- | constants::DW_OP_lit18
- | constants::DW_OP_lit19
- | constants::DW_OP_lit20
- | constants::DW_OP_lit21
- | constants::DW_OP_lit22
- | constants::DW_OP_lit23
- | constants::DW_OP_lit24
- | constants::DW_OP_lit25
- | constants::DW_OP_lit26
- | constants::DW_OP_lit27
- | constants::DW_OP_lit28
- | constants::DW_OP_lit29
- | constants::DW_OP_lit30
- | constants::DW_OP_lit31 => Ok(Operation::UnsignedConstant {
- value: (opcode - constants::DW_OP_lit0.0).into(),
- }),
- constants::DW_OP_reg0
- | constants::DW_OP_reg1
- | constants::DW_OP_reg2
- | constants::DW_OP_reg3
- | constants::DW_OP_reg4
- | constants::DW_OP_reg5
- | constants::DW_OP_reg6
- | constants::DW_OP_reg7
- | constants::DW_OP_reg8
- | constants::DW_OP_reg9
- | constants::DW_OP_reg10
- | constants::DW_OP_reg11
- | constants::DW_OP_reg12
- | constants::DW_OP_reg13
- | constants::DW_OP_reg14
- | constants::DW_OP_reg15
- | constants::DW_OP_reg16
- | constants::DW_OP_reg17
- | constants::DW_OP_reg18
- | constants::DW_OP_reg19
- | constants::DW_OP_reg20
- | constants::DW_OP_reg21
- | constants::DW_OP_reg22
- | constants::DW_OP_reg23
- | constants::DW_OP_reg24
- | constants::DW_OP_reg25
- | constants::DW_OP_reg26
- | constants::DW_OP_reg27
- | constants::DW_OP_reg28
- | constants::DW_OP_reg29
- | constants::DW_OP_reg30
- | constants::DW_OP_reg31 => Ok(Operation::Register {
- register: Register((opcode - constants::DW_OP_reg0.0).into()),
- }),
- constants::DW_OP_breg0
- | constants::DW_OP_breg1
- | constants::DW_OP_breg2
- | constants::DW_OP_breg3
- | constants::DW_OP_breg4
- | constants::DW_OP_breg5
- | constants::DW_OP_breg6
- | constants::DW_OP_breg7
- | constants::DW_OP_breg8
- | constants::DW_OP_breg9
- | constants::DW_OP_breg10
- | constants::DW_OP_breg11
- | constants::DW_OP_breg12
- | constants::DW_OP_breg13
- | constants::DW_OP_breg14
- | constants::DW_OP_breg15
- | constants::DW_OP_breg16
- | constants::DW_OP_breg17
- | constants::DW_OP_breg18
- | constants::DW_OP_breg19
- | constants::DW_OP_breg20
- | constants::DW_OP_breg21
- | constants::DW_OP_breg22
- | constants::DW_OP_breg23
- | constants::DW_OP_breg24
- | constants::DW_OP_breg25
- | constants::DW_OP_breg26
- | constants::DW_OP_breg27
- | constants::DW_OP_breg28
- | constants::DW_OP_breg29
- | constants::DW_OP_breg30
- | constants::DW_OP_breg31 => {
- let value = bytes.read_sleb128()?;
- Ok(Operation::RegisterOffset {
- register: Register((opcode - constants::DW_OP_breg0.0).into()),
- offset: value,
- base_type: generic_type(),
- })
- }
- constants::DW_OP_regx => {
- let register = bytes.read_uleb128().and_then(Register::from_u64)?;
- Ok(Operation::Register { register })
- }
- constants::DW_OP_fbreg => {
- let value = bytes.read_sleb128()?;
- Ok(Operation::FrameOffset { offset: value })
- }
- constants::DW_OP_bregx => {
- let register = bytes.read_uleb128().and_then(Register::from_u64)?;
- let offset = bytes.read_sleb128()?;
- Ok(Operation::RegisterOffset {
- register,
- offset,
- base_type: generic_type(),
- })
- }
- constants::DW_OP_piece => {
- let size = bytes.read_uleb128()?;
- Ok(Operation::Piece {
- size_in_bits: 8 * size,
- bit_offset: None,
- })
- }
- constants::DW_OP_deref_size => {
- let size = bytes.read_u8()?;
- Ok(Operation::Deref {
- base_type: generic_type(),
- size,
- space: false,
- })
- }
- constants::DW_OP_xderef_size => {
- let size = bytes.read_u8()?;
- Ok(Operation::Deref {
- base_type: generic_type(),
- size,
- space: true,
- })
- }
- constants::DW_OP_nop => Ok(Operation::Nop),
- constants::DW_OP_push_object_address => Ok(Operation::PushObjectAddress),
- constants::DW_OP_call2 => {
- let value = bytes.read_u16().map(R::Offset::from_u16)?;
- Ok(Operation::Call {
- offset: DieReference::UnitRef(UnitOffset(value)),
- })
- }
- constants::DW_OP_call4 => {
- let value = bytes.read_u32().map(R::Offset::from_u32)?;
- Ok(Operation::Call {
- offset: DieReference::UnitRef(UnitOffset(value)),
- })
- }
- constants::DW_OP_call_ref => {
- let value = bytes.read_offset(encoding.format)?;
- Ok(Operation::Call {
- offset: DieReference::DebugInfoRef(DebugInfoOffset(value)),
- })
- }
- constants::DW_OP_form_tls_address | constants::DW_OP_GNU_push_tls_address => {
- Ok(Operation::TLS)
- }
- constants::DW_OP_call_frame_cfa => Ok(Operation::CallFrameCFA),
- constants::DW_OP_bit_piece => {
- let size = bytes.read_uleb128()?;
- let offset = bytes.read_uleb128()?;
- Ok(Operation::Piece {
- size_in_bits: size,
- bit_offset: Some(offset),
- })
- }
- constants::DW_OP_implicit_value => {
- let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- let data = bytes.split(len)?;
- Ok(Operation::ImplicitValue { data })
- }
- constants::DW_OP_stack_value => Ok(Operation::StackValue),
- constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => {
- let value = if encoding.version == 2 {
- bytes
- .read_address(encoding.address_size)
- .and_then(Offset::from_u64)?
- } else {
- bytes.read_offset(encoding.format)?
- };
- let byte_offset = bytes.read_sleb128()?;
- Ok(Operation::ImplicitPointer {
- value: DebugInfoOffset(value),
- byte_offset,
- })
- }
- constants::DW_OP_addrx | constants::DW_OP_GNU_addr_index => {
- let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::AddressIndex {
- index: DebugAddrIndex(index),
- })
- }
- constants::DW_OP_constx | constants::DW_OP_GNU_const_index => {
- let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::ConstantIndex {
- index: DebugAddrIndex(index),
- })
- }
- constants::DW_OP_entry_value | constants::DW_OP_GNU_entry_value => {
- let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- let expression = bytes.split(len)?;
- Ok(Operation::EntryValue { expression })
- }
- constants::DW_OP_GNU_parameter_ref => {
- let value = bytes.read_u32().map(R::Offset::from_u32)?;
- Ok(Operation::ParameterRef {
- offset: UnitOffset(value),
- })
- }
- constants::DW_OP_const_type | constants::DW_OP_GNU_const_type => {
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- let len = bytes.read_u8()?;
- let value = bytes.split(R::Offset::from_u8(len))?;
- Ok(Operation::TypedLiteral {
- base_type: UnitOffset(base_type),
- value,
- })
- }
- constants::DW_OP_regval_type | constants::DW_OP_GNU_regval_type => {
- let register = bytes.read_uleb128().and_then(Register::from_u64)?;
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::RegisterOffset {
- register,
- offset: 0,
- base_type: UnitOffset(base_type),
- })
- }
- constants::DW_OP_deref_type | constants::DW_OP_GNU_deref_type => {
- let size = bytes.read_u8()?;
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::Deref {
- base_type: UnitOffset(base_type),
- size,
- space: false,
- })
- }
- constants::DW_OP_xderef_type => {
- let size = bytes.read_u8()?;
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::Deref {
- base_type: UnitOffset(base_type),
- size,
- space: true,
- })
- }
- constants::DW_OP_convert | constants::DW_OP_GNU_convert => {
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::Convert {
- base_type: UnitOffset(base_type),
- })
- }
- constants::DW_OP_reinterpret | constants::DW_OP_GNU_reinterpret => {
- let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?;
- Ok(Operation::Reinterpret {
- base_type: UnitOffset(base_type),
- })
- }
- constants::DW_OP_WASM_location => match bytes.read_u8()? {
- 0x0 => {
- let index = bytes.read_uleb128_u32()?;
- Ok(Operation::WasmLocal { index })
- }
- 0x1 => {
- let index = bytes.read_uleb128_u32()?;
- Ok(Operation::WasmGlobal { index })
- }
- 0x2 => {
- let index = bytes.read_uleb128_u32()?;
- Ok(Operation::WasmStack { index })
- }
- 0x3 => {
- let index = bytes.read_u32()?;
- Ok(Operation::WasmGlobal { index })
- }
- _ => Err(Error::InvalidExpression(name)),
- },
- _ => Err(Error::InvalidExpression(name)),
- }
- }
-}
-
-#[derive(Debug)]
-enum EvaluationState<R: Reader> {
- Start(Option<u64>),
- Ready,
- Error(Error),
- Complete,
- Waiting(EvaluationWaiting<R>),
-}
-
-#[derive(Debug)]
-enum EvaluationWaiting<R: Reader> {
- Memory,
- Register { offset: i64 },
- FrameBase { offset: i64 },
- Tls,
- Cfa,
- AtLocation,
- EntryValue,
- ParameterRef,
- RelocatedAddress,
- IndexedAddress,
- TypedLiteral { value: R },
- Convert,
- Reinterpret,
-}
-
-/// The state of an `Evaluation` after evaluating a DWARF expression.
-/// The evaluation is either `Complete`, or it requires more data
-/// to continue, as described by the variant.
-#[derive(Debug, PartialEq)]
-pub enum EvaluationResult<R: Reader> {
- /// The `Evaluation` is complete, and `Evaluation::result()` can be called.
- Complete,
- /// The `Evaluation` needs a value from memory to proceed further. Once the
- /// caller determines what value to provide it should resume the `Evaluation`
- /// by calling `Evaluation::resume_with_memory`.
- RequiresMemory {
- /// The address of the value required.
- address: u64,
- /// The size of the value required. This is guaranteed to be at most the
- /// word size of the target architecture.
- size: u8,
- /// If not `None`, a target-specific address space value.
- space: Option<u64>,
- /// The DIE of the base type or 0 to indicate the generic type
- base_type: UnitOffset<R::Offset>,
- },
- /// The `Evaluation` needs a value from a register to proceed further. Once
- /// the caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_register`.
- RequiresRegister {
- /// The register number.
- register: Register,
- /// The DIE of the base type or 0 to indicate the generic type
- base_type: UnitOffset<R::Offset>,
- },
- /// The `Evaluation` needs the frame base address to proceed further. Once
- /// the caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_frame_base`. The frame
- /// base address is the address produced by the location description in the
- /// `DW_AT_frame_base` attribute of the current function.
- RequiresFrameBase,
- /// The `Evaluation` needs a value from TLS to proceed further. Once the
- /// caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_tls`.
- RequiresTls(u64),
- /// The `Evaluation` needs the CFA to proceed further. Once the caller
- /// determines what value to provide it should resume the `Evaluation` by
- /// calling `Evaluation::resume_with_call_frame_cfa`.
- RequiresCallFrameCfa,
- /// The `Evaluation` needs the DWARF expression at the given location to
- /// proceed further. Once the caller determines what value to provide it
- /// should resume the `Evaluation` by calling
- /// `Evaluation::resume_with_at_location`.
- RequiresAtLocation(DieReference<R::Offset>),
- /// The `Evaluation` needs the value produced by evaluating a DWARF
- /// expression at the entry point of the current subprogram. Once the
- /// caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_entry_value`.
- RequiresEntryValue(Expression<R>),
- /// The `Evaluation` needs the value of the parameter at the given location
- /// in the current function's caller. Once the caller determines what value
- /// to provide it should resume the `Evaluation` by calling
- /// `Evaluation::resume_with_parameter_ref`.
- RequiresParameterRef(UnitOffset<R::Offset>),
- /// The `Evaluation` needs an address to be relocated to proceed further.
- /// Once the caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`.
- RequiresRelocatedAddress(u64),
- /// The `Evaluation` needs an address from the `.debug_addr` section.
- /// This address may also need to be relocated.
- /// Once the caller determines what value to provide it should resume the
- /// `Evaluation` by calling `Evaluation::resume_with_indexed_address`.
- RequiresIndexedAddress {
- /// The index of the address in the `.debug_addr` section,
- /// relative to the `DW_AT_addr_base` of the compilation unit.
- index: DebugAddrIndex<R::Offset>,
- /// Whether the address also needs to be relocated.
- relocate: bool,
- },
- /// The `Evaluation` needs the `ValueType` for the base type DIE at
- /// the give unit offset. Once the caller determines what value to provide it
- /// should resume the `Evaluation` by calling
- /// `Evaluation::resume_with_base_type`.
- RequiresBaseType(UnitOffset<R::Offset>),
-}
-
-/// The bytecode for a DWARF expression or location description.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Expression<R: Reader>(pub R);
-
-impl<R: Reader> Expression<R> {
- /// Create an evaluation for this expression.
- ///
- /// The `encoding` is determined by the
- /// [`CompilationUnitHeader`](struct.CompilationUnitHeader.html) or
- /// [`TypeUnitHeader`](struct.TypeUnitHeader.html) that this expression
- /// relates to.
- ///
- /// # Examples
- /// ```rust,no_run
- /// use gimli::Expression;
- /// # let endian = gimli::LittleEndian;
- /// # let debug_info = gimli::DebugInfo::from(gimli::EndianSlice::new(&[], endian));
- /// # let unit = debug_info.units().next().unwrap().unwrap();
- /// # let bytecode = gimli::EndianSlice::new(&[], endian);
- /// let expression = gimli::Expression(bytecode);
- /// let mut eval = expression.evaluation(unit.encoding());
- /// let mut result = eval.evaluate().unwrap();
- /// ```
- #[cfg(feature = "read")]
- #[inline]
- pub fn evaluation(self, encoding: Encoding) -> Evaluation<R> {
- Evaluation::new(self.0, encoding)
- }
-
- /// Return an iterator for the operations in the expression.
- pub fn operations(self, encoding: Encoding) -> OperationIter<R> {
- OperationIter {
- input: self.0,
- encoding,
- }
- }
-}
-
-/// An iterator for the operations in an expression.
-#[derive(Debug, Clone, Copy)]
-pub struct OperationIter<R: Reader> {
- input: R,
- encoding: Encoding,
-}
-
-impl<R: Reader> OperationIter<R> {
- /// Read the next operation in an expression.
- pub fn next(&mut self) -> Result<Option<Operation<R>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
- match Operation::parse(&mut self.input, self.encoding) {
- Ok(op) => Ok(Some(op)),
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-
- /// Return the current byte offset of the iterator.
- pub fn offset_from(&self, expression: &Expression<R>) -> R::Offset {
- self.input.offset_from(&expression.0)
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for OperationIter<R> {
- type Item = Operation<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- OperationIter::next(self)
- }
-}
-
-/// Specification of what storage should be used for [`Evaluation`].
-///
-#[cfg_attr(
- feature = "read",
- doc = "
-Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results
-on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`].
-"
-)]
-///
-/// If you need to avoid [`Evaluation`] from allocating memory, e.g. for signal safety,
-/// you can provide you own storage specification:
-/// ```rust,no_run
-/// # use gimli::*;
-/// # let bytecode = EndianSlice::new(&[], LittleEndian);
-/// # let encoding = unimplemented!();
-/// # let get_register_value = |_, _| Value::Generic(42);
-/// # let get_frame_base = || 0xdeadbeef;
-/// #
-/// struct StoreOnStack;
-///
-/// impl<R: Reader> EvaluationStorage<R> for StoreOnStack {
-/// type Stack = [Value; 64];
-/// type ExpressionStack = [(R, R); 4];
-/// type Result = [Piece<R>; 1];
-/// }
-///
-/// let mut eval = Evaluation::<_, StoreOnStack>::new_in(bytecode, encoding);
-/// let mut result = eval.evaluate().unwrap();
-/// while result != EvaluationResult::Complete {
-/// match result {
-/// EvaluationResult::RequiresRegister { register, base_type } => {
-/// let value = get_register_value(register, base_type);
-/// result = eval.resume_with_register(value).unwrap();
-/// },
-/// EvaluationResult::RequiresFrameBase => {
-/// let frame_base = get_frame_base();
-/// result = eval.resume_with_frame_base(frame_base).unwrap();
-/// },
-/// _ => unimplemented!(),
-/// };
-/// }
-///
-/// let result = eval.as_result();
-/// println!("{:?}", result);
-/// ```
-pub trait EvaluationStorage<R: Reader> {
- /// The storage used for the evaluation stack.
- type Stack: ArrayLike<Item = Value>;
- /// The storage used for the expression stack.
- type ExpressionStack: ArrayLike<Item = (R, R)>;
- /// The storage used for the results.
- type Result: ArrayLike<Item = Piece<R>>;
-}
-
-#[cfg(feature = "read")]
-impl<R: Reader> EvaluationStorage<R> for StoreOnHeap {
- type Stack = Vec<Value>;
- type ExpressionStack = Vec<(R, R)>;
- type Result = Vec<Piece<R>>;
-}
-
-/// A DWARF expression evaluator.
-///
-/// # Usage
-/// A DWARF expression may require additional data to produce a final result,
-/// such as the value of a register or a memory location. Once initial setup
-/// is complete (i.e. `set_initial_value()`, `set_object_address()`) the
-/// consumer calls the `evaluate()` method. That returns an `EvaluationResult`,
-/// which is either `EvaluationResult::Complete` or a value indicating what
-/// data is needed to resume the `Evaluation`. The consumer is responsible for
-/// producing that data and resuming the computation with the correct method,
-/// as documented for `EvaluationResult`. Only once an `EvaluationResult::Complete`
-/// is returned can the consumer call `result()`.
-///
-/// This design allows the consumer of `Evaluation` to decide how and when to
-/// produce the required data and resume the computation. The `Evaluation` can
-/// be driven synchronously (as shown below) or by some asynchronous mechanism
-/// such as futures.
-///
-/// # Examples
-/// ```rust,no_run
-/// use gimli::{Evaluation, EvaluationResult, Expression};
-/// # let bytecode = gimli::EndianSlice::new(&[], gimli::LittleEndian);
-/// # let encoding = unimplemented!();
-/// # let get_register_value = |_, _| gimli::Value::Generic(42);
-/// # let get_frame_base = || 0xdeadbeef;
-///
-/// let mut eval = Evaluation::new(bytecode, encoding);
-/// let mut result = eval.evaluate().unwrap();
-/// while result != EvaluationResult::Complete {
-/// match result {
-/// EvaluationResult::RequiresRegister { register, base_type } => {
-/// let value = get_register_value(register, base_type);
-/// result = eval.resume_with_register(value).unwrap();
-/// },
-/// EvaluationResult::RequiresFrameBase => {
-/// let frame_base = get_frame_base();
-/// result = eval.resume_with_frame_base(frame_base).unwrap();
-/// },
-/// _ => unimplemented!(),
-/// };
-/// }
-///
-/// let result = eval.result();
-/// println!("{:?}", result);
-/// ```
-#[derive(Debug)]
-pub struct Evaluation<R: Reader, S: EvaluationStorage<R> = StoreOnHeap> {
- bytecode: R,
- encoding: Encoding,
- object_address: Option<u64>,
- max_iterations: Option<u32>,
- iteration: u32,
- state: EvaluationState<R>,
-
- // Stack operations are done on word-sized values. We do all
- // operations on 64-bit values, and then mask the results
- // appropriately when popping.
- addr_mask: u64,
-
- // The stack.
- stack: ArrayVec<S::Stack>,
-
- // The next operation to decode and evaluate.
- pc: R,
-
- // If we see a DW_OP_call* operation, the previous PC and bytecode
- // is stored here while evaluating the subroutine.
- expression_stack: ArrayVec<S::ExpressionStack>,
-
- value_result: Option<Value>,
- result: ArrayVec<S::Result>,
-}
-
-#[cfg(feature = "read")]
-impl<R: Reader> Evaluation<R> {
- /// Create a new DWARF expression evaluator.
- ///
- /// The new evaluator is created without an initial value, without
- /// an object address, and without a maximum number of iterations.
- pub fn new(bytecode: R, encoding: Encoding) -> Self {
- Self::new_in(bytecode, encoding)
- }
-
- /// Get the result of this `Evaluation`.
- ///
- /// # Panics
- /// Panics if this `Evaluation` has not been driven to completion.
- pub fn result(self) -> Vec<Piece<R>> {
- match self.state {
- EvaluationState::Complete => self.result.into_vec(),
- _ => {
- panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed")
- }
- }
- }
-}
-
-impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> {
- /// Create a new DWARF expression evaluator.
- ///
- /// The new evaluator is created without an initial value, without
- /// an object address, and without a maximum number of iterations.
- pub fn new_in(bytecode: R, encoding: Encoding) -> Self {
- let pc = bytecode.clone();
- Evaluation {
- bytecode,
- encoding,
- object_address: None,
- max_iterations: None,
- iteration: 0,
- state: EvaluationState::Start(None),
- addr_mask: if encoding.address_size == 8 {
- !0u64
- } else {
- (1 << (8 * u64::from(encoding.address_size))) - 1
- },
- stack: Default::default(),
- expression_stack: Default::default(),
- pc,
- value_result: None,
- result: Default::default(),
- }
- }
-
- /// Set an initial value to be pushed on the DWARF expression
- /// evaluator's stack. This can be used in cases like
- /// `DW_AT_vtable_elem_location`, which require a value on the
- /// stack before evaluation commences. If no initial value is
- /// set, and the expression uses an opcode requiring the initial
- /// value, then evaluation will fail with an error.
- ///
- /// # Panics
- /// Panics if `set_initial_value()` has already been called, or if
- /// `evaluate()` has already been called.
- pub fn set_initial_value(&mut self, value: u64) {
- match self.state {
- EvaluationState::Start(None) => {
- self.state = EvaluationState::Start(Some(value));
- }
- _ => panic!(
- "`Evaluation::set_initial_value` was called twice, or after evaluation began."
- ),
- };
- }
-
- /// Set the enclosing object's address, as used by
- /// `DW_OP_push_object_address`. If no object address is set, and
- /// the expression uses an opcode requiring the object address,
- /// then evaluation will fail with an error.
- pub fn set_object_address(&mut self, value: u64) {
- self.object_address = Some(value);
- }
-
- /// Set the maximum number of iterations to be allowed by the
- /// expression evaluator.
- ///
- /// An iteration corresponds approximately to the evaluation of a
- /// single operation in an expression ("approximately" because the
- /// implementation may allow two such operations in some cases).
- /// The default is not to have a maximum; once set, it's not
- /// possible to go back to this default state. This value can be
- /// set to avoid denial of service attacks by bad DWARF bytecode.
- pub fn set_max_iterations(&mut self, value: u32) {
- self.max_iterations = Some(value);
- }
-
- fn pop(&mut self) -> Result<Value> {
- match self.stack.pop() {
- Some(value) => Ok(value),
- None => Err(Error::NotEnoughStackItems),
- }
- }
-
- fn push(&mut self, value: Value) -> Result<()> {
- self.stack.try_push(value).map_err(|_| Error::StackFull)
- }
-
- fn evaluate_one_operation(&mut self) -> Result<OperationEvaluationResult<R>> {
- let operation = Operation::parse(&mut self.pc, self.encoding)?;
-
- match operation {
- Operation::Deref {
- base_type,
- size,
- space,
- } => {
- let entry = self.pop()?;
- let addr = entry.to_u64(self.addr_mask)?;
- let addr_space = if space {
- let entry = self.pop()?;
- let value = entry.to_u64(self.addr_mask)?;
- Some(value)
- } else {
- None
- };
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Memory,
- EvaluationResult::RequiresMemory {
- address: addr,
- size,
- space: addr_space,
- base_type,
- },
- ));
- }
-
- Operation::Drop => {
- self.pop()?;
- }
- Operation::Pick { index } => {
- let len = self.stack.len();
- let index = index as usize;
- if index >= len {
- return Err(Error::NotEnoughStackItems);
- }
- let value = self.stack[len - index - 1];
- self.push(value)?;
- }
- Operation::Swap => {
- let top = self.pop()?;
- let next = self.pop()?;
- self.push(top)?;
- self.push(next)?;
- }
- Operation::Rot => {
- let one = self.pop()?;
- let two = self.pop()?;
- let three = self.pop()?;
- self.push(one)?;
- self.push(three)?;
- self.push(two)?;
- }
-
- Operation::Abs => {
- let value = self.pop()?;
- let result = value.abs(self.addr_mask)?;
- self.push(result)?;
- }
- Operation::And => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.and(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Div => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.div(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Minus => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.sub(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Mod => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.rem(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Mul => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.mul(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Neg => {
- let v = self.pop()?;
- let result = v.neg(self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Not => {
- let value = self.pop()?;
- let result = value.not(self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Or => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.or(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Plus => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.add(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::PlusConstant { value } => {
- let lhs = self.pop()?;
- let rhs = Value::from_u64(lhs.value_type(), value)?;
- let result = lhs.add(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Shl => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.shl(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Shr => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.shr(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Shra => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.shra(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Xor => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.xor(rhs, self.addr_mask)?;
- self.push(result)?;
- }
-
- Operation::Bra { target } => {
- let entry = self.pop()?;
- let v = entry.to_u64(self.addr_mask)?;
- if v != 0 {
- self.pc = compute_pc(&self.pc, &self.bytecode, target)?;
- }
- }
-
- Operation::Eq => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.eq(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Ge => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.ge(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Gt => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.gt(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Le => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.le(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Lt => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.lt(rhs, self.addr_mask)?;
- self.push(result)?;
- }
- Operation::Ne => {
- let rhs = self.pop()?;
- let lhs = self.pop()?;
- let result = lhs.ne(rhs, self.addr_mask)?;
- self.push(result)?;
- }
-
- Operation::Skip { target } => {
- self.pc = compute_pc(&self.pc, &self.bytecode, target)?;
- }
-
- Operation::UnsignedConstant { value } => {
- self.push(Value::Generic(value))?;
- }
-
- Operation::SignedConstant { value } => {
- self.push(Value::Generic(value as u64))?;
- }
-
- Operation::RegisterOffset {
- register,
- offset,
- base_type,
- } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Register { offset },
- EvaluationResult::RequiresRegister {
- register,
- base_type,
- },
- ));
- }
-
- Operation::FrameOffset { offset } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::FrameBase { offset },
- EvaluationResult::RequiresFrameBase,
- ));
- }
-
- Operation::Nop => {}
-
- Operation::PushObjectAddress => {
- if let Some(value) = self.object_address {
- self.push(Value::Generic(value))?;
- } else {
- return Err(Error::InvalidPushObjectAddress);
- }
- }
-
- Operation::Call { offset } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::AtLocation,
- EvaluationResult::RequiresAtLocation(offset),
- ));
- }
-
- Operation::TLS => {
- let entry = self.pop()?;
- let index = entry.to_u64(self.addr_mask)?;
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Tls,
- EvaluationResult::RequiresTls(index),
- ));
- }
-
- Operation::CallFrameCFA => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Cfa,
- EvaluationResult::RequiresCallFrameCfa,
- ));
- }
-
- Operation::Register { register } => {
- let location = Location::Register { register };
- return Ok(OperationEvaluationResult::Complete { location });
- }
-
- Operation::ImplicitValue { ref data } => {
- let location = Location::Bytes {
- value: data.clone(),
- };
- return Ok(OperationEvaluationResult::Complete { location });
- }
-
- Operation::StackValue => {
- let value = self.pop()?;
- let location = Location::Value { value };
- return Ok(OperationEvaluationResult::Complete { location });
- }
-
- Operation::ImplicitPointer { value, byte_offset } => {
- let location = Location::ImplicitPointer { value, byte_offset };
- return Ok(OperationEvaluationResult::Complete { location });
- }
-
- Operation::EntryValue { ref expression } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::EntryValue,
- EvaluationResult::RequiresEntryValue(Expression(expression.clone())),
- ));
- }
-
- Operation::ParameterRef { offset } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::ParameterRef,
- EvaluationResult::RequiresParameterRef(offset),
- ));
- }
-
- Operation::Address { address } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::RelocatedAddress,
- EvaluationResult::RequiresRelocatedAddress(address),
- ));
- }
-
- Operation::AddressIndex { index } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::IndexedAddress,
- EvaluationResult::RequiresIndexedAddress {
- index,
- relocate: true,
- },
- ));
- }
-
- Operation::ConstantIndex { index } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::IndexedAddress,
- EvaluationResult::RequiresIndexedAddress {
- index,
- relocate: false,
- },
- ));
- }
-
- Operation::Piece {
- size_in_bits,
- bit_offset,
- } => {
- let location = if self.stack.is_empty() {
- Location::Empty
- } else {
- let entry = self.pop()?;
- let address = entry.to_u64(self.addr_mask)?;
- Location::Address { address }
- };
- self.result
- .try_push(Piece {
- size_in_bits: Some(size_in_bits),
- bit_offset,
- location,
- })
- .map_err(|_| Error::StackFull)?;
- return Ok(OperationEvaluationResult::Piece);
- }
-
- Operation::TypedLiteral { base_type, value } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::TypedLiteral { value },
- EvaluationResult::RequiresBaseType(base_type),
- ));
- }
- Operation::Convert { base_type } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Convert,
- EvaluationResult::RequiresBaseType(base_type),
- ));
- }
- Operation::Reinterpret { base_type } => {
- return Ok(OperationEvaluationResult::Waiting(
- EvaluationWaiting::Reinterpret,
- EvaluationResult::RequiresBaseType(base_type),
- ));
- }
- Operation::WasmLocal { .. }
- | Operation::WasmGlobal { .. }
- | Operation::WasmStack { .. } => {
- return Err(Error::UnsupportedEvaluation);
- }
- }
-
- Ok(OperationEvaluationResult::Incomplete)
- }
-
- /// Get the result if this is an evaluation for a value.
- ///
- /// Returns `None` if the evaluation contained operations that are only
- /// valid for location descriptions.
- ///
- /// # Panics
- /// Panics if this `Evaluation` has not been driven to completion.
- pub fn value_result(&self) -> Option<Value> {
- match self.state {
- EvaluationState::Complete => self.value_result,
- _ => {
- panic!("Called `Evaluation::value_result` on an `Evaluation` that has not been completed")
- }
- }
- }
-
- /// Get the result of this `Evaluation`.
- ///
- /// # Panics
- /// Panics if this `Evaluation` has not been driven to completion.
- pub fn as_result(&self) -> &[Piece<R>] {
- match self.state {
- EvaluationState::Complete => &self.result,
- _ => {
- panic!(
- "Called `Evaluation::as_result` on an `Evaluation` that has not been completed"
- )
- }
- }
- }
-
- /// Evaluate a DWARF expression. This method should only ever be called
- /// once. If the returned `EvaluationResult` is not
- /// `EvaluationResult::Complete`, the caller should provide the required
- /// value and resume the evaluation by calling the appropriate resume_with
- /// method on `Evaluation`.
- pub fn evaluate(&mut self) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Start(initial_value) => {
- if let Some(value) = initial_value {
- self.push(Value::Generic(value))?;
- }
- self.state = EvaluationState::Ready;
- }
- EvaluationState::Ready => {}
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Complete => return Ok(EvaluationResult::Complete),
- EvaluationState::Waiting(_) => panic!(),
- };
-
- match self.evaluate_internal() {
- Ok(r) => Ok(r),
- Err(e) => {
- self.state = EvaluationState::Error(e);
- Err(e)
- }
- }
- }
-
- /// Resume the `Evaluation` with the provided memory `value`. This will apply
- /// the provided memory value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresMemory`.
- pub fn resume_with_memory(&mut self, value: Value) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::Memory) => {
- self.push(value)?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_memory` without a preceding `EvaluationResult::RequiresMemory`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `register` value. This will apply
- /// the provided register value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresRegister`.
- pub fn resume_with_register(&mut self, value: Value) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::Register { offset }) => {
- let offset = Value::from_u64(value.value_type(), offset as u64)?;
- let value = value.add(offset, self.addr_mask)?;
- self.push(value)?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_register` without a preceding `EvaluationResult::RequiresRegister`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `frame_base`. This will
- /// apply the provided frame base value to the evaluation and continue
- /// evaluating opcodes until the evaluation is completed, reaches an error,
- /// or needs more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresFrameBase`.
- pub fn resume_with_frame_base(&mut self, frame_base: u64) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::FrameBase { offset }) => {
- self.push(Value::Generic(frame_base.wrapping_add(offset as u64)))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_frame_base` without a preceding `EvaluationResult::RequiresFrameBase`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `value`. This will apply
- /// the provided TLS value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresTls`.
- pub fn resume_with_tls(&mut self, value: u64) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::Tls) => {
- self.push(Value::Generic(value))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_tls` without a preceding `EvaluationResult::RequiresTls`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `cfa`. This will
- /// apply the provided CFA value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresCallFrameCfa`.
- pub fn resume_with_call_frame_cfa(&mut self, cfa: u64) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::Cfa) => {
- self.push(Value::Generic(cfa))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_call_frame_cfa` without a preceding `EvaluationResult::RequiresCallFrameCfa`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `bytes`. This will
- /// continue processing the evaluation with the new expression provided
- /// until the evaluation is completed, reaches an error, or needs more
- /// information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresAtLocation`.
- pub fn resume_with_at_location(&mut self, mut bytes: R) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::AtLocation) => {
- if !bytes.is_empty() {
- let mut pc = bytes.clone();
- mem::swap(&mut pc, &mut self.pc);
- mem::swap(&mut bytes, &mut self.bytecode);
- self.expression_stack.try_push((pc, bytes)).map_err(|_| Error::StackFull)?;
- }
- }
- _ => panic!(
- "Called `Evaluation::resume_with_at_location` without a precedeing `EvaluationResult::RequiresAtLocation`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `entry_value`. This will
- /// apply the provided entry value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresEntryValue`.
- pub fn resume_with_entry_value(&mut self, entry_value: Value) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::EntryValue) => {
- self.push(entry_value)?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_entry_value` without a preceding `EvaluationResult::RequiresEntryValue`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `parameter_value`. This will
- /// apply the provided parameter value to the evaluation and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresParameterRef`.
- pub fn resume_with_parameter_ref(
- &mut self,
- parameter_value: u64,
- ) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::ParameterRef) => {
- self.push(Value::Generic(parameter_value))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_parameter_ref` without a preceding `EvaluationResult::RequiresParameterRef`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided relocated `address`. This will use the
- /// provided relocated address for the operation that required it, and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with
- /// `EvaluationResult::RequiresRelocatedAddress`.
- pub fn resume_with_relocated_address(&mut self, address: u64) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::RelocatedAddress) => {
- self.push(Value::Generic(address))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_relocated_address` without a preceding `EvaluationResult::RequiresRelocatedAddress`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided indexed `address`. This will use the
- /// provided indexed address for the operation that required it, and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with
- /// `EvaluationResult::RequiresIndexedAddress`.
- pub fn resume_with_indexed_address(&mut self, address: u64) -> Result<EvaluationResult<R>> {
- match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::IndexedAddress) => {
- self.push(Value::Generic(address))?;
- }
- _ => panic!(
- "Called `Evaluation::resume_with_indexed_address` without a preceding `EvaluationResult::RequiresIndexedAddress`"
- ),
- };
-
- self.evaluate_internal()
- }
-
- /// Resume the `Evaluation` with the provided `base_type`. This will use the
- /// provided base type for the operation that required it, and continue evaluating
- /// opcodes until the evaluation is completed, reaches an error, or needs
- /// more information again.
- ///
- /// # Panics
- /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresBaseType`.
- pub fn resume_with_base_type(&mut self, base_type: ValueType) -> Result<EvaluationResult<R>> {
- let value = match self.state {
- EvaluationState::Error(err) => return Err(err),
- EvaluationState::Waiting(EvaluationWaiting::TypedLiteral { ref value }) => {
- Value::parse(base_type, value.clone())?
- }
- EvaluationState::Waiting(EvaluationWaiting::Convert) => {
- let entry = self.pop()?;
- entry.convert(base_type, self.addr_mask)?
- }
- EvaluationState::Waiting(EvaluationWaiting::Reinterpret) => {
- let entry = self.pop()?;
- entry.reinterpret(base_type, self.addr_mask)?
- }
- _ => panic!(
- "Called `Evaluation::resume_with_base_type` without a preceding `EvaluationResult::RequiresBaseType`"
- ),
- };
- self.push(value)?;
- self.evaluate_internal()
- }
-
- fn end_of_expression(&mut self) -> bool {
- while self.pc.is_empty() {
- match self.expression_stack.pop() {
- Some((newpc, newbytes)) => {
- self.pc = newpc;
- self.bytecode = newbytes;
- }
- None => return true,
- }
- }
- false
- }
-
- fn evaluate_internal(&mut self) -> Result<EvaluationResult<R>> {
- while !self.end_of_expression() {
- self.iteration += 1;
- if let Some(max_iterations) = self.max_iterations {
- if self.iteration > max_iterations {
- return Err(Error::TooManyIterations);
- }
- }
-
- let op_result = self.evaluate_one_operation()?;
- match op_result {
- OperationEvaluationResult::Piece => {}
- OperationEvaluationResult::Incomplete => {
- if self.end_of_expression() && !self.result.is_empty() {
- // We saw a piece earlier and then some
- // unterminated piece. It's not clear this is
- // well-defined.
- return Err(Error::InvalidPiece);
- }
- }
- OperationEvaluationResult::Complete { location } => {
- if self.end_of_expression() {
- if !self.result.is_empty() {
- // We saw a piece earlier and then some
- // unterminated piece. It's not clear this is
- // well-defined.
- return Err(Error::InvalidPiece);
- }
- self.result
- .try_push(Piece {
- size_in_bits: None,
- bit_offset: None,
- location,
- })
- .map_err(|_| Error::StackFull)?;
- } else {
- // If there are more operations, then the next operation must
- // be a Piece.
- match Operation::parse(&mut self.pc, self.encoding)? {
- Operation::Piece {
- size_in_bits,
- bit_offset,
- } => {
- self.result
- .try_push(Piece {
- size_in_bits: Some(size_in_bits),
- bit_offset,
- location,
- })
- .map_err(|_| Error::StackFull)?;
- }
- _ => {
- let value =
- self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1;
- return Err(Error::InvalidExpressionTerminator(value));
- }
- }
- }
- }
- OperationEvaluationResult::Waiting(waiting, result) => {
- self.state = EvaluationState::Waiting(waiting);
- return Ok(result);
- }
- }
- }
-
- // If no pieces have been seen, use the stack top as the
- // result.
- if self.result.is_empty() {
- let entry = self.pop()?;
- self.value_result = Some(entry);
- let addr = entry.to_u64(self.addr_mask)?;
- self.result
- .try_push(Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Address { address: addr },
- })
- .map_err(|_| Error::StackFull)?;
- }
-
- self.state = EvaluationState::Complete;
- Ok(EvaluationResult::Complete)
- }
-}
-
-#[cfg(test)]
-// Tests require leb128::write.
-#[cfg(feature = "write")]
-mod tests {
- use super::*;
- use crate::common::Format;
- use crate::constants;
- use crate::endianity::LittleEndian;
- use crate::leb128;
- use crate::read::{EndianSlice, Error, Result, UnitOffset};
- use crate::test_util::GimliSectionMethods;
- use core::usize;
- use test_assembler::{Endian, Section};
-
- fn encoding4() -> Encoding {
- Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- }
- }
-
- fn encoding8() -> Encoding {
- Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- }
- }
-
- #[test]
- fn test_compute_pc() {
- // Contents don't matter for this test, just length.
- let bytes = [0, 1, 2, 3, 4];
- let bytecode = &bytes[..];
- let ebuf = &EndianSlice::new(bytecode, LittleEndian);
-
- assert_eq!(compute_pc(ebuf, ebuf, 0), Ok(*ebuf));
- assert_eq!(
- compute_pc(ebuf, ebuf, -1),
- Err(Error::BadBranchTarget(usize::MAX as u64))
- );
- assert_eq!(compute_pc(ebuf, ebuf, 5), Ok(ebuf.range_from(5..)));
- assert_eq!(
- compute_pc(&ebuf.range_from(3..), ebuf, -2),
- Ok(ebuf.range_from(1..))
- );
- assert_eq!(
- compute_pc(&ebuf.range_from(2..), ebuf, 2),
- Ok(ebuf.range_from(4..))
- );
- }
-
- fn check_op_parse_simple<'input>(
- input: &'input [u8],
- expect: &Operation<EndianSlice<'input, LittleEndian>>,
- encoding: Encoding,
- ) {
- let buf = EndianSlice::new(input, LittleEndian);
- let mut pc = buf;
- let value = Operation::parse(&mut pc, encoding);
- match value {
- Ok(val) => {
- assert_eq!(val, *expect);
- assert_eq!(pc.len(), 0);
- }
- _ => panic!("Unexpected result"),
- }
- }
-
- fn check_op_parse_eof(input: &[u8], encoding: Encoding) {
- let buf = EndianSlice::new(input, LittleEndian);
- let mut pc = buf;
- match Operation::parse(&mut pc, encoding) {
- Err(Error::UnexpectedEof(id)) => {
- assert!(buf.lookup_offset_id(id).is_some());
- }
-
- _ => panic!("Unexpected result"),
- }
- }
-
- fn check_op_parse<F>(
- input: F,
- expect: &Operation<EndianSlice<LittleEndian>>,
- encoding: Encoding,
- ) where
- F: Fn(Section) -> Section,
- {
- let input = input(Section::with_endian(Endian::Little))
- .get_contents()
- .unwrap();
- for i in 1..input.len() {
- check_op_parse_eof(&input[..i], encoding);
- }
- check_op_parse_simple(&input, expect, encoding);
- }
-
- #[test]
- fn test_op_parse_onebyte() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- // Test all single-byte opcodes.
- #[rustfmt::skip]
- let inputs = [
- (
- constants::DW_OP_deref,
- Operation::Deref {
- base_type: generic_type(),
- size: encoding.address_size,
- space: false,
- },
- ),
- (constants::DW_OP_dup, Operation::Pick { index: 0 }),
- (constants::DW_OP_drop, Operation::Drop),
- (constants::DW_OP_over, Operation::Pick { index: 1 }),
- (constants::DW_OP_swap, Operation::Swap),
- (constants::DW_OP_rot, Operation::Rot),
- (
- constants::DW_OP_xderef,
- Operation::Deref {
- base_type: generic_type(),
- size: encoding.address_size,
- space: true,
- },
- ),
- (constants::DW_OP_abs, Operation::Abs),
- (constants::DW_OP_and, Operation::And),
- (constants::DW_OP_div, Operation::Div),
- (constants::DW_OP_minus, Operation::Minus),
- (constants::DW_OP_mod, Operation::Mod),
- (constants::DW_OP_mul, Operation::Mul),
- (constants::DW_OP_neg, Operation::Neg),
- (constants::DW_OP_not, Operation::Not),
- (constants::DW_OP_or, Operation::Or),
- (constants::DW_OP_plus, Operation::Plus),
- (constants::DW_OP_shl, Operation::Shl),
- (constants::DW_OP_shr, Operation::Shr),
- (constants::DW_OP_shra, Operation::Shra),
- (constants::DW_OP_xor, Operation::Xor),
- (constants::DW_OP_eq, Operation::Eq),
- (constants::DW_OP_ge, Operation::Ge),
- (constants::DW_OP_gt, Operation::Gt),
- (constants::DW_OP_le, Operation::Le),
- (constants::DW_OP_lt, Operation::Lt),
- (constants::DW_OP_ne, Operation::Ne),
- (constants::DW_OP_lit0, Operation::UnsignedConstant { value: 0 }),
- (constants::DW_OP_lit1, Operation::UnsignedConstant { value: 1 }),
- (constants::DW_OP_lit2, Operation::UnsignedConstant { value: 2 }),
- (constants::DW_OP_lit3, Operation::UnsignedConstant { value: 3 }),
- (constants::DW_OP_lit4, Operation::UnsignedConstant { value: 4 }),
- (constants::DW_OP_lit5, Operation::UnsignedConstant { value: 5 }),
- (constants::DW_OP_lit6, Operation::UnsignedConstant { value: 6 }),
- (constants::DW_OP_lit7, Operation::UnsignedConstant { value: 7 }),
- (constants::DW_OP_lit8, Operation::UnsignedConstant { value: 8 }),
- (constants::DW_OP_lit9, Operation::UnsignedConstant { value: 9 }),
- (constants::DW_OP_lit10, Operation::UnsignedConstant { value: 10 }),
- (constants::DW_OP_lit11, Operation::UnsignedConstant { value: 11 }),
- (constants::DW_OP_lit12, Operation::UnsignedConstant { value: 12 }),
- (constants::DW_OP_lit13, Operation::UnsignedConstant { value: 13 }),
- (constants::DW_OP_lit14, Operation::UnsignedConstant { value: 14 }),
- (constants::DW_OP_lit15, Operation::UnsignedConstant { value: 15 }),
- (constants::DW_OP_lit16, Operation::UnsignedConstant { value: 16 }),
- (constants::DW_OP_lit17, Operation::UnsignedConstant { value: 17 }),
- (constants::DW_OP_lit18, Operation::UnsignedConstant { value: 18 }),
- (constants::DW_OP_lit19, Operation::UnsignedConstant { value: 19 }),
- (constants::DW_OP_lit20, Operation::UnsignedConstant { value: 20 }),
- (constants::DW_OP_lit21, Operation::UnsignedConstant { value: 21 }),
- (constants::DW_OP_lit22, Operation::UnsignedConstant { value: 22 }),
- (constants::DW_OP_lit23, Operation::UnsignedConstant { value: 23 }),
- (constants::DW_OP_lit24, Operation::UnsignedConstant { value: 24 }),
- (constants::DW_OP_lit25, Operation::UnsignedConstant { value: 25 }),
- (constants::DW_OP_lit26, Operation::UnsignedConstant { value: 26 }),
- (constants::DW_OP_lit27, Operation::UnsignedConstant { value: 27 }),
- (constants::DW_OP_lit28, Operation::UnsignedConstant { value: 28 }),
- (constants::DW_OP_lit29, Operation::UnsignedConstant { value: 29 }),
- (constants::DW_OP_lit30, Operation::UnsignedConstant { value: 30 }),
- (constants::DW_OP_lit31, Operation::UnsignedConstant { value: 31 }),
- (constants::DW_OP_reg0, Operation::Register { register: Register(0) }),
- (constants::DW_OP_reg1, Operation::Register { register: Register(1) }),
- (constants::DW_OP_reg2, Operation::Register { register: Register(2) }),
- (constants::DW_OP_reg3, Operation::Register { register: Register(3) }),
- (constants::DW_OP_reg4, Operation::Register { register: Register(4) }),
- (constants::DW_OP_reg5, Operation::Register { register: Register(5) }),
- (constants::DW_OP_reg6, Operation::Register { register: Register(6) }),
- (constants::DW_OP_reg7, Operation::Register { register: Register(7) }),
- (constants::DW_OP_reg8, Operation::Register { register: Register(8) }),
- (constants::DW_OP_reg9, Operation::Register { register: Register(9) }),
- (constants::DW_OP_reg10, Operation::Register { register: Register(10) }),
- (constants::DW_OP_reg11, Operation::Register { register: Register(11) }),
- (constants::DW_OP_reg12, Operation::Register { register: Register(12) }),
- (constants::DW_OP_reg13, Operation::Register { register: Register(13) }),
- (constants::DW_OP_reg14, Operation::Register { register: Register(14) }),
- (constants::DW_OP_reg15, Operation::Register { register: Register(15) }),
- (constants::DW_OP_reg16, Operation::Register { register: Register(16) }),
- (constants::DW_OP_reg17, Operation::Register { register: Register(17) }),
- (constants::DW_OP_reg18, Operation::Register { register: Register(18) }),
- (constants::DW_OP_reg19, Operation::Register { register: Register(19) }),
- (constants::DW_OP_reg20, Operation::Register { register: Register(20) }),
- (constants::DW_OP_reg21, Operation::Register { register: Register(21) }),
- (constants::DW_OP_reg22, Operation::Register { register: Register(22) }),
- (constants::DW_OP_reg23, Operation::Register { register: Register(23) }),
- (constants::DW_OP_reg24, Operation::Register { register: Register(24) }),
- (constants::DW_OP_reg25, Operation::Register { register: Register(25) }),
- (constants::DW_OP_reg26, Operation::Register { register: Register(26) }),
- (constants::DW_OP_reg27, Operation::Register { register: Register(27) }),
- (constants::DW_OP_reg28, Operation::Register { register: Register(28) }),
- (constants::DW_OP_reg29, Operation::Register { register: Register(29) }),
- (constants::DW_OP_reg30, Operation::Register { register: Register(30) }),
- (constants::DW_OP_reg31, Operation::Register { register: Register(31) }),
- (constants::DW_OP_nop, Operation::Nop),
- (constants::DW_OP_push_object_address, Operation::PushObjectAddress),
- (constants::DW_OP_form_tls_address, Operation::TLS),
- (constants::DW_OP_GNU_push_tls_address, Operation::TLS),
- (constants::DW_OP_call_frame_cfa, Operation::CallFrameCFA),
- (constants::DW_OP_stack_value, Operation::StackValue),
- ];
-
- let input = [];
- check_op_parse_eof(&input[..], encoding);
-
- for item in inputs.iter() {
- let (opcode, ref result) = *item;
- check_op_parse(|s| s.D8(opcode.0), result, encoding);
- }
- }
-
- #[test]
- fn test_op_parse_twobyte() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let inputs = [
- (
- constants::DW_OP_const1u,
- 23,
- Operation::UnsignedConstant { value: 23 },
- ),
- (
- constants::DW_OP_const1s,
- (-23i8) as u8,
- Operation::SignedConstant { value: -23 },
- ),
- (constants::DW_OP_pick, 7, Operation::Pick { index: 7 }),
- (
- constants::DW_OP_deref_size,
- 19,
- Operation::Deref {
- base_type: generic_type(),
- size: 19,
- space: false,
- },
- ),
- (
- constants::DW_OP_xderef_size,
- 19,
- Operation::Deref {
- base_type: generic_type(),
- size: 19,
- space: true,
- },
- ),
- ];
-
- for item in inputs.iter() {
- let (opcode, arg, ref result) = *item;
- check_op_parse(|s| s.D8(opcode.0).D8(arg), result, encoding);
- }
- }
-
- #[test]
- fn test_op_parse_threebyte() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- // While bra and skip are 3-byte opcodes, they aren't tested here,
- // but rather specially in their own function.
- let inputs = [
- (
- constants::DW_OP_const2u,
- 23,
- Operation::UnsignedConstant { value: 23 },
- ),
- (
- constants::DW_OP_const2s,
- (-23i16) as u16,
- Operation::SignedConstant { value: -23 },
- ),
- (
- constants::DW_OP_call2,
- 1138,
- Operation::Call {
- offset: DieReference::UnitRef(UnitOffset(1138)),
- },
- ),
- (
- constants::DW_OP_bra,
- (-23i16) as u16,
- Operation::Bra { target: -23 },
- ),
- (
- constants::DW_OP_skip,
- (-23i16) as u16,
- Operation::Skip { target: -23 },
- ),
- ];
-
- for item in inputs.iter() {
- let (opcode, arg, ref result) = *item;
- check_op_parse(|s| s.D8(opcode.0).L16(arg), result, encoding);
- }
- }
-
- #[test]
- fn test_op_parse_fivebyte() {
- // There are some tests here that depend on address size.
- let encoding = encoding4();
-
- let inputs = [
- (
- constants::DW_OP_addr,
- 0x1234_5678,
- Operation::Address {
- address: 0x1234_5678,
- },
- ),
- (
- constants::DW_OP_const4u,
- 0x1234_5678,
- Operation::UnsignedConstant { value: 0x1234_5678 },
- ),
- (
- constants::DW_OP_const4s,
- (-23i32) as u32,
- Operation::SignedConstant { value: -23 },
- ),
- (
- constants::DW_OP_call4,
- 0x1234_5678,
- Operation::Call {
- offset: DieReference::UnitRef(UnitOffset(0x1234_5678)),
- },
- ),
- (
- constants::DW_OP_call_ref,
- 0x1234_5678,
- Operation::Call {
- offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678)),
- },
- ),
- ];
-
- for item in inputs.iter() {
- let (op, arg, ref expect) = *item;
- check_op_parse(|s| s.D8(op.0).L32(arg), expect, encoding);
- }
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_op_parse_ninebyte() {
- // There are some tests here that depend on address size.
- let encoding = encoding8();
-
- let inputs = [
- (
- constants::DW_OP_addr,
- 0x1234_5678_1234_5678,
- Operation::Address {
- address: 0x1234_5678_1234_5678,
- },
- ),
- (
- constants::DW_OP_const8u,
- 0x1234_5678_1234_5678,
- Operation::UnsignedConstant {
- value: 0x1234_5678_1234_5678,
- },
- ),
- (
- constants::DW_OP_const8s,
- (-23i64) as u64,
- Operation::SignedConstant { value: -23 },
- ),
- (
- constants::DW_OP_call_ref,
- 0x1234_5678_1234_5678,
- Operation::Call {
- offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678_1234_5678)),
- },
- ),
- ];
-
- for item in inputs.iter() {
- let (op, arg, ref expect) = *item;
- check_op_parse(|s| s.D8(op.0).L64(arg), expect, encoding);
- }
- }
-
- #[test]
- fn test_op_parse_sleb() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let values = [
- -1i64,
- 0,
- 1,
- 0x100,
- 0x1eee_eeee,
- 0x7fff_ffff_ffff_ffff,
- -0x100,
- -0x1eee_eeee,
- -0x7fff_ffff_ffff_ffff,
- ];
- for value in values.iter() {
- let mut inputs = vec![
- (
- constants::DW_OP_consts.0,
- Operation::SignedConstant { value: *value },
- ),
- (
- constants::DW_OP_fbreg.0,
- Operation::FrameOffset { offset: *value },
- ),
- ];
-
- for i in 0..32 {
- inputs.push((
- constants::DW_OP_breg0.0 + i,
- Operation::RegisterOffset {
- register: Register(i.into()),
- offset: *value,
- base_type: UnitOffset(0),
- },
- ));
- }
-
- for item in inputs.iter() {
- let (op, ref expect) = *item;
- check_op_parse(|s| s.D8(op).sleb(*value), expect, encoding);
- }
- }
- }
-
- #[test]
- fn test_op_parse_uleb() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let values = [
- 0,
- 1,
- 0x100,
- (!0u16).into(),
- 0x1eee_eeee,
- 0x7fff_ffff_ffff_ffff,
- !0u64,
- ];
- for value in values.iter() {
- let mut inputs = vec![
- (
- constants::DW_OP_constu,
- Operation::UnsignedConstant { value: *value },
- ),
- (
- constants::DW_OP_plus_uconst,
- Operation::PlusConstant { value: *value },
- ),
- ];
-
- if *value <= (!0u16).into() {
- inputs.push((
- constants::DW_OP_regx,
- Operation::Register {
- register: Register::from_u64(*value).unwrap(),
- },
- ));
- }
-
- if *value <= (!0u32).into() {
- inputs.extend(&[
- (
- constants::DW_OP_addrx,
- Operation::AddressIndex {
- index: DebugAddrIndex(*value as usize),
- },
- ),
- (
- constants::DW_OP_constx,
- Operation::ConstantIndex {
- index: DebugAddrIndex(*value as usize),
- },
- ),
- ]);
- }
-
- // FIXME
- if *value < !0u64 / 8 {
- inputs.push((
- constants::DW_OP_piece,
- Operation::Piece {
- size_in_bits: 8 * value,
- bit_offset: None,
- },
- ));
- }
-
- for item in inputs.iter() {
- let (op, ref expect) = *item;
- let input = Section::with_endian(Endian::Little)
- .D8(op.0)
- .uleb(*value)
- .get_contents()
- .unwrap();
- check_op_parse_simple(&input, expect, encoding);
- }
- }
- }
-
- #[test]
- fn test_op_parse_bregx() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let uvalues = [0, 1, 0x100, !0u16];
- let svalues = [
- -1i64,
- 0,
- 1,
- 0x100,
- 0x1eee_eeee,
- 0x7fff_ffff_ffff_ffff,
- -0x100,
- -0x1eee_eeee,
- -0x7fff_ffff_ffff_ffff,
- ];
-
- for v1 in uvalues.iter() {
- for v2 in svalues.iter() {
- check_op_parse(
- |s| s.D8(constants::DW_OP_bregx.0).uleb((*v1).into()).sleb(*v2),
- &Operation::RegisterOffset {
- register: Register(*v1),
- offset: *v2,
- base_type: UnitOffset(0),
- },
- encoding,
- );
- }
- }
- }
-
- #[test]
- fn test_op_parse_bit_piece() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let values = [0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, !0u64];
-
- for v1 in values.iter() {
- for v2 in values.iter() {
- let input = Section::with_endian(Endian::Little)
- .D8(constants::DW_OP_bit_piece.0)
- .uleb(*v1)
- .uleb(*v2)
- .get_contents()
- .unwrap();
- check_op_parse_simple(
- &input,
- &Operation::Piece {
- size_in_bits: *v1,
- bit_offset: Some(*v2),
- },
- encoding,
- );
- }
- }
- }
-
- #[test]
- fn test_op_parse_implicit_value() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let data = b"hello";
-
- check_op_parse(
- |s| {
- s.D8(constants::DW_OP_implicit_value.0)
- .uleb(data.len() as u64)
- .append_bytes(&data[..])
- },
- &Operation::ImplicitValue {
- data: EndianSlice::new(&data[..], LittleEndian),
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_parse_const_type() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- let data = b"hello";
-
- check_op_parse(
- |s| {
- s.D8(constants::DW_OP_const_type.0)
- .uleb(100)
- .D8(data.len() as u8)
- .append_bytes(&data[..])
- },
- &Operation::TypedLiteral {
- base_type: UnitOffset(100),
- value: EndianSlice::new(&data[..], LittleEndian),
- },
- encoding,
- );
- check_op_parse(
- |s| {
- s.D8(constants::DW_OP_GNU_const_type.0)
- .uleb(100)
- .D8(data.len() as u8)
- .append_bytes(&data[..])
- },
- &Operation::TypedLiteral {
- base_type: UnitOffset(100),
- value: EndianSlice::new(&data[..], LittleEndian),
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_parse_regval_type() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- check_op_parse(
- |s| s.D8(constants::DW_OP_regval_type.0).uleb(1).uleb(100),
- &Operation::RegisterOffset {
- register: Register(1),
- offset: 0,
- base_type: UnitOffset(100),
- },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_GNU_regval_type.0).uleb(1).uleb(100),
- &Operation::RegisterOffset {
- register: Register(1),
- offset: 0,
- base_type: UnitOffset(100),
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_parse_deref_type() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- check_op_parse(
- |s| s.D8(constants::DW_OP_deref_type.0).D8(8).uleb(100),
- &Operation::Deref {
- base_type: UnitOffset(100),
- size: 8,
- space: false,
- },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_GNU_deref_type.0).D8(8).uleb(100),
- &Operation::Deref {
- base_type: UnitOffset(100),
- size: 8,
- space: false,
- },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_xderef_type.0).D8(8).uleb(100),
- &Operation::Deref {
- base_type: UnitOffset(100),
- size: 8,
- space: true,
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_convert() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- check_op_parse(
- |s| s.D8(constants::DW_OP_convert.0).uleb(100),
- &Operation::Convert {
- base_type: UnitOffset(100),
- },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_GNU_convert.0).uleb(100),
- &Operation::Convert {
- base_type: UnitOffset(100),
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_reinterpret() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- check_op_parse(
- |s| s.D8(constants::DW_OP_reinterpret.0).uleb(100),
- &Operation::Reinterpret {
- base_type: UnitOffset(100),
- },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_GNU_reinterpret.0).uleb(100),
- &Operation::Reinterpret {
- base_type: UnitOffset(100),
- },
- encoding,
- );
- }
-
- #[test]
- fn test_op_parse_implicit_pointer() {
- for op in &[
- constants::DW_OP_implicit_pointer,
- constants::DW_OP_GNU_implicit_pointer,
- ] {
- check_op_parse(
- |s| s.D8(op.0).D32(0x1234_5678).sleb(0x123),
- &Operation::ImplicitPointer {
- value: DebugInfoOffset(0x1234_5678),
- byte_offset: 0x123,
- },
- encoding4(),
- );
-
- check_op_parse(
- |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123),
- &Operation::ImplicitPointer {
- value: DebugInfoOffset(0x1234_5678),
- byte_offset: 0x123,
- },
- encoding8(),
- );
-
- check_op_parse(
- |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123),
- &Operation::ImplicitPointer {
- value: DebugInfoOffset(0x1234_5678),
- byte_offset: 0x123,
- },
- Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 8,
- },
- )
- }
- }
-
- #[test]
- fn test_op_parse_entry_value() {
- for op in &[
- constants::DW_OP_entry_value,
- constants::DW_OP_GNU_entry_value,
- ] {
- let data = b"hello";
- check_op_parse(
- |s| s.D8(op.0).uleb(data.len() as u64).append_bytes(&data[..]),
- &Operation::EntryValue {
- expression: EndianSlice::new(&data[..], LittleEndian),
- },
- encoding4(),
- );
- }
- }
-
- #[test]
- fn test_op_parse_gnu_parameter_ref() {
- check_op_parse(
- |s| s.D8(constants::DW_OP_GNU_parameter_ref.0).D32(0x1234_5678),
- &Operation::ParameterRef {
- offset: UnitOffset(0x1234_5678),
- },
- encoding4(),
- )
- }
-
- #[test]
- fn test_op_wasm() {
- // Doesn't matter for this test.
- let encoding = encoding4();
-
- check_op_parse(
- |s| s.D8(constants::DW_OP_WASM_location.0).D8(0).uleb(1000),
- &Operation::WasmLocal { index: 1000 },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_WASM_location.0).D8(1).uleb(1000),
- &Operation::WasmGlobal { index: 1000 },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_WASM_location.0).D8(2).uleb(1000),
- &Operation::WasmStack { index: 1000 },
- encoding,
- );
- check_op_parse(
- |s| s.D8(constants::DW_OP_WASM_location.0).D8(3).D32(1000),
- &Operation::WasmGlobal { index: 1000 },
- encoding,
- );
- }
-
- enum AssemblerEntry {
- Op(constants::DwOp),
- Mark(u8),
- Branch(u8),
- U8(u8),
- U16(u16),
- U32(u32),
- U64(u64),
- Uleb(u64),
- Sleb(u64),
- }
-
- fn assemble(entries: &[AssemblerEntry]) -> Vec<u8> {
- let mut result = Vec::new();
-
- struct Marker(Option<usize>, Vec<usize>);
-
- let mut markers = Vec::new();
- for _ in 0..256 {
- markers.push(Marker(None, Vec::new()));
- }
-
- fn write(stack: &mut Vec<u8>, index: usize, mut num: u64, nbytes: u8) {
- for i in 0..nbytes as usize {
- stack[index + i] = (num & 0xff) as u8;
- num >>= 8;
- }
- }
-
- fn push(stack: &mut Vec<u8>, num: u64, nbytes: u8) {
- let index = stack.len();
- for _ in 0..nbytes {
- stack.push(0);
- }
- write(stack, index, num, nbytes);
- }
-
- for item in entries {
- match *item {
- AssemblerEntry::Op(op) => result.push(op.0),
- AssemblerEntry::Mark(num) => {
- assert!(markers[num as usize].0.is_none());
- markers[num as usize].0 = Some(result.len());
- }
- AssemblerEntry::Branch(num) => {
- markers[num as usize].1.push(result.len());
- push(&mut result, 0, 2);
- }
- AssemblerEntry::U8(num) => result.push(num),
- AssemblerEntry::U16(num) => push(&mut result, u64::from(num), 2),
- AssemblerEntry::U32(num) => push(&mut result, u64::from(num), 4),
- AssemblerEntry::U64(num) => push(&mut result, num, 8),
- AssemblerEntry::Uleb(num) => {
- leb128::write::unsigned(&mut result, num).unwrap();
- }
- AssemblerEntry::Sleb(num) => {
- leb128::write::signed(&mut result, num as i64).unwrap();
- }
- }
- }
-
- // Update all the branches.
- for marker in markers {
- if let Some(offset) = marker.0 {
- for branch_offset in marker.1 {
- let delta = offset.wrapping_sub(branch_offset + 2) as u64;
- write(&mut result, branch_offset, delta, 2);
- }
- }
- }
-
- result
- }
-
- fn check_eval_with_args<F>(
- program: &[AssemblerEntry],
- expect: Result<&[Piece<EndianSlice<LittleEndian>>]>,
- encoding: Encoding,
- object_address: Option<u64>,
- initial_value: Option<u64>,
- max_iterations: Option<u32>,
- f: F,
- ) where
- for<'a> F: Fn(
- &mut Evaluation<EndianSlice<'a, LittleEndian>>,
- EvaluationResult<EndianSlice<'a, LittleEndian>>,
- ) -> Result<EvaluationResult<EndianSlice<'a, LittleEndian>>>,
- {
- let bytes = assemble(program);
- let bytes = EndianSlice::new(&bytes, LittleEndian);
-
- let mut eval = Evaluation::new(bytes, encoding);
-
- if let Some(val) = object_address {
- eval.set_object_address(val);
- }
- if let Some(val) = initial_value {
- eval.set_initial_value(val);
- }
- if let Some(val) = max_iterations {
- eval.set_max_iterations(val);
- }
-
- let result = match eval.evaluate() {
- Err(e) => Err(e),
- Ok(r) => f(&mut eval, r),
- };
-
- match (result, expect) {
- (Ok(EvaluationResult::Complete), Ok(pieces)) => {
- let vec = eval.result();
- assert_eq!(vec.len(), pieces.len());
- for i in 0..pieces.len() {
- assert_eq!(vec[i], pieces[i]);
- }
- }
- (Err(f1), Err(f2)) => {
- assert_eq!(f1, f2);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- fn check_eval(
- program: &[AssemblerEntry],
- expect: Result<&[Piece<EndianSlice<LittleEndian>>]>,
- encoding: Encoding,
- ) {
- check_eval_with_args(program, expect, encoding, None, None, None, |_, result| {
- Ok(result)
- });
- }
-
- #[test]
- fn test_eval_arith() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Indices of marks in the assembly.
- let done = 0;
- let fail = 1;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_const1u), U8(23),
- Op(DW_OP_const1s), U8((-23i8) as u8),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const2u), U16(23),
- Op(DW_OP_const2s), U16((-23i16) as u16),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4u), U32(0x1111_2222),
- Op(DW_OP_const4s), U32((-0x1111_2222i32) as u32),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- // Plus should overflow.
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1u), U8(1),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_plus_uconst), Uleb(1),
- Op(DW_OP_bra), Branch(fail),
-
- // Minus should underflow.
- Op(DW_OP_const1s), U8(0),
- Op(DW_OP_const1u), U8(1),
- Op(DW_OP_minus),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_abs),
- Op(DW_OP_const1u), U8(1),
- Op(DW_OP_minus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4u), U32(0xf078_fffe),
- Op(DW_OP_const4u), U32(0x0f87_0001),
- Op(DW_OP_and),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4u), U32(0xf078_fffe),
- Op(DW_OP_const4u), U32(0xf000_00fe),
- Op(DW_OP_and),
- Op(DW_OP_const4u), U32(0xf000_00fe),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- // Division is signed.
- Op(DW_OP_const1s), U8(0xfe),
- Op(DW_OP_const1s), U8(2),
- Op(DW_OP_div),
- Op(DW_OP_plus_uconst), Uleb(1),
- Op(DW_OP_bra), Branch(fail),
-
- // Mod is unsigned.
- Op(DW_OP_const1s), U8(0xfd),
- Op(DW_OP_const1s), U8(2),
- Op(DW_OP_mod),
- Op(DW_OP_neg),
- Op(DW_OP_plus_uconst), Uleb(1),
- Op(DW_OP_bra), Branch(fail),
-
- // Overflow is defined for multiplication.
- Op(DW_OP_const4u), U32(0x8000_0001),
- Op(DW_OP_lit2),
- Op(DW_OP_mul),
- Op(DW_OP_lit2),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4u), U32(0xf0f0_f0f0),
- Op(DW_OP_const4u), U32(0xf0f0_f0f0),
- Op(DW_OP_xor),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4u), U32(0xf0f0_f0f0),
- Op(DW_OP_const4u), U32(0x0f0f_0f0f),
- Op(DW_OP_or),
- Op(DW_OP_not),
- Op(DW_OP_bra), Branch(fail),
-
- // In 32 bit mode, values are truncated.
- Op(DW_OP_const8u), U64(0xffff_ffff_0000_0000),
- Op(DW_OP_lit2),
- Op(DW_OP_div),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1u), U8(0xff),
- Op(DW_OP_lit1),
- Op(DW_OP_shl),
- Op(DW_OP_const2u), U16(0x1fe),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1u), U8(0xff),
- Op(DW_OP_const1u), U8(50),
- Op(DW_OP_shl),
- Op(DW_OP_bra), Branch(fail),
-
- // Absurd shift.
- Op(DW_OP_const1u), U8(0xff),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_shl),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_lit1),
- Op(DW_OP_shr),
- Op(DW_OP_const4u), U32(0x7fff_ffff),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1u), U8(0xff),
- Op(DW_OP_shr),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_lit1),
- Op(DW_OP_shra),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1u), U8(0xff),
- Op(DW_OP_shra),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- // Success.
- Op(DW_OP_lit0),
- Op(DW_OP_nop),
- Op(DW_OP_skip), Branch(done),
-
- Mark(fail),
- Op(DW_OP_lit1),
-
- Mark(done),
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
- }
-
- #[test]
- fn test_eval_arith64() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Indices of marks in the assembly.
- let done = 0;
- let fail = 1;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_const8u), U64(0x1111_2222_3333_4444),
- Op(DW_OP_const8s), U64((-0x1111_2222_3333_4444i64) as u64),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_constu), Uleb(0x1111_2222_3333_4444),
- Op(DW_OP_consts), Sleb((-0x1111_2222_3333_4444i64) as u64),
- Op(DW_OP_plus),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit1),
- Op(DW_OP_plus_uconst), Uleb(!0u64),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit1),
- Op(DW_OP_neg),
- Op(DW_OP_not),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const8u), U64(0x8000_0000_0000_0000),
- Op(DW_OP_const1u), U8(63),
- Op(DW_OP_shr),
- Op(DW_OP_lit1),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const8u), U64(0x8000_0000_0000_0000),
- Op(DW_OP_const1u), U8(62),
- Op(DW_OP_shra),
- Op(DW_OP_plus_uconst), Uleb(2),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit1),
- Op(DW_OP_const1u), U8(63),
- Op(DW_OP_shl),
- Op(DW_OP_const8u), U64(0x8000_0000_0000_0000),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- // Success.
- Op(DW_OP_lit0),
- Op(DW_OP_nop),
- Op(DW_OP_skip), Branch(done),
-
- Mark(fail),
- Op(DW_OP_lit1),
-
- Mark(done),
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding8());
- }
-
- #[test]
- fn test_eval_compare() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Indices of marks in the assembly.
- let done = 0;
- let fail = 1;
-
- #[rustfmt::skip]
- let program = [
- // Comparisons are signed.
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_lt),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_gt),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_le),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_ge),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const1s), U8(0xff),
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_eq),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_const4s), U32(1),
- Op(DW_OP_const1s), U8(1),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- // Success.
- Op(DW_OP_lit0),
- Op(DW_OP_nop),
- Op(DW_OP_skip), Branch(done),
-
- Mark(fail),
- Op(DW_OP_lit1),
-
- Mark(done),
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
- }
-
- #[test]
- fn test_eval_stack() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_lit17), // -- 17
- Op(DW_OP_dup), // -- 17 17
- Op(DW_OP_over), // -- 17 17 17
- Op(DW_OP_minus), // -- 17 0
- Op(DW_OP_swap), // -- 0 17
- Op(DW_OP_dup), // -- 0 17 17
- Op(DW_OP_plus_uconst), Uleb(1), // -- 0 17 18
- Op(DW_OP_rot), // -- 18 0 17
- Op(DW_OP_pick), U8(2), // -- 18 0 17 18
- Op(DW_OP_pick), U8(3), // -- 18 0 17 18 18
- Op(DW_OP_minus), // -- 18 0 17 0
- Op(DW_OP_drop), // -- 18 0 17
- Op(DW_OP_swap), // -- 18 17 0
- Op(DW_OP_drop), // -- 18 17
- Op(DW_OP_minus), // -- 1
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(1),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
- }
-
- #[test]
- fn test_eval_lit_and_reg() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- let mut program = Vec::new();
- program.push(Op(DW_OP_lit0));
- for i in 0..32 {
- program.push(Op(DwOp(DW_OP_lit0.0 + i)));
- program.push(Op(DwOp(DW_OP_breg0.0 + i)));
- program.push(Sleb(u64::from(i)));
- program.push(Op(DW_OP_plus));
- program.push(Op(DW_OP_plus));
- }
-
- program.push(Op(DW_OP_bregx));
- program.push(Uleb(0x1234));
- program.push(Sleb(0x1234));
- program.push(Op(DW_OP_plus));
-
- program.push(Op(DW_OP_stack_value));
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(496),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, mut result| {
- while result != EvaluationResult::Complete {
- result = eval.resume_with_register(match result {
- EvaluationResult::RequiresRegister {
- register,
- base_type,
- } => {
- assert_eq!(base_type, UnitOffset(0));
- Value::Generic(u64::from(register.0).wrapping_neg())
- }
- _ => panic!(),
- })?;
- }
- Ok(result)
- },
- );
- }
-
- #[test]
- fn test_eval_memory() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Indices of marks in the assembly.
- let done = 0;
- let fail = 1;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_deref),
- Op(DW_OP_const4u), U32(0xffff_fffc),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_deref_size), U8(2),
- Op(DW_OP_const4u), U32(0xfffc),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit1),
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_xderef),
- Op(DW_OP_const4u), U32(0xffff_fffd),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit1),
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_xderef_size), U8(2),
- Op(DW_OP_const4u), U32(0xfffd),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit17),
- Op(DW_OP_form_tls_address),
- Op(DW_OP_constu), Uleb(!17),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_lit17),
- Op(DW_OP_GNU_push_tls_address),
- Op(DW_OP_constu), Uleb(!17),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_addrx), Uleb(0x10),
- Op(DW_OP_deref),
- Op(DW_OP_const4u), U32(0x4040),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- Op(DW_OP_constx), Uleb(17),
- Op(DW_OP_form_tls_address),
- Op(DW_OP_constu), Uleb(!27),
- Op(DW_OP_ne),
- Op(DW_OP_bra), Branch(fail),
-
- // Success.
- Op(DW_OP_lit0),
- Op(DW_OP_nop),
- Op(DW_OP_skip), Branch(done),
-
- Mark(fail),
- Op(DW_OP_lit1),
-
- Mark(done),
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, mut result| {
- while result != EvaluationResult::Complete {
- result = match result {
- EvaluationResult::RequiresMemory {
- address,
- size,
- space,
- base_type,
- } => {
- assert_eq!(base_type, UnitOffset(0));
- let mut v = address << 2;
- if let Some(value) = space {
- v += value;
- }
- v &= (1u64 << (8 * size)) - 1;
- eval.resume_with_memory(Value::Generic(v))?
- }
- EvaluationResult::RequiresTls(slot) => eval.resume_with_tls(!slot)?,
- EvaluationResult::RequiresRelocatedAddress(address) => {
- eval.resume_with_relocated_address(address)?
- }
- EvaluationResult::RequiresIndexedAddress { index, relocate } => {
- if relocate {
- eval.resume_with_indexed_address(0x1000 + index.0 as u64)?
- } else {
- eval.resume_with_indexed_address(10 + index.0 as u64)?
- }
- }
- _ => panic!(),
- };
- }
-
- Ok(result)
- },
- );
- }
-
- #[test]
- fn test_eval_register() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- for i in 0..32 {
- #[rustfmt::skip]
- let program = [
- Op(DwOp(DW_OP_reg0.0 + i)),
- // Included only in the "bad" run.
- Op(DW_OP_lit23),
- ];
- let ok_result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Register {
- register: Register(i.into()),
- },
- }];
-
- check_eval(&program[..1], Ok(&ok_result), encoding4());
-
- check_eval(
- &program,
- Err(Error::InvalidExpressionTerminator(1)),
- encoding4(),
- );
- }
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_regx), Uleb(0x1234)
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Register {
- register: Register(0x1234),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
- }
-
- #[test]
- fn test_eval_context() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Test `frame_base` and `call_frame_cfa` callbacks.
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_fbreg), Sleb((-8i8) as u64),
- Op(DW_OP_call_frame_cfa),
- Op(DW_OP_plus),
- Op(DW_OP_neg),
- Op(DW_OP_stack_value)
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(9),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding8(),
- None,
- None,
- None,
- |eval, result| {
- match result {
- EvaluationResult::RequiresFrameBase => {}
- _ => panic!(),
- };
- match eval.resume_with_frame_base(0x0123_4567_89ab_cdef)? {
- EvaluationResult::RequiresCallFrameCfa => {}
- _ => panic!(),
- };
- eval.resume_with_call_frame_cfa(0xfedc_ba98_7654_3210)
- },
- );
-
- // Test `evaluate_entry_value` callback.
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_entry_value), Uleb(8), U64(0x1234_5678),
- Op(DW_OP_stack_value)
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0x1234_5678),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding8(),
- None,
- None,
- None,
- |eval, result| {
- let entry_value = match result {
- EvaluationResult::RequiresEntryValue(mut expression) => {
- expression.0.read_u64()?
- }
- _ => panic!(),
- };
- eval.resume_with_entry_value(Value::Generic(entry_value))
- },
- );
-
- // Test missing `object_address` field.
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_push_object_address),
- ];
-
- check_eval_with_args(
- &program,
- Err(Error::InvalidPushObjectAddress),
- encoding4(),
- None,
- None,
- None,
- |_, _| panic!(),
- );
-
- // Test `object_address` field.
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_push_object_address),
- Op(DW_OP_stack_value),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(0xff),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding8(),
- Some(0xff),
- None,
- None,
- |_, result| Ok(result),
- );
-
- // Test `initial_value` field.
- #[rustfmt::skip]
- let program = [
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Address {
- address: 0x1234_5678,
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding8(),
- None,
- Some(0x1234_5678),
- None,
- |_, result| Ok(result),
- );
- }
-
- #[test]
- fn test_eval_empty_stack() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_stack_value)
- ];
-
- check_eval(&program, Err(Error::NotEnoughStackItems), encoding4());
- }
-
- #[test]
- fn test_eval_call() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_lit23),
- Op(DW_OP_call2), U16(0x7755),
- Op(DW_OP_call4), U32(0x7755_aaee),
- Op(DW_OP_call_ref), U32(0x7755_aaee),
- Op(DW_OP_stack_value)
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(23),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, result| {
- let buf = EndianSlice::new(&[], LittleEndian);
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)?;
-
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)?;
-
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)
- },
- );
-
- // DW_OP_lit2 DW_OP_mul
- const SUBR: &[u8] = &[0x32, 0x1e];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value {
- value: Value::Generic(184),
- },
- }];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, result| {
- let buf = EndianSlice::new(SUBR, LittleEndian);
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)?;
-
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)?;
-
- match result {
- EvaluationResult::RequiresAtLocation(_) => {}
- _ => panic!(),
- };
-
- eval.resume_with_at_location(buf)
- },
- );
- }
-
- #[test]
- fn test_eval_pieces() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- // Example from DWARF 2.6.1.3.
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_reg3),
- Op(DW_OP_piece), Uleb(4),
- Op(DW_OP_reg4),
- Op(DW_OP_piece), Uleb(2),
- ];
-
- let result = [
- Piece {
- size_in_bits: Some(32),
- bit_offset: None,
- location: Location::Register {
- register: Register(3),
- },
- },
- Piece {
- size_in_bits: Some(16),
- bit_offset: None,
- location: Location::Register {
- register: Register(4),
- },
- },
- ];
-
- check_eval(&program, Ok(&result), encoding4());
-
- // Example from DWARF 2.6.1.3 (but hacked since dealing with fbreg
- // in the tests is a pain).
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_reg0),
- Op(DW_OP_piece), Uleb(4),
- Op(DW_OP_piece), Uleb(4),
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_piece), Uleb(4),
- ];
-
- let result = [
- Piece {
- size_in_bits: Some(32),
- bit_offset: None,
- location: Location::Register {
- register: Register(0),
- },
- },
- Piece {
- size_in_bits: Some(32),
- bit_offset: None,
- location: Location::Empty,
- },
- Piece {
- size_in_bits: Some(32),
- bit_offset: None,
- location: Location::Address {
- address: 0x7fff_ffff,
- },
- },
- ];
-
- check_eval_with_args(
- &program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, mut result| {
- while result != EvaluationResult::Complete {
- result = match result {
- EvaluationResult::RequiresRelocatedAddress(address) => {
- eval.resume_with_relocated_address(address)?
- }
- _ => panic!(),
- };
- }
-
- Ok(result)
- },
- );
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_implicit_value), Uleb(5),
- U8(23), U8(24), U8(25), U8(26), U8(0),
- ];
-
- const BYTES: &[u8] = &[23, 24, 25, 26, 0];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Bytes {
- value: EndianSlice::new(BYTES, LittleEndian),
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_lit7),
- Op(DW_OP_stack_value),
- Op(DW_OP_bit_piece), Uleb(5), Uleb(0),
- Op(DW_OP_bit_piece), Uleb(3), Uleb(0),
- ];
-
- let result = [
- Piece {
- size_in_bits: Some(5),
- bit_offset: Some(0),
- location: Location::Value {
- value: Value::Generic(7),
- },
- },
- Piece {
- size_in_bits: Some(3),
- bit_offset: Some(0),
- location: Location::Empty,
- },
- ];
-
- check_eval(&program, Ok(&result), encoding4());
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_lit7),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Address { address: 7 },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_implicit_pointer), U32(0x1234_5678), Sleb(0x123),
- ];
-
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::ImplicitPointer {
- value: DebugInfoOffset(0x1234_5678),
- byte_offset: 0x123,
- },
- }];
-
- check_eval(&program, Ok(&result), encoding4());
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_reg3),
- Op(DW_OP_piece), Uleb(4),
- Op(DW_OP_reg4),
- ];
-
- check_eval(&program, Err(Error::InvalidPiece), encoding4());
-
- #[rustfmt::skip]
- let program = [
- Op(DW_OP_reg3),
- Op(DW_OP_piece), Uleb(4),
- Op(DW_OP_lit0),
- ];
-
- check_eval(&program, Err(Error::InvalidPiece), encoding4());
- }
-
- #[test]
- fn test_eval_max_iterations() {
- // It's nice if an operation and its arguments can fit on a single
- // line in the test program.
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- #[rustfmt::skip]
- let program = [
- Mark(1),
- Op(DW_OP_skip), Branch(1),
- ];
-
- check_eval_with_args(
- &program,
- Err(Error::TooManyIterations),
- encoding4(),
- None,
- None,
- Some(150),
- |_, _| panic!(),
- );
- }
-
- #[test]
- fn test_eval_typed_stack() {
- use self::AssemblerEntry::*;
- use crate::constants::*;
-
- let base_types = [
- ValueType::Generic,
- ValueType::U16,
- ValueType::U32,
- ValueType::F32,
- ];
-
- // TODO: convert, reinterpret
- #[rustfmt::skip]
- let tests = [
- (
- &[
- Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234),
- Op(DW_OP_stack_value),
- ][..],
- Value::U16(0x1234),
- ),
- (
- &[
- Op(DW_OP_regval_type), Uleb(0x1234), Uleb(1),
- Op(DW_OP_stack_value),
- ][..],
- Value::U16(0x2340),
- ),
- (
- &[
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_deref_type), U8(2), Uleb(1),
- Op(DW_OP_stack_value),
- ][..],
- Value::U16(0xfff0),
- ),
- (
- &[
- Op(DW_OP_lit1),
- Op(DW_OP_addr), U32(0x7fff_ffff),
- Op(DW_OP_xderef_type), U8(2), Uleb(1),
- Op(DW_OP_stack_value),
- ][..],
- Value::U16(0xfff1),
- ),
- (
- &[
- Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234),
- Op(DW_OP_convert), Uleb(2),
- Op(DW_OP_stack_value),
- ][..],
- Value::U32(0x1234),
- ),
- (
- &[
- Op(DW_OP_const_type), Uleb(2), U8(4), U32(0x3f80_0000),
- Op(DW_OP_reinterpret), Uleb(3),
- Op(DW_OP_stack_value),
- ][..],
- Value::F32(1.0),
- ),
- ];
- for &(program, value) in &tests {
- let result = [Piece {
- size_in_bits: None,
- bit_offset: None,
- location: Location::Value { value },
- }];
-
- check_eval_with_args(
- program,
- Ok(&result),
- encoding4(),
- None,
- None,
- None,
- |eval, mut result| {
- while result != EvaluationResult::Complete {
- result = match result {
- EvaluationResult::RequiresMemory {
- address,
- size,
- space,
- base_type,
- } => {
- let mut v = address << 4;
- if let Some(value) = space {
- v += value;
- }
- v &= (1u64 << (8 * size)) - 1;
- let v = Value::from_u64(base_types[base_type.0], v)?;
- eval.resume_with_memory(v)?
- }
- EvaluationResult::RequiresRegister {
- register,
- base_type,
- } => {
- let v = Value::from_u64(
- base_types[base_type.0],
- u64::from(register.0) << 4,
- )?;
- eval.resume_with_register(v)?
- }
- EvaluationResult::RequiresBaseType(offset) => {
- eval.resume_with_base_type(base_types[offset.0])?
- }
- EvaluationResult::RequiresRelocatedAddress(address) => {
- eval.resume_with_relocated_address(address)?
- }
- _ => panic!("Unexpected result {:?}", result),
- }
- }
- Ok(result)
- },
- );
- }
- }
-}
diff --git a/vendor/gimli/src/read/pubnames.rs b/vendor/gimli/src/read/pubnames.rs
deleted file mode 100644
index e8b7e55..0000000
--- a/vendor/gimli/src/read/pubnames.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::common::{DebugInfoOffset, SectionId};
-use crate::endianity::Endianity;
-use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser};
-use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset};
-
-/// A single parsed pubname.
-#[derive(Debug, Clone)]
-pub struct PubNamesEntry<R: Reader> {
- unit_header_offset: DebugInfoOffset<R::Offset>,
- die_offset: UnitOffset<R::Offset>,
- name: R,
-}
-
-impl<R: Reader> PubNamesEntry<R> {
- /// Returns the name this entry refers to.
- pub fn name(&self) -> &R {
- &self.name
- }
-
- /// Returns the offset into the .debug_info section for the header of the compilation unit
- /// which contains this name.
- pub fn unit_header_offset(&self) -> DebugInfoOffset<R::Offset> {
- self.unit_header_offset
- }
-
- /// Returns the offset into the compilation unit for the debugging information entry which
- /// has this name.
- pub fn die_offset(&self) -> UnitOffset<R::Offset> {
- self.die_offset
- }
-}
-
-impl<R: Reader> PubStuffEntry<R> for PubNamesEntry<R> {
- fn new(
- die_offset: UnitOffset<R::Offset>,
- name: R,
- unit_header_offset: DebugInfoOffset<R::Offset>,
- ) -> Self {
- PubNamesEntry {
- unit_header_offset,
- die_offset,
- name,
- }
- }
-}
-
-/// The `DebugPubNames` struct represents the DWARF public names information
-/// found in the `.debug_pubnames` section.
-#[derive(Debug, Clone)]
-pub struct DebugPubNames<R: Reader>(DebugLookup<R, PubStuffParser<R, PubNamesEntry<R>>>);
-
-impl<'input, Endian> DebugPubNames<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugPubNames` instance from the data in the `.debug_pubnames`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_pubnames` 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::{DebugPubNames, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_pubnames_section_somehow = || &buf;
- /// let debug_pubnames =
- /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_pubnames_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_pubnames_section, endian))
- }
-}
-
-impl<R: Reader> DebugPubNames<R> {
- /// Iterate the pubnames in the `.debug_pubnames` section.
- ///
- /// ```
- /// use gimli::{DebugPubNames, EndianSlice, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_pubnames_section_somehow = || &buf;
- /// let debug_pubnames =
- /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian);
- ///
- /// let mut iter = debug_pubnames.items();
- /// while let Some(pubname) = iter.next().unwrap() {
- /// println!("pubname {} found!", pubname.name().to_string_lossy());
- /// }
- /// ```
- pub fn items(&self) -> PubNamesEntryIter<R> {
- PubNamesEntryIter(self.0.items())
- }
-}
-
-impl<R: Reader> Section<R> for DebugPubNames<R> {
- fn id() -> SectionId {
- SectionId::DebugPubNames
- }
-
- fn reader(&self) -> &R {
- self.0.reader()
- }
-}
-
-impl<R: Reader> From<R> for DebugPubNames<R> {
- fn from(debug_pubnames_section: R) -> Self {
- DebugPubNames(DebugLookup::from(debug_pubnames_section))
- }
-}
-
-/// An iterator over the pubnames from a `.debug_pubnames` section.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-#[derive(Debug, Clone)]
-pub struct PubNamesEntryIter<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubNamesEntry<R>>>);
-
-impl<R: Reader> PubNamesEntryIter<R> {
- /// Advance the iterator and return the next pubname.
- ///
- /// Returns the newly parsed pubname as `Ok(Some(pubname))`. Returns
- /// `Ok(None)` when iteration is complete and all pubnames have already been
- /// parsed and yielded. If an error occurs while parsing the next pubname,
- /// then this error is returned as `Err(e)`, and all subsequent calls return
- /// `Ok(None)`.
- pub fn next(&mut self) -> Result<Option<PubNamesEntry<R>>> {
- self.0.next()
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for PubNamesEntryIter<R> {
- type Item = PubNamesEntry<R>;
- type Error = crate::read::Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- self.0.next()
- }
-}
diff --git a/vendor/gimli/src/read/pubtypes.rs b/vendor/gimli/src/read/pubtypes.rs
deleted file mode 100644
index 6723b42..0000000
--- a/vendor/gimli/src/read/pubtypes.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::common::{DebugInfoOffset, SectionId};
-use crate::endianity::Endianity;
-use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser};
-use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset};
-
-/// A single parsed pubtype.
-#[derive(Debug, Clone)]
-pub struct PubTypesEntry<R: Reader> {
- unit_header_offset: DebugInfoOffset<R::Offset>,
- die_offset: UnitOffset<R::Offset>,
- name: R,
-}
-
-impl<R: Reader> PubTypesEntry<R> {
- /// Returns the name of the type this entry refers to.
- pub fn name(&self) -> &R {
- &self.name
- }
-
- /// Returns the offset into the .debug_info section for the header of the compilation unit
- /// which contains the type with this name.
- pub fn unit_header_offset(&self) -> DebugInfoOffset<R::Offset> {
- self.unit_header_offset
- }
-
- /// Returns the offset into the compilation unit for the debugging information entry which
- /// the type with this name.
- pub fn die_offset(&self) -> UnitOffset<R::Offset> {
- self.die_offset
- }
-}
-
-impl<R: Reader> PubStuffEntry<R> for PubTypesEntry<R> {
- fn new(
- die_offset: UnitOffset<R::Offset>,
- name: R,
- unit_header_offset: DebugInfoOffset<R::Offset>,
- ) -> Self {
- PubTypesEntry {
- unit_header_offset,
- die_offset,
- name,
- }
- }
-}
-
-/// The `DebugPubTypes` struct represents the DWARF public types information
-/// found in the `.debug_info` section.
-#[derive(Debug, Clone)]
-pub struct DebugPubTypes<R: Reader>(DebugLookup<R, PubStuffParser<R, PubTypesEntry<R>>>);
-
-impl<'input, Endian> DebugPubTypes<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugPubTypes` instance from the data in the `.debug_pubtypes`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_pubtypes` 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::{DebugPubTypes, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_pubtypes_somehow = || &buf;
- /// let debug_pubtypes =
- /// DebugPubTypes::new(read_debug_pubtypes_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_pubtypes_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_pubtypes_section, endian))
- }
-}
-
-impl<R: Reader> DebugPubTypes<R> {
- /// Iterate the pubtypes in the `.debug_pubtypes` section.
- ///
- /// ```
- /// use gimli::{DebugPubTypes, EndianSlice, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_pubtypes_section_somehow = || &buf;
- /// let debug_pubtypes =
- /// DebugPubTypes::new(read_debug_pubtypes_section_somehow(), LittleEndian);
- ///
- /// let mut iter = debug_pubtypes.items();
- /// while let Some(pubtype) = iter.next().unwrap() {
- /// println!("pubtype {} found!", pubtype.name().to_string_lossy());
- /// }
- /// ```
- pub fn items(&self) -> PubTypesEntryIter<R> {
- PubTypesEntryIter(self.0.items())
- }
-}
-
-impl<R: Reader> Section<R> for DebugPubTypes<R> {
- fn id() -> SectionId {
- SectionId::DebugPubTypes
- }
-
- fn reader(&self) -> &R {
- self.0.reader()
- }
-}
-
-impl<R: Reader> From<R> for DebugPubTypes<R> {
- fn from(debug_pubtypes_section: R) -> Self {
- DebugPubTypes(DebugLookup::from(debug_pubtypes_section))
- }
-}
-
-/// An iterator over the pubtypes from a `.debug_pubtypes` section.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-#[derive(Debug, Clone)]
-pub struct PubTypesEntryIter<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubTypesEntry<R>>>);
-
-impl<R: Reader> PubTypesEntryIter<R> {
- /// Advance the iterator and return the next pubtype.
- ///
- /// Returns the newly parsed pubtype as `Ok(Some(pubtype))`. Returns
- /// `Ok(None)` when iteration is complete and all pubtypes have already been
- /// parsed and yielded. If an error occurs while parsing the next pubtype,
- /// then this error is returned as `Err(e)`, and all subsequent calls return
- /// `Ok(None)`.
- pub fn next(&mut self) -> Result<Option<PubTypesEntry<R>>> {
- self.0.next()
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for PubTypesEntryIter<R> {
- type Item = PubTypesEntry<R>;
- type Error = crate::read::Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- self.0.next()
- }
-}
diff --git a/vendor/gimli/src/read/reader.rs b/vendor/gimli/src/read/reader.rs
deleted file mode 100644
index e7dd477..0000000
--- a/vendor/gimli/src/read/reader.rs
+++ /dev/null
@@ -1,502 +0,0 @@
-#[cfg(feature = "read")]
-use alloc::borrow::Cow;
-use core::convert::TryInto;
-use core::fmt::Debug;
-use core::hash::Hash;
-use core::ops::{Add, AddAssign, Sub};
-
-use crate::common::Format;
-use crate::endianity::Endianity;
-use crate::leb128;
-use crate::read::{Error, Result};
-
-/// An identifier for an offset within a section reader.
-///
-/// This is used for error reporting. The meaning of this value is specific to
-/// each reader implementation. The values should be chosen to be unique amongst
-/// all readers. If values are not unique then errors may point to the wrong reader.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct ReaderOffsetId(pub u64);
-
-/// A trait for offsets with a DWARF section.
-///
-/// This allows consumers to choose a size that is appropriate for their address space.
-pub trait ReaderOffset:
- Debug + Copy + Eq + Ord + Hash + Add<Output = Self> + AddAssign + Sub<Output = Self>
-{
- /// Convert a u8 to an offset.
- fn from_u8(offset: u8) -> Self;
-
- /// Convert a u16 to an offset.
- fn from_u16(offset: u16) -> Self;
-
- /// Convert an i16 to an offset.
- fn from_i16(offset: i16) -> Self;
-
- /// Convert a u32 to an offset.
- fn from_u32(offset: u32) -> Self;
-
- /// Convert a u64 to an offset.
- ///
- /// Returns `Error::UnsupportedOffset` if the value is too large.
- fn from_u64(offset: u64) -> Result<Self>;
-
- /// Convert an offset to a u64.
- fn into_u64(self) -> u64;
-
- /// Wrapping (modular) addition. Computes `self + other`.
- fn wrapping_add(self, other: Self) -> Self;
-
- /// Checked subtraction. Computes `self - other`.
- fn checked_sub(self, other: Self) -> Option<Self>;
-}
-
-impl ReaderOffset for u64 {
- #[inline]
- fn from_u8(offset: u8) -> Self {
- u64::from(offset)
- }
-
- #[inline]
- fn from_u16(offset: u16) -> Self {
- u64::from(offset)
- }
-
- #[inline]
- fn from_i16(offset: i16) -> Self {
- offset as u64
- }
-
- #[inline]
- fn from_u32(offset: u32) -> Self {
- u64::from(offset)
- }
-
- #[inline]
- fn from_u64(offset: u64) -> Result<Self> {
- Ok(offset)
- }
-
- #[inline]
- fn into_u64(self) -> u64 {
- self
- }
-
- #[inline]
- fn wrapping_add(self, other: Self) -> Self {
- self.wrapping_add(other)
- }
-
- #[inline]
- fn checked_sub(self, other: Self) -> Option<Self> {
- self.checked_sub(other)
- }
-}
-
-impl ReaderOffset for u32 {
- #[inline]
- fn from_u8(offset: u8) -> Self {
- u32::from(offset)
- }
-
- #[inline]
- fn from_u16(offset: u16) -> Self {
- u32::from(offset)
- }
-
- #[inline]
- fn from_i16(offset: i16) -> Self {
- offset as u32
- }
-
- #[inline]
- fn from_u32(offset: u32) -> Self {
- offset
- }
-
- #[inline]
- fn from_u64(offset64: u64) -> Result<Self> {
- let offset = offset64 as u32;
- if u64::from(offset) == offset64 {
- Ok(offset)
- } else {
- Err(Error::UnsupportedOffset)
- }
- }
-
- #[inline]
- fn into_u64(self) -> u64 {
- u64::from(self)
- }
-
- #[inline]
- fn wrapping_add(self, other: Self) -> Self {
- self.wrapping_add(other)
- }
-
- #[inline]
- fn checked_sub(self, other: Self) -> Option<Self> {
- self.checked_sub(other)
- }
-}
-
-impl ReaderOffset for usize {
- #[inline]
- fn from_u8(offset: u8) -> Self {
- offset as usize
- }
-
- #[inline]
- fn from_u16(offset: u16) -> Self {
- offset as usize
- }
-
- #[inline]
- fn from_i16(offset: i16) -> Self {
- offset as usize
- }
-
- #[inline]
- fn from_u32(offset: u32) -> Self {
- offset as usize
- }
-
- #[inline]
- fn from_u64(offset64: u64) -> Result<Self> {
- let offset = offset64 as usize;
- if offset as u64 == offset64 {
- Ok(offset)
- } else {
- Err(Error::UnsupportedOffset)
- }
- }
-
- #[inline]
- fn into_u64(self) -> u64 {
- self as u64
- }
-
- #[inline]
- fn wrapping_add(self, other: Self) -> Self {
- self.wrapping_add(other)
- }
-
- #[inline]
- fn checked_sub(self, other: Self) -> Option<Self> {
- self.checked_sub(other)
- }
-}
-
-#[cfg(not(feature = "read"))]
-pub(crate) mod seal_if_no_alloc {
- #[derive(Debug)]
- pub struct Sealed;
-}
-
-/// A trait for reading the data from a DWARF section.
-///
-/// All read operations advance the section offset of the reader
-/// unless specified otherwise.
-///
-/// ## Choosing a `Reader` Implementation
-///
-/// `gimli` comes with a few different `Reader` implementations and lets you
-/// choose the one that is right for your use case. A `Reader` is essentially a
-/// view into the raw bytes that make up some DWARF, but this view might borrow
-/// the underlying data or use reference counting ownership, and it might be
-/// thread safe or not.
-///
-/// | Implementation | Ownership | Thread Safe | Notes |
-/// |:------------------|:------------------|:------------|:------|
-/// | [`EndianSlice`](./struct.EndianSlice.html) | Borrowed | Yes | Fastest, but requires that all of your code work with borrows. |
-/// | [`EndianRcSlice`](./struct.EndianRcSlice.html) | Reference counted | No | Shared ownership via reference counting, which alleviates the borrow restrictions of `EndianSlice` but imposes reference counting increments and decrements. Cannot be sent across threads, because the reference count is not atomic. |
-/// | [`EndianArcSlice`](./struct.EndianArcSlice.html) | Reference counted | Yes | The same as `EndianRcSlice`, but uses atomic reference counting, and therefore reference counting operations are slower but `EndianArcSlice`s may be sent across threads. |
-/// | [`EndianReader<T>`](./struct.EndianReader.html) | Same as `T` | Same as `T` | Escape hatch for easily defining your own type of `Reader`. |
-pub trait Reader: Debug + Clone {
- /// The endianity of bytes that are read.
- type Endian: Endianity;
-
- /// The type used for offsets and lengths.
- type Offset: ReaderOffset;
-
- /// Return the endianity of bytes that are read.
- fn endian(&self) -> Self::Endian;
-
- /// Return the number of bytes remaining.
- fn len(&self) -> Self::Offset;
-
- /// Set the number of bytes remaining to zero.
- fn empty(&mut self);
-
- /// Set the number of bytes remaining to the specified length.
- fn truncate(&mut self, len: Self::Offset) -> Result<()>;
-
- /// Return the offset of this reader's data relative to the start of
- /// the given base reader's data.
- ///
- /// May panic if this reader's data is not contained within the given
- /// base reader's data.
- fn offset_from(&self, base: &Self) -> Self::Offset;
-
- /// Return an identifier for the current reader offset.
- fn offset_id(&self) -> ReaderOffsetId;
-
- /// Return the offset corresponding to the given `id` if
- /// it is associated with this reader.
- fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset>;
-
- /// Find the index of the first occurrence of the given byte.
- /// The offset of the reader is not changed.
- fn find(&self, byte: u8) -> Result<Self::Offset>;
-
- /// Discard the specified number of bytes.
- fn skip(&mut self, len: Self::Offset) -> Result<()>;
-
- /// Split a reader in two.
- ///
- /// A new reader is returned that can be used to read the next
- /// `len` bytes, and `self` is advanced so that it reads the remainder.
- fn split(&mut self, len: Self::Offset) -> Result<Self>;
-
- /// This trait cannot be implemented if "read" feature is not enabled.
- ///
- /// `Reader` trait has a few methods that depend on `alloc` crate.
- /// Disallowing `Reader` trait implementation prevents a crate that only depends on
- /// "read-core" from being broken if another crate depending on `gimli` enables
- /// "read" feature.
- #[cfg(not(feature = "read"))]
- fn cannot_implement() -> seal_if_no_alloc::Sealed;
-
- /// Return all remaining data as a clone-on-write slice.
- ///
- /// The slice will be borrowed where possible, but some readers may
- /// always return an owned vector.
- ///
- /// Does not advance the reader.
- #[cfg(feature = "read")]
- fn to_slice(&self) -> Result<Cow<[u8]>>;
-
- /// Convert all remaining data to a clone-on-write string.
- ///
- /// The string will be borrowed where possible, but some readers may
- /// always return an owned string.
- ///
- /// Does not advance the reader.
- ///
- /// Returns an error if the data contains invalid characters.
- #[cfg(feature = "read")]
- fn to_string(&self) -> Result<Cow<str>>;
-
- /// Convert all remaining data to a clone-on-write string, including invalid characters.
- ///
- /// The string will be borrowed where possible, but some readers may
- /// always return an owned string.
- ///
- /// Does not advance the reader.
- #[cfg(feature = "read")]
- fn to_string_lossy(&self) -> Result<Cow<str>>;
-
- /// Read exactly `buf.len()` bytes into `buf`.
- fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>;
-
- /// Read a u8 array.
- #[inline]
- fn read_u8_array<A>(&mut self) -> Result<A>
- where
- A: Sized + Default + AsMut<[u8]>,
- {
- let mut val = Default::default();
- self.read_slice(<A as AsMut<[u8]>>::as_mut(&mut val))?;
- Ok(val)
- }
-
- /// Return true if the number of bytes remaining is zero.
- #[inline]
- fn is_empty(&self) -> bool {
- self.len() == Self::Offset::from_u8(0)
- }
-
- /// Read a u8.
- #[inline]
- fn read_u8(&mut self) -> Result<u8> {
- let a: [u8; 1] = self.read_u8_array()?;
- Ok(a[0])
- }
-
- /// Read an i8.
- #[inline]
- fn read_i8(&mut self) -> Result<i8> {
- let a: [u8; 1] = self.read_u8_array()?;
- Ok(a[0] as i8)
- }
-
- /// Read a u16.
- #[inline]
- fn read_u16(&mut self) -> Result<u16> {
- let a: [u8; 2] = self.read_u8_array()?;
- Ok(self.endian().read_u16(&a))
- }
-
- /// Read an i16.
- #[inline]
- fn read_i16(&mut self) -> Result<i16> {
- let a: [u8; 2] = self.read_u8_array()?;
- Ok(self.endian().read_i16(&a))
- }
-
- /// Read a u32.
- #[inline]
- fn read_u32(&mut self) -> Result<u32> {
- let a: [u8; 4] = self.read_u8_array()?;
- Ok(self.endian().read_u32(&a))
- }
-
- /// Read an i32.
- #[inline]
- fn read_i32(&mut self) -> Result<i32> {
- let a: [u8; 4] = self.read_u8_array()?;
- Ok(self.endian().read_i32(&a))
- }
-
- /// Read a u64.
- #[inline]
- fn read_u64(&mut self) -> Result<u64> {
- let a: [u8; 8] = self.read_u8_array()?;
- Ok(self.endian().read_u64(&a))
- }
-
- /// Read an i64.
- #[inline]
- fn read_i64(&mut self) -> Result<i64> {
- let a: [u8; 8] = self.read_u8_array()?;
- Ok(self.endian().read_i64(&a))
- }
-
- /// Read a f32.
- #[inline]
- fn read_f32(&mut self) -> Result<f32> {
- let a: [u8; 4] = self.read_u8_array()?;
- Ok(self.endian().read_f32(&a))
- }
-
- /// Read a f64.
- #[inline]
- fn read_f64(&mut self) -> Result<f64> {
- let a: [u8; 8] = self.read_u8_array()?;
- Ok(self.endian().read_f64(&a))
- }
-
- /// Read an unsigned n-bytes integer u64.
- ///
- /// # Panics
- ///
- /// Panics when nbytes < 1 or nbytes > 8
- #[inline]
- fn read_uint(&mut self, n: usize) -> Result<u64> {
- let mut buf = [0; 8];
- self.read_slice(&mut buf[..n])?;
- Ok(self.endian().read_uint(&buf[..n]))
- }
-
- /// Read a null-terminated slice, and return it (excluding the null).
- fn read_null_terminated_slice(&mut self) -> Result<Self> {
- let idx = self.find(0)?;
- let val = self.split(idx)?;
- self.skip(Self::Offset::from_u8(1))?;
- Ok(val)
- }
-
- /// Skip a LEB128 encoded integer.
- fn skip_leb128(&mut self) -> Result<()> {
- leb128::read::skip(self)
- }
-
- /// Read an unsigned LEB128 encoded integer.
- fn read_uleb128(&mut self) -> Result<u64> {
- leb128::read::unsigned(self)
- }
-
- /// Read an unsigned LEB128 encoded u32.
- fn read_uleb128_u32(&mut self) -> Result<u32> {
- leb128::read::unsigned(self)?
- .try_into()
- .map_err(|_| Error::BadUnsignedLeb128)
- }
-
- /// Read an unsigned LEB128 encoded u16.
- fn read_uleb128_u16(&mut self) -> Result<u16> {
- leb128::read::u16(self)
- }
-
- /// Read a signed LEB128 encoded integer.
- fn read_sleb128(&mut self) -> Result<i64> {
- leb128::read::signed(self)
- }
-
- /// Read an initial length field.
- ///
- /// This field is encoded as either a 32-bit length or
- /// a 64-bit length, and the returned `Format` indicates which.
- fn read_initial_length(&mut self) -> Result<(Self::Offset, Format)> {
- const MAX_DWARF_32_UNIT_LENGTH: u32 = 0xffff_fff0;
- const DWARF_64_INITIAL_UNIT_LENGTH: u32 = 0xffff_ffff;
-
- let val = self.read_u32()?;
- if val < MAX_DWARF_32_UNIT_LENGTH {
- Ok((Self::Offset::from_u32(val), Format::Dwarf32))
- } else if val == DWARF_64_INITIAL_UNIT_LENGTH {
- let val = self.read_u64().and_then(Self::Offset::from_u64)?;
- Ok((val, Format::Dwarf64))
- } else {
- Err(Error::UnknownReservedLength)
- }
- }
-
- /// Read an address-sized integer, and return it as a `u64`.
- fn read_address(&mut self, address_size: u8) -> Result<u64> {
- match address_size {
- 1 => self.read_u8().map(u64::from),
- 2 => self.read_u16().map(u64::from),
- 4 => self.read_u32().map(u64::from),
- 8 => self.read_u64(),
- otherwise => Err(Error::UnsupportedAddressSize(otherwise)),
- }
- }
-
- /// Parse a word-sized integer according to the DWARF format.
- ///
- /// These are always used to encode section offsets or lengths,
- /// and so have a type of `Self::Offset`.
- fn read_word(&mut self, format: Format) -> Result<Self::Offset> {
- match format {
- Format::Dwarf32 => self.read_u32().map(Self::Offset::from_u32),
- Format::Dwarf64 => self.read_u64().and_then(Self::Offset::from_u64),
- }
- }
-
- /// Parse a word-sized section length according to the DWARF format.
- #[inline]
- fn read_length(&mut self, format: Format) -> Result<Self::Offset> {
- self.read_word(format)
- }
-
- /// Parse a word-sized section offset according to the DWARF format.
- #[inline]
- fn read_offset(&mut self, format: Format) -> Result<Self::Offset> {
- self.read_word(format)
- }
-
- /// Parse a section offset of the given size.
- ///
- /// This is used for `DW_FORM_ref_addr` values in DWARF version 2.
- fn read_sized_offset(&mut self, size: u8) -> Result<Self::Offset> {
- match size {
- 1 => self.read_u8().map(u64::from),
- 2 => self.read_u16().map(u64::from),
- 4 => self.read_u32().map(u64::from),
- 8 => self.read_u64(),
- otherwise => Err(Error::UnsupportedOffsetSize(otherwise)),
- }
- .and_then(Self::Offset::from_u64)
- }
-}
diff --git a/vendor/gimli/src/read/rnglists.rs b/vendor/gimli/src/read/rnglists.rs
deleted file mode 100644
index 12e3e04..0000000
--- a/vendor/gimli/src/read/rnglists.rs
+++ /dev/null
@@ -1,1458 +0,0 @@
-use crate::common::{
- DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding,
- RangeListsOffset, SectionId,
-};
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::{
- lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId,
- Result, Section,
-};
-
-/// The raw contents of the `.debug_ranges` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugRanges<R> {
- pub(crate) section: R,
-}
-
-impl<'input, Endian> DebugRanges<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_ranges` 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::{DebugRanges, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_ranges_section_somehow = || &buf;
- /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugRanges<R> {
- fn id() -> SectionId {
- SectionId::DebugRanges
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugRanges<R> {
- fn from(section: R) -> Self {
- DebugRanges { section }
- }
-}
-
-/// The `DebugRngLists` struct represents the contents of the
-/// `.debug_rnglists` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugRngLists<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugRngLists<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugRngLists` instance from the data in the
- /// `.debug_rnglists` section.
- ///
- /// It is the caller's responsibility to read the `.debug_rnglists`
- /// 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::{DebugRngLists, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_rnglists_section_somehow = || &buf;
- /// let debug_rnglists =
- /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian);
- /// ```
- pub fn new(section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(section, endian))
- }
-}
-
-impl<R> Section<R> for DebugRngLists<R> {
- fn id() -> SectionId {
- SectionId::DebugRngLists
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugRngLists<R> {
- fn from(section: R) -> Self {
- DebugRngLists { section }
- }
-}
-
-#[allow(unused)]
-pub(crate) type RngListsHeader = ListsHeader;
-
-impl<Offset> DebugRngListsBase<Offset>
-where
- Offset: ReaderOffset,
-{
- /// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base
- /// for the given `Encoding` and `DwarfFileType`.
- pub fn default_for_encoding_and_file(
- encoding: Encoding,
- file_type: DwarfFileType,
- ) -> DebugRngListsBase<Offset> {
- if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
- // In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is
- // only a single unit in the file) but we must skip past the header, which the attribute
- // would normally do for us.
- DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding)))
- } else {
- DebugRngListsBase(Offset::from_u8(0))
- }
- }
-}
-
-/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct RangeLists<R> {
- debug_ranges: DebugRanges<R>,
- debug_rnglists: DebugRngLists<R>,
-}
-
-impl<R> RangeLists<R> {
- /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and
- /// `.debug_rnglists` sections.
- pub fn new(debug_ranges: DebugRanges<R>, debug_rnglists: DebugRngLists<R>) -> RangeLists<R> {
- RangeLists {
- debug_ranges,
- debug_rnglists,
- }
- }
-
- /// Return the `.debug_ranges` section.
- pub fn debug_ranges(&self) -> &DebugRanges<R> {
- &self.debug_ranges
- }
-
- /// Replace the `.debug_ranges` section.
- ///
- /// This is useful for `.dwo` files when using the GNU split-dwarf extension to DWARF 4.
- pub fn set_debug_ranges(&mut self, debug_ranges: DebugRanges<R>) {
- self.debug_ranges = debug_ranges;
- }
-
- /// Return the `.debug_rnglists` section.
- pub fn debug_rnglists(&self) -> &DebugRngLists<R> {
- &self.debug_rnglists
- }
-}
-
-impl<T> RangeLists<T> {
- /// Create a `RangeLists` that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::RangeLists<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> RangeLists<R>
- where
- F: FnMut(&'a T) -> R,
- {
- RangeLists {
- debug_ranges: borrow(&self.debug_ranges.section).into(),
- debug_rnglists: borrow(&self.debug_rnglists.section).into(),
- }
- }
-}
-
-impl<R: Reader> RangeLists<R> {
- /// Iterate over the `Range` list entries starting at the given offset.
- ///
- /// The `unit_version` and `address_size` must match the compilation unit that the
- /// offset was contained in.
- ///
- /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the
- /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn ranges(
- &self,
- offset: RangeListsOffset<R::Offset>,
- unit_encoding: Encoding,
- base_address: u64,
- debug_addr: &DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
- ) -> Result<RngListIter<R>> {
- Ok(RngListIter::new(
- self.raw_ranges(offset, unit_encoding)?,
- base_address,
- debug_addr.clone(),
- debug_addr_base,
- ))
- }
-
- /// Iterate over the `RawRngListEntry`ies starting at the given offset.
- ///
- /// The `unit_encoding` must match the compilation unit that the
- /// offset was contained in.
- ///
- /// This iterator does not perform any processing of the range entries,
- /// such as handling base addresses.
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn raw_ranges(
- &self,
- offset: RangeListsOffset<R::Offset>,
- unit_encoding: Encoding,
- ) -> Result<RawRngListIter<R>> {
- let (mut input, format) = if unit_encoding.version <= 4 {
- (self.debug_ranges.section.clone(), RangeListsFormat::Bare)
- } else {
- (self.debug_rnglists.section.clone(), RangeListsFormat::Rle)
- };
- input.skip(offset.0)?;
- Ok(RawRngListIter::new(input, unit_encoding, format))
- }
-
- /// Returns the `.debug_rnglists` offset at the given `base` and `index`.
- ///
- /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE.
- /// This is an offset that points to the first entry following the header.
- ///
- /// The `index` is the value of a `DW_FORM_rnglistx` attribute.
- ///
- /// The `unit_encoding` must match the compilation unit that the
- /// index was contained in.
- pub fn get_offset(
- &self,
- unit_encoding: Encoding,
- base: DebugRngListsBase<R::Offset>,
- index: DebugRngListsIndex<R::Offset>,
- ) -> Result<RangeListsOffset<R::Offset>> {
- let format = unit_encoding.format;
- let input = &mut self.debug_rnglists.section.clone();
- input.skip(base.0)?;
- input.skip(R::Offset::from_u64(
- index.0.into_u64() * u64::from(format.word_size()),
- )?)?;
- input
- .read_offset(format)
- .map(|x| RangeListsOffset(base.0 + x))
- }
-
- /// Call `Reader::lookup_offset_id` for each section, and return the first match.
- pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> {
- self.debug_ranges
- .lookup_offset_id(id)
- .or_else(|| self.debug_rnglists.lookup_offset_id(id))
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum RangeListsFormat {
- /// The bare range list format used before DWARF 5.
- Bare,
- /// The DW_RLE encoded range list format used in DWARF 5.
- Rle,
-}
-
-/// A raw iterator over an address range list.
-///
-/// This iterator does not perform any processing of the range entries,
-/// such as handling base addresses.
-#[derive(Debug)]
-pub struct RawRngListIter<R: Reader> {
- input: R,
- encoding: Encoding,
- format: RangeListsFormat,
-}
-
-/// A raw entry in .debug_rnglists
-#[derive(Clone, Debug)]
-pub enum RawRngListEntry<T> {
- /// A range from DWARF version <= 4.
- AddressOrOffsetPair {
- /// Start of range. May be an address or an offset.
- begin: u64,
- /// End of range. May be an address or an offset.
- end: u64,
- },
- /// DW_RLE_base_address
- BaseAddress {
- /// base address
- addr: u64,
- },
- /// DW_RLE_base_addressx
- BaseAddressx {
- /// base address
- addr: DebugAddrIndex<T>,
- },
- /// DW_RLE_startx_endx
- StartxEndx {
- /// start of range
- begin: DebugAddrIndex<T>,
- /// end of range
- end: DebugAddrIndex<T>,
- },
- /// DW_RLE_startx_length
- StartxLength {
- /// start of range
- begin: DebugAddrIndex<T>,
- /// length of range
- length: u64,
- },
- /// DW_RLE_offset_pair
- OffsetPair {
- /// start of range
- begin: u64,
- /// end of range
- end: u64,
- },
- /// DW_RLE_start_end
- StartEnd {
- /// start of range
- begin: u64,
- /// end of range
- end: u64,
- },
- /// DW_RLE_start_length
- StartLength {
- /// start of range
- begin: u64,
- /// length of range
- length: u64,
- },
-}
-
-impl<T: ReaderOffset> RawRngListEntry<T> {
- /// Parse a range entry from `.debug_rnglists`
- fn parse<R: Reader<Offset = T>>(
- input: &mut R,
- encoding: Encoding,
- format: RangeListsFormat,
- ) -> Result<Option<Self>> {
- Ok(match format {
- RangeListsFormat::Bare => {
- let range = RawRange::parse(input, encoding.address_size)?;
- if range.is_end() {
- None
- } else if range.is_base_address(encoding.address_size) {
- Some(RawRngListEntry::BaseAddress { addr: range.end })
- } else {
- Some(RawRngListEntry::AddressOrOffsetPair {
- begin: range.begin,
- end: range.end,
- })
- }
- }
- RangeListsFormat::Rle => match constants::DwRle(input.read_u8()?) {
- constants::DW_RLE_end_of_list => None,
- constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx {
- addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- }),
- constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx {
- begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- }),
- constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength {
- begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
- length: input.read_uleb128()?,
- }),
- constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair {
- begin: input.read_uleb128()?,
- end: input.read_uleb128()?,
- }),
- constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress {
- addr: input.read_address(encoding.address_size)?,
- }),
- constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd {
- begin: input.read_address(encoding.address_size)?,
- end: input.read_address(encoding.address_size)?,
- }),
- constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength {
- begin: input.read_address(encoding.address_size)?,
- length: input.read_uleb128()?,
- }),
- _ => {
- return Err(Error::InvalidAddressRange);
- }
- },
- })
- }
-}
-
-impl<R: Reader> RawRngListIter<R> {
- /// Construct a `RawRngListIter`.
- fn new(input: R, encoding: Encoding, format: RangeListsFormat) -> RawRngListIter<R> {
- RawRngListIter {
- input,
- encoding,
- format,
- }
- }
-
- /// Advance the iterator to the next range.
- pub fn next(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> {
- if self.input.is_empty() {
- return Ok(None);
- }
-
- match RawRngListEntry::parse(&mut self.input, self.encoding, self.format) {
- Ok(range) => {
- if range.is_none() {
- self.input.empty();
- }
- Ok(range)
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for RawRngListIter<R> {
- type Item = RawRngListEntry<R::Offset>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- RawRngListIter::next(self)
- }
-}
-
-/// An iterator over an address range list.
-///
-/// This iterator internally handles processing of base addresses and different
-/// entry types. Thus, it only returns range entries that are valid
-/// and already adjusted for the base address.
-#[derive(Debug)]
-pub struct RngListIter<R: Reader> {
- raw: RawRngListIter<R>,
- base_address: u64,
- debug_addr: DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
-}
-
-impl<R: Reader> RngListIter<R> {
- /// Construct a `RngListIter`.
- fn new(
- raw: RawRngListIter<R>,
- base_address: u64,
- debug_addr: DebugAddr<R>,
- debug_addr_base: DebugAddrBase<R::Offset>,
- ) -> RngListIter<R> {
- RngListIter {
- raw,
- base_address,
- debug_addr,
- debug_addr_base,
- }
- }
-
- #[inline]
- fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
- self.debug_addr
- .get_address(self.raw.encoding.address_size, self.debug_addr_base, index)
- }
-
- /// Advance the iterator to the next range.
- pub fn next(&mut self) -> Result<Option<Range>> {
- loop {
- let raw_range = match self.raw.next()? {
- Some(range) => range,
- None => return Ok(None),
- };
-
- let range = self.convert_raw(raw_range)?;
- if range.is_some() {
- return Ok(range);
- }
- }
- }
-
- /// Return the next raw range.
- ///
- /// The raw range should be passed to `convert_range`.
- #[doc(hidden)]
- pub fn next_raw(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> {
- self.raw.next()
- }
-
- /// Convert a raw range into a range, and update the state of the iterator.
- ///
- /// The raw range should have been obtained from `next_raw`.
- #[doc(hidden)]
- pub fn convert_raw(&mut self, raw_range: RawRngListEntry<R::Offset>) -> Result<Option<Range>> {
- let mask = !0 >> (64 - self.raw.encoding.address_size * 8);
- let tombstone = if self.raw.encoding.version <= 4 {
- mask - 1
- } else {
- mask
- };
-
- let range = match raw_range {
- RawRngListEntry::BaseAddress { addr } => {
- self.base_address = addr;
- return Ok(None);
- }
- RawRngListEntry::BaseAddressx { addr } => {
- self.base_address = self.get_address(addr)?;
- return Ok(None);
- }
- RawRngListEntry::StartxEndx { begin, end } => {
- let begin = self.get_address(begin)?;
- let end = self.get_address(end)?;
- Range { begin, end }
- }
- RawRngListEntry::StartxLength { begin, length } => {
- let begin = self.get_address(begin)?;
- let end = begin.wrapping_add(length) & mask;
- Range { begin, end }
- }
- RawRngListEntry::AddressOrOffsetPair { begin, end }
- | RawRngListEntry::OffsetPair { begin, end } => {
- if self.base_address == tombstone {
- return Ok(None);
- }
- let mut range = Range { begin, end };
- range.add_base_address(self.base_address, self.raw.encoding.address_size);
- range
- }
- RawRngListEntry::StartEnd { begin, end } => Range { begin, end },
- RawRngListEntry::StartLength { begin, length } => {
- let end = begin.wrapping_add(length) & mask;
- Range { begin, end }
- }
- };
-
- if range.begin == tombstone {
- return Ok(None);
- }
-
- if range.begin > range.end {
- self.raw.input.empty();
- return Err(Error::InvalidAddressRange);
- }
-
- Ok(Some(range))
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for RngListIter<R> {
- type Item = Range;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- RngListIter::next(self)
- }
-}
-
-/// A raw address range from the `.debug_ranges` section.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) struct RawRange {
- /// The beginning address of the range.
- pub begin: u64,
-
- /// The first address past the end of the range.
- pub end: u64,
-}
-
-impl RawRange {
- /// Check if this is a range end entry.
- #[inline]
- pub fn is_end(&self) -> bool {
- self.begin == 0 && self.end == 0
- }
-
- /// Check if this is a base address selection entry.
- ///
- /// A base address selection entry changes the base address that subsequent
- /// range entries are relative to.
- #[inline]
- pub fn is_base_address(&self, address_size: u8) -> bool {
- self.begin == !0 >> (64 - address_size * 8)
- }
-
- /// Parse an address range entry from `.debug_ranges` or `.debug_loc`.
- #[inline]
- pub fn parse<R: Reader>(input: &mut R, address_size: u8) -> Result<RawRange> {
- let begin = input.read_address(address_size)?;
- let end = input.read_address(address_size)?;
- let range = RawRange { begin, end };
- Ok(range)
- }
-}
-
-/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Range {
- /// The beginning address of the range.
- pub begin: u64,
-
- /// The first address past the end of the range.
- pub end: u64,
-}
-
-impl Range {
- /// Add a base address to this range.
- #[inline]
- pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) {
- let mask = !0 >> (64 - address_size * 8);
- self.begin = base_address.wrapping_add(self.begin) & mask;
- self.end = base_address.wrapping_add(self.end) & mask;
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::common::Format;
- use crate::endianity::LittleEndian;
- use crate::test_util::GimliSectionMethods;
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- #[test]
- fn test_rnglists_32() {
- let tombstone = !0u32;
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
- let section = Section::with_endian(Endian::Little)
- .L32(0x0300_0000)
- .L32(0x0301_0300)
- .L32(0x0301_0400)
- .L32(0x0301_0500)
- .L32(tombstone)
- .L32(0x0301_0600);
- let buf = section.get_contents().unwrap();
- let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
-
- let start = Label::new();
- let first = Label::new();
- let size = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // Header
- .mark(&start)
- .L32(&size)
- .L16(encoding.version)
- .L8(encoding.address_size)
- .L8(0)
- .L32(0)
- .mark(&first)
- // An OffsetPair using the unit base address.
- .L8(4).uleb(0x10200).uleb(0x10300)
- // A base address selection followed by an OffsetPair.
- .L8(5).L32(0x0200_0000)
- .L8(4).uleb(0x10400).uleb(0x10500)
- // An empty OffsetPair followed by a normal OffsetPair.
- .L8(4).uleb(0x10600).uleb(0x10600)
- .L8(4).uleb(0x10800).uleb(0x10900)
- // A StartEnd
- .L8(6).L32(0x201_0a00).L32(0x201_0b00)
- // A StartLength
- .L8(7).L32(0x201_0c00).uleb(0x100)
- // An OffsetPair that starts at 0.
- .L8(4).uleb(0).uleb(1)
- // An OffsetPair that starts and ends at 0.
- .L8(4).uleb(0).uleb(0)
- // An OffsetPair that ends at -1.
- .L8(5).L32(0)
- .L8(4).uleb(0).uleb(0xffff_ffff)
- // A BaseAddressx + OffsetPair
- .L8(1).uleb(0)
- .L8(4).uleb(0x10100).uleb(0x10200)
- // A StartxEndx
- .L8(2).uleb(1).uleb(2)
- // A StartxLength
- .L8(3).uleb(3).uleb(0x100)
-
- // Tombstone entries, all of which should be ignored.
- // A BaseAddressx that is a tombstone.
- .L8(1).uleb(4)
- .L8(4).uleb(0x11100).uleb(0x11200)
- // A BaseAddress that is a tombstone.
- .L8(5).L32(tombstone)
- .L8(4).uleb(0x11300).uleb(0x11400)
- // A StartxEndx that is a tombstone.
- .L8(2).uleb(4).uleb(5)
- // A StartxLength that is a tombstone.
- .L8(3).uleb(4).uleb(0x100)
- // A StartEnd that is a tombstone.
- .L8(6).L32(tombstone).L32(0x201_1500)
- // A StartLength that is a tombstone.
- .L8(7).L32(tombstone).uleb(0x100)
- // A StartEnd (not ignored)
- .L8(6).L32(0x201_1600).L32(0x201_1700)
-
- // A range end.
- .L8(0)
- // Some extra data.
- .L32(0xffff_ffff);
- size.set_const((&section.here() - &start - 4) as u64);
-
- let buf = section.get_contents().unwrap();
- let debug_ranges = DebugRanges::new(&[], LittleEndian);
- let debug_rnglists = DebugRngLists::new(&buf, LittleEndian);
- let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
- let offset = RangeListsOffset((&first - &start) as usize);
- let mut ranges = rnglists
- .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- }))
- );
-
- // A base address selection followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- }))
- );
-
- // An empty range followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- }))
- );
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- }))
- );
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0a00,
- end: 0x0201_0b00,
- }))
- );
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0c00,
- end: 0x0201_0d00,
- }))
- );
-
- // A range that starts at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- }))
- );
-
- // A range that starts and ends at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0000,
- }))
- );
-
- // A range that ends at -1.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- }))
- );
-
- // A BaseAddressx + OffsetPair
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0100,
- end: 0x0301_0200,
- }))
- );
-
- // A StartxEndx
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0300,
- end: 0x0301_0400,
- }))
- );
-
- // A StartxLength
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0500,
- end: 0x0301_0600,
- }))
- );
-
- // A StartEnd range following the tombstones
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_1600,
- end: 0x0201_1700,
- }))
- );
-
- // A range end.
- assert_eq!(ranges.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Ok(None));
- }
-
- #[test]
- fn test_rnglists_64() {
- let tombstone = !0u64;
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let section = Section::with_endian(Endian::Little)
- .L64(0x0300_0000)
- .L64(0x0301_0300)
- .L64(0x0301_0400)
- .L64(0x0301_0500)
- .L64(tombstone)
- .L64(0x0301_0600);
- let buf = section.get_contents().unwrap();
- let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
-
- let start = Label::new();
- let first = Label::new();
- let size = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // Header
- .mark(&start)
- .L32(0xffff_ffff)
- .L64(&size)
- .L16(encoding.version)
- .L8(encoding.address_size)
- .L8(0)
- .L32(0)
- .mark(&first)
- // An OffsetPair using the unit base address.
- .L8(4).uleb(0x10200).uleb(0x10300)
- // A base address selection followed by an OffsetPair.
- .L8(5).L64(0x0200_0000)
- .L8(4).uleb(0x10400).uleb(0x10500)
- // An empty OffsetPair followed by a normal OffsetPair.
- .L8(4).uleb(0x10600).uleb(0x10600)
- .L8(4).uleb(0x10800).uleb(0x10900)
- // A StartEnd
- .L8(6).L64(0x201_0a00).L64(0x201_0b00)
- // A StartLength
- .L8(7).L64(0x201_0c00).uleb(0x100)
- // An OffsetPair that starts at 0.
- .L8(4).uleb(0).uleb(1)
- // An OffsetPair that starts and ends at 0.
- .L8(4).uleb(0).uleb(0)
- // An OffsetPair that ends at -1.
- .L8(5).L64(0)
- .L8(4).uleb(0).uleb(0xffff_ffff)
- // A BaseAddressx + OffsetPair
- .L8(1).uleb(0)
- .L8(4).uleb(0x10100).uleb(0x10200)
- // A StartxEndx
- .L8(2).uleb(1).uleb(2)
- // A StartxLength
- .L8(3).uleb(3).uleb(0x100)
-
- // Tombstone entries, all of which should be ignored.
- // A BaseAddressx that is a tombstone.
- .L8(1).uleb(4)
- .L8(4).uleb(0x11100).uleb(0x11200)
- // A BaseAddress that is a tombstone.
- .L8(5).L64(tombstone)
- .L8(4).uleb(0x11300).uleb(0x11400)
- // A StartxEndx that is a tombstone.
- .L8(2).uleb(4).uleb(5)
- // A StartxLength that is a tombstone.
- .L8(3).uleb(4).uleb(0x100)
- // A StartEnd that is a tombstone.
- .L8(6).L64(tombstone).L64(0x201_1500)
- // A StartLength that is a tombstone.
- .L8(7).L64(tombstone).uleb(0x100)
- // A StartEnd (not ignored)
- .L8(6).L64(0x201_1600).L64(0x201_1700)
-
- // A range end.
- .L8(0)
- // Some extra data.
- .L32(0xffff_ffff);
- size.set_const((&section.here() - &start - 12) as u64);
-
- let buf = section.get_contents().unwrap();
- let debug_ranges = DebugRanges::new(&[], LittleEndian);
- let debug_rnglists = DebugRngLists::new(&buf, LittleEndian);
- let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
- let offset = RangeListsOffset((&first - &start) as usize);
- let mut ranges = rnglists
- .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- }))
- );
-
- // A base address selection followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- }))
- );
-
- // An empty range followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- }))
- );
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- }))
- );
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0a00,
- end: 0x0201_0b00,
- }))
- );
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0c00,
- end: 0x0201_0d00,
- }))
- );
-
- // A range that starts at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- }))
- );
-
- // A range that starts and ends at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0000,
- }))
- );
-
- // A range that ends at -1.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- }))
- );
-
- // A BaseAddressx + OffsetPair
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0100,
- end: 0x0301_0200,
- }))
- );
-
- // A StartxEndx
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0300,
- end: 0x0301_0400,
- }))
- );
-
- // A StartxLength
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0301_0500,
- end: 0x0301_0600,
- }))
- );
-
- // A StartEnd range following the tombstones
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_1600,
- end: 0x0201_1700,
- }))
- );
-
- // A range end.
- assert_eq!(ranges.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Ok(None));
- }
-
- #[test]
- fn test_raw_range() {
- let range = RawRange {
- begin: 0,
- end: 0xffff_ffff,
- };
- assert!(!range.is_end());
- assert!(!range.is_base_address(4));
- assert!(!range.is_base_address(8));
-
- let range = RawRange { begin: 0, end: 0 };
- assert!(range.is_end());
- assert!(!range.is_base_address(4));
- assert!(!range.is_base_address(8));
-
- let range = RawRange {
- begin: 0xffff_ffff,
- end: 0,
- };
- assert!(!range.is_end());
- assert!(range.is_base_address(4));
- assert!(!range.is_base_address(8));
-
- let range = RawRange {
- begin: 0xffff_ffff_ffff_ffff,
- end: 0,
- };
- assert!(!range.is_end());
- assert!(!range.is_base_address(4));
- assert!(range.is_base_address(8));
- }
-
- #[test]
- fn test_ranges_32() {
- let tombstone = !0u32 - 1;
- let start = Label::new();
- let first = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // A range before the offset.
- .mark(&start)
- .L32(0x10000).L32(0x10100)
- .mark(&first)
- // A normal range.
- .L32(0x10200).L32(0x10300)
- // A base address selection followed by a normal range.
- .L32(0xffff_ffff).L32(0x0200_0000)
- .L32(0x10400).L32(0x10500)
- // An empty range followed by a normal range.
- .L32(0x10600).L32(0x10600)
- .L32(0x10800).L32(0x10900)
- // A range that starts at 0.
- .L32(0).L32(1)
- // A range that ends at -1.
- .L32(0xffff_ffff).L32(0x0000_0000)
- .L32(0).L32(0xffff_ffff)
- // A normal range with tombstone.
- .L32(tombstone).L32(tombstone)
- // A base address selection with tombstone followed by a normal range.
- .L32(0xffff_ffff).L32(tombstone)
- .L32(0x10a00).L32(0x10b00)
- // A range end.
- .L32(0).L32(0)
- // Some extra data.
- .L32(0);
-
- let buf = section.get_contents().unwrap();
- let debug_ranges = DebugRanges::new(&buf, LittleEndian);
- let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
- let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
- let offset = RangeListsOffset((&first - &start) as usize);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut ranges = rnglists
- .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- }))
- );
-
- // A base address selection followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- }))
- );
-
- // An empty range followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- }))
- );
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- }))
- );
-
- // A range that starts at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- }))
- );
-
- // A range that ends at -1.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0000_0000,
- end: 0xffff_ffff,
- }))
- );
-
- // A range end.
- assert_eq!(ranges.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Ok(None));
- }
-
- #[test]
- fn test_ranges_64() {
- let tombstone = !0u64 - 1;
- let start = Label::new();
- let first = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // A range before the offset.
- .mark(&start)
- .L64(0x10000).L64(0x10100)
- .mark(&first)
- // A normal range.
- .L64(0x10200).L64(0x10300)
- // A base address selection followed by a normal range.
- .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000)
- .L64(0x10400).L64(0x10500)
- // An empty range followed by a normal range.
- .L64(0x10600).L64(0x10600)
- .L64(0x10800).L64(0x10900)
- // A range that starts at 0.
- .L64(0).L64(1)
- // A range that ends at -1.
- .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000)
- .L64(0).L64(0xffff_ffff_ffff_ffff)
- // A normal range with tombstone.
- .L64(tombstone).L64(tombstone)
- // A base address selection with tombstone followed by a normal range.
- .L64(0xffff_ffff_ffff_ffff).L64(tombstone)
- .L64(0x10a00).L64(0x10b00)
- // A range end.
- .L64(0).L64(0)
- // Some extra data.
- .L64(0);
-
- let buf = section.get_contents().unwrap();
- let debug_ranges = DebugRanges::new(&buf, LittleEndian);
- let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
- let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
- let offset = RangeListsOffset((&first - &start) as usize);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- };
- let mut ranges = rnglists
- .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
- .unwrap();
-
- // A normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0101_0200,
- end: 0x0101_0300,
- }))
- );
-
- // A base address selection followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0400,
- end: 0x0201_0500,
- }))
- );
-
- // An empty range followed by a normal range.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0600,
- end: 0x0201_0600,
- }))
- );
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0201_0800,
- end: 0x0201_0900,
- }))
- );
-
- // A range that starts at 0.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0200_0000,
- end: 0x0200_0001,
- }))
- );
-
- // A range that ends at -1.
- assert_eq!(
- ranges.next(),
- Ok(Some(Range {
- begin: 0x0,
- end: 0xffff_ffff_ffff_ffff,
- }))
- );
-
- // A range end.
- assert_eq!(ranges.next(), Ok(None));
-
- // An offset at the end of buf.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(buf.len()),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Ok(None));
- }
-
- #[test]
- fn test_ranges_invalid() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- // An invalid range.
- .L32(0x20000).L32(0x10000)
- // An invalid range after wrapping.
- .L32(0x20000).L32(0xff01_0000);
-
- let buf = section.get_contents().unwrap();
- let debug_ranges = DebugRanges::new(&buf, LittleEndian);
- let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
- let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
- let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
- let debug_addr_base = DebugAddrBase(0);
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
-
- // An invalid range.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(0x0),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Err(Error::InvalidAddressRange));
-
- // An invalid range after wrapping.
- let mut ranges = rnglists
- .ranges(
- RangeListsOffset(0x8),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- )
- .unwrap();
- assert_eq!(ranges.next(), Err(Error::InvalidAddressRange));
-
- // An invalid offset.
- match rnglists.ranges(
- RangeListsOffset(buf.len() + 1),
- encoding,
- 0x0100_0000,
- debug_addr,
- debug_addr_base,
- ) {
- Err(Error::UnexpectedEof(_)) => {}
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_get_offset() {
- for format in vec![Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version: 5,
- address_size: 4,
- };
-
- let zero = Label::new();
- let length = Label::new();
- let start = Label::new();
- let first = Label::new();
- let end = Label::new();
- let mut section = Section::with_endian(Endian::Little)
- .mark(&zero)
- .initial_length(format, &length, &start)
- .D16(encoding.version)
- .D8(encoding.address_size)
- .D8(0)
- .D32(20)
- .mark(&first);
- for i in 0..20 {
- section = section.word(format.word_size(), 1000 + i);
- }
- section = section.mark(&end);
- length.set_const((&end - &start) as u64);
- let section = section.get_contents().unwrap();
-
- let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian));
- let debug_rnglists = DebugRngLists::from(EndianSlice::new(&section, LittleEndian));
- let ranges = RangeLists::new(debug_ranges, debug_rnglists);
-
- let base = DebugRngListsBase((&first - &zero) as usize);
- assert_eq!(
- ranges.get_offset(encoding, base, DebugRngListsIndex(0)),
- Ok(RangeListsOffset(base.0 + 1000))
- );
- assert_eq!(
- ranges.get_offset(encoding, base, DebugRngListsIndex(19)),
- Ok(RangeListsOffset(base.0 + 1019))
- );
- }
- }
-}
diff --git a/vendor/gimli/src/read/str.rs b/vendor/gimli/src/read/str.rs
deleted file mode 100644
index c6b87d8..0000000
--- a/vendor/gimli/src/read/str.rs
+++ /dev/null
@@ -1,321 +0,0 @@
-use crate::common::{
- DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
- Encoding, SectionId,
-};
-use crate::endianity::Endianity;
-use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
-use crate::Format;
-
-/// The `DebugStr` struct represents the DWARF strings
-/// found in the `.debug_str` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugStr<R> {
- debug_str_section: R,
-}
-
-impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugStr` instance from the data in the `.debug_str`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_str` 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::{DebugStr, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_str_section_somehow = || &buf;
- /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_str_section, endian))
- }
-}
-
-impl<R: Reader> DebugStr<R> {
- /// Lookup a string from the `.debug_str` section by DebugStrOffset.
- ///
- /// ```
- /// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
- ///
- /// # let buf = [0x01, 0x02, 0x00];
- /// # let offset = DebugStrOffset(0);
- /// # let read_debug_str_section_somehow = || &buf;
- /// # let debug_str_offset_somehow = || offset;
- /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
- /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
- /// ```
- pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
- let input = &mut self.debug_str_section.clone();
- input.skip(offset.0)?;
- input.read_null_terminated_slice()
- }
-}
-
-impl<T> DebugStr<T> {
- /// Create a `DebugStr` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.debug_str_section).into()
- }
-}
-
-impl<R> Section<R> for DebugStr<R> {
- fn id() -> SectionId {
- SectionId::DebugStr
- }
-
- fn reader(&self) -> &R {
- &self.debug_str_section
- }
-}
-
-impl<R> From<R> for DebugStr<R> {
- fn from(debug_str_section: R) -> Self {
- DebugStr { debug_str_section }
- }
-}
-
-/// The raw contents of the `.debug_str_offsets` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugStrOffsets<R> {
- section: R,
-}
-
-impl<R: Reader> DebugStrOffsets<R> {
- // TODO: add an iterator over the sets of entries in the section.
- // This is not needed for common usage of the section though.
-
- /// Returns the `.debug_str` offset at the given `base` and `index`.
- ///
- /// A set of entries in the `.debug_str_offsets` section consists of a header
- /// followed by a series of string table offsets.
- ///
- /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
- /// This is an offset that points to the first entry following the header.
- ///
- /// The `index` is the value of a `DW_FORM_strx` attribute.
- ///
- /// The `format` must be the DWARF format of the compilation unit. This format must
- /// match the header. However, note that we do not parse the header to validate this,
- /// since locating the header is unreliable, and the GNU extensions do not emit it.
- pub fn get_str_offset(
- &self,
- format: Format,
- base: DebugStrOffsetsBase<R::Offset>,
- index: DebugStrOffsetsIndex<R::Offset>,
- ) -> Result<DebugStrOffset<R::Offset>> {
- let input = &mut self.section.clone();
- input.skip(base.0)?;
- input.skip(R::Offset::from_u64(
- index.0.into_u64() * u64::from(format.word_size()),
- )?)?;
- input.read_offset(format).map(DebugStrOffset)
- }
-}
-
-impl<T> DebugStrOffsets<T> {
- /// Create a `DebugStrOffsets` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.section).into()
- }
-}
-
-impl<R> Section<R> for DebugStrOffsets<R> {
- fn id() -> SectionId {
- SectionId::DebugStrOffsets
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugStrOffsets<R> {
- fn from(section: R) -> Self {
- DebugStrOffsets { section }
- }
-}
-
-impl<Offset> DebugStrOffsetsBase<Offset>
-where
- Offset: ReaderOffset,
-{
- /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
- /// for the given `Encoding` and `DwarfFileType`.
- pub fn default_for_encoding_and_file(
- encoding: Encoding,
- file_type: DwarfFileType,
- ) -> DebugStrOffsetsBase<Offset> {
- if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
- // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
- // only a single unit in the file) but we must skip past the header, which the attribute
- // would normally do for us.
- // initial_length_size + version + 2 bytes of padding.
- DebugStrOffsetsBase(Offset::from_u8(
- encoding.format.initial_length_size() + 2 + 2,
- ))
- } else {
- DebugStrOffsetsBase(Offset::from_u8(0))
- }
- }
-}
-
-/// The `DebugLineStr` struct represents the DWARF strings
-/// found in the `.debug_line_str` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugLineStr<R> {
- section: R,
-}
-
-impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_line_str` 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::{DebugLineStr, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_line_str_section_somehow = || &buf;
- /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_line_str_section, endian))
- }
-}
-
-impl<R: Reader> DebugLineStr<R> {
- /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
- pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
- let input = &mut self.section.clone();
- input.skip(offset.0)?;
- input.read_null_terminated_slice()
- }
-}
-
-impl<T> DebugLineStr<T> {
- /// Create a `DebugLineStr` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.section).into()
- }
-}
-
-impl<R> Section<R> for DebugLineStr<R> {
- fn id() -> SectionId {
- SectionId::DebugLineStr
- }
-
- fn reader(&self) -> &R {
- &self.section
- }
-}
-
-impl<R> From<R> for DebugLineStr<R> {
- fn from(section: R) -> Self {
- DebugLineStr { section }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::test_util::GimliSectionMethods;
- use crate::LittleEndian;
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- #[test]
- fn test_get_str_offset() {
- for format in vec![Format::Dwarf32, Format::Dwarf64] {
- let zero = Label::new();
- let length = Label::new();
- let start = Label::new();
- let first = Label::new();
- let end = Label::new();
- let mut section = Section::with_endian(Endian::Little)
- .mark(&zero)
- .initial_length(format, &length, &start)
- .D16(5)
- .D16(0)
- .mark(&first);
- for i in 0..20 {
- section = section.word(format.word_size(), 1000 + i);
- }
- section = section.mark(&end);
- length.set_const((&end - &start) as u64);
-
- let section = section.get_contents().unwrap();
- let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(&section, LittleEndian));
- let base = DebugStrOffsetsBase((&first - &zero) as usize);
-
- assert_eq!(
- debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
- Ok(DebugStrOffset(1000))
- );
- assert_eq!(
- debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
- Ok(DebugStrOffset(1019))
- );
- }
- }
-}
diff --git a/vendor/gimli/src/read/unit.rs b/vendor/gimli/src/read/unit.rs
deleted file mode 100644
index d799f0f..0000000
--- a/vendor/gimli/src/read/unit.rs
+++ /dev/null
@@ -1,6139 +0,0 @@
-//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections.
-
-use core::cell::Cell;
-use core::ops::{Range, RangeFrom, RangeTo};
-use core::{u16, u8};
-
-use crate::common::{
- DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset,
- DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset,
- DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
- DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format,
- LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset,
-};
-use crate::constants;
-use crate::endianity::Endianity;
-use crate::read::abbrev::get_attribute_size;
-use crate::read::{
- Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error,
- Expression, Reader, ReaderOffset, Result, Section, UnitOffset,
-};
-
-impl<T: ReaderOffset> DebugTypesOffset<T> {
- /// Convert an offset to be relative to the start of the given unit,
- /// instead of relative to the start of the .debug_types section.
- /// Returns `None` if the offset is not within the unit entries.
- pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
- where
- R: Reader<Offset = T>,
- {
- let unit_offset = unit.offset().as_debug_types_offset()?;
- let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
- if !unit.is_valid_offset(offset) {
- return None;
- }
- Some(offset)
- }
-}
-
-impl<T: ReaderOffset> DebugInfoOffset<T> {
- /// Convert an offset to be relative to the start of the given unit,
- /// instead of relative to the start of the .debug_info section.
- /// Returns `None` if the offset is not within this unit entries.
- pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
- where
- R: Reader<Offset = T>,
- {
- let unit_offset = unit.offset().as_debug_info_offset()?;
- let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
- if !unit.is_valid_offset(offset) {
- return None;
- }
- Some(offset)
- }
-}
-
-impl<T: ReaderOffset> UnitOffset<T> {
- /// Convert an offset to be relative to the start of the .debug_info section,
- /// instead of relative to the start of the given unit. Returns None if the
- /// provided unit lives in the .debug_types section.
- pub fn to_debug_info_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugInfoOffset<T>>
- where
- R: Reader<Offset = T>,
- {
- let unit_offset = unit.offset().as_debug_info_offset()?;
- Some(DebugInfoOffset(unit_offset.0 + self.0))
- }
-
- /// Convert an offset to be relative to the start of the .debug_types section,
- /// instead of relative to the start of the given unit. Returns None if the
- /// provided unit lives in the .debug_info section.
- pub fn to_debug_types_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugTypesOffset<T>>
- where
- R: Reader<Offset = T>,
- {
- let unit_offset = unit.offset().as_debug_types_offset()?;
- Some(DebugTypesOffset(unit_offset.0 + self.0))
- }
-}
-
-/// The `DebugInfo` struct represents the DWARF debugging information found in
-/// the `.debug_info` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugInfo<R> {
- debug_info_section: R,
-}
-
-impl<'input, Endian> DebugInfo<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugInfo` instance from the data in the `.debug_info`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_info` section and
- /// present it as a `&[u8]` slice. That means using some ELF loader on
- /// Linux, a Mach-O loader on macOS, etc.
- ///
- /// ```
- /// use gimli::{DebugInfo, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_info_section_somehow = || &buf;
- /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_info_section, endian))
- }
-}
-
-impl<R: Reader> DebugInfo<R> {
- /// Iterate the units in this `.debug_info` section.
- ///
- /// ```
- /// use gimli::{DebugInfo, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_info_section_somehow = || &buf;
- /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
- ///
- /// let mut iter = debug_info.units();
- /// while let Some(unit) = iter.next().unwrap() {
- /// println!("unit's length is {}", unit.unit_length());
- /// }
- /// ```
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
- DebugInfoUnitHeadersIter {
- input: self.debug_info_section.clone(),
- offset: DebugInfoOffset(R::Offset::from_u8(0)),
- }
- }
-
- /// Get the UnitHeader located at offset from this .debug_info section.
- ///
- ///
- pub fn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> {
- let input = &mut self.debug_info_section.clone();
- input.skip(offset.0)?;
- parse_unit_header(input, offset.into())
- }
-}
-
-impl<T> DebugInfo<T> {
- /// Create a `DebugInfo` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugInfo<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.debug_info_section).into()
- }
-}
-
-impl<R> Section<R> for DebugInfo<R> {
- fn id() -> SectionId {
- SectionId::DebugInfo
- }
-
- fn reader(&self) -> &R {
- &self.debug_info_section
- }
-}
-
-impl<R> From<R> for DebugInfo<R> {
- fn from(debug_info_section: R) -> Self {
- DebugInfo { debug_info_section }
- }
-}
-
-/// An iterator over the units of a .debug_info section.
-///
-/// See the [documentation on
-/// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail.
-#[derive(Clone, Debug)]
-pub struct DebugInfoUnitHeadersIter<R: Reader> {
- input: R,
- offset: DebugInfoOffset<R::Offset>,
-}
-
-impl<R: Reader> DebugInfoUnitHeadersIter<R> {
- /// Advance the iterator to the next unit header.
- pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
- if self.input.is_empty() {
- Ok(None)
- } else {
- let len = self.input.len();
- match parse_unit_header(&mut self.input, self.offset.into()) {
- Ok(header) => {
- self.offset.0 += len - self.input.len();
- Ok(Some(header))
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter<R> {
- type Item = UnitHeader<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- DebugInfoUnitHeadersIter::next(self)
- }
-}
-
-/// Parse the unit type from the unit header.
-fn parse_unit_type<R: Reader>(input: &mut R) -> Result<constants::DwUt> {
- let val = input.read_u8()?;
- Ok(constants::DwUt(val))
-}
-
-/// Parse the `debug_abbrev_offset` in the compilation unit header.
-fn parse_debug_abbrev_offset<R: Reader>(
- input: &mut R,
- format: Format,
-) -> Result<DebugAbbrevOffset<R::Offset>> {
- input.read_offset(format).map(DebugAbbrevOffset)
-}
-
-/// Parse the `debug_info_offset` in the arange header.
-pub(crate) fn parse_debug_info_offset<R: Reader>(
- input: &mut R,
- format: Format,
-) -> Result<DebugInfoOffset<R::Offset>> {
- input.read_offset(format).map(DebugInfoOffset)
-}
-
-/// This enum specifies the type of the unit and any type
-/// specific data carried in the header (e.g. the type
-/// signature/type offset of a type unit).
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum UnitType<Offset>
-where
- Offset: ReaderOffset,
-{
- /// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions,
- /// any unit appearing in the .debug_info section.
- Compilation,
- /// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing
- /// in the .debug_types section.
- Type {
- /// The unique type signature for this type unit.
- type_signature: DebugTypeSignature,
- /// The offset within this type unit where the type is defined.
- type_offset: UnitOffset<Offset>,
- },
- /// A unit with type `DW_UT_partial`. The root DIE of this unit should be a
- /// `DW_TAG_partial_unit`.
- Partial,
- /// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to
- /// link this with the corresponding `SplitCompilation` unit in a dwo file.
- /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
- /// be a `Compilation` unit with the dwo_id present as an attribute on the
- /// root DIE.
- Skeleton(DwoId),
- /// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to
- /// link this with the corresponding `Skeleton` unit in the original binary.
- /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead
- /// be a `Compilation` unit with the dwo_id present as an attribute on the
- /// root DIE.
- SplitCompilation(DwoId),
- /// A unit with type `DW_UT_split_type`. A split type unit is identical to a
- /// conventional type unit except for the section in which it appears.
- SplitType {
- /// The unique type signature for this type unit.
- type_signature: DebugTypeSignature,
- /// The offset within this type unit where the type is defined.
- type_offset: UnitOffset<Offset>,
- },
-}
-
-impl<Offset> UnitType<Offset>
-where
- Offset: ReaderOffset,
-{
- // TODO: This will be used by the DWARF writing code once it
- // supports unit types other than simple compilation units.
- #[allow(unused)]
- pub(crate) fn dw_ut(&self) -> constants::DwUt {
- match self {
- UnitType::Compilation => constants::DW_UT_compile,
- UnitType::Type { .. } => constants::DW_UT_type,
- UnitType::Partial => constants::DW_UT_partial,
- UnitType::Skeleton(_) => constants::DW_UT_skeleton,
- UnitType::SplitCompilation(_) => constants::DW_UT_split_compile,
- UnitType::SplitType { .. } => constants::DW_UT_split_type,
- }
- }
-}
-
-/// The common fields for the headers of compilation units and
-/// type units.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct UnitHeader<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- encoding: Encoding,
- unit_length: Offset,
- unit_type: UnitType<Offset>,
- debug_abbrev_offset: DebugAbbrevOffset<Offset>,
- unit_offset: UnitSectionOffset<Offset>,
- entries_buf: R,
-}
-
-/// Static methods.
-impl<R, Offset> UnitHeader<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Construct a new `UnitHeader`.
- pub fn new(
- encoding: Encoding,
- unit_length: Offset,
- unit_type: UnitType<Offset>,
- debug_abbrev_offset: DebugAbbrevOffset<Offset>,
- unit_offset: UnitSectionOffset<Offset>,
- entries_buf: R,
- ) -> Self {
- UnitHeader {
- encoding,
- unit_length,
- unit_type,
- debug_abbrev_offset,
- unit_offset,
- entries_buf,
- }
- }
-}
-
-/// Instance methods.
-impl<R, Offset> UnitHeader<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Get the offset of this unit within its section.
- pub fn offset(&self) -> UnitSectionOffset<Offset> {
- self.unit_offset
- }
-
- /// Return the serialized size of the common unit header for the given
- /// DWARF format.
- pub fn size_of_header(&self) -> usize {
- let unit_length_size = self.encoding.format.initial_length_size() as usize;
- let version_size = 2;
- let debug_abbrev_offset_size = self.encoding.format.word_size() as usize;
- let address_size_size = 1;
- let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 };
- let type_specific_size = match self.unit_type {
- UnitType::Compilation | UnitType::Partial => 0,
- UnitType::Type { .. } | UnitType::SplitType { .. } => {
- let type_signature_size = 8;
- let type_offset_size = self.encoding.format.word_size() as usize;
- type_signature_size + type_offset_size
- }
- UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8,
- };
-
- unit_length_size
- + version_size
- + debug_abbrev_offset_size
- + address_size_size
- + unit_type_size
- + type_specific_size
- }
-
- /// Get the length of the debugging info for this compilation unit, not
- /// including the byte length of the encoded length itself.
- pub fn unit_length(&self) -> Offset {
- self.unit_length
- }
-
- /// Get the length of the debugging info for this compilation unit,
- /// including the byte length of the encoded length itself.
- pub fn length_including_self(&self) -> Offset {
- Offset::from_u8(self.format().initial_length_size()) + self.unit_length
- }
-
- /// Return the encoding parameters for this unit.
- pub fn encoding(&self) -> Encoding {
- self.encoding
- }
-
- /// Get the DWARF version of the debugging info for this compilation unit.
- pub fn version(&self) -> u16 {
- self.encoding.version
- }
-
- /// Get the UnitType of this unit.
- pub fn type_(&self) -> UnitType<Offset> {
- self.unit_type
- }
-
- /// The offset into the `.debug_abbrev` section for this compilation unit's
- /// debugging information entries' abbreviations.
- pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> {
- self.debug_abbrev_offset
- }
-
- /// The size of addresses (in bytes) in this compilation unit.
- pub fn address_size(&self) -> u8 {
- self.encoding.address_size
- }
-
- /// Whether this compilation unit is encoded in 64- or 32-bit DWARF.
- pub fn format(&self) -> Format {
- self.encoding.format
- }
-
- /// The serialized size of the header for this compilation unit.
- pub fn header_size(&self) -> Offset {
- self.length_including_self() - self.entries_buf.len()
- }
-
- pub(crate) fn is_valid_offset(&self, offset: UnitOffset<Offset>) -> bool {
- let size_of_header = self.header_size();
- if offset.0 < size_of_header {
- return false;
- }
-
- let relative_to_entries_buf = offset.0 - size_of_header;
- relative_to_entries_buf < self.entries_buf.len()
- }
-
- /// Get the underlying bytes for the supplied range.
- pub fn range(&self, idx: Range<UnitOffset<Offset>>) -> Result<R> {
- if !self.is_valid_offset(idx.start) {
- return Err(Error::OffsetOutOfBounds);
- }
- if !self.is_valid_offset(idx.end) {
- return Err(Error::OffsetOutOfBounds);
- }
- assert!(idx.start <= idx.end);
- let size_of_header = self.header_size();
- let start = idx.start.0 - size_of_header;
- let end = idx.end.0 - size_of_header;
- let mut input = self.entries_buf.clone();
- input.skip(start)?;
- input.truncate(end - start)?;
- Ok(input)
- }
-
- /// Get the underlying bytes for the supplied range.
- pub fn range_from(&self, idx: RangeFrom<UnitOffset<Offset>>) -> Result<R> {
- if !self.is_valid_offset(idx.start) {
- return Err(Error::OffsetOutOfBounds);
- }
- let start = idx.start.0 - self.header_size();
- let mut input = self.entries_buf.clone();
- input.skip(start)?;
- Ok(input)
- }
-
- /// Get the underlying bytes for the supplied range.
- pub fn range_to(&self, idx: RangeTo<UnitOffset<Offset>>) -> Result<R> {
- if !self.is_valid_offset(idx.end) {
- return Err(Error::OffsetOutOfBounds);
- }
- let end = idx.end.0 - self.header_size();
- let mut input = self.entries_buf.clone();
- input.truncate(end)?;
- Ok(input)
- }
-
- /// Read the `DebuggingInformationEntry` at the given offset.
- pub fn entry<'me, 'abbrev>(
- &'me self,
- abbreviations: &'abbrev Abbreviations,
- offset: UnitOffset<Offset>,
- ) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> {
- let mut input = self.range_from(offset..)?;
- let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?;
- entry.ok_or(Error::NoEntryAtGivenOffset)
- }
-
- /// Navigate this unit's `DebuggingInformationEntry`s.
- pub fn entries<'me, 'abbrev>(
- &'me self,
- abbreviations: &'abbrev Abbreviations,
- ) -> EntriesCursor<'abbrev, 'me, R> {
- EntriesCursor {
- unit: self,
- input: self.entries_buf.clone(),
- abbreviations,
- cached_current: None,
- delta_depth: 0,
- }
- }
-
- /// Navigate this compilation unit's `DebuggingInformationEntry`s
- /// starting at the given offset.
- pub fn entries_at_offset<'me, 'abbrev>(
- &'me self,
- abbreviations: &'abbrev Abbreviations,
- offset: UnitOffset<Offset>,
- ) -> Result<EntriesCursor<'abbrev, 'me, R>> {
- let input = self.range_from(offset..)?;
- Ok(EntriesCursor {
- unit: self,
- input,
- abbreviations,
- cached_current: None,
- delta_depth: 0,
- })
- }
-
- /// Navigate this unit's `DebuggingInformationEntry`s as a tree
- /// starting at the given offset.
- pub fn entries_tree<'me, 'abbrev>(
- &'me self,
- abbreviations: &'abbrev Abbreviations,
- offset: Option<UnitOffset<Offset>>,
- ) -> Result<EntriesTree<'abbrev, 'me, R>> {
- let input = match offset {
- Some(offset) => self.range_from(offset..)?,
- None => self.entries_buf.clone(),
- };
- Ok(EntriesTree::new(input, self, abbreviations))
- }
-
- /// Read the raw data that defines the Debugging Information Entries.
- pub fn entries_raw<'me, 'abbrev>(
- &'me self,
- abbreviations: &'abbrev Abbreviations,
- offset: Option<UnitOffset<Offset>>,
- ) -> Result<EntriesRaw<'abbrev, 'me, R>> {
- let input = match offset {
- Some(offset) => self.range_from(offset..)?,
- None => self.entries_buf.clone(),
- };
- Ok(EntriesRaw {
- input,
- unit: self,
- abbreviations,
- depth: 0,
- })
- }
-
- /// Parse this unit's abbreviations.
- pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev<R>) -> Result<Abbreviations> {
- debug_abbrev.abbreviations(self.debug_abbrev_offset())
- }
-}
-
-/// Parse a unit header.
-fn parse_unit_header<R, Offset>(
- input: &mut R,
- unit_offset: UnitSectionOffset<Offset>,
-) -> Result<UnitHeader<R>>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- let (unit_length, format) = input.read_initial_length()?;
- let mut rest = input.split(unit_length)?;
-
- let version = rest.read_u16()?;
- let abbrev_offset;
- let address_size;
- let unit_type;
- // DWARF 1 was very different, and is obsolete, so isn't supported by this
- // reader.
- if 2 <= version && version <= 4 {
- abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
- address_size = rest.read_u8()?;
- // Before DWARF5, all units in the .debug_info section are compilation
- // units, and all units in the .debug_types section are type units.
- unit_type = match unit_offset {
- UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile,
- UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type,
- };
- } else if version == 5 {
- unit_type = parse_unit_type(&mut rest)?;
- address_size = rest.read_u8()?;
- abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
- } else {
- return Err(Error::UnknownVersion(u64::from(version)));
- }
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
-
- // Parse any data specific to this type of unit.
- let unit_type = match unit_type {
- constants::DW_UT_compile => UnitType::Compilation,
- constants::DW_UT_type => {
- let type_signature = parse_type_signature(&mut rest)?;
- let type_offset = parse_type_offset(&mut rest, format)?;
- UnitType::Type {
- type_signature,
- type_offset,
- }
- }
- constants::DW_UT_partial => UnitType::Partial,
- constants::DW_UT_skeleton => {
- let dwo_id = parse_dwo_id(&mut rest)?;
- UnitType::Skeleton(dwo_id)
- }
- constants::DW_UT_split_compile => {
- let dwo_id = parse_dwo_id(&mut rest)?;
- UnitType::SplitCompilation(dwo_id)
- }
- constants::DW_UT_split_type => {
- let type_signature = parse_type_signature(&mut rest)?;
- let type_offset = parse_type_offset(&mut rest, format)?;
- UnitType::SplitType {
- type_signature,
- type_offset,
- }
- }
- _ => return Err(Error::UnsupportedUnitType),
- };
-
- Ok(UnitHeader::new(
- encoding,
- unit_length,
- unit_type,
- abbrev_offset,
- unit_offset,
- rest,
- ))
-}
-
-/// Parse a dwo_id from a header
-fn parse_dwo_id<R: Reader>(input: &mut R) -> Result<DwoId> {
- Ok(DwoId(input.read_u64()?))
-}
-
-/// A Debugging Information Entry (DIE).
-///
-/// DIEs have a set of attributes and optionally have children DIEs as well.
-#[derive(Clone, Debug)]
-pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- offset: UnitOffset<Offset>,
- attrs_slice: R,
- attrs_len: Cell<Option<Offset>>,
- abbrev: &'abbrev Abbreviation,
- unit: &'unit UnitHeader<R, Offset>,
-}
-
-impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Construct a new `DebuggingInformationEntry`.
- pub fn new(
- offset: UnitOffset<Offset>,
- attrs_slice: R,
- abbrev: &'abbrev Abbreviation,
- unit: &'unit UnitHeader<R, Offset>,
- ) -> Self {
- DebuggingInformationEntry {
- offset,
- attrs_slice,
- attrs_len: Cell::new(None),
- abbrev,
- unit,
- }
- }
-
- /// Get this entry's code.
- pub fn code(&self) -> u64 {
- self.abbrev.code()
- }
-
- /// Get this entry's offset.
- pub fn offset(&self) -> UnitOffset<Offset> {
- self.offset
- }
-
- /// Get this entry's `DW_TAG_whatever` tag.
- ///
- /// ```
- /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
- /// # let info_buf = [
- /// # // Comilation unit header
- /// #
- /// # // 32-bit unit length = 12
- /// # 0x0c, 0x00, 0x00, 0x00,
- /// # // Version 4
- /// # 0x04, 0x00,
- /// # // debug_abbrev_offset
- /// # 0x00, 0x00, 0x00, 0x00,
- /// # // Address size
- /// # 0x04,
- /// #
- /// # // DIEs
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// # ];
- /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian);
- /// # let abbrev_buf = [
- /// # // Code
- /// # 0x01,
- /// # // DW_TAG_subprogram
- /// # 0x2e,
- /// # // DW_CHILDREN_no
- /// # 0x00,
- /// # // Begin attributes
- /// # // Attribute name = DW_AT_name
- /// # 0x03,
- /// # // Attribute form = DW_FORM_string
- /// # 0x08,
- /// # // End attributes
- /// # 0x00,
- /// # 0x00,
- /// # // Null terminator
- /// # 0x00
- /// # ];
- /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
- /// # let unit = debug_info.units().next().unwrap().unwrap();
- /// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
- /// # let mut cursor = unit.entries(&abbrevs);
- /// # let (_, entry) = cursor.next_dfs().unwrap().unwrap();
- /// # let mut get_some_entry = || entry;
- /// let entry = get_some_entry();
- ///
- /// match entry.tag() {
- /// gimli::DW_TAG_subprogram =>
- /// println!("this entry contains debug info about a function"),
- /// gimli::DW_TAG_inlined_subroutine =>
- /// println!("this entry contains debug info about a particular instance of inlining"),
- /// gimli::DW_TAG_variable =>
- /// println!("this entry contains debug info about a local variable"),
- /// gimli::DW_TAG_formal_parameter =>
- /// println!("this entry contains debug info about a function parameter"),
- /// otherwise =>
- /// println!("this entry is some other kind of data: {:?}", otherwise),
- /// };
- /// ```
- pub fn tag(&self) -> constants::DwTag {
- self.abbrev.tag()
- }
-
- /// Return true if this entry's type can have children, false otherwise.
- pub fn has_children(&self) -> bool {
- self.abbrev.has_children()
- }
-
- /// Iterate over this entry's set of attributes.
- ///
- /// ```
- /// use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
- ///
- /// // Read the `.debug_info` section.
- ///
- /// # let info_buf = [
- /// # // Comilation unit header
- /// #
- /// # // 32-bit unit length = 12
- /// # 0x0c, 0x00, 0x00, 0x00,
- /// # // Version 4
- /// # 0x04, 0x00,
- /// # // debug_abbrev_offset
- /// # 0x00, 0x00, 0x00, 0x00,
- /// # // Address size
- /// # 0x04,
- /// #
- /// # // DIEs
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// # ];
- /// # let read_debug_info_section_somehow = || &info_buf;
- /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian);
- ///
- /// // Get the data about the first compilation unit out of the `.debug_info`.
- ///
- /// let unit = debug_info.units().next()
- /// .expect("Should have at least one compilation unit")
- /// .expect("and it should parse ok");
- ///
- /// // Read the `.debug_abbrev` section and parse the
- /// // abbreviations for our compilation unit.
- ///
- /// # let abbrev_buf = [
- /// # // Code
- /// # 0x01,
- /// # // DW_TAG_subprogram
- /// # 0x2e,
- /// # // DW_CHILDREN_no
- /// # 0x00,
- /// # // Begin attributes
- /// # // Attribute name = DW_AT_name
- /// # 0x03,
- /// # // Attribute form = DW_FORM_string
- /// # 0x08,
- /// # // End attributes
- /// # 0x00,
- /// # 0x00,
- /// # // Null terminator
- /// # 0x00
- /// # ];
- /// # let read_debug_abbrev_section_somehow = || &abbrev_buf;
- /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian);
- /// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap();
- ///
- /// // Get the first entry from that compilation unit.
- ///
- /// let mut cursor = unit.entries(&abbrevs);
- /// let (_, entry) = cursor.next_dfs()
- /// .expect("Should parse next entry")
- /// .expect("Should have at least one entry");
- ///
- /// // Finally, print the first entry's attributes.
- ///
- /// let mut attrs = entry.attrs();
- /// while let Some(attr) = attrs.next().unwrap() {
- /// println!("Attribute name = {:?}", attr.name());
- /// println!("Attribute value = {:?}", attr.value());
- /// }
- /// ```
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> {
- AttrsIter {
- input: self.attrs_slice.clone(),
- attributes: self.abbrev.attributes(),
- entry: self,
- }
- }
-
- /// Find the first attribute in this entry which has the given name,
- /// and return it. Returns `Ok(None)` if no attribute is found.
- pub fn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> {
- let mut attrs = self.attrs();
- while let Some(attr) = attrs.next()? {
- if attr.name() == name {
- return Ok(Some(attr));
- }
- }
- Ok(None)
- }
-
- /// Find the first attribute in this entry which has the given name,
- /// and return its raw value. Returns `Ok(None)` if no attribute is found.
- pub fn attr_value_raw(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
- self.attr(name)
- .map(|attr| attr.map(|attr| attr.raw_value()))
- }
-
- /// Find the first attribute in this entry which has the given name,
- /// and return its normalized value. Returns `Ok(None)` if no
- /// attribute is found.
- pub fn attr_value(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
- self.attr(name).map(|attr| attr.map(|attr| attr.value()))
- }
-
- /// Return the input buffer after the last attribute.
- #[inline(always)]
- fn after_attrs(&self) -> Result<R> {
- if let Some(attrs_len) = self.attrs_len.get() {
- let mut input = self.attrs_slice.clone();
- input.skip(attrs_len)?;
- Ok(input)
- } else {
- let mut attrs = self.attrs();
- while attrs.next()?.is_some() {}
- Ok(attrs.input)
- }
- }
-
- /// Use the `DW_AT_sibling` attribute to find the input buffer for the
- /// next sibling. Returns `None` if the attribute is missing or invalid.
- fn sibling(&self) -> Option<R> {
- let attr = self.attr_value(constants::DW_AT_sibling);
- if let Ok(Some(AttributeValue::UnitRef(offset))) = attr {
- if offset.0 > self.offset.0 {
- if let Ok(input) = self.unit.range_from(offset..) {
- return Some(input);
- }
- }
- }
- None
- }
-
- /// Parse an entry. Returns `Ok(None)` for null entries.
- #[inline(always)]
- fn parse(
- input: &mut R,
- unit: &'unit UnitHeader<R>,
- abbreviations: &'abbrev Abbreviations,
- ) -> Result<Option<Self>> {
- let offset = unit.header_size() + input.offset_from(&unit.entries_buf);
- let code = input.read_uleb128()?;
- if code == 0 {
- return Ok(None);
- };
- let abbrev = abbreviations.get(code).ok_or(Error::UnknownAbbreviation)?;
- Ok(Some(DebuggingInformationEntry {
- offset: UnitOffset(offset),
- attrs_slice: input.clone(),
- attrs_len: Cell::new(None),
- abbrev,
- unit,
- }))
- }
-}
-
-/// The value of an attribute in a `DebuggingInformationEntry`.
-//
-// Set the discriminant size so that all variants use the same alignment
-// for their data. This gives better code generation in `parse_attribute`.
-#[repr(u64)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum AttributeValue<R, Offset = <R as Reader>::Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// "Refers to some location in the address space of the described program."
- Addr(u64),
-
- /// A slice of an arbitrary number of bytes.
- Block(R),
-
- /// A one byte constant data value. How to interpret the byte depends on context.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data1(u8),
-
- /// A two byte constant data value. How to interpret the bytes depends on context.
- ///
- /// These bytes have been converted from `R::Endian`. This may need to be reversed
- /// if this was not required.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data2(u16),
-
- /// A four byte constant data value. How to interpret the bytes depends on context.
- ///
- /// These bytes have been converted from `R::Endian`. This may need to be reversed
- /// if this was not required.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data4(u32),
-
- /// An eight byte constant data value. How to interpret the bytes depends on context.
- ///
- /// These bytes have been converted from `R::Endian`. This may need to be reversed
- /// if this was not required.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data8(u64),
-
- /// A signed integer constant.
- Sdata(i64),
-
- /// An unsigned integer constant.
- Udata(u64),
-
- /// "The information bytes contain a DWARF expression (see Section 2.5) or
- /// location description (see Section 2.6)."
- Exprloc(Expression<R>),
-
- /// A boolean that indicates presence or absence of the attribute.
- Flag(bool),
-
- /// An offset into another section. Which section this is an offset into
- /// depends on context.
- SecOffset(Offset),
-
- /// An offset to a set of addresses in the `.debug_addr` section.
- DebugAddrBase(DebugAddrBase<Offset>),
-
- /// An index into a set of addresses in the `.debug_addr` section.
- DebugAddrIndex(DebugAddrIndex<Offset>),
-
- /// An offset into the current compilation unit.
- UnitRef(UnitOffset<Offset>),
-
- /// An offset into the current `.debug_info` section, but possibly a
- /// different compilation unit from the current one.
- DebugInfoRef(DebugInfoOffset<Offset>),
-
- /// An offset into the `.debug_info` section of the supplementary object file.
- DebugInfoRefSup(DebugInfoOffset<Offset>),
-
- /// An offset into the `.debug_line` section.
- DebugLineRef(DebugLineOffset<Offset>),
-
- /// An offset into either the `.debug_loc` section or the `.debug_loclists` section.
- LocationListsRef(LocationListsOffset<Offset>),
-
- /// An offset to a set of offsets in the `.debug_loclists` section.
- DebugLocListsBase(DebugLocListsBase<Offset>),
-
- /// An index into a set of offsets in the `.debug_loclists` section.
- DebugLocListsIndex(DebugLocListsIndex<Offset>),
-
- /// An offset into the `.debug_macinfo` section.
- DebugMacinfoRef(DebugMacinfoOffset<Offset>),
-
- /// An offset into the `.debug_macro` section.
- DebugMacroRef(DebugMacroOffset<Offset>),
-
- /// An offset into the `.debug_ranges` section.
- RangeListsRef(RawRangeListsOffset<Offset>),
-
- /// An offset to a set of offsets in the `.debug_rnglists` section.
- DebugRngListsBase(DebugRngListsBase<Offset>),
-
- /// An index into a set of offsets in the `.debug_rnglists` section.
- DebugRngListsIndex(DebugRngListsIndex<Offset>),
-
- /// A type signature.
- DebugTypesRef(DebugTypeSignature),
-
- /// An offset into the `.debug_str` section.
- DebugStrRef(DebugStrOffset<Offset>),
-
- /// An offset into the `.debug_str` section of the supplementary object file.
- DebugStrRefSup(DebugStrOffset<Offset>),
-
- /// An offset to a set of entries in the `.debug_str_offsets` section.
- DebugStrOffsetsBase(DebugStrOffsetsBase<Offset>),
-
- /// An index into a set of entries in the `.debug_str_offsets` section.
- DebugStrOffsetsIndex(DebugStrOffsetsIndex<Offset>),
-
- /// An offset into the `.debug_line_str` section.
- DebugLineStrRef(DebugLineStrOffset<Offset>),
-
- /// A slice of bytes representing a string. Does not include a final null byte.
- /// Not guaranteed to be UTF-8 or anything like that.
- String(R),
-
- /// The value of a `DW_AT_encoding` attribute.
- Encoding(constants::DwAte),
-
- /// The value of a `DW_AT_decimal_sign` attribute.
- DecimalSign(constants::DwDs),
-
- /// The value of a `DW_AT_endianity` attribute.
- Endianity(constants::DwEnd),
-
- /// The value of a `DW_AT_accessibility` attribute.
- Accessibility(constants::DwAccess),
-
- /// The value of a `DW_AT_visibility` attribute.
- Visibility(constants::DwVis),
-
- /// The value of a `DW_AT_virtuality` attribute.
- Virtuality(constants::DwVirtuality),
-
- /// The value of a `DW_AT_language` attribute.
- Language(constants::DwLang),
-
- /// The value of a `DW_AT_address_class` attribute.
- AddressClass(constants::DwAddr),
-
- /// The value of a `DW_AT_identifier_case` attribute.
- IdentifierCase(constants::DwId),
-
- /// The value of a `DW_AT_calling_convention` attribute.
- CallingConvention(constants::DwCc),
-
- /// The value of a `DW_AT_inline` attribute.
- Inline(constants::DwInl),
-
- /// The value of a `DW_AT_ordering` attribute.
- Ordering(constants::DwOrd),
-
- /// An index into the filename entries from the line number information
- /// table for the compilation unit containing this value.
- FileIndex(u64),
-
- /// An implementation-defined identifier uniquely identifying a compilation
- /// unit.
- DwoId(DwoId),
-}
-
-/// An attribute in a `DebuggingInformationEntry`, consisting of a name and
-/// associated value.
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct Attribute<R: Reader> {
- name: constants::DwAt,
- value: AttributeValue<R>,
-}
-
-impl<R: Reader> Attribute<R> {
- /// Get this attribute's name.
- pub fn name(&self) -> constants::DwAt {
- self.name
- }
-
- /// Get this attribute's raw value.
- pub fn raw_value(&self) -> AttributeValue<R> {
- self.value.clone()
- }
-
- /// Get this attribute's normalized value.
- ///
- /// Attribute values can potentially be encoded in multiple equivalent forms,
- /// and may have special meaning depending on the attribute name. This method
- /// converts the attribute value to a normalized form based on the attribute
- /// name.
- ///
- /// See "Table 7.5: Attribute encodings" and "Table 7.6: Attribute form encodings".
- pub fn value(&self) -> AttributeValue<R> {
- // Table 7.5 shows the possible attribute classes for each name.
- // Table 7.6 shows the possible attribute classes for each form.
- // For each attribute name, we need to match on the form, and
- // convert it to one of the classes that is allowed for both
- // the name and the form.
- //
- // The individual class conversions rarely vary for each name,
- // so for each class conversion we define a macro that matches
- // on the allowed forms for that class.
- //
- // For some classes, we don't need to do any conversion, so their
- // macro is empty. In the future we may want to fill them in to
- // provide strict checking of the forms for each class. For now,
- // they simply provide a way to document the allowed classes for
- // each name.
-
- // DW_FORM_addr
- // DW_FORM_addrx
- // DW_FORM_addrx1
- // DW_FORM_addrx2
- // DW_FORM_addrx3
- // DW_FORM_addrx4
- macro_rules! address {
- () => {};
- }
- // DW_FORM_sec_offset
- macro_rules! addrptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugAddrBase(DebugAddrBase(offset));
- }
- };
- }
- // DW_FORM_block
- // DW_FORM_block1
- // DW_FORM_block2
- // DW_FORM_block4
- macro_rules! block {
- () => {};
- }
- // DW_FORM_sdata
- // DW_FORM_udata
- // DW_FORM_data1
- // DW_FORM_data2
- // DW_FORM_data4
- // DW_FORM_data8
- // DW_FORM_data16
- // DW_FORM_implicit_const
- macro_rules! constant {
- ($value:ident, $variant:ident) => {
- if let Some(value) = self.$value() {
- return AttributeValue::$variant(value);
- }
- };
- ($value:ident, $variant:ident, $constant:ident) => {
- if let Some(value) = self.$value() {
- return AttributeValue::$variant(constants::$constant(value));
- }
- };
- }
- // DW_FORM_exprloc
- macro_rules! exprloc {
- () => {
- if let Some(value) = self.exprloc_value() {
- return AttributeValue::Exprloc(value);
- }
- };
- }
- // DW_FORM_flag
- // DW_FORM_flag_present
- macro_rules! flag {
- () => {};
- }
- // DW_FORM_sec_offset
- macro_rules! lineptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugLineRef(DebugLineOffset(offset));
- }
- };
- }
- // This also covers `loclist` in DWARF version 5.
- // DW_FORM_sec_offset
- // DW_FORM_loclistx
- macro_rules! loclistptr {
- () => {
- // DebugLocListsIndex is also an allowed form in DWARF version 5.
- if let Some(offset) = self.offset_value() {
- return AttributeValue::LocationListsRef(LocationListsOffset(offset));
- }
- };
- }
- // DW_FORM_sec_offset
- macro_rules! loclistsptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset));
- }
- };
- }
- // DWARF version <= 4.
- // DW_FORM_sec_offset
- macro_rules! macinfoptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset));
- }
- };
- }
- // DWARF version >= 5.
- // DW_FORM_sec_offset
- macro_rules! macroptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugMacroRef(DebugMacroOffset(offset));
- }
- };
- }
- // DW_FORM_ref_addr
- // DW_FORM_ref1
- // DW_FORM_ref2
- // DW_FORM_ref4
- // DW_FORM_ref8
- // DW_FORM_ref_udata
- // DW_FORM_ref_sig8
- // DW_FORM_ref_sup4
- // DW_FORM_ref_sup8
- macro_rules! reference {
- () => {};
- }
- // This also covers `rnglist` in DWARF version 5.
- // DW_FORM_sec_offset
- // DW_FORM_rnglistx
- macro_rules! rangelistptr {
- () => {
- // DebugRngListsIndex is also an allowed form in DWARF version 5.
- if let Some(offset) = self.offset_value() {
- return AttributeValue::RangeListsRef(RawRangeListsOffset(offset));
- }
- };
- }
- // DW_FORM_sec_offset
- macro_rules! rnglistsptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset));
- }
- };
- }
- // DW_FORM_string
- // DW_FORM_strp
- // DW_FORM_strx
- // DW_FORM_strx1
- // DW_FORM_strx2
- // DW_FORM_strx3
- // DW_FORM_strx4
- // DW_FORM_strp_sup
- // DW_FORM_line_strp
- macro_rules! string {
- () => {};
- }
- // DW_FORM_sec_offset
- macro_rules! stroffsetsptr {
- () => {
- if let Some(offset) = self.offset_value() {
- return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset));
- }
- };
- }
- // This isn't a separate form but it's useful to distinguish it from a generic udata.
- macro_rules! dwoid {
- () => {
- if let Some(value) = self.udata_value() {
- return AttributeValue::DwoId(DwoId(value));
- }
- };
- }
-
- // Perform the allowed class conversions for each attribute name.
- match self.name {
- constants::DW_AT_sibling => {
- reference!();
- }
- constants::DW_AT_location => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_name => {
- string!();
- }
- constants::DW_AT_ordering => {
- constant!(u8_value, Ordering, DwOrd);
- }
- constants::DW_AT_byte_size
- | constants::DW_AT_bit_offset
- | constants::DW_AT_bit_size => {
- constant!(udata_value, Udata);
- exprloc!();
- reference!();
- }
- constants::DW_AT_stmt_list => {
- lineptr!();
- }
- constants::DW_AT_low_pc => {
- address!();
- }
- constants::DW_AT_high_pc => {
- address!();
- constant!(udata_value, Udata);
- }
- constants::DW_AT_language => {
- constant!(u16_value, Language, DwLang);
- }
- constants::DW_AT_discr => {
- reference!();
- }
- constants::DW_AT_discr_value => {
- // constant: depends on type of DW_TAG_variant_part,
- // so caller must normalize.
- }
- constants::DW_AT_visibility => {
- constant!(u8_value, Visibility, DwVis);
- }
- constants::DW_AT_import => {
- reference!();
- }
- constants::DW_AT_string_length => {
- exprloc!();
- loclistptr!();
- reference!();
- }
- constants::DW_AT_common_reference => {
- reference!();
- }
- constants::DW_AT_comp_dir => {
- string!();
- }
- constants::DW_AT_const_value => {
- // TODO: constant: sign depends on DW_AT_type.
- block!();
- string!();
- }
- constants::DW_AT_containing_type => {
- reference!();
- }
- constants::DW_AT_default_value => {
- // TODO: constant: sign depends on DW_AT_type.
- reference!();
- flag!();
- }
- constants::DW_AT_inline => {
- constant!(u8_value, Inline, DwInl);
- }
- constants::DW_AT_is_optional => {
- flag!();
- }
- constants::DW_AT_lower_bound => {
- // TODO: constant: sign depends on DW_AT_type.
- exprloc!();
- reference!();
- }
- constants::DW_AT_producer => {
- string!();
- }
- constants::DW_AT_prototyped => {
- flag!();
- }
- constants::DW_AT_return_addr => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_start_scope => {
- // TODO: constant
- rangelistptr!();
- }
- constants::DW_AT_bit_stride => {
- constant!(udata_value, Udata);
- exprloc!();
- reference!();
- }
- constants::DW_AT_upper_bound => {
- // TODO: constant: sign depends on DW_AT_type.
- exprloc!();
- reference!();
- }
- constants::DW_AT_abstract_origin => {
- reference!();
- }
- constants::DW_AT_accessibility => {
- constant!(u8_value, Accessibility, DwAccess);
- }
- constants::DW_AT_address_class => {
- constant!(udata_value, AddressClass, DwAddr);
- }
- constants::DW_AT_artificial => {
- flag!();
- }
- constants::DW_AT_base_types => {
- reference!();
- }
- constants::DW_AT_calling_convention => {
- constant!(u8_value, CallingConvention, DwCc);
- }
- constants::DW_AT_count => {
- // TODO: constant
- exprloc!();
- reference!();
- }
- constants::DW_AT_data_member_location => {
- // Constants must be handled before loclistptr so that DW_FORM_data4/8
- // are correctly interpreted for DWARF version 4+.
- constant!(udata_value, Udata);
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_decl_column => {
- constant!(udata_value, Udata);
- }
- constants::DW_AT_decl_file => {
- constant!(udata_value, FileIndex);
- }
- constants::DW_AT_decl_line => {
- constant!(udata_value, Udata);
- }
- constants::DW_AT_declaration => {
- flag!();
- }
- constants::DW_AT_discr_list => {
- block!();
- }
- constants::DW_AT_encoding => {
- constant!(u8_value, Encoding, DwAte);
- }
- constants::DW_AT_external => {
- flag!();
- }
- constants::DW_AT_frame_base => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_friend => {
- reference!();
- }
- constants::DW_AT_identifier_case => {
- constant!(u8_value, IdentifierCase, DwId);
- }
- constants::DW_AT_macro_info => {
- macinfoptr!();
- }
- constants::DW_AT_namelist_item => {
- reference!();
- }
- constants::DW_AT_priority => {
- reference!();
- }
- constants::DW_AT_segment => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_specification => {
- reference!();
- }
- constants::DW_AT_static_link => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_type => {
- reference!();
- }
- constants::DW_AT_use_location => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_variable_parameter => {
- flag!();
- }
- constants::DW_AT_virtuality => {
- constant!(u8_value, Virtuality, DwVirtuality);
- }
- constants::DW_AT_vtable_elem_location => {
- exprloc!();
- loclistptr!();
- }
- constants::DW_AT_allocated => {
- // TODO: constant
- exprloc!();
- reference!();
- }
- constants::DW_AT_associated => {
- // TODO: constant
- exprloc!();
- reference!();
- }
- constants::DW_AT_data_location => {
- exprloc!();
- }
- constants::DW_AT_byte_stride => {
- constant!(udata_value, Udata);
- exprloc!();
- reference!();
- }
- constants::DW_AT_entry_pc => {
- // TODO: constant
- address!();
- }
- constants::DW_AT_use_UTF8 => {
- flag!();
- }
- constants::DW_AT_extension => {
- reference!();
- }
- constants::DW_AT_ranges => {
- rangelistptr!();
- }
- constants::DW_AT_trampoline => {
- address!();
- flag!();
- reference!();
- string!();
- }
- constants::DW_AT_call_column => {
- constant!(udata_value, Udata);
- }
- constants::DW_AT_call_file => {
- constant!(udata_value, FileIndex);
- }
- constants::DW_AT_call_line => {
- constant!(udata_value, Udata);
- }
- constants::DW_AT_description => {
- string!();
- }
- constants::DW_AT_binary_scale => {
- // TODO: constant
- }
- constants::DW_AT_decimal_scale => {
- // TODO: constant
- }
- constants::DW_AT_small => {
- reference!();
- }
- constants::DW_AT_decimal_sign => {
- constant!(u8_value, DecimalSign, DwDs);
- }
- constants::DW_AT_digit_count => {
- // TODO: constant
- }
- constants::DW_AT_picture_string => {
- string!();
- }
- constants::DW_AT_mutable => {
- flag!();
- }
- constants::DW_AT_threads_scaled => {
- flag!();
- }
- constants::DW_AT_explicit => {
- flag!();
- }
- constants::DW_AT_object_pointer => {
- reference!();
- }
- constants::DW_AT_endianity => {
- constant!(u8_value, Endianity, DwEnd);
- }
- constants::DW_AT_elemental => {
- flag!();
- }
- constants::DW_AT_pure => {
- flag!();
- }
- constants::DW_AT_recursive => {
- flag!();
- }
- constants::DW_AT_signature => {
- reference!();
- }
- constants::DW_AT_main_subprogram => {
- flag!();
- }
- constants::DW_AT_data_bit_offset => {
- // TODO: constant
- }
- constants::DW_AT_const_expr => {
- flag!();
- }
- constants::DW_AT_enum_class => {
- flag!();
- }
- constants::DW_AT_linkage_name => {
- string!();
- }
- constants::DW_AT_string_length_bit_size => {
- // TODO: constant
- }
- constants::DW_AT_string_length_byte_size => {
- // TODO: constant
- }
- constants::DW_AT_rank => {
- // TODO: constant
- exprloc!();
- }
- constants::DW_AT_str_offsets_base => {
- stroffsetsptr!();
- }
- constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
- addrptr!();
- }
- constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
- rnglistsptr!();
- }
- constants::DW_AT_dwo_name => {
- string!();
- }
- constants::DW_AT_reference => {
- flag!();
- }
- constants::DW_AT_rvalue_reference => {
- flag!();
- }
- constants::DW_AT_macros => {
- macroptr!();
- }
- constants::DW_AT_call_all_calls => {
- flag!();
- }
- constants::DW_AT_call_all_source_calls => {
- flag!();
- }
- constants::DW_AT_call_all_tail_calls => {
- flag!();
- }
- constants::DW_AT_call_return_pc => {
- address!();
- }
- constants::DW_AT_call_value => {
- exprloc!();
- }
- constants::DW_AT_call_origin => {
- exprloc!();
- }
- constants::DW_AT_call_parameter => {
- reference!();
- }
- constants::DW_AT_call_pc => {
- address!();
- }
- constants::DW_AT_call_tail_call => {
- flag!();
- }
- constants::DW_AT_call_target => {
- exprloc!();
- }
- constants::DW_AT_call_target_clobbered => {
- exprloc!();
- }
- constants::DW_AT_call_data_location => {
- exprloc!();
- }
- constants::DW_AT_call_data_value => {
- exprloc!();
- }
- constants::DW_AT_noreturn => {
- flag!();
- }
- constants::DW_AT_alignment => {
- // TODO: constant
- }
- constants::DW_AT_export_symbols => {
- flag!();
- }
- constants::DW_AT_deleted => {
- flag!();
- }
- constants::DW_AT_defaulted => {
- // TODO: constant
- }
- constants::DW_AT_loclists_base => {
- loclistsptr!();
- }
- constants::DW_AT_GNU_dwo_id => {
- dwoid!();
- }
- _ => {}
- }
- self.value.clone()
- }
-
- /// Try to convert this attribute's value to a u8.
- #[inline]
- pub fn u8_value(&self) -> Option<u8> {
- self.value.u8_value()
- }
-
- /// Try to convert this attribute's value to a u16.
- #[inline]
- pub fn u16_value(&self) -> Option<u16> {
- self.value.u16_value()
- }
-
- /// Try to convert this attribute's value to an unsigned integer.
- #[inline]
- pub fn udata_value(&self) -> Option<u64> {
- self.value.udata_value()
- }
-
- /// Try to convert this attribute's value to a signed integer.
- #[inline]
- pub fn sdata_value(&self) -> Option<i64> {
- self.value.sdata_value()
- }
-
- /// Try to convert this attribute's value to an offset.
- #[inline]
- pub fn offset_value(&self) -> Option<R::Offset> {
- self.value.offset_value()
- }
-
- /// Try to convert this attribute's value to an expression or location buffer.
- ///
- /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
- /// The standard doesn't mention `DW_FORM_block*` as a possible form, but
- /// it is encountered in practice.
- #[inline]
- pub fn exprloc_value(&self) -> Option<Expression<R>> {
- self.value.exprloc_value()
- }
-
- /// Try to return this attribute's value as a string slice.
- ///
- /// If this attribute's value is either an inline `DW_FORM_string` string,
- /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
- /// section, return the attribute's string value as `Some`. Other attribute
- /// value forms are returned as `None`.
- ///
- /// Warning: this function does not handle all possible string forms.
- /// Use `Dwarf::attr_string` instead.
- #[inline]
- pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
- self.value.string_value(debug_str)
- }
-
- /// Try to return this attribute's value as a string slice.
- ///
- /// If this attribute's value is either an inline `DW_FORM_string` string,
- /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
- /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
- /// object file, return the attribute's string value as `Some`. Other attribute
- /// value forms are returned as `None`.
- ///
- /// Warning: this function does not handle all possible string forms.
- /// Use `Dwarf::attr_string` instead.
- #[inline]
- pub fn string_value_sup(
- &self,
- debug_str: &DebugStr<R>,
- debug_str_sup: Option<&DebugStr<R>>,
- ) -> Option<R> {
- self.value.string_value_sup(debug_str, debug_str_sup)
- }
-}
-
-impl<R, Offset> AttributeValue<R, Offset>
-where
- R: Reader<Offset = Offset>,
- Offset: ReaderOffset,
-{
- /// Try to convert this attribute's value to a u8.
- pub fn u8_value(&self) -> Option<u8> {
- if let Some(value) = self.udata_value() {
- if value <= u64::from(u8::MAX) {
- return Some(value as u8);
- }
- }
- None
- }
-
- /// Try to convert this attribute's value to a u16.
- pub fn u16_value(&self) -> Option<u16> {
- if let Some(value) = self.udata_value() {
- if value <= u64::from(u16::MAX) {
- return Some(value as u16);
- }
- }
- None
- }
-
- /// Try to convert this attribute's value to an unsigned integer.
- pub fn udata_value(&self) -> Option<u64> {
- Some(match *self {
- AttributeValue::Data1(data) => u64::from(data),
- AttributeValue::Data2(data) => u64::from(data),
- AttributeValue::Data4(data) => u64::from(data),
- AttributeValue::Data8(data) => data,
- AttributeValue::Udata(data) => data,
- AttributeValue::Sdata(data) => {
- if data < 0 {
- // Maybe we should emit a warning here
- return None;
- }
- data as u64
- }
- _ => return None,
- })
- }
-
- /// Try to convert this attribute's value to a signed integer.
- pub fn sdata_value(&self) -> Option<i64> {
- Some(match *self {
- AttributeValue::Data1(data) => i64::from(data as i8),
- AttributeValue::Data2(data) => i64::from(data as i16),
- AttributeValue::Data4(data) => i64::from(data as i32),
- AttributeValue::Data8(data) => data as i64,
- AttributeValue::Sdata(data) => data,
- AttributeValue::Udata(data) => {
- if data > i64::max_value() as u64 {
- // Maybe we should emit a warning here
- return None;
- }
- data as i64
- }
- _ => return None,
- })
- }
-
- /// Try to convert this attribute's value to an offset.
- pub fn offset_value(&self) -> Option<R::Offset> {
- // While offsets will be DW_FORM_data4/8 in DWARF version 2/3,
- // these have already been converted to `SecOffset.
- if let AttributeValue::SecOffset(offset) = *self {
- Some(offset)
- } else {
- None
- }
- }
-
- /// Try to convert this attribute's value to an expression or location buffer.
- ///
- /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`.
- /// The standard doesn't mention `DW_FORM_block*` as a possible form, but
- /// it is encountered in practice.
- pub fn exprloc_value(&self) -> Option<Expression<R>> {
- Some(match *self {
- AttributeValue::Block(ref data) => Expression(data.clone()),
- AttributeValue::Exprloc(ref data) => data.clone(),
- _ => return None,
- })
- }
-
- /// Try to return this attribute's value as a string slice.
- ///
- /// If this attribute's value is either an inline `DW_FORM_string` string,
- /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
- /// section, return the attribute's string value as `Some`. Other attribute
- /// value forms are returned as `None`.
- ///
- /// Warning: this function does not handle all possible string forms.
- /// Use `Dwarf::attr_string` instead.
- pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
- match *self {
- AttributeValue::String(ref string) => Some(string.clone()),
- AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
- _ => None,
- }
- }
-
- /// Try to return this attribute's value as a string slice.
- ///
- /// If this attribute's value is either an inline `DW_FORM_string` string,
- /// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
- /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
- /// object file, return the attribute's string value as `Some`. Other attribute
- /// value forms are returned as `None`.
- ///
- /// Warning: this function does not handle all possible string forms.
- /// Use `Dwarf::attr_string` instead.
- pub fn string_value_sup(
- &self,
- debug_str: &DebugStr<R>,
- debug_str_sup: Option<&DebugStr<R>>,
- ) -> Option<R> {
- match *self {
- AttributeValue::String(ref string) => Some(string.clone()),
- AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
- AttributeValue::DebugStrRefSup(offset) => {
- debug_str_sup.and_then(|s| s.get_str(offset).ok())
- }
- _ => None,
- }
- }
-}
-
-fn length_u8_value<R: Reader>(input: &mut R) -> Result<R> {
- let len = input.read_u8().map(R::Offset::from_u8)?;
- input.split(len)
-}
-
-fn length_u16_value<R: Reader>(input: &mut R) -> Result<R> {
- let len = input.read_u16().map(R::Offset::from_u16)?;
- input.split(len)
-}
-
-fn length_u32_value<R: Reader>(input: &mut R) -> Result<R> {
- let len = input.read_u32().map(R::Offset::from_u32)?;
- input.split(len)
-}
-
-fn length_uleb128_value<R: Reader>(input: &mut R) -> Result<R> {
- let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
- input.split(len)
-}
-
-// Return true if the given `name` can be a section offset in DWARF version 2/3.
-// This is required to correctly handle relocations.
-fn allow_section_offset(name: constants::DwAt, version: u16) -> bool {
- match name {
- constants::DW_AT_location
- | constants::DW_AT_stmt_list
- | constants::DW_AT_string_length
- | constants::DW_AT_return_addr
- | constants::DW_AT_start_scope
- | constants::DW_AT_frame_base
- | constants::DW_AT_macro_info
- | constants::DW_AT_macros
- | constants::DW_AT_segment
- | constants::DW_AT_static_link
- | constants::DW_AT_use_location
- | constants::DW_AT_vtable_elem_location
- | constants::DW_AT_ranges => true,
- constants::DW_AT_data_member_location => version == 2 || version == 3,
- _ => false,
- }
-}
-
-pub(crate) fn parse_attribute<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- spec: AttributeSpecification,
-) -> Result<Attribute<R>> {
- let mut form = spec.form();
- loop {
- let value = match form {
- constants::DW_FORM_indirect => {
- let dynamic_form = input.read_uleb128_u16()?;
- form = constants::DwForm(dynamic_form);
- continue;
- }
- constants::DW_FORM_addr => {
- let addr = input.read_address(encoding.address_size)?;
- AttributeValue::Addr(addr)
- }
- constants::DW_FORM_block1 => {
- let block = length_u8_value(input)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block2 => {
- let block = length_u16_value(input)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block4 => {
- let block = length_u32_value(input)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_block => {
- let block = length_uleb128_value(input)?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_data1 => {
- let data = input.read_u8()?;
- AttributeValue::Data1(data)
- }
- constants::DW_FORM_data2 => {
- let data = input.read_u16()?;
- AttributeValue::Data2(data)
- }
- constants::DW_FORM_data4 => {
- // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets.
- // Ensure we handle relocations here.
- if encoding.format == Format::Dwarf32
- && allow_section_offset(spec.name(), encoding.version)
- {
- let offset = input.read_offset(Format::Dwarf32)?;
- AttributeValue::SecOffset(offset)
- } else {
- let data = input.read_u32()?;
- AttributeValue::Data4(data)
- }
- }
- constants::DW_FORM_data8 => {
- // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets.
- // Ensure we handle relocations here.
- if encoding.format == Format::Dwarf64
- && allow_section_offset(spec.name(), encoding.version)
- {
- let offset = input.read_offset(Format::Dwarf64)?;
- AttributeValue::SecOffset(offset)
- } else {
- let data = input.read_u64()?;
- AttributeValue::Data8(data)
- }
- }
- constants::DW_FORM_data16 => {
- let block = input.split(R::Offset::from_u8(16))?;
- AttributeValue::Block(block)
- }
- constants::DW_FORM_udata => {
- let data = input.read_uleb128()?;
- AttributeValue::Udata(data)
- }
- constants::DW_FORM_sdata => {
- let data = input.read_sleb128()?;
- AttributeValue::Sdata(data)
- }
- constants::DW_FORM_exprloc => {
- let block = length_uleb128_value(input)?;
- AttributeValue::Exprloc(Expression(block))
- }
- constants::DW_FORM_flag => {
- let present = input.read_u8()?;
- AttributeValue::Flag(present != 0)
- }
- constants::DW_FORM_flag_present => {
- // FlagPresent is this weird compile time always true thing that
- // isn't actually present in the serialized DIEs, only in the abbreviation.
- AttributeValue::Flag(true)
- }
- constants::DW_FORM_sec_offset => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::SecOffset(offset)
- }
- constants::DW_FORM_ref1 => {
- let reference = input.read_u8().map(R::Offset::from_u8)?;
- AttributeValue::UnitRef(UnitOffset(reference))
- }
- constants::DW_FORM_ref2 => {
- let reference = input.read_u16().map(R::Offset::from_u16)?;
- AttributeValue::UnitRef(UnitOffset(reference))
- }
- constants::DW_FORM_ref4 => {
- let reference = input.read_u32().map(R::Offset::from_u32)?;
- AttributeValue::UnitRef(UnitOffset(reference))
- }
- constants::DW_FORM_ref8 => {
- let reference = input.read_u64().and_then(R::Offset::from_u64)?;
- AttributeValue::UnitRef(UnitOffset(reference))
- }
- constants::DW_FORM_ref_udata => {
- let reference = input.read_uleb128().and_then(R::Offset::from_u64)?;
- AttributeValue::UnitRef(UnitOffset(reference))
- }
- constants::DW_FORM_ref_addr => {
- // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr
- // has the same size as an address on the target system. This was changed
- // in DWARF version 3.
- let offset = if encoding.version == 2 {
- input.read_sized_offset(encoding.address_size)?
- } else {
- input.read_offset(encoding.format)?
- };
- AttributeValue::DebugInfoRef(DebugInfoOffset(offset))
- }
- constants::DW_FORM_ref_sig8 => {
- let signature = input.read_u64()?;
- AttributeValue::DebugTypesRef(DebugTypeSignature(signature))
- }
- constants::DW_FORM_ref_sup4 => {
- let offset = input.read_u32().map(R::Offset::from_u32)?;
- AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
- }
- constants::DW_FORM_ref_sup8 => {
- let offset = input.read_u64().and_then(R::Offset::from_u64)?;
- AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
- }
- constants::DW_FORM_GNU_ref_alt => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
- }
- constants::DW_FORM_string => {
- let string = input.read_null_terminated_slice()?;
- AttributeValue::String(string)
- }
- constants::DW_FORM_strp => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::DebugStrRef(DebugStrOffset(offset))
- }
- constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::DebugStrRefSup(DebugStrOffset(offset))
- }
- constants::DW_FORM_line_strp => {
- let offset = input.read_offset(encoding.format)?;
- AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset))
- }
- constants::DW_FORM_implicit_const => {
- let data = spec
- .implicit_const_value()
- .ok_or(Error::InvalidImplicitConst)?;
- AttributeValue::Sdata(data)
- }
- constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => {
- let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
- AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
- }
- constants::DW_FORM_strx1 => {
- let index = input.read_u8().map(R::Offset::from_u8)?;
- AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
- }
- constants::DW_FORM_strx2 => {
- let index = input.read_u16().map(R::Offset::from_u16)?;
- AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
- }
- constants::DW_FORM_strx3 => {
- let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
- AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
- }
- constants::DW_FORM_strx4 => {
- let index = input.read_u32().map(R::Offset::from_u32)?;
- AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
- }
- constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => {
- let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
- AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
- }
- constants::DW_FORM_addrx1 => {
- let index = input.read_u8().map(R::Offset::from_u8)?;
- AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
- }
- constants::DW_FORM_addrx2 => {
- let index = input.read_u16().map(R::Offset::from_u16)?;
- AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
- }
- constants::DW_FORM_addrx3 => {
- let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
- AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
- }
- constants::DW_FORM_addrx4 => {
- let index = input.read_u32().map(R::Offset::from_u32)?;
- AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
- }
- constants::DW_FORM_loclistx => {
- let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
- AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index))
- }
- constants::DW_FORM_rnglistx => {
- let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
- AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index))
- }
- _ => {
- return Err(Error::UnknownForm);
- }
- };
- let attr = Attribute {
- name: spec.name(),
- value,
- };
- return Ok(attr);
- }
-}
-
-pub(crate) fn skip_attributes<R: Reader>(
- input: &mut R,
- encoding: Encoding,
- specs: &[AttributeSpecification],
-) -> Result<()> {
- let mut skip_bytes = R::Offset::from_u8(0);
- for spec in specs {
- let mut form = spec.form();
- loop {
- if let Some(len) = get_attribute_size(form, encoding) {
- // We know the length of this attribute. Accumulate that length.
- skip_bytes += R::Offset::from_u8(len);
- break;
- }
-
- // We have encountered a variable-length attribute.
- if skip_bytes != R::Offset::from_u8(0) {
- // Skip the accumulated skip bytes and then read the attribute normally.
- input.skip(skip_bytes)?;
- skip_bytes = R::Offset::from_u8(0);
- }
-
- match form {
- constants::DW_FORM_indirect => {
- let dynamic_form = input.read_uleb128_u16()?;
- form = constants::DwForm(dynamic_form);
- continue;
- }
- constants::DW_FORM_block1 => {
- skip_bytes = input.read_u8().map(R::Offset::from_u8)?;
- }
- constants::DW_FORM_block2 => {
- skip_bytes = input.read_u16().map(R::Offset::from_u16)?;
- }
- constants::DW_FORM_block4 => {
- skip_bytes = input.read_u32().map(R::Offset::from_u32)?;
- }
- constants::DW_FORM_block | constants::DW_FORM_exprloc => {
- skip_bytes = input.read_uleb128().and_then(R::Offset::from_u64)?;
- }
- constants::DW_FORM_string => {
- let _ = input.read_null_terminated_slice()?;
- }
- constants::DW_FORM_udata
- | constants::DW_FORM_sdata
- | constants::DW_FORM_ref_udata
- | constants::DW_FORM_strx
- | constants::DW_FORM_GNU_str_index
- | constants::DW_FORM_addrx
- | constants::DW_FORM_GNU_addr_index
- | constants::DW_FORM_loclistx
- | constants::DW_FORM_rnglistx => {
- input.skip_leb128()?;
- }
- _ => {
- return Err(Error::UnknownForm);
- }
- };
- break;
- }
- }
- if skip_bytes != R::Offset::from_u8(0) {
- // Skip the remaining accumulated skip bytes.
- input.skip(skip_bytes)?;
- }
- Ok(())
-}
-
-/// An iterator over a particular entry's attributes.
-///
-/// See [the documentation for
-/// `DebuggingInformationEntry::attrs()`](./struct.DebuggingInformationEntry.html#method.attrs)
-/// for details.
-///
-/// Can be [used with
-/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
-#[derive(Clone, Copy, Debug)]
-pub struct AttrsIter<'abbrev, 'entry, 'unit, R: Reader> {
- input: R,
- attributes: &'abbrev [AttributeSpecification],
- entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>,
-}
-
-impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> {
- /// Advance the iterator and return the next attribute.
- ///
- /// Returns `None` when iteration is finished. If an error
- /// occurs while parsing the next attribute, then this error
- /// is returned, and all subsequent calls return `None`.
- #[inline(always)]
- pub fn next(&mut self) -> Result<Option<Attribute<R>>> {
- if self.attributes.is_empty() {
- // Now that we have parsed all of the attributes, we know where
- // either (1) this entry's children start, if the abbreviation says
- // this entry has children; or (2) where this entry's siblings
- // begin.
- if let Some(end) = self.entry.attrs_len.get() {
- debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice));
- } else {
- self.entry
- .attrs_len
- .set(Some(self.input.offset_from(&self.entry.attrs_slice)));
- }
-
- return Ok(None);
- }
-
- let spec = self.attributes[0];
- let rest_spec = &self.attributes[1..];
- match parse_attribute(&mut self.input, self.entry.unit.encoding(), spec) {
- Ok(attr) => {
- self.attributes = rest_spec;
- Ok(Some(attr))
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<'abbrev, 'entry, 'unit, R: Reader> fallible_iterator::FallibleIterator
- for AttrsIter<'abbrev, 'entry, 'unit, R>
-{
- type Item = Attribute<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- AttrsIter::next(self)
- }
-}
-
-/// A raw reader of the data that defines the Debugging Information Entries.
-///
-/// `EntriesRaw` provides primitives to read the components of Debugging Information
-/// Entries (DIEs). A DIE consists of an abbreviation code (read with `read_abbreviation`)
-/// followed by a number of attributes (read with `read_attribute`).
-/// The user must provide the control flow to read these correctly.
-/// In particular, all attributes must always be read before reading another
-/// abbreviation code.
-///
-/// `EntriesRaw` lacks some features of `EntriesCursor`, such as the ability to skip
-/// to the next sibling DIE. However, this also allows it to optimize better, since it
-/// does not need to perform the extra bookkeeping required to support these features,
-/// and thus it is suitable for cases where performance is important.
-///
-/// ## Example Usage
-/// ```rust,no_run
-/// # fn example() -> Result<(), gimli::Error> {
-/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian);
-/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap();
-/// let unit = get_some_unit();
-/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian);
-/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap();
-/// let abbrevs = get_abbrevs_for_unit(&unit);
-///
-/// let mut entries = unit.entries_raw(&abbrevs, None)?;
-/// while !entries.is_empty() {
-/// let abbrev = if let Some(abbrev) = entries.read_abbreviation()? {
-/// abbrev
-/// } else {
-/// // Null entry with no attributes.
-/// continue
-/// };
-/// match abbrev.tag() {
-/// gimli::DW_TAG_subprogram => {
-/// // Loop over attributes for DIEs we care about.
-/// for spec in abbrev.attributes() {
-/// let attr = entries.read_attribute(*spec)?;
-/// match attr.name() {
-/// // Handle attributes.
-/// _ => {}
-/// }
-/// }
-/// }
-/// _ => {
-/// // Skip attributes for DIEs we don't care about.
-/// entries.skip_attributes(abbrev.attributes());
-/// }
-/// }
-/// }
-/// # unreachable!()
-/// # }
-/// ```
-#[derive(Clone, Debug)]
-pub struct EntriesRaw<'abbrev, 'unit, R>
-where
- R: Reader,
-{
- input: R,
- unit: &'unit UnitHeader<R>,
- abbreviations: &'abbrev Abbreviations,
- depth: isize,
-}
-
-impl<'abbrev, 'unit, R: Reader> EntriesRaw<'abbrev, 'unit, R> {
- /// Return true if there is no more input.
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.input.is_empty()
- }
-
- /// Return the unit offset at which the reader will read next.
- ///
- /// If you want the offset of the next entry, then this must be called prior to reading
- /// the next entry.
- pub fn next_offset(&self) -> UnitOffset<R::Offset> {
- UnitOffset(self.unit.header_size() + self.input.offset_from(&self.unit.entries_buf))
- }
-
- /// Return the depth of the next entry.
- ///
- /// This depth is updated when `read_abbreviation` is called, and is updated
- /// based on null entries and the `has_children` field in the abbreviation.
- #[inline]
- pub fn next_depth(&self) -> isize {
- self.depth
- }
-
- /// Read an abbreviation code and lookup the corresponding `Abbreviation`.
- ///
- /// Returns `Ok(None)` for null entries.
- #[inline]
- pub fn read_abbreviation(&mut self) -> Result<Option<&'abbrev Abbreviation>> {
- let code = self.input.read_uleb128()?;
- if code == 0 {
- self.depth -= 1;
- return Ok(None);
- };
- let abbrev = self
- .abbreviations
- .get(code)
- .ok_or(Error::UnknownAbbreviation)?;
- if abbrev.has_children() {
- self.depth += 1;
- }
- Ok(Some(abbrev))
- }
-
- /// Read an attribute.
- #[inline]
- pub fn read_attribute(&mut self, spec: AttributeSpecification) -> Result<Attribute<R>> {
- parse_attribute(&mut self.input, self.unit.encoding(), spec)
- }
-
- /// Skip all the attributes of an abbreviation.
- #[inline]
- pub fn skip_attributes(&mut self, specs: &[AttributeSpecification]) -> Result<()> {
- skip_attributes(&mut self.input, self.unit.encoding(), specs)
- }
-}
-
-/// A cursor into the Debugging Information Entries tree for a compilation unit.
-///
-/// The `EntriesCursor` can traverse the DIE tree in DFS order using `next_dfs()`,
-/// or skip to the next sibling of the entry the cursor is currently pointing to
-/// using `next_sibling()`.
-///
-/// It is also possible to traverse the DIE tree at a lower abstraction level
-/// using `next_entry()`. This method does not skip over null entries, or provide
-/// any indication of the current tree depth. In this case, you must use `current()`
-/// to obtain the current entry, and `current().has_children()` to determine if
-/// the entry following the current entry will be a sibling or child. `current()`
-/// will return `None` if the current entry is a null entry, which signifies the
-/// end of the current tree depth.
-#[derive(Clone, Debug)]
-pub struct EntriesCursor<'abbrev, 'unit, R>
-where
- R: Reader,
-{
- input: R,
- unit: &'unit UnitHeader<R>,
- abbreviations: &'abbrev Abbreviations,
- cached_current: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>,
- delta_depth: isize,
-}
-
-impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> {
- /// Get a reference to the entry that the cursor is currently pointing to.
- ///
- /// If the cursor is not pointing at an entry, or if the current entry is a
- /// null entry, then `None` is returned.
- #[inline]
- pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> {
- self.cached_current.as_ref()
- }
-
- /// Move the cursor to the next DIE in the tree.
- ///
- /// Returns `Some` if there is a next entry, even if this entry is null.
- /// If there is no next entry, then `None` is returned.
- pub fn next_entry(&mut self) -> Result<Option<()>> {
- if let Some(ref current) = self.cached_current {
- self.input = current.after_attrs()?;
- }
-
- if self.input.is_empty() {
- self.cached_current = None;
- self.delta_depth = 0;
- return Ok(None);
- }
-
- match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) {
- Ok(Some(entry)) => {
- self.delta_depth = entry.has_children() as isize;
- self.cached_current = Some(entry);
- Ok(Some(()))
- }
- Ok(None) => {
- self.delta_depth = -1;
- self.cached_current = None;
- Ok(Some(()))
- }
- Err(e) => {
- self.input.empty();
- self.delta_depth = 0;
- self.cached_current = None;
- Err(e)
- }
- }
- }
-
- /// Move the cursor to the next DIE in the tree in DFS order.
- ///
- /// Upon successful movement of the cursor, return the delta traversal
- /// depth and the entry:
- ///
- /// * If we moved down into the previous current entry's children, we get
- /// `Some((1, entry))`.
- ///
- /// * If we moved to the previous current entry's sibling, we get
- /// `Some((0, entry))`.
- ///
- /// * If the previous entry does not have any siblings and we move up to
- /// its parent's next sibling, then we get `Some((-1, entry))`. Note that
- /// if the parent doesn't have a next sibling, then it could go up to the
- /// parent's parent's next sibling and return `Some((-2, entry))`, etc.
- ///
- /// If there is no next entry, then `None` is returned.
- ///
- /// Here is an example that finds the first entry in a compilation unit that
- /// does not have any children.
- ///
- /// ```
- /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
- /// # let info_buf = [
- /// # // Comilation unit header
- /// #
- /// # // 32-bit unit length = 25
- /// # 0x19, 0x00, 0x00, 0x00,
- /// # // Version 4
- /// # 0x04, 0x00,
- /// # // debug_abbrev_offset
- /// # 0x00, 0x00, 0x00, 0x00,
- /// # // Address size
- /// # 0x04,
- /// #
- /// # // DIEs
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // End of children
- /// # 0x00,
- /// #
- /// # // End of children
- /// # 0x00,
- /// #
- /// # // End of children
- /// # 0x00,
- /// # ];
- /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian);
- /// #
- /// # let abbrev_buf = [
- /// # // Code
- /// # 0x01,
- /// # // DW_TAG_subprogram
- /// # 0x2e,
- /// # // DW_CHILDREN_yes
- /// # 0x01,
- /// # // Begin attributes
- /// # // Attribute name = DW_AT_name
- /// # 0x03,
- /// # // Attribute form = DW_FORM_string
- /// # 0x08,
- /// # // End attributes
- /// # 0x00,
- /// # 0x00,
- /// # // Null terminator
- /// # 0x00
- /// # ];
- /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
- /// #
- /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap();
- ///
- /// let unit = get_some_unit();
- /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap();
- /// let abbrevs = get_abbrevs_for_unit(&unit);
- ///
- /// let mut first_entry_with_no_children = None;
- /// let mut cursor = unit.entries(&abbrevs);
- ///
- /// // Move the cursor to the root.
- /// assert!(cursor.next_dfs().unwrap().is_some());
- ///
- /// // Traverse the DIE tree in depth-first search order.
- /// let mut depth = 0;
- /// while let Some((delta_depth, current)) = cursor.next_dfs().expect("Should parse next dfs") {
- /// // Update depth value, and break out of the loop when we
- /// // return to the original starting position.
- /// depth += delta_depth;
- /// if depth <= 0 {
- /// break;
- /// }
- ///
- /// first_entry_with_no_children = Some(current.clone());
- /// }
- ///
- /// println!("The first entry with no children is {:?}",
- /// first_entry_with_no_children.unwrap());
- /// ```
- pub fn next_dfs(
- &mut self,
- ) -> Result<Option<(isize, &DebuggingInformationEntry<'abbrev, 'unit, R>)>> {
- let mut delta_depth = self.delta_depth;
- loop {
- // The next entry should be the one we want.
- if self.next_entry()?.is_some() {
- if let Some(ref entry) = self.cached_current {
- return Ok(Some((delta_depth, entry)));
- }
-
- // next_entry() read a null entry.
- delta_depth += self.delta_depth;
- } else {
- return Ok(None);
- }
- }
- }
-
- /// Move the cursor to the next sibling DIE of the current one.
- ///
- /// Returns `Ok(Some(entry))` when the cursor has been moved to
- /// the next sibling, `Ok(None)` when there is no next sibling.
- ///
- /// The depth of the cursor is never changed if this method returns `Ok`.
- /// Once `Ok(None)` is returned, this method will continue to return
- /// `Ok(None)` until either `next_entry` or `next_dfs` is called.
- ///
- /// Here is an example that iterates over all of the direct children of the
- /// root entry:
- ///
- /// ```
- /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian};
- /// # let info_buf = [
- /// # // Comilation unit header
- /// #
- /// # // 32-bit unit length = 25
- /// # 0x19, 0x00, 0x00, 0x00,
- /// # // Version 4
- /// # 0x04, 0x00,
- /// # // debug_abbrev_offset
- /// # 0x00, 0x00, 0x00, 0x00,
- /// # // Address size
- /// # 0x04,
- /// #
- /// # // DIEs
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // Abbreviation code
- /// # 0x01,
- /// # // Attribute of form DW_FORM_string = "foo\0"
- /// # 0x66, 0x6f, 0x6f, 0x00,
- /// #
- /// # // Children
- /// #
- /// # // End of children
- /// # 0x00,
- /// #
- /// # // End of children
- /// # 0x00,
- /// #
- /// # // End of children
- /// # 0x00,
- /// # ];
- /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian);
- /// #
- /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap();
- ///
- /// # let abbrev_buf = [
- /// # // Code
- /// # 0x01,
- /// # // DW_TAG_subprogram
- /// # 0x2e,
- /// # // DW_CHILDREN_yes
- /// # 0x01,
- /// # // Begin attributes
- /// # // Attribute name = DW_AT_name
- /// # 0x03,
- /// # // Attribute form = DW_FORM_string
- /// # 0x08,
- /// # // End attributes
- /// # 0x00,
- /// # 0x00,
- /// # // Null terminator
- /// # 0x00
- /// # ];
- /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
- /// #
- /// let unit = get_some_unit();
- /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap();
- /// let abbrevs = get_abbrevs_for_unit(&unit);
- ///
- /// let mut cursor = unit.entries(&abbrevs);
- ///
- /// // Move the cursor to the root.
- /// assert!(cursor.next_dfs().unwrap().is_some());
- ///
- /// // Move the cursor to the root's first child.
- /// assert!(cursor.next_dfs().unwrap().is_some());
- ///
- /// // Iterate the root's children.
- /// loop {
- /// {
- /// let current = cursor.current().expect("Should be at an entry");
- /// println!("{:?} is a child of the root", current);
- /// }
- ///
- /// if cursor.next_sibling().expect("Should parse next sibling").is_none() {
- /// break;
- /// }
- /// }
- /// ```
- pub fn next_sibling(
- &mut self,
- ) -> Result<Option<&DebuggingInformationEntry<'abbrev, 'unit, R>>> {
- if self.current().is_none() {
- // We're already at the null for the end of the sibling list.
- return Ok(None);
- }
-
- // Loop until we find an entry at the current level.
- let mut depth = 0;
- loop {
- // Use is_some() and unwrap() to keep borrow checker happy.
- if self.current().is_some() && self.current().unwrap().has_children() {
- if let Some(sibling_input) = self.current().unwrap().sibling() {
- // Fast path: this entry has a DW_AT_sibling
- // attribute pointing to its sibling, so jump
- // to it (which keeps us at the same depth).
- self.input = sibling_input;
- self.cached_current = None;
- } else {
- // This entry has children, so the next entry is
- // down one level.
- depth += 1;
- }
- }
-
- if self.next_entry()?.is_none() {
- // End of input.
- return Ok(None);
- }
-
- if depth == 0 {
- // Found an entry at the current level.
- return Ok(self.current());
- }
-
- if self.current().is_none() {
- // A null entry means the end of a child list, so we're
- // back up a level.
- depth -= 1;
- }
- }
- }
-}
-
-/// The state information for a tree view of the Debugging Information Entries.
-///
-/// The `EntriesTree` can be used to recursively iterate through the DIE
-/// tree, following the parent/child relationships. The `EntriesTree` contains
-/// shared state for all nodes in the tree, avoiding any duplicate parsing of
-/// entries during the traversal.
-///
-/// ## Example Usage
-/// ```rust,no_run
-/// # fn example() -> Result<(), gimli::Error> {
-/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian);
-/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap();
-/// let unit = get_some_unit();
-/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian);
-/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap();
-/// let abbrevs = get_abbrevs_for_unit(&unit);
-///
-/// let mut tree = unit.entries_tree(&abbrevs, None)?;
-/// let root = tree.root()?;
-/// process_tree(root)?;
-/// # unreachable!()
-/// # }
-///
-/// fn process_tree<R>(mut node: gimli::EntriesTreeNode<R>) -> gimli::Result<()>
-/// where R: gimli::Reader
-/// {
-/// {
-/// // Examine the entry attributes.
-/// let mut attrs = node.entry().attrs();
-/// while let Some(attr) = attrs.next()? {
-/// }
-/// }
-/// let mut children = node.children();
-/// while let Some(child) = children.next()? {
-/// // Recursively process a child.
-/// process_tree(child);
-/// }
-/// Ok(())
-/// }
-/// ```
-#[derive(Clone, Debug)]
-pub struct EntriesTree<'abbrev, 'unit, R>
-where
- R: Reader,
-{
- root: R,
- unit: &'unit UnitHeader<R>,
- abbreviations: &'abbrev Abbreviations,
- input: R,
- entry: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>,
- depth: isize,
-}
-
-impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> {
- fn new(root: R, unit: &'unit UnitHeader<R>, abbreviations: &'abbrev Abbreviations) -> Self {
- let input = root.clone();
- EntriesTree {
- root,
- unit,
- abbreviations,
- input,
- entry: None,
- depth: 0,
- }
- }
-
- /// Returns the root node of the tree.
- pub fn root<'me>(&'me mut self) -> Result<EntriesTreeNode<'abbrev, 'unit, 'me, R>> {
- self.input = self.root.clone();
- self.entry =
- DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?;
- if self.entry.is_none() {
- return Err(Error::UnexpectedNull);
- }
- self.depth = 0;
- Ok(EntriesTreeNode::new(self, 1))
- }
-
- /// Move the cursor to the next entry at the specified depth.
- ///
- /// Requires `depth <= self.depth + 1`.
- ///
- /// Returns `true` if successful.
- fn next(&mut self, depth: isize) -> Result<bool> {
- if self.depth < depth {
- debug_assert_eq!(self.depth + 1, depth);
-
- match self.entry {
- Some(ref entry) => {
- if !entry.has_children() {
- return Ok(false);
- }
- self.depth += 1;
- self.input = entry.after_attrs()?;
- }
- None => return Ok(false),
- }
-
- if self.input.is_empty() {
- self.entry = None;
- return Ok(false);
- }
-
- return match DebuggingInformationEntry::parse(
- &mut self.input,
- self.unit,
- self.abbreviations,
- ) {
- Ok(entry) => {
- self.entry = entry;
- Ok(self.entry.is_some())
- }
- Err(e) => {
- self.input.empty();
- self.entry = None;
- Err(e)
- }
- };
- }
-
- loop {
- match self.entry {
- Some(ref entry) => {
- if entry.has_children() {
- if let Some(sibling_input) = entry.sibling() {
- // Fast path: this entry has a DW_AT_sibling
- // attribute pointing to its sibling, so jump
- // to it (which keeps us at the same depth).
- self.input = sibling_input;
- } else {
- // This entry has children, so the next entry is
- // down one level.
- self.depth += 1;
- self.input = entry.after_attrs()?;
- }
- } else {
- // This entry has no children, so next entry is at same depth.
- self.input = entry.after_attrs()?;
- }
- }
- None => {
- // This entry is a null, so next entry is up one level.
- self.depth -= 1;
- }
- }
-
- if self.input.is_empty() {
- self.entry = None;
- return Ok(false);
- }
-
- match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) {
- Ok(entry) => {
- self.entry = entry;
- if self.depth == depth {
- return Ok(self.entry.is_some());
- }
- }
- Err(e) => {
- self.input.empty();
- self.entry = None;
- return Err(e);
- }
- }
- }
- }
-}
-
-/// A node in the Debugging Information Entry tree.
-///
-/// The root node of a tree can be obtained
-/// via [`EntriesTree::root`](./struct.EntriesTree.html#method.root).
-#[derive(Debug)]
-pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> {
- tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
- depth: isize,
-}
-
-impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> {
- fn new(
- tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
- depth: isize,
- ) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> {
- debug_assert!(tree.entry.is_some());
- EntriesTreeNode { tree, depth }
- }
-
- /// Returns the current entry in the tree.
- pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> {
- // We never create a node without an entry.
- self.tree.entry.as_ref().unwrap()
- }
-
- /// Create an iterator for the children of the current entry.
- ///
- /// The current entry can no longer be accessed after creating the
- /// iterator.
- pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
- EntriesTreeIter::new(self.tree, self.depth)
- }
-}
-
-/// An iterator that allows traversal of the children of an
-/// `EntriesTreeNode`.
-///
-/// The items returned by this iterator are also `EntriesTreeNode`s,
-/// which allow recursive traversal of grandchildren, etc.
-#[derive(Debug)]
-pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> {
- tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
- depth: isize,
- empty: bool,
-}
-
-impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
- fn new(
- tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
- depth: isize,
- ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
- EntriesTreeIter {
- tree,
- depth,
- empty: false,
- }
- }
-
- /// Returns an `EntriesTreeNode` for the next child entry.
- ///
- /// Returns `None` if there are no more children.
- pub fn next<'me>(&'me mut self) -> Result<Option<EntriesTreeNode<'abbrev, 'unit, 'me, R>>> {
- if self.empty {
- Ok(None)
- } else if self.tree.next(self.depth)? {
- Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1)))
- } else {
- self.empty = true;
- Ok(None)
- }
- }
-}
-
-/// Parse a type unit header's unique type signature. Callers should handle
-/// unique-ness checking.
-fn parse_type_signature<R: Reader>(input: &mut R) -> Result<DebugTypeSignature> {
- input.read_u64().map(DebugTypeSignature)
-}
-
-/// Parse a type unit header's type offset.
-fn parse_type_offset<R: Reader>(input: &mut R, format: Format) -> Result<UnitOffset<R::Offset>> {
- input.read_offset(format).map(UnitOffset)
-}
-
-/// The `DebugTypes` struct represents the DWARF type information
-/// found in the `.debug_types` section.
-#[derive(Debug, Default, Clone, Copy)]
-pub struct DebugTypes<R> {
- debug_types_section: R,
-}
-
-impl<'input, Endian> DebugTypes<EndianSlice<'input, Endian>>
-where
- Endian: Endianity,
-{
- /// Construct a new `DebugTypes` instance from the data in the `.debug_types`
- /// section.
- ///
- /// It is the caller's responsibility to read the `.debug_types` section and
- /// present it as a `&[u8]` slice. That means using some ELF loader on
- /// Linux, a Mach-O loader on macOS, etc.
- ///
- /// ```
- /// use gimli::{DebugTypes, LittleEndian};
- ///
- /// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_types_section_somehow = || &buf;
- /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian);
- /// ```
- pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self {
- Self::from(EndianSlice::new(debug_types_section, endian))
- }
-}
-
-impl<T> DebugTypes<T> {
- /// Create a `DebugTypes` section that references the data in `self`.
- ///
- /// This is useful when `R` implements `Reader` but `T` does not.
- ///
- /// ## Example Usage
- ///
- /// ```rust,no_run
- /// # let load_section = || unimplemented!();
- /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
- /// let owned_section: gimli::DebugTypes<Vec<u8>> = load_section();
- /// // Create a reference to the DWARF section.
- /// let section = owned_section.borrow(|section| {
- /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
- /// });
- /// ```
- pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes<R>
- where
- F: FnMut(&'a T) -> R,
- {
- borrow(&self.debug_types_section).into()
- }
-}
-
-impl<R> Section<R> for DebugTypes<R> {
- fn id() -> SectionId {
- SectionId::DebugTypes
- }
-
- fn reader(&self) -> &R {
- &self.debug_types_section
- }
-}
-
-impl<R> From<R> for DebugTypes<R> {
- fn from(debug_types_section: R) -> Self {
- DebugTypes {
- debug_types_section,
- }
- }
-}
-
-impl<R: Reader> DebugTypes<R> {
- /// Iterate the type-units in this `.debug_types` section.
- ///
- /// ```
- /// use gimli::{DebugTypes, LittleEndian};
- ///
- /// # let buf = [];
- /// # let read_debug_types_section_somehow = || &buf;
- /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian);
- ///
- /// let mut iter = debug_types.units();
- /// while let Some(unit) = iter.next().unwrap() {
- /// println!("unit's length is {}", unit.unit_length());
- /// }
- /// ```
- ///
- /// Can be [used with
- /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
- pub fn units(&self) -> DebugTypesUnitHeadersIter<R> {
- DebugTypesUnitHeadersIter {
- input: self.debug_types_section.clone(),
- offset: DebugTypesOffset(R::Offset::from_u8(0)),
- }
- }
-}
-
-/// An iterator over the type-units of this `.debug_types` section.
-///
-/// See the [documentation on
-/// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for
-/// more detail.
-#[derive(Clone, Debug)]
-pub struct DebugTypesUnitHeadersIter<R: Reader> {
- input: R,
- offset: DebugTypesOffset<R::Offset>,
-}
-
-impl<R: Reader> DebugTypesUnitHeadersIter<R> {
- /// Advance the iterator to the next type unit header.
- pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
- if self.input.is_empty() {
- Ok(None)
- } else {
- let len = self.input.len();
- match parse_unit_header(&mut self.input, self.offset.into()) {
- Ok(header) => {
- self.offset.0 += len - self.input.len();
- Ok(Some(header))
- }
- Err(e) => {
- self.input.empty();
- Err(e)
- }
- }
- }
- }
-}
-
-#[cfg(feature = "fallible-iterator")]
-impl<R: Reader> fallible_iterator::FallibleIterator for DebugTypesUnitHeadersIter<R> {
- type Item = UnitHeader<R>;
- type Error = Error;
-
- fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
- DebugTypesUnitHeadersIter::next(self)
- }
-}
-
-#[cfg(test)]
-// Tests require leb128::write.
-#[cfg(feature = "write")]
-mod tests {
- use super::*;
- use crate::constants;
- use crate::constants::*;
- use crate::endianity::{Endianity, LittleEndian};
- use crate::leb128;
- use crate::read::abbrev::tests::AbbrevSectionMethods;
- use crate::read::{
- Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result,
- };
- use crate::test_util::GimliSectionMethods;
- use alloc::vec::Vec;
- use core::cell::Cell;
- use test_assembler::{Endian, Label, LabelMaker, Section};
-
- // Mixin methods for `Section` to help define binary test data.
-
- trait UnitSectionMethods {
- fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self
- where
- E: Endianity;
- fn die<F>(self, code: u64, attr: F) -> Self
- where
- F: Fn(Section) -> Section;
- fn die_null(self) -> Self;
- fn attr_string(self, s: &str) -> Self;
- fn attr_ref1(self, o: u8) -> Self;
- fn offset(self, offset: usize, format: Format) -> Self;
- }
-
- impl UnitSectionMethods for Section {
- fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self
- where
- E: Endianity,
- {
- let size = self.size();
- let length = Label::new();
- let start = Label::new();
- let end = Label::new();
-
- let section = match unit.format() {
- Format::Dwarf32 => self.L32(&length),
- Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length),
- };
-
- let section = match unit.version() {
- 2 | 3 | 4 => section
- .mark(&start)
- .L16(unit.version())
- .offset(unit.debug_abbrev_offset.0, unit.format())
- .D8(unit.address_size()),
- 5 => section
- .mark(&start)
- .L16(unit.version())
- .D8(unit.type_().dw_ut().0)
- .D8(unit.address_size())
- .offset(unit.debug_abbrev_offset.0, unit.format()),
- _ => unreachable!(),
- };
-
- let section = match unit.type_() {
- UnitType::Compilation | UnitType::Partial => {
- unit.unit_offset = DebugInfoOffset(size as usize).into();
- section
- }
- UnitType::Type {
- type_signature,
- type_offset,
- }
- | UnitType::SplitType {
- type_signature,
- type_offset,
- } => {
- if unit.version() == 5 {
- unit.unit_offset = DebugInfoOffset(size as usize).into();
- } else {
- unit.unit_offset = DebugTypesOffset(size as usize).into();
- }
- section
- .L64(type_signature.0)
- .offset(type_offset.0, unit.format())
- }
- UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => {
- unit.unit_offset = DebugInfoOffset(size as usize).into();
- section.L64(dwo_id.0)
- }
- };
-
- let section = section.append_bytes(unit.entries_buf.slice()).mark(&end);
-
- unit.unit_length = (&end - &start) as usize;
- length.set_const(unit.unit_length as u64);
-
- section
- }
-
- fn die<F>(self, code: u64, attr: F) -> Self
- where
- F: Fn(Section) -> Section,
- {
- let section = self.uleb(code);
- attr(section)
- }
-
- fn die_null(self) -> Self {
- self.D8(0)
- }
-
- fn attr_string(self, attr: &str) -> Self {
- self.append_bytes(attr.as_bytes()).D8(0)
- }
-
- fn attr_ref1(self, attr: u8) -> Self {
- self.D8(attr)
- }
-
- fn offset(self, offset: usize, format: Format) -> Self {
- match format {
- Format::Dwarf32 => self.L32(offset as u32),
- Format::Dwarf64 => self.L64(offset as u64),
- }
- }
- }
-
- /// Ensure that `UnitHeader<R>` is covariant wrt R.
- #[test]
- fn test_unit_header_variance() {
- /// This only needs to compile.
- fn _f<'a: 'b, 'b, E: Endianity>(
- x: UnitHeader<EndianSlice<'a, E>>,
- ) -> UnitHeader<EndianSlice<'b, E>> {
- x
- }
- }
-
- #[test]
- fn test_parse_debug_abbrev_offset_32() {
- let section = Section::with_endian(Endian::Little).L32(0x0403_0201);
- let buf = section.get_contents().unwrap();
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_abbrev_offset(buf, Format::Dwarf32) {
- Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_debug_abbrev_offset_32_incomplete() {
- let buf = [0x01, 0x02];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_abbrev_offset(buf, Format::Dwarf32) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_debug_abbrev_offset_64() {
- let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201);
- let buf = section.get_contents().unwrap();
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_abbrev_offset(buf, Format::Dwarf64) {
- Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_debug_abbrev_offset_64_incomplete() {
- let buf = [0x01, 0x02];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_abbrev_offset(buf, Format::Dwarf64) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_debug_info_offset_32() {
- let section = Section::with_endian(Endian::Little).L32(0x0403_0201);
- let buf = section.get_contents().unwrap();
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_info_offset(buf, Format::Dwarf32) {
- Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_debug_info_offset_32_incomplete() {
- let buf = [0x01, 0x02];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_info_offset(buf, Format::Dwarf32) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_debug_info_offset_64() {
- let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201);
- let buf = section.get_contents().unwrap();
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_info_offset(buf, Format::Dwarf64) {
- Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_debug_info_offset_64_incomplete() {
- let buf = [0x01, 0x02];
- let buf = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_debug_info_offset(buf, Format::Dwarf64) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_units() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let mut unit64 = UnitHeader {
- encoding: Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- },
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let mut unit32 = UnitHeader {
- encoding: Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- },
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut unit64)
- .unit(&mut unit32);
- let buf = section.get_contents().unwrap();
-
- let debug_info = DebugInfo::new(&buf, LittleEndian);
- let mut units = debug_info.units();
-
- assert_eq!(units.next(), Ok(Some(unit64)));
- assert_eq!(units.next(), Ok(Some(unit32)));
- assert_eq!(units.next(), Ok(None));
- }
-
- #[test]
- fn test_unit_version_unknown_version() {
- let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_unit_header(rest, DebugInfoOffset(0).into()) {
- Err(Error::UnknownVersion(0xcdab)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
-
- let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_unit_header(rest, DebugInfoOffset(0).into()) {
- Err(Error::UnknownVersion(1)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_unit_version_incomplete() {
- let buf = [0x01, 0x00, 0x00, 0x00, 0x04];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_unit_header(rest, DebugInfoOffset(0).into()) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_partial_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Partial,
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_partial_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Partial,
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_skeleton_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)),
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_skeleton_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)),
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_split_compilation_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 4,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)),
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_split_compilation_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)),
- debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_type_offset_32_ok() {
- let buf = [0x12, 0x34, 0x56, 0x78, 0x00];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_type_offset(rest, Format::Dwarf32) {
- Ok(offset) => {
- assert_eq!(rest.len(), 1);
- assert_eq!(UnitOffset(0x7856_3412), offset);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_type_offset_64_ok() {
- let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_type_offset(rest, Format::Dwarf64) {
- Ok(offset) => {
- assert_eq!(rest.len(), 1);
- assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset);
- }
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- }
- }
-
- #[test]
- fn test_parse_type_offset_incomplete() {
- // Need at least 4 bytes.
- let buf = [0xff, 0xff, 0xff];
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- match parse_type_offset(rest, Format::Dwarf32) {
- Err(Error::UnexpectedEof(_)) => assert!(true),
- otherwise => panic!("Unexpected result: {:?}", otherwise),
- };
- }
-
- #[test]
- fn test_parse_type_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugTypesOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugTypesOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_type_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 4,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412_7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugTypesOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugTypesOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_type_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_type_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412_7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- fn test_parse_v5_split_type_unit_header_32_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::SplitType {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_v5_split_type_unit_header_64_ok() {
- let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
- let encoding = Encoding {
- format: Format::Dwarf64,
- version: 5,
- address_size: 8,
- };
- let mut expected_unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::SplitType {
- type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
- type_offset: UnitOffset(0x7856_3412_7856_3412),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(expected_rest, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little)
- .unit(&mut expected_unit)
- .append_bytes(expected_rest);
- let buf = section.get_contents().unwrap();
- let rest = &mut EndianSlice::new(&buf, LittleEndian);
-
- assert_eq!(
- parse_unit_header(rest, DebugInfoOffset(0).into()),
- Ok(expected_unit)
- );
- assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
- }
-
- fn section_contents<F>(f: F) -> Vec<u8>
- where
- F: Fn(Section) -> Section,
- {
- f(Section::with_endian(Endian::Little))
- .get_contents()
- .unwrap()
- }
-
- #[test]
- fn test_attribute_value() {
- let mut unit = test_parse_attribute_unit_default();
- let endian = unit.entries_buf.endian();
-
- let block_data = &[1, 2, 3, 4];
- let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data));
- let block = EndianSlice::new(&buf, endian);
-
- let buf = section_contents(|s| s.L32(0x0102_0304));
- let data4 = EndianSlice::new(&buf, endian);
-
- let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708));
- let data8 = EndianSlice::new(&buf, endian);
-
- let tests = [
- (
- Format::Dwarf32,
- 2,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_block,
- block,
- AttributeValue::Block(EndianSlice::new(block_data, endian)),
- AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))),
- ),
- (
- Format::Dwarf32,
- 2,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data4,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)),
- ),
- (
- Format::Dwarf64,
- 2,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data4,
- data4,
- AttributeValue::Data4(0x0102_0304),
- AttributeValue::Udata(0x0102_0304),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data4,
- data4,
- AttributeValue::Data4(0x0102_0304),
- AttributeValue::Udata(0x0102_0304),
- ),
- (
- Format::Dwarf32,
- 2,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data8,
- data8,
- AttributeValue::Data8(0x0102_0304_0506_0708),
- AttributeValue::Udata(0x0102_0304_0506_0708),
- ),
- #[cfg(target_pointer_width = "64")]
- (
- Format::Dwarf64,
- 2,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data8,
- data8,
- AttributeValue::SecOffset(0x0102_0304_0506_0708),
- AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)),
- ),
- (
- Format::Dwarf64,
- 4,
- constants::DW_AT_data_member_location,
- constants::DW_FORM_data8,
- data8,
- AttributeValue::Data8(0x0102_0304_0506_0708),
- AttributeValue::Udata(0x0102_0304_0506_0708),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_location,
- constants::DW_FORM_data4,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)),
- ),
- #[cfg(target_pointer_width = "64")]
- (
- Format::Dwarf64,
- 4,
- constants::DW_AT_location,
- constants::DW_FORM_data8,
- data8,
- AttributeValue::SecOffset(0x0102_0304_0506_0708),
- AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_str_offsets_base,
- constants::DW_FORM_sec_offset,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_stmt_list,
- constants::DW_FORM_sec_offset,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::DebugLineRef(DebugLineOffset(0x0102_0304)),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_addr_base,
- constants::DW_FORM_sec_offset,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_rnglists_base,
- constants::DW_FORM_sec_offset,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)),
- ),
- (
- Format::Dwarf32,
- 4,
- constants::DW_AT_loclists_base,
- constants::DW_FORM_sec_offset,
- data4,
- AttributeValue::SecOffset(0x0102_0304),
- AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)),
- ),
- ];
-
- for test in tests.iter() {
- let (format, version, name, form, mut input, expect_raw, expect_value) = *test;
- unit.encoding.format = format;
- unit.encoding.version = version;
- let spec = AttributeSpecification::new(name, form, None);
- let attribute =
- parse_attribute(&mut input, unit.encoding(), spec).expect("Should parse attribute");
- assert_eq!(attribute.raw_value(), expect_raw);
- assert_eq!(attribute.value(), expect_value);
- }
- }
-
- #[test]
- fn test_attribute_udata_sdata_value() {
- let tests: &[(
- AttributeValue<EndianSlice<LittleEndian>>,
- Option<u64>,
- Option<i64>,
- )] = &[
- (AttributeValue::Data1(1), Some(1), Some(1)),
- (
- AttributeValue::Data1(core::u8::MAX),
- Some(u64::from(std::u8::MAX)),
- Some(-1),
- ),
- (AttributeValue::Data2(1), Some(1), Some(1)),
- (
- AttributeValue::Data2(core::u16::MAX),
- Some(u64::from(std::u16::MAX)),
- Some(-1),
- ),
- (AttributeValue::Data4(1), Some(1), Some(1)),
- (
- AttributeValue::Data4(core::u32::MAX),
- Some(u64::from(std::u32::MAX)),
- Some(-1),
- ),
- (AttributeValue::Data8(1), Some(1), Some(1)),
- (
- AttributeValue::Data8(core::u64::MAX),
- Some(core::u64::MAX),
- Some(-1),
- ),
- (AttributeValue::Sdata(1), Some(1), Some(1)),
- (AttributeValue::Sdata(-1), None, Some(-1)),
- (AttributeValue::Udata(1), Some(1), Some(1)),
- (AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None),
- ];
- for test in tests.iter() {
- let (value, expect_udata, expect_sdata) = *test;
- let attribute = Attribute {
- name: DW_AT_data_member_location,
- value,
- };
- assert_eq!(attribute.udata_value(), expect_udata);
- assert_eq!(attribute.sdata_value(), expect_sdata);
- }
- }
-
- fn test_parse_attribute_unit<Endian>(
- address_size: u8,
- format: Format,
- endian: Endian,
- ) -> UnitHeader<EndianSlice<'static, Endian>>
- where
- Endian: Endianity,
- {
- let encoding = Encoding {
- format,
- version: 4,
- address_size,
- };
- UnitHeader::new(
- encoding,
- 7,
- UnitType::Compilation,
- DebugAbbrevOffset(0x0807_0605),
- DebugInfoOffset(0).into(),
- EndianSlice::new(&[], endian),
- )
- }
-
- fn test_parse_attribute_unit_default() -> UnitHeader<EndianSlice<'static, LittleEndian>> {
- test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian)
- }
-
- fn test_parse_attribute<'input, Endian>(
- buf: &'input [u8],
- len: usize,
- unit: &UnitHeader<EndianSlice<'input, Endian>>,
- form: constants::DwForm,
- value: AttributeValue<EndianSlice<'input, Endian>>,
- ) where
- Endian: Endianity,
- {
- let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form, None);
-
- let expect = Attribute {
- name: constants::DW_AT_low_pc,
- value,
- };
-
- let rest = &mut EndianSlice::new(buf, Endian::default());
- match parse_attribute(rest, unit.encoding(), spec) {
- Ok(attr) => {
- assert_eq!(attr, expect);
- assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default()));
- if let Some(size) = spec.size(unit) {
- assert_eq!(rest.len() + size, buf.len());
- }
- }
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- };
- }
-
- #[test]
- fn test_parse_attribute_addr() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_addr;
- let value = AttributeValue::Addr(0x0403_0201);
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addr8() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
- let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_addr;
- let value = AttributeValue::Addr(0x0807_0605_0403_0201);
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_block1() {
- // Length of data (3), three bytes of data, two bytes of left over input.
- let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_block1;
- let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_block2() {
- // Two byte length of data (2), two bytes of data, two bytes of left over input.
- let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_block2;
- let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_block4() {
- // Four byte length of data (2), two bytes of data, no left over input.
- let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_block4;
- let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian));
- test_parse_attribute(&buf, 6, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_block() {
- // LEB length of data (2, one byte), two bytes of data, no left over input.
- let buf = [0x02, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_block;
- let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian));
- test_parse_attribute(&buf, 3, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_data1() {
- let buf = [0x03];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_data1;
- let value = AttributeValue::Data1(0x03);
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_data2() {
- let buf = [0x02, 0x01, 0x0];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_data2;
- let value = AttributeValue::Data2(0x0102);
- test_parse_attribute(&buf, 2, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_data4() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_data4;
- let value = AttributeValue::Data4(0x0403_0201);
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_data8() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_data8;
- let value = AttributeValue::Data8(0x0807_0605_0403_0201);
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_udata() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_udata;
- let value = AttributeValue::Udata(4097);
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_sdata() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::signed(&mut writable, -4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_sdata;
- let value = AttributeValue::Sdata(-4097);
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_exprloc() {
- // LEB length of data (2, one byte), two bytes of data, one byte left over input.
- let buf = [0x02, 0x99, 0x99, 0x11];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_exprloc;
- let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian)));
- test_parse_attribute(&buf, 3, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_flag_true() {
- let buf = [0x42];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_flag;
- let value = AttributeValue::Flag(true);
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_flag_false() {
- let buf = [0x00];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_flag;
- let value = AttributeValue::Flag(false);
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_flag_present() {
- let buf = [0x01, 0x02, 0x03, 0x04];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_flag_present;
- let value = AttributeValue::Flag(true);
- // DW_FORM_flag_present does not consume any bytes of the input stream.
- test_parse_attribute(&buf, 0, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_sec_offset_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_sec_offset;
- let value = AttributeValue::SecOffset(0x0403_0201);
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_sec_offset_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_sec_offset;
- let value = AttributeValue::SecOffset(0x0807_0605_0403_0201);
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_ref1() {
- let buf = [0x03];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref1;
- let value = AttributeValue::UnitRef(UnitOffset(3));
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_ref2() {
- let buf = [0x02, 0x01, 0x0];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref2;
- let value = AttributeValue::UnitRef(UnitOffset(258));
- test_parse_attribute(&buf, 2, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_ref4() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref4;
- let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_ref8() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref8;
- let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_ref_sup4() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref_sup4;
- let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_ref_sup8() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref_sup8;
- let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_refudata() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref_udata;
- let value = AttributeValue::UnitRef(UnitOffset(4097));
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_refaddr_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_ref_addr;
- let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_refaddr_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_ref_addr;
- let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_refaddr_version2() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- unit.encoding.version = 2;
- let form = constants::DW_FORM_ref_addr;
- let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_refaddr8_version2() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian);
- unit.encoding.version = 2;
- let form = constants::DW_FORM_ref_addr;
- let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_gnu_ref_alt_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_GNU_ref_alt;
- let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_gnu_ref_alt_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_GNU_ref_alt;
- let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_refsig8() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_ref_sig8;
- let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_string() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99];
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_string;
- let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian));
- test_parse_attribute(&buf, 6, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strp_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_strp;
- let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_strp_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strp;
- let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strp_sup_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_strp_sup;
- let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_strp_sup_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strp_sup;
- let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_gnu_strp_alt_32() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
- let form = constants::DW_FORM_GNU_strp_alt;
- let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- #[cfg(target_pointer_width = "64")]
- fn test_parse_attribute_gnu_strp_alt_64() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_GNU_strp_alt;
- let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201));
- test_parse_attribute(&buf, 8, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strx() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_strx;
- let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097));
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strx1() {
- let buf = [0x01, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strx1;
- let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01));
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strx2() {
- let buf = [0x01, 0x02, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strx2;
- let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201));
- test_parse_attribute(&buf, 2, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strx3() {
- let buf = [0x01, 0x02, 0x03, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strx3;
- let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201));
- test_parse_attribute(&buf, 3, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_strx4() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_strx4;
- let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addrx() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_addrx;
- let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097));
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addrx1() {
- let buf = [0x01, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_addrx1;
- let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01));
- test_parse_attribute(&buf, 1, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addrx2() {
- let buf = [0x01, 0x02, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_addrx2;
- let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201));
- test_parse_attribute(&buf, 2, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addrx3() {
- let buf = [0x01, 0x02, 0x03, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_addrx3;
- let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201));
- test_parse_attribute(&buf, 3, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_addrx4() {
- let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
- let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
- let form = constants::DW_FORM_addrx4;
- let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201));
- test_parse_attribute(&buf, 4, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_loclistx() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_loclistx;
- let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097));
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_rnglistx() {
- let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_rnglistx;
- let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097));
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_indirect() {
- let mut buf = [0; 100];
-
- let bytes_written = {
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0.into())
- .expect("should write udata")
- + leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value")
- };
-
- let unit = test_parse_attribute_unit_default();
- let form = constants::DW_FORM_indirect;
- let value = AttributeValue::Udata(9_999_999);
- test_parse_attribute(&buf, bytes_written, &unit, form, value);
- }
-
- #[test]
- fn test_parse_attribute_indirect_implicit_const() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut buf = [0; 100];
- let mut writable = &mut buf[..];
- leb128::write::unsigned(&mut writable, constants::DW_FORM_implicit_const.0.into())
- .expect("should write implicit_const");
-
- let input = &mut EndianSlice::new(&buf, LittleEndian);
- let spec =
- AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_indirect, None);
- assert_eq!(
- parse_attribute(input, encoding, spec),
- Err(Error::InvalidImplicitConst)
- );
- }
-
- #[test]
- fn test_attrs_iter() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let unit = UnitHeader::new(
- encoding,
- 7,
- UnitType::Compilation,
- DebugAbbrevOffset(0x0807_0605),
- DebugInfoOffset(0).into(),
- EndianSlice::new(&[], LittleEndian),
- );
-
- let abbrev = Abbreviation::new(
- 42,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_yes,
- vec![
- AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
- AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
- AttributeSpecification::new(
- constants::DW_AT_high_pc,
- constants::DW_FORM_addr,
- None,
- ),
- ]
- .into(),
- );
-
- // "foo", 42, 1337, 4 dangling bytes of 0xaa where children would be
- let buf = [
- 0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa,
- 0xaa, 0xaa,
- ];
-
- let entry = DebuggingInformationEntry {
- offset: UnitOffset(0),
- attrs_slice: EndianSlice::new(&buf, LittleEndian),
- attrs_len: Cell::new(None),
- abbrev: &abbrev,
- unit: &unit,
- };
-
- let mut attrs = AttrsIter {
- input: EndianSlice::new(&buf, LittleEndian),
- attributes: abbrev.attributes(),
- entry: &entry,
- };
-
- match attrs.next() {
- Ok(Some(attr)) => {
- assert_eq!(
- attr,
- Attribute {
- name: constants::DW_AT_name,
- value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)),
- }
- );
- }
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
-
- assert!(entry.attrs_len.get().is_none());
-
- match attrs.next() {
- Ok(Some(attr)) => {
- assert_eq!(
- attr,
- Attribute {
- name: constants::DW_AT_low_pc,
- value: AttributeValue::Addr(0x2a),
- }
- );
- }
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
-
- assert!(entry.attrs_len.get().is_none());
-
- match attrs.next() {
- Ok(Some(attr)) => {
- assert_eq!(
- attr,
- Attribute {
- name: constants::DW_AT_high_pc,
- value: AttributeValue::Addr(0x539),
- }
- );
- }
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
-
- assert!(entry.attrs_len.get().is_none());
-
- assert!(attrs.next().expect("should parse next").is_none());
- assert!(entry.attrs_len.get().is_some());
- assert_eq!(
- entry.attrs_len.get().expect("should have entry.attrs_len"),
- buf.len() - 4
- )
- }
-
- #[test]
- fn test_attrs_iter_incomplete() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let unit = UnitHeader::new(
- encoding,
- 7,
- UnitType::Compilation,
- DebugAbbrevOffset(0x0807_0605),
- DebugInfoOffset(0).into(),
- EndianSlice::new(&[], LittleEndian),
- );
-
- let abbrev = Abbreviation::new(
- 42,
- constants::DW_TAG_subprogram,
- constants::DW_CHILDREN_yes,
- vec![
- AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
- AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
- AttributeSpecification::new(
- constants::DW_AT_high_pc,
- constants::DW_FORM_addr,
- None,
- ),
- ]
- .into(),
- );
-
- // "foo"
- let buf = [0x66, 0x6f, 0x6f, 0x00];
-
- let entry = DebuggingInformationEntry {
- offset: UnitOffset(0),
- attrs_slice: EndianSlice::new(&buf, LittleEndian),
- attrs_len: Cell::new(None),
- abbrev: &abbrev,
- unit: &unit,
- };
-
- let mut attrs = AttrsIter {
- input: EndianSlice::new(&buf, LittleEndian),
- attributes: abbrev.attributes(),
- entry: &entry,
- };
-
- match attrs.next() {
- Ok(Some(attr)) => {
- assert_eq!(
- attr,
- Attribute {
- name: constants::DW_AT_name,
- value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)),
- }
- );
- }
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
-
- assert!(entry.attrs_len.get().is_none());
-
- // Return error for incomplete attribute.
- assert!(attrs.next().is_err());
- assert!(entry.attrs_len.get().is_none());
-
- // Return error for all subsequent calls.
- assert!(attrs.next().is_err());
- assert!(attrs.next().is_err());
- assert!(attrs.next().is_err());
- assert!(attrs.next().is_err());
- assert!(entry.attrs_len.get().is_none());
- }
-
- fn assert_entry_name<Endian>(entry: &DebuggingInformationEntry<EndianSlice<Endian>>, name: &str)
- where
- Endian: Endianity,
- {
- let value = entry
- .attr_value(constants::DW_AT_name)
- .expect("Should have parsed the name attribute")
- .expect("Should have found the name attribute");
-
- assert_eq!(
- value,
- AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default()))
- );
- }
-
- fn assert_current_name<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>, name: &str)
- where
- Endian: Endianity,
- {
- let entry = cursor.current().expect("Should have an entry result");
- assert_entry_name(entry, name);
- }
-
- fn assert_next_entry<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str)
- where
- Endian: Endianity,
- {
- cursor
- .next_entry()
- .expect("Should parse next entry")
- .expect("Should have an entry");
- assert_current_name(cursor, name);
- }
-
- fn assert_next_entry_null<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>)
- where
- Endian: Endianity,
- {
- cursor
- .next_entry()
- .expect("Should parse next entry")
- .expect("Should have an entry");
- assert!(cursor.current().is_none());
- }
-
- fn assert_next_dfs<Endian>(
- cursor: &mut EntriesCursor<EndianSlice<Endian>>,
- name: &str,
- depth: isize,
- ) where
- Endian: Endianity,
- {
- {
- let (val, entry) = cursor
- .next_dfs()
- .expect("Should parse next dfs")
- .expect("Should not be done with traversal");
- assert_eq!(val, depth);
- assert_entry_name(entry, name);
- }
- assert_current_name(cursor, name);
- }
-
- fn assert_next_sibling<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str)
- where
- Endian: Endianity,
- {
- {
- let entry = cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .expect("Should not be done with traversal");
- assert_entry_name(entry, name);
- }
- assert_current_name(cursor, name);
- }
-
- fn assert_valid_sibling_ptr<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>)
- where
- Endian: Endianity,
- {
- let sibling_ptr = cursor
- .current()
- .expect("Should have current entry")
- .attr_value(constants::DW_AT_sibling);
- match sibling_ptr {
- Ok(Some(AttributeValue::UnitRef(offset))) => {
- cursor
- .unit
- .range_from(offset..)
- .expect("Sibling offset should be valid");
- }
- _ => panic!("Invalid sibling pointer {:?}", sibling_ptr),
- }
- }
-
- fn entries_cursor_tests_abbrev_buf() -> Vec<u8> {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev_null();
- section.get_contents().unwrap()
- }
-
- fn entries_cursor_tests_debug_info_buf() -> Vec<u8> {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .die(1, |s| s.attr_string("001"))
- .die(1, |s| s.attr_string("002"))
- .die(1, |s| s.attr_string("003"))
- .die_null()
- .die_null()
- .die(1, |s| s.attr_string("004"))
- .die(1, |s| s.attr_string("005"))
- .die_null()
- .die(1, |s| s.attr_string("006"))
- .die_null()
- .die_null()
- .die(1, |s| s.attr_string("007"))
- .die(1, |s| s.attr_string("008"))
- .die(1, |s| s.attr_string("009"))
- .die_null()
- .die_null()
- .die_null()
- .die(1, |s| s.attr_string("010"))
- .die_null()
- .die_null();
- let entries_buf = section.get_contents().unwrap();
-
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little).unit(&mut unit);
- section.get_contents().unwrap()
- }
-
- #[test]
- fn test_cursor_next_entry_incomplete() {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .die(1, |s| s.attr_string("001"))
- .die(1, |s| s.attr_string("002"))
- .die(1, |s| s);
- let entries_buf = section.get_contents().unwrap();
-
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little).unit(&mut unit);
- let info_buf = &section.get_contents().unwrap();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
-
- assert_next_entry(&mut cursor, "001");
- assert_next_entry(&mut cursor, "002");
-
- {
- // Entry code is present, but none of the attributes.
- cursor
- .next_entry()
- .expect("Should parse next entry")
- .expect("Should have an entry");
- let entry = cursor.current().expect("Should have an entry result");
- assert!(entry.attrs().next().is_err());
- }
-
- assert!(cursor.next_entry().is_err());
- assert!(cursor.next_entry().is_err());
- }
-
- #[test]
- fn test_cursor_next_entry() {
- let info_buf = &entries_cursor_tests_debug_info_buf();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
-
- assert_next_entry(&mut cursor, "001");
- assert_next_entry(&mut cursor, "002");
- assert_next_entry(&mut cursor, "003");
- assert_next_entry_null(&mut cursor);
- assert_next_entry_null(&mut cursor);
- assert_next_entry(&mut cursor, "004");
- assert_next_entry(&mut cursor, "005");
- assert_next_entry_null(&mut cursor);
- assert_next_entry(&mut cursor, "006");
- assert_next_entry_null(&mut cursor);
- assert_next_entry_null(&mut cursor);
- assert_next_entry(&mut cursor, "007");
- assert_next_entry(&mut cursor, "008");
- assert_next_entry(&mut cursor, "009");
- assert_next_entry_null(&mut cursor);
- assert_next_entry_null(&mut cursor);
- assert_next_entry_null(&mut cursor);
- assert_next_entry(&mut cursor, "010");
- assert_next_entry_null(&mut cursor);
- assert_next_entry_null(&mut cursor);
-
- assert!(cursor
- .next_entry()
- .expect("Should parse next entry")
- .is_none());
- assert!(cursor.current().is_none());
- }
-
- #[test]
- fn test_cursor_next_dfs() {
- let info_buf = &entries_cursor_tests_debug_info_buf();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
-
- assert_next_dfs(&mut cursor, "001", 0);
- assert_next_dfs(&mut cursor, "002", 1);
- assert_next_dfs(&mut cursor, "003", 1);
- assert_next_dfs(&mut cursor, "004", -1);
- assert_next_dfs(&mut cursor, "005", 1);
- assert_next_dfs(&mut cursor, "006", 0);
- assert_next_dfs(&mut cursor, "007", -1);
- assert_next_dfs(&mut cursor, "008", 1);
- assert_next_dfs(&mut cursor, "009", 1);
- assert_next_dfs(&mut cursor, "010", -2);
-
- assert!(cursor.next_dfs().expect("Should parse next dfs").is_none());
- assert!(cursor.current().is_none());
- }
-
- #[test]
- fn test_cursor_next_sibling_no_sibling_ptr() {
- let info_buf = &entries_cursor_tests_debug_info_buf();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
-
- assert_next_dfs(&mut cursor, "001", 0);
-
- // Down to the first child of the root entry.
-
- assert_next_dfs(&mut cursor, "002", 1);
-
- // Now iterate all children of the root via `next_sibling`.
-
- assert_next_sibling(&mut cursor, "004");
- assert_next_sibling(&mut cursor, "007");
- assert_next_sibling(&mut cursor, "010");
-
- // There should be no more siblings.
-
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor.current().is_none());
- }
-
- #[test]
- fn test_cursor_next_sibling_continuation() {
- let info_buf = &entries_cursor_tests_debug_info_buf();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
-
- assert_next_dfs(&mut cursor, "001", 0);
-
- // Down to the first child of the root entry.
-
- assert_next_dfs(&mut cursor, "002", 1);
-
- // Get the next sibling, then iterate its children
-
- assert_next_sibling(&mut cursor, "004");
- assert_next_dfs(&mut cursor, "005", 1);
- assert_next_sibling(&mut cursor, "006");
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
-
- // And we should be able to continue with the children of the root entry.
-
- assert_next_dfs(&mut cursor, "007", -1);
- assert_next_sibling(&mut cursor, "010");
-
- // There should be no more siblings.
-
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor.current().is_none());
- }
-
- fn entries_cursor_sibling_abbrev_buf() -> Vec<u8> {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr(DW_AT_sibling, DW_FORM_ref1)
- .abbrev_attr_null()
- .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev_null();
- section.get_contents().unwrap()
- }
-
- fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec<u8> {
- let start = Label::new();
- let sibling004_ref = Label::new();
- let sibling004 = Label::new();
- let sibling009_ref = Label::new();
- let sibling009 = Label::new();
-
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .mark(&start)
- .die(2, |s| s.attr_string("001"))
- // Valid sibling attribute.
- .die(1, |s| s.attr_string("002").D8(&sibling004_ref))
- // Invalid code to ensure the sibling attribute was used.
- .die(10, |s| s.attr_string("003"))
- .die_null()
- .die_null()
- .mark(&sibling004)
- // Invalid sibling attribute.
- .die(1, |s| s.attr_string("004").attr_ref1(255))
- .die(2, |s| s.attr_string("005"))
- .die_null()
- .die_null()
- // Sibling attribute in child only.
- .die(2, |s| s.attr_string("006"))
- // Valid sibling attribute.
- .die(1, |s| s.attr_string("007").D8(&sibling009_ref))
- // Invalid code to ensure the sibling attribute was used.
- .die(10, |s| s.attr_string("008"))
- .die_null()
- .die_null()
- .mark(&sibling009)
- .die(2, |s| s.attr_string("009"))
- .die_null()
- .die_null()
- // No sibling attribute.
- .die(2, |s| s.attr_string("010"))
- .die(2, |s| s.attr_string("011"))
- .die_null()
- .die_null()
- .die_null();
-
- let offset = header_size as u64 + (&sibling004 - &start) as u64;
- sibling004_ref.set_const(offset);
-
- let offset = header_size as u64 + (&sibling009 - &start) as u64;
- sibling009_ref.set_const(offset);
-
- section.get_contents().unwrap()
- }
-
- fn test_cursor_next_sibling_with_ptr(cursor: &mut EntriesCursor<EndianSlice<LittleEndian>>) {
- assert_next_dfs(cursor, "001", 0);
-
- // Down to the first child of the root.
-
- assert_next_dfs(cursor, "002", 1);
-
- // Now iterate all children of the root via `next_sibling`.
-
- assert_valid_sibling_ptr(&cursor);
- assert_next_sibling(cursor, "004");
- assert_next_sibling(cursor, "006");
- assert_next_sibling(cursor, "010");
-
- // There should be no more siblings.
-
- assert!(cursor
- .next_sibling()
- .expect("Should parse next sibling")
- .is_none());
- assert!(cursor.current().is_none());
- }
-
- #[test]
- fn test_debug_info_next_sibling_with_ptr() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
-
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&[], LittleEndian),
- };
- let header_size = unit.size_of_header();
- let entries_buf = entries_cursor_sibling_entries_buf(header_size);
- unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
- let section = Section::with_endian(Endian::Little).unit(&mut unit);
- let info_buf = section.get_contents().unwrap();
- let debug_info = DebugInfo::new(&info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrev_buf = entries_cursor_sibling_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
- test_cursor_next_sibling_with_ptr(&mut cursor);
- }
-
- #[test]
- fn test_debug_types_next_sibling_with_ptr() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0),
- type_offset: UnitOffset(0),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugTypesOffset(0).into(),
- entries_buf: EndianSlice::new(&[], LittleEndian),
- };
- let header_size = unit.size_of_header();
- let entries_buf = entries_cursor_sibling_entries_buf(header_size);
- unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
- let section = Section::with_endian(Endian::Little).unit(&mut unit);
- let info_buf = section.get_contents().unwrap();
- let debug_types = DebugTypes::new(&info_buf, LittleEndian);
-
- let unit = debug_types
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrev_buf = entries_cursor_sibling_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit.entries(&abbrevs);
- test_cursor_next_sibling_with_ptr(&mut cursor);
- }
-
- #[test]
- fn test_entries_at_offset() {
- let info_buf = &entries_cursor_tests_debug_info_buf();
- let debug_info = DebugInfo::new(info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
- let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut cursor = unit
- .entries_at_offset(&abbrevs, UnitOffset(unit.header_size()))
- .unwrap();
- assert_next_entry(&mut cursor, "001");
-
- let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0));
- match cursor {
- Err(Error::OffsetOutOfBounds) => {}
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
- }
-
- fn entries_tree_tests_debug_abbrevs_buf() -> Vec<u8> {
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev_null()
- .get_contents()
- .unwrap();
- section
- }
-
- fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec<u8>, UnitOffset) {
- let start = Label::new();
- let entry2 = Label::new();
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .mark(&start)
- .die(1, |s| s.attr_string("root"))
- .die(1, |s| s.attr_string("1"))
- .die(1, |s| s.attr_string("1a"))
- .die_null()
- .die(2, |s| s.attr_string("1b"))
- .die_null()
- .mark(&entry2)
- .die(1, |s| s.attr_string("2"))
- .die(1, |s| s.attr_string("2a"))
- .die(1, |s| s.attr_string("2a1"))
- .die_null()
- .die_null()
- .die(1, |s| s.attr_string("2b"))
- .die(2, |s| s.attr_string("2b1"))
- .die_null()
- .die_null()
- .die(1, |s| s.attr_string("3"))
- .die(1, |s| s.attr_string("3a"))
- .die(2, |s| s.attr_string("3a1"))
- .die(2, |s| s.attr_string("3a2"))
- .die_null()
- .die(2, |s| s.attr_string("3b"))
- .die_null()
- .die(2, |s| s.attr_string("final"))
- .die_null()
- .get_contents()
- .unwrap();
- let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize);
- (section, entry2)
- }
-
- #[test]
- fn test_entries_tree() {
- fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>(
- node: Result<
- Option<EntriesTreeNode<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>>,
- >,
- name: &str,
- ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>
- where
- Endian: Endianity,
- {
- let node = node
- .expect("Should parse entry")
- .expect("Should have entry");
- assert_entry_name(node.entry(), name);
- node.children()
- }
-
- fn assert_null<E: Endianity>(node: Result<Option<EntriesTreeNode<EndianSlice<E>>>>) {
- match node {
- Ok(None) => {}
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
- }
-
- let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf();
- let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian);
-
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&[], LittleEndian),
- };
- let header_size = unit.size_of_header();
- let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size);
- unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
- let info_buf = Section::with_endian(Endian::Little)
- .unit(&mut unit)
- .get_contents()
- .unwrap();
- let debug_info = DebugInfo::new(&info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("Should parse unit")
- .expect("and it should be some");
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
- let mut tree = unit
- .entries_tree(&abbrevs, None)
- .expect("Should have entries tree");
-
- // Test we can restart iteration of the tree.
- {
- let mut iter = assert_entry(tree.root().map(Some), "root");
- assert_entry(iter.next(), "1");
- }
- {
- let mut iter = assert_entry(tree.root().map(Some), "root");
- assert_entry(iter.next(), "1");
- }
-
- let mut iter = assert_entry(tree.root().map(Some), "root");
- {
- // Test iteration with children.
- let mut iter = assert_entry(iter.next(), "1");
- {
- // Test iteration with children flag, but no children.
- let mut iter = assert_entry(iter.next(), "1a");
- assert_null(iter.next());
- assert_null(iter.next());
- }
- {
- // Test iteration without children flag.
- let mut iter = assert_entry(iter.next(), "1b");
- assert_null(iter.next());
- assert_null(iter.next());
- }
- assert_null(iter.next());
- assert_null(iter.next());
- }
- {
- // Test skipping over children.
- let mut iter = assert_entry(iter.next(), "2");
- assert_entry(iter.next(), "2a");
- assert_entry(iter.next(), "2b");
- assert_null(iter.next());
- }
- {
- // Test skipping after partial iteration.
- let mut iter = assert_entry(iter.next(), "3");
- {
- let mut iter = assert_entry(iter.next(), "3a");
- assert_entry(iter.next(), "3a1");
- // Parent iter should be able to skip over "3a2".
- }
- assert_entry(iter.next(), "3b");
- assert_null(iter.next());
- }
- assert_entry(iter.next(), "final");
- assert_null(iter.next());
-
- // Test starting at an offset.
- let mut tree = unit
- .entries_tree(&abbrevs, Some(entry2))
- .expect("Should have entries tree");
- let mut iter = assert_entry(tree.root().map(Some), "2");
- assert_entry(iter.next(), "2a");
- assert_entry(iter.next(), "2b");
- assert_null(iter.next());
- }
-
- #[test]
- fn test_entries_raw() {
- fn assert_abbrev<'input, 'abbrev, 'unit, Endian>(
- entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>,
- tag: DwTag,
- ) -> &'abbrev Abbreviation
- where
- Endian: Endianity,
- {
- let abbrev = entries
- .read_abbreviation()
- .expect("Should parse abbrev")
- .expect("Should have abbrev");
- assert_eq!(abbrev.tag(), tag);
- abbrev
- }
-
- fn assert_null<'input, 'abbrev, 'unit, Endian>(
- entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>,
- ) where
- Endian: Endianity,
- {
- match entries.read_abbreviation() {
- Ok(None) => {}
- otherwise => {
- assert!(false, "Unexpected parse result = {:#?}", otherwise);
- }
- }
- }
-
- fn assert_attr<'input, 'abbrev, 'unit, Endian>(
- entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>,
- spec: Option<AttributeSpecification>,
- name: DwAt,
- value: &str,
- ) where
- Endian: Endianity,
- {
- let spec = spec.expect("Should have attribute specification");
- let attr = entries
- .read_attribute(spec)
- .expect("Should parse attribute");
- assert_eq!(attr.name(), name);
- assert_eq!(
- attr.value(),
- AttributeValue::String(EndianSlice::new(value.as_bytes(), Endian::default()))
- );
- }
-
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr(DW_AT_linkage_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev(2, DW_TAG_variable, DW_CHILDREN_no)
- .abbrev_attr(DW_AT_name, DW_FORM_string)
- .abbrev_attr_null()
- .abbrev_null();
- let abbrevs_buf = section.get_contents().unwrap();
- let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian);
-
- #[rustfmt::skip]
- let section = Section::with_endian(Endian::Little)
- .die(1, |s| s.attr_string("f1").attr_string("l1"))
- .die(2, |s| s.attr_string("v1"))
- .die(2, |s| s.attr_string("v2"))
- .die(1, |s| s.attr_string("f2").attr_string("l2"))
- .die_null()
- .die_null();
- let entries_buf = section.get_contents().unwrap();
-
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
- };
- let section = Section::with_endian(Endian::Little).unit(&mut unit);
- let info_buf = section.get_contents().unwrap();
- let debug_info = DebugInfo::new(&info_buf, LittleEndian);
-
- let unit = debug_info
- .units()
- .next()
- .expect("should have a unit result")
- .expect("and it should be ok");
-
- let abbrevs = unit
- .abbreviations(&debug_abbrev)
- .expect("Should parse abbreviations");
-
- let mut entries = unit
- .entries_raw(&abbrevs, None)
- .expect("Should have entries");
-
- assert_eq!(entries.next_depth(), 0);
- let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram);
- let mut attrs = abbrev.attributes().iter().copied();
- assert_attr(&mut entries, attrs.next(), DW_AT_name, "f1");
- assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l1");
- assert!(attrs.next().is_none());
-
- assert_eq!(entries.next_depth(), 1);
- let abbrev = assert_abbrev(&mut entries, DW_TAG_variable);
- let mut attrs = abbrev.attributes().iter().copied();
- assert_attr(&mut entries, attrs.next(), DW_AT_name, "v1");
- assert!(attrs.next().is_none());
-
- assert_eq!(entries.next_depth(), 1);
- let abbrev = assert_abbrev(&mut entries, DW_TAG_variable);
- let mut attrs = abbrev.attributes().iter().copied();
- assert_attr(&mut entries, attrs.next(), DW_AT_name, "v2");
- assert!(attrs.next().is_none());
-
- assert_eq!(entries.next_depth(), 1);
- let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram);
- let mut attrs = abbrev.attributes().iter().copied();
- assert_attr(&mut entries, attrs.next(), DW_AT_name, "f2");
- assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l2");
- assert!(attrs.next().is_none());
-
- assert_eq!(entries.next_depth(), 2);
- assert_null(&mut entries);
-
- assert_eq!(entries.next_depth(), 1);
- assert_null(&mut entries);
-
- assert_eq!(entries.next_depth(), 0);
- assert!(entries.is_empty());
- }
-
- #[test]
- fn test_debug_info_offset() {
- let padding = &[0; 10];
- let entries = &[0; 20];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(entries, LittleEndian),
- };
- Section::with_endian(Endian::Little)
- .append_bytes(padding)
- .unit(&mut unit);
- let offset = padding.len();
- let header_length = unit.size_of_header();
- let length = unit.length_including_self();
- assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None);
- assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None);
- assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None);
- assert_eq!(
- DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit),
- None
- );
- assert_eq!(
- DebugInfoOffset(offset + header_length).to_unit_offset(&unit),
- Some(UnitOffset(header_length))
- );
- assert_eq!(
- DebugInfoOffset(offset + length - 1).to_unit_offset(&unit),
- Some(UnitOffset(length - 1))
- );
- assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None);
- assert_eq!(
- UnitOffset(header_length).to_debug_info_offset(&unit),
- Some(DebugInfoOffset(offset + header_length))
- );
- assert_eq!(
- UnitOffset(length - 1).to_debug_info_offset(&unit),
- Some(DebugInfoOffset(offset + length - 1))
- );
- }
-
- #[test]
- fn test_debug_types_offset() {
- let padding = &[0; 10];
- let entries = &[0; 20];
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Type {
- type_signature: DebugTypeSignature(0),
- type_offset: UnitOffset(0),
- },
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugTypesOffset(0).into(),
- entries_buf: EndianSlice::new(entries, LittleEndian),
- };
- Section::with_endian(Endian::Little)
- .append_bytes(padding)
- .unit(&mut unit);
- let offset = padding.len();
- let header_length = unit.size_of_header();
- let length = unit.length_including_self();
- assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None);
- assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None);
- assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None);
- assert_eq!(
- DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit),
- None
- );
- assert_eq!(
- DebugTypesOffset(offset + header_length).to_unit_offset(&unit),
- Some(UnitOffset(header_length))
- );
- assert_eq!(
- DebugTypesOffset(offset + length - 1).to_unit_offset(&unit),
- Some(UnitOffset(length - 1))
- );
- assert_eq!(
- DebugTypesOffset(offset + length).to_unit_offset(&unit),
- None
- );
- assert_eq!(
- UnitOffset(header_length).to_debug_types_offset(&unit),
- Some(DebugTypesOffset(offset + header_length))
- );
- assert_eq!(
- UnitOffset(length - 1).to_debug_types_offset(&unit),
- Some(DebugTypesOffset(offset + length - 1))
- );
- }
-
- #[test]
- fn test_length_including_self() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let mut unit = UnitHeader {
- encoding,
- unit_length: 0,
- unit_type: UnitType::Compilation,
- debug_abbrev_offset: DebugAbbrevOffset(0),
- unit_offset: DebugInfoOffset(0).into(),
- entries_buf: EndianSlice::new(&[], LittleEndian),
- };
- unit.encoding.format = Format::Dwarf32;
- assert_eq!(unit.length_including_self(), 4);
- unit.encoding.format = Format::Dwarf64;
- assert_eq!(unit.length_including_self(), 12);
- unit.unit_length = 10;
- assert_eq!(unit.length_including_self(), 22);
- }
-
- #[test]
- fn test_parse_type_unit_abbrevs() {
- let types_buf = [
- // Type unit header
- 0x25, 0x00, 0x00, 0x00, // 32-bit unit length = 37
- 0x04, 0x00, // Version 4
- 0x00, 0x00, 0x00, 0x00, // debug_abbrev_offset
- 0x04, // Address size
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Type signature
- 0x01, 0x02, 0x03, 0x04, // Type offset
- // DIEs
- // Abbreviation code
- 0x01, // Attribute of form DW_FORM_string = "foo\0"
- 0x66, 0x6f, 0x6f, 0x00, // Children
- // Abbreviation code
- 0x01, // Attribute of form DW_FORM_string = "foo\0"
- 0x66, 0x6f, 0x6f, 0x00, // Children
- // Abbreviation code
- 0x01, // Attribute of form DW_FORM_string = "foo\0"
- 0x66, 0x6f, 0x6f, 0x00, // Children
- 0x00, // End of children
- 0x00, // End of children
- 0x00, // End of children
- ];
- let debug_types = DebugTypes::new(&types_buf, LittleEndian);
-
- let abbrev_buf = [
- // Code
- 0x01, // DW_TAG_subprogram
- 0x2e, // DW_CHILDREN_yes
- 0x01, // Begin attributes
- 0x03, // Attribute name = DW_AT_name
- 0x08, // Attribute form = DW_FORM_string
- 0x00, 0x00, // End attributes
- 0x00, // Null terminator
- ];
-
- let get_some_type_unit = || debug_types.units().next().unwrap().unwrap();
-
- let unit = get_some_type_unit();
-
- let read_debug_abbrev_section_somehow = || &abbrev_buf;
- let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian);
- let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap();
- }
-}
diff --git a/vendor/gimli/src/read/util.rs b/vendor/gimli/src/read/util.rs
deleted file mode 100644
index 041ca5a..0000000
--- a/vendor/gimli/src/read/util.rs
+++ /dev/null
@@ -1,283 +0,0 @@
-#[cfg(feature = "read")]
-use alloc::boxed::Box;
-#[cfg(feature = "read")]
-use alloc::vec::Vec;
-use core::fmt;
-use core::mem::MaybeUninit;
-use core::ops;
-use core::ptr;
-use core::slice;
-
-mod sealed {
- /// # Safety
- /// Implementer must not modify the content in storage.
- pub unsafe trait Sealed {
- type Storage;
-
- fn new_storage() -> Self::Storage;
-
- fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> {
- Err(CapacityFull)
- }
- }
-
- #[derive(Clone, Copy, Debug)]
- pub struct CapacityFull;
-}
-
-use sealed::*;
-
-/// Marker trait for types that can be used as backing storage when a growable array type is needed.
-///
-/// This trait is sealed and cannot be implemented for types outside this crate.
-pub trait ArrayLike: Sealed {
- /// Type of the elements being stored.
- type Item;
-
- #[doc(hidden)]
- fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<Self::Item>];
-
- #[doc(hidden)]
- fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<Self::Item>];
-}
-
-// Use macro since const generics can't be used due to MSRV.
-macro_rules! impl_array {
- () => {};
- ($n:literal $($rest:tt)*) => {
- // SAFETY: does not modify the content in storage.
- unsafe impl<T> Sealed for [T; $n] {
- type Storage = [MaybeUninit<T>; $n];
-
- fn new_storage() -> Self::Storage {
- // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
- unsafe { MaybeUninit::uninit().assume_init() }
- }
- }
-
- impl<T> ArrayLike for [T; $n] {
- type Item = T;
-
- fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
- storage
- }
-
- fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
- storage
- }
- }
-
- impl_array!($($rest)*);
- }
-}
-
-#[cfg(feature = "read")]
-macro_rules! impl_box {
- () => {};
- ($n:literal $($rest:tt)*) => {
- // SAFETY: does not modify the content in storage.
- unsafe impl<T> Sealed for Box<[T; $n]> {
- type Storage = Box<[MaybeUninit<T>; $n]>;
-
- fn new_storage() -> Self::Storage {
- // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
- Box::new(unsafe { MaybeUninit::uninit().assume_init() })
- }
- }
-
- impl<T> ArrayLike for Box<[T; $n]> {
- type Item = T;
-
- fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
- &storage[..]
- }
-
- fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
- &mut storage[..]
- }
- }
-
- impl_box!($($rest)*);
- }
-}
-
-impl_array!(0 1 2 3 4 8 16 32 64 128 192);
-#[cfg(feature = "read")]
-impl_box!(0 1 2 3 4 8 16 32 64 128 192);
-
-#[cfg(feature = "read")]
-unsafe impl<T> Sealed for Vec<T> {
- type Storage = Box<[MaybeUninit<T>]>;
-
- fn new_storage() -> Self::Storage {
- Box::new([])
- }
-
- fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> {
- let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into();
- vec.reserve(additional);
- // SAFETY: This is a `Vec` of `MaybeUninit`.
- unsafe { vec.set_len(vec.capacity()) };
- *storage = vec.into_boxed_slice();
- Ok(())
- }
-}
-
-#[cfg(feature = "read")]
-impl<T> ArrayLike for Vec<T> {
- type Item = T;
-
- fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
- storage
- }
-
- fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
- storage
- }
-}
-
-pub(crate) struct ArrayVec<A: ArrayLike> {
- storage: A::Storage,
- len: usize,
-}
-
-impl<A: ArrayLike> ArrayVec<A> {
- pub fn new() -> Self {
- Self {
- storage: A::new_storage(),
- len: 0,
- }
- }
-
- pub fn clear(&mut self) {
- let ptr: *mut [A::Item] = &mut **self;
- // Set length first so the type invariant is upheld even if `drop_in_place` panicks.
- self.len = 0;
- // SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length.
- unsafe { ptr::drop_in_place(ptr) };
- }
-
- pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> {
- let mut storage = A::as_mut_slice(&mut self.storage);
- if self.len >= storage.len() {
- A::grow(&mut self.storage, 1)?;
- storage = A::as_mut_slice(&mut self.storage);
- }
-
- storage[self.len] = MaybeUninit::new(value);
- self.len += 1;
- Ok(())
- }
-
- pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> {
- assert!(index <= self.len);
-
- let mut storage = A::as_mut_slice(&mut self.storage);
- if self.len >= storage.len() {
- A::grow(&mut self.storage, 1)?;
- storage = A::as_mut_slice(&mut self.storage);
- }
-
- // SAFETY: storage[index] is filled later.
- unsafe {
- let p = storage.as_mut_ptr().add(index);
- core::ptr::copy(p as *const _, p.add(1), self.len - index);
- }
- storage[index] = MaybeUninit::new(element);
- self.len += 1;
- Ok(())
- }
-
- pub fn pop(&mut self) -> Option<A::Item> {
- if self.len == 0 {
- None
- } else {
- self.len -= 1;
- // SAFETY: this element is valid and we "forget" it by setting the length.
- Some(unsafe { A::as_slice(&self.storage)[self.len].as_ptr().read() })
- }
- }
-
- pub fn swap_remove(&mut self, index: usize) -> A::Item {
- assert!(self.len > 0);
- A::as_mut_slice(&mut self.storage).swap(index, self.len - 1);
- self.pop().unwrap()
- }
-}
-
-#[cfg(feature = "read")]
-impl<T> ArrayVec<Vec<T>> {
- pub fn into_vec(mut self) -> Vec<T> {
- let len = core::mem::replace(&mut self.len, 0);
- let storage = core::mem::replace(&mut self.storage, Box::new([]));
- let slice = Box::leak(storage);
- debug_assert!(len <= slice.len());
- // SAFETY: valid elements.
- unsafe { Vec::from_raw_parts(slice.as_mut_ptr() as *mut T, len, slice.len()) }
- }
-}
-
-impl<A: ArrayLike> Drop for ArrayVec<A> {
- fn drop(&mut self) {
- self.clear();
- }
-}
-
-impl<A: ArrayLike> Default for ArrayVec<A> {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl<A: ArrayLike> ops::Deref for ArrayVec<A> {
- type Target = [A::Item];
-
- fn deref(&self) -> &[A::Item] {
- let slice = &A::as_slice(&self.storage);
- debug_assert!(self.len <= slice.len());
- // SAFETY: valid elements.
- unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) }
- }
-}
-
-impl<A: ArrayLike> ops::DerefMut for ArrayVec<A> {
- fn deref_mut(&mut self) -> &mut [A::Item] {
- let slice = &mut A::as_mut_slice(&mut self.storage);
- debug_assert!(self.len <= slice.len());
- // SAFETY: valid elements.
- unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) }
- }
-}
-
-impl<A: ArrayLike> Clone for ArrayVec<A>
-where
- A::Item: Clone,
-{
- fn clone(&self) -> Self {
- let mut new = Self::default();
- for value in &**self {
- new.try_push(value.clone()).unwrap();
- }
- new
- }
-}
-
-impl<A: ArrayLike> PartialEq for ArrayVec<A>
-where
- A::Item: PartialEq,
-{
- fn eq(&self, other: &Self) -> bool {
- **self == **other
- }
-}
-
-impl<A: ArrayLike> Eq for ArrayVec<A> where A::Item: Eq {}
-
-impl<A: ArrayLike> fmt::Debug for ArrayVec<A>
-where
- A::Item: fmt::Debug,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
- }
-}
diff --git a/vendor/gimli/src/read/value.rs b/vendor/gimli/src/read/value.rs
deleted file mode 100644
index 77b08ed..0000000
--- a/vendor/gimli/src/read/value.rs
+++ /dev/null
@@ -1,1621 +0,0 @@
-//! Definitions for values used in DWARF expressions.
-
-use crate::constants;
-#[cfg(feature = "read")]
-use crate::read::{AttributeValue, DebuggingInformationEntry};
-use crate::read::{Error, Reader, Result};
-
-/// Convert a u64 to an i64, with sign extension if required.
-///
-/// This is primarily used when needing to treat `Value::Generic`
-/// as a signed value.
-#[inline]
-fn sign_extend(value: u64, mask: u64) -> i64 {
- let value = (value & mask) as i64;
- let sign = ((mask >> 1) + 1) as i64;
- (value ^ sign).wrapping_sub(sign)
-}
-
-#[inline]
-fn mask_bit_size(addr_mask: u64) -> u32 {
- 64 - addr_mask.leading_zeros()
-}
-
-/// The type of an entry on the DWARF stack.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ValueType {
- /// The generic type, which is address-sized and of unspecified sign,
- /// as specified in the DWARF 5 standard, section 2.5.1.
- /// This type is also used to represent address base types.
- Generic,
- /// Signed 8-bit integer type.
- I8,
- /// Unsigned 8-bit integer type.
- U8,
- /// Signed 16-bit integer type.
- I16,
- /// Unsigned 16-bit integer type.
- U16,
- /// Signed 32-bit integer type.
- I32,
- /// Unsigned 32-bit integer type.
- U32,
- /// Signed 64-bit integer type.
- I64,
- /// Unsigned 64-bit integer type.
- U64,
- /// 32-bit floating point type.
- F32,
- /// 64-bit floating point type.
- F64,
-}
-
-/// The value of an entry on the DWARF stack.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Value {
- /// A generic value, which is address-sized and of unspecified sign.
- Generic(u64),
- /// A signed 8-bit integer value.
- I8(i8),
- /// An unsigned 8-bit integer value.
- U8(u8),
- /// A signed 16-bit integer value.
- I16(i16),
- /// An unsigned 16-bit integer value.
- U16(u16),
- /// A signed 32-bit integer value.
- I32(i32),
- /// An unsigned 32-bit integer value.
- U32(u32),
- /// A signed 64-bit integer value.
- I64(i64),
- /// An unsigned 64-bit integer value.
- U64(u64),
- /// A 32-bit floating point value.
- F32(f32),
- /// A 64-bit floating point value.
- F64(f64),
-}
-
-impl ValueType {
- /// The size in bits of a value for this type.
- pub fn bit_size(self, addr_mask: u64) -> u32 {
- match self {
- ValueType::Generic => mask_bit_size(addr_mask),
- ValueType::I8 | ValueType::U8 => 8,
- ValueType::I16 | ValueType::U16 => 16,
- ValueType::I32 | ValueType::U32 | ValueType::F32 => 32,
- ValueType::I64 | ValueType::U64 | ValueType::F64 => 64,
- }
- }
-
- /// Construct a `ValueType` from the attributes of a base type DIE.
- pub fn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option<ValueType> {
- Some(match (encoding, byte_size) {
- (constants::DW_ATE_signed, 1) => ValueType::I8,
- (constants::DW_ATE_signed, 2) => ValueType::I16,
- (constants::DW_ATE_signed, 4) => ValueType::I32,
- (constants::DW_ATE_signed, 8) => ValueType::I64,
- (constants::DW_ATE_unsigned, 1) => ValueType::U8,
- (constants::DW_ATE_unsigned, 2) => ValueType::U16,
- (constants::DW_ATE_unsigned, 4) => ValueType::U32,
- (constants::DW_ATE_unsigned, 8) => ValueType::U64,
- (constants::DW_ATE_float, 4) => ValueType::F32,
- (constants::DW_ATE_float, 8) => ValueType::F64,
- _ => return None,
- })
- }
-
- /// Construct a `ValueType` from a base type DIE.
- #[cfg(feature = "read")]
- pub fn from_entry<R: Reader>(
- entry: &DebuggingInformationEntry<R>,
- ) -> Result<Option<ValueType>> {
- if entry.tag() != constants::DW_TAG_base_type {
- return Ok(None);
- }
- let mut encoding = None;
- let mut byte_size = None;
- let mut endianity = constants::DW_END_default;
- let mut attrs = entry.attrs();
- while let Some(attr) = attrs.next()? {
- match attr.name() {
- constants::DW_AT_byte_size => byte_size = attr.udata_value(),
- constants::DW_AT_encoding => {
- if let AttributeValue::Encoding(x) = attr.value() {
- encoding = Some(x);
- }
- }
- constants::DW_AT_endianity => {
- if let AttributeValue::Endianity(x) = attr.value() {
- endianity = x;
- }
- }
- _ => {}
- }
- }
-
- if endianity != constants::DW_END_default {
- // TODO: we could check if it matches the reader endianity,
- // but normally it would use DW_END_default in that case.
- return Ok(None);
- }
-
- if let (Some(encoding), Some(byte_size)) = (encoding, byte_size) {
- Ok(ValueType::from_encoding(encoding, byte_size))
- } else {
- Ok(None)
- }
- }
-}
-
-impl Value {
- /// Return the `ValueType` corresponding to this `Value`.
- pub fn value_type(&self) -> ValueType {
- match *self {
- Value::Generic(_) => ValueType::Generic,
- Value::I8(_) => ValueType::I8,
- Value::U8(_) => ValueType::U8,
- Value::I16(_) => ValueType::I16,
- Value::U16(_) => ValueType::U16,
- Value::I32(_) => ValueType::I32,
- Value::U32(_) => ValueType::U32,
- Value::I64(_) => ValueType::I64,
- Value::U64(_) => ValueType::U64,
- Value::F32(_) => ValueType::F32,
- Value::F64(_) => ValueType::F64,
- }
- }
-
- /// Read a `Value` with the given `value_type` from a `Reader`.
- pub fn parse<R: Reader>(value_type: ValueType, mut bytes: R) -> Result<Value> {
- let value = match value_type {
- ValueType::I8 => Value::I8(bytes.read_i8()?),
- ValueType::U8 => Value::U8(bytes.read_u8()?),
- ValueType::I16 => Value::I16(bytes.read_i16()?),
- ValueType::U16 => Value::U16(bytes.read_u16()?),
- ValueType::I32 => Value::I32(bytes.read_i32()?),
- ValueType::U32 => Value::U32(bytes.read_u32()?),
- ValueType::I64 => Value::I64(bytes.read_i64()?),
- ValueType::U64 => Value::U64(bytes.read_u64()?),
- ValueType::F32 => Value::F32(bytes.read_f32()?),
- ValueType::F64 => Value::F64(bytes.read_f64()?),
- _ => return Err(Error::UnsupportedTypeOperation),
- };
- Ok(value)
- }
-
- /// Convert a `Value` to a `u64`.
- ///
- /// The `ValueType` of `self` must be integral.
- /// Values are sign extended if the source value is signed.
- pub fn to_u64(self, addr_mask: u64) -> Result<u64> {
- let value = match self {
- Value::Generic(value) => value & addr_mask,
- Value::I8(value) => value as u64,
- Value::U8(value) => u64::from(value),
- Value::I16(value) => value as u64,
- Value::U16(value) => u64::from(value),
- Value::I32(value) => value as u64,
- Value::U32(value) => u64::from(value),
- Value::I64(value) => value as u64,
- Value::U64(value) => value as u64,
- _ => return Err(Error::IntegralTypeRequired),
- };
- Ok(value)
- }
-
- /// Create a `Value` with the given `value_type` from a `u64` value.
- ///
- /// The `value_type` may be integral or floating point.
- /// The result is truncated if the `u64` value does
- /// not fit the bounds of the `value_type`.
- pub fn from_u64(value_type: ValueType, value: u64) -> Result<Value> {
- let value = match value_type {
- ValueType::Generic => Value::Generic(value),
- ValueType::I8 => Value::I8(value as i8),
- ValueType::U8 => Value::U8(value as u8),
- ValueType::I16 => Value::I16(value as i16),
- ValueType::U16 => Value::U16(value as u16),
- ValueType::I32 => Value::I32(value as i32),
- ValueType::U32 => Value::U32(value as u32),
- ValueType::I64 => Value::I64(value as i64),
- ValueType::U64 => Value::U64(value),
- ValueType::F32 => Value::F32(value as f32),
- ValueType::F64 => Value::F64(value as f64),
- };
- Ok(value)
- }
-
- /// Create a `Value` with the given `value_type` from a `f32` value.
- ///
- /// The `value_type` may be integral or floating point.
- /// The result is not defined if the `f32` value does
- /// not fit the bounds of the `value_type`.
- fn from_f32(value_type: ValueType, value: f32) -> Result<Value> {
- let value = match value_type {
- ValueType::Generic => Value::Generic(value as u64),
- ValueType::I8 => Value::I8(value as i8),
- ValueType::U8 => Value::U8(value as u8),
- ValueType::I16 => Value::I16(value as i16),
- ValueType::U16 => Value::U16(value as u16),
- ValueType::I32 => Value::I32(value as i32),
- ValueType::U32 => Value::U32(value as u32),
- ValueType::I64 => Value::I64(value as i64),
- ValueType::U64 => Value::U64(value as u64),
- ValueType::F32 => Value::F32(value),
- ValueType::F64 => Value::F64(f64::from(value)),
- };
- Ok(value)
- }
-
- /// Create a `Value` with the given `value_type` from a `f64` value.
- ///
- /// The `value_type` may be integral or floating point.
- /// The result is not defined if the `f64` value does
- /// not fit the bounds of the `value_type`.
- fn from_f64(value_type: ValueType, value: f64) -> Result<Value> {
- let value = match value_type {
- ValueType::Generic => Value::Generic(value as u64),
- ValueType::I8 => Value::I8(value as i8),
- ValueType::U8 => Value::U8(value as u8),
- ValueType::I16 => Value::I16(value as i16),
- ValueType::U16 => Value::U16(value as u16),
- ValueType::I32 => Value::I32(value as i32),
- ValueType::U32 => Value::U32(value as u32),
- ValueType::I64 => Value::I64(value as i64),
- ValueType::U64 => Value::U64(value as u64),
- ValueType::F32 => Value::F32(value as f32),
- ValueType::F64 => Value::F64(value),
- };
- Ok(value)
- }
-
- /// Convert a `Value` to the given `value_type`.
- ///
- /// When converting between integral types, the result is truncated
- /// if the source value does not fit the bounds of the `value_type`.
- /// When converting from floating point types, the result is not defined
- /// if the source value does not fit the bounds of the `value_type`.
- ///
- /// This corresponds to the DWARF `DW_OP_convert` operation.
- pub fn convert(self, value_type: ValueType, addr_mask: u64) -> Result<Value> {
- match self {
- Value::F32(value) => Value::from_f32(value_type, value),
- Value::F64(value) => Value::from_f64(value_type, value),
- _ => Value::from_u64(value_type, self.to_u64(addr_mask)?),
- }
- }
-
- /// Reinterpret the bits in a `Value` as the given `value_type`.
- ///
- /// The source and result value types must have equal sizes.
- ///
- /// This corresponds to the DWARF `DW_OP_reinterpret` operation.
- pub fn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result<Value> {
- if self.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) {
- return Err(Error::TypeMismatch);
- }
- let bits = match self {
- Value::Generic(value) => value,
- Value::I8(value) => value as u64,
- Value::U8(value) => u64::from(value),
- Value::I16(value) => value as u64,
- Value::U16(value) => u64::from(value),
- Value::I32(value) => value as u64,
- Value::U32(value) => u64::from(value),
- Value::I64(value) => value as u64,
- Value::U64(value) => value,
- Value::F32(value) => u64::from(f32::to_bits(value)),
- Value::F64(value) => f64::to_bits(value),
- };
- let value = match value_type {
- ValueType::Generic => Value::Generic(bits),
- ValueType::I8 => Value::I8(bits as i8),
- ValueType::U8 => Value::U8(bits as u8),
- ValueType::I16 => Value::I16(bits as i16),
- ValueType::U16 => Value::U16(bits as u16),
- ValueType::I32 => Value::I32(bits as i32),
- ValueType::U32 => Value::U32(bits as u32),
- ValueType::I64 => Value::I64(bits as i64),
- ValueType::U64 => Value::U64(bits),
- ValueType::F32 => Value::F32(f32::from_bits(bits as u32)),
- ValueType::F64 => Value::F64(f64::from_bits(bits)),
- };
- Ok(value)
- }
-
- /// Perform an absolute value operation.
- ///
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_abs` operation.
- pub fn abs(self, addr_mask: u64) -> Result<Value> {
- // wrapping_abs() can be used because DWARF specifies that the result is undefined
- // for negative minimal values.
- let value = match self {
- Value::Generic(value) => {
- Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64)
- }
- Value::I8(value) => Value::I8(value.wrapping_abs()),
- Value::I16(value) => Value::I16(value.wrapping_abs()),
- Value::I32(value) => Value::I32(value.wrapping_abs()),
- Value::I64(value) => Value::I64(value.wrapping_abs()),
- // f32/f64::abs() is not available in libcore
- Value::F32(value) => Value::F32(if value < 0. { -value } else { value }),
- Value::F64(value) => Value::F64(if value < 0. { -value } else { value }),
- Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self,
- };
- Ok(value)
- }
-
- /// Perform a negation operation.
- ///
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_neg` operation.
- pub fn neg(self, addr_mask: u64) -> Result<Value> {
- // wrapping_neg() can be used because DWARF specifies that the result is undefined
- // for negative minimal values.
- let value = match self {
- Value::Generic(value) => {
- Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64)
- }
- Value::I8(value) => Value::I8(value.wrapping_neg()),
- Value::I16(value) => Value::I16(value.wrapping_neg()),
- Value::I32(value) => Value::I32(value.wrapping_neg()),
- Value::I64(value) => Value::I64(value.wrapping_neg()),
- Value::F32(value) => Value::F32(-value),
- Value::F64(value) => Value::F64(-value),
- // It's unclear if these should implicitly convert to a signed value.
- // For now, we don't support them.
- Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => {
- return Err(Error::UnsupportedTypeOperation);
- }
- };
- Ok(value)
- }
-
- /// Perform an addition operation.
- ///
- /// This operation requires matching types.
- ///
- /// This corresponds to the DWARF `DW_OP_plus` operation.
- pub fn add(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- Value::Generic(v1.wrapping_add(v2) & addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_add(v2)),
- (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_add(v2)),
- (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_add(v2)),
- (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_add(v2)),
- (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)),
- (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)),
- (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)),
- (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)),
- (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 + v2),
- (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 + v2),
- _ => return Err(Error::TypeMismatch),
- };
- Ok(value)
- }
-
- /// Perform a subtraction operation.
- ///
- /// This operation requires matching types.
- ///
- /// This corresponds to the DWARF `DW_OP_minus` operation.
- pub fn sub(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- Value::Generic(v1.wrapping_sub(v2) & addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_sub(v2)),
- (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_sub(v2)),
- (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_sub(v2)),
- (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_sub(v2)),
- (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_sub(v2)),
- (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_sub(v2)),
- (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_sub(v2)),
- (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_sub(v2)),
- (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 - v2),
- (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 - v2),
- _ => return Err(Error::TypeMismatch),
- };
- Ok(value)
- }
-
- /// Perform a multiplication operation.
- ///
- /// This operation requires matching types.
- ///
- /// This corresponds to the DWARF `DW_OP_mul` operation.
- pub fn mul(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- Value::Generic(v1.wrapping_mul(v2) & addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_mul(v2)),
- (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_mul(v2)),
- (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_mul(v2)),
- (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_mul(v2)),
- (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_mul(v2)),
- (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_mul(v2)),
- (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_mul(v2)),
- (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_mul(v2)),
- (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 * v2),
- (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 * v2),
- _ => return Err(Error::TypeMismatch),
- };
- Ok(value)
- }
-
- /// Perform a division operation.
- ///
- /// This operation requires matching types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_div` operation.
- pub fn div(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- match rhs {
- Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => {
- return Err(Error::DivisionByZero);
- }
- Value::I8(0)
- | Value::U8(0)
- | Value::I16(0)
- | Value::U16(0)
- | Value::I32(0)
- | Value::U32(0)
- | Value::I64(0)
- | Value::U64(0) => {
- return Err(Error::DivisionByZero);
- }
- _ => {}
- }
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- // Signed division
- Value::Generic(
- sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64,
- )
- }
- (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)),
- (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)),
- (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)),
- (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)),
- (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)),
- (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)),
- (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)),
- (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)),
- (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2),
- (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2),
- _ => return Err(Error::TypeMismatch),
- };
- Ok(value)
- }
-
- /// Perform a remainder operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as an unsigned value.
- ///
- /// This corresponds to the DWARF `DW_OP_mod` operation.
- pub fn rem(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- match rhs {
- Value::Generic(rhs) if (rhs & addr_mask) == 0 => {
- return Err(Error::DivisionByZero);
- }
- Value::I8(0)
- | Value::U8(0)
- | Value::I16(0)
- | Value::U16(0)
- | Value::I32(0)
- | Value::U32(0)
- | Value::I64(0)
- | Value::U64(0) => {
- return Err(Error::DivisionByZero);
- }
- _ => {}
- }
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- // Unsigned modulus
- Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask))
- }
- (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)),
- (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)),
- (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)),
- (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)),
- (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)),
- (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)),
- (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)),
- (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)),
- (Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired),
- (Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired),
- _ => return Err(Error::TypeMismatch),
- };
- Ok(value)
- }
-
- /// Perform a bitwise not operation.
- ///
- /// This operation requires matching integral types.
- ///
- /// This corresponds to the DWARF `DW_OP_not` operation.
- pub fn not(self, addr_mask: u64) -> Result<Value> {
- let value_type = self.value_type();
- let v = self.to_u64(addr_mask)?;
- Value::from_u64(value_type, !v)
- }
-
- /// Perform a bitwise and operation.
- ///
- /// This operation requires matching integral types.
- ///
- /// This corresponds to the DWARF `DW_OP_and` operation.
- pub fn and(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value_type = self.value_type();
- if value_type != rhs.value_type() {
- return Err(Error::TypeMismatch);
- }
- let v1 = self.to_u64(addr_mask)?;
- let v2 = rhs.to_u64(addr_mask)?;
- Value::from_u64(value_type, v1 & v2)
- }
-
- /// Perform a bitwise or operation.
- ///
- /// This operation requires matching integral types.
- ///
- /// This corresponds to the DWARF `DW_OP_or` operation.
- pub fn or(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value_type = self.value_type();
- if value_type != rhs.value_type() {
- return Err(Error::TypeMismatch);
- }
- let v1 = self.to_u64(addr_mask)?;
- let v2 = rhs.to_u64(addr_mask)?;
- Value::from_u64(value_type, v1 | v2)
- }
-
- /// Perform a bitwise exclusive-or operation.
- ///
- /// This operation requires matching integral types.
- ///
- /// This corresponds to the DWARF `DW_OP_xor` operation.
- pub fn xor(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value_type = self.value_type();
- if value_type != rhs.value_type() {
- return Err(Error::TypeMismatch);
- }
- let v1 = self.to_u64(addr_mask)?;
- let v2 = rhs.to_u64(addr_mask)?;
- Value::from_u64(value_type, v1 ^ v2)
- }
-
- /// Convert value to bit length suitable for a shift operation.
- ///
- /// If the value is negative then an error is returned.
- fn shift_length(self) -> Result<u64> {
- let value = match self {
- Value::Generic(value) => value,
- Value::I8(value) if value >= 0 => value as u64,
- Value::U8(value) => u64::from(value),
- Value::I16(value) if value >= 0 => value as u64,
- Value::U16(value) => u64::from(value),
- Value::I32(value) if value >= 0 => value as u64,
- Value::U32(value) => u64::from(value),
- Value::I64(value) if value >= 0 => value as u64,
- Value::U64(value) => value,
- _ => return Err(Error::InvalidShiftExpression),
- };
- Ok(value)
- }
-
- /// Perform a shift left operation.
- ///
- /// This operation requires integral types.
- /// If the shift length exceeds the type size, then 0 is returned.
- /// If the shift length is negative then an error is returned.
- ///
- /// This corresponds to the DWARF `DW_OP_shl` operation.
- pub fn shl(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let v2 = rhs.shift_length()?;
- let value = match self {
- Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) {
- 0
- } else {
- (v1 & addr_mask) << v2
- }),
- Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }),
- Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }),
- Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }),
- Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }),
- Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }),
- Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }),
- Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }),
- Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }),
- _ => return Err(Error::IntegralTypeRequired),
- };
- Ok(value)
- }
-
- /// Perform a logical shift right operation.
- ///
- /// This operation requires an unsigned integral type for the value.
- /// If the value type is `Generic`, then it is interpreted as an unsigned value.
- ///
- /// This operation requires an integral type for the shift length.
- /// If the shift length exceeds the type size, then 0 is returned.
- /// If the shift length is negative then an error is returned.
- ///
- /// This corresponds to the DWARF `DW_OP_shr` operation.
- pub fn shr(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let v2 = rhs.shift_length()?;
- let value = match self {
- Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) {
- 0
- } else {
- (v1 & addr_mask) >> v2
- }),
- Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }),
- Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }),
- Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }),
- Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }),
- // It's unclear if signed values should implicitly convert to an unsigned value.
- // For now, we don't support them.
- Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => {
- return Err(Error::UnsupportedTypeOperation);
- }
- _ => return Err(Error::IntegralTypeRequired),
- };
- Ok(value)
- }
-
- /// Perform an arithmetic shift right operation.
- ///
- /// This operation requires a signed integral type for the value.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This operation requires an integral type for the shift length.
- /// If the shift length exceeds the type size, then 0 is returned for positive values,
- /// and -1 is returned for negative values.
- /// If the shift length is negative then an error is returned.
- ///
- /// This corresponds to the DWARF `DW_OP_shra` operation.
- pub fn shra(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let v2 = rhs.shift_length()?;
- let value = match self {
- Value::Generic(v1) => {
- let v1 = sign_extend(v1, addr_mask);
- let value = if v2 >= u64::from(mask_bit_size(addr_mask)) {
- if v1 < 0 {
- !0
- } else {
- 0
- }
- } else {
- (v1 >> v2) as u64
- };
- Value::Generic(value)
- }
- Value::I8(v1) => Value::I8(if v2 >= 8 {
- if v1 < 0 {
- !0
- } else {
- 0
- }
- } else {
- v1 >> v2
- }),
- Value::I16(v1) => Value::I16(if v2 >= 16 {
- if v1 < 0 {
- !0
- } else {
- 0
- }
- } else {
- v1 >> v2
- }),
- Value::I32(v1) => Value::I32(if v2 >= 32 {
- if v1 < 0 {
- !0
- } else {
- 0
- }
- } else {
- v1 >> v2
- }),
- Value::I64(v1) => Value::I64(if v2 >= 64 {
- if v1 < 0 {
- !0
- } else {
- 0
- }
- } else {
- v1 >> v2
- }),
- // It's unclear if unsigned values should implicitly convert to a signed value.
- // For now, we don't support them.
- Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => {
- return Err(Error::UnsupportedTypeOperation);
- }
- _ => return Err(Error::IntegralTypeRequired),
- };
- Ok(value)
- }
-
- /// Perform the `==` relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_eq` operation.
- pub fn eq(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 == v2,
- (Value::U8(v1), Value::U8(v2)) => v1 == v2,
- (Value::I16(v1), Value::I16(v2)) => v1 == v2,
- (Value::U16(v1), Value::U16(v2)) => v1 == v2,
- (Value::I32(v1), Value::I32(v2)) => v1 == v2,
- (Value::U32(v1), Value::U32(v2)) => v1 == v2,
- (Value::I64(v1), Value::I64(v2)) => v1 == v2,
- (Value::U64(v1), Value::U64(v2)) => v1 == v2,
- (Value::F32(v1), Value::F32(v2)) => v1 == v2,
- (Value::F64(v1), Value::F64(v2)) => v1 == v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-
- /// Perform the `>=` relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_ge` operation.
- pub fn ge(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 >= v2,
- (Value::U8(v1), Value::U8(v2)) => v1 >= v2,
- (Value::I16(v1), Value::I16(v2)) => v1 >= v2,
- (Value::U16(v1), Value::U16(v2)) => v1 >= v2,
- (Value::I32(v1), Value::I32(v2)) => v1 >= v2,
- (Value::U32(v1), Value::U32(v2)) => v1 >= v2,
- (Value::I64(v1), Value::I64(v2)) => v1 >= v2,
- (Value::U64(v1), Value::U64(v2)) => v1 >= v2,
- (Value::F32(v1), Value::F32(v2)) => v1 >= v2,
- (Value::F64(v1), Value::F64(v2)) => v1 >= v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-
- /// Perform the `>` relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_gt` operation.
- pub fn gt(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 > v2,
- (Value::U8(v1), Value::U8(v2)) => v1 > v2,
- (Value::I16(v1), Value::I16(v2)) => v1 > v2,
- (Value::U16(v1), Value::U16(v2)) => v1 > v2,
- (Value::I32(v1), Value::I32(v2)) => v1 > v2,
- (Value::U32(v1), Value::U32(v2)) => v1 > v2,
- (Value::I64(v1), Value::I64(v2)) => v1 > v2,
- (Value::U64(v1), Value::U64(v2)) => v1 > v2,
- (Value::F32(v1), Value::F32(v2)) => v1 > v2,
- (Value::F64(v1), Value::F64(v2)) => v1 > v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-
- /// Perform the `<= relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_le` operation.
- pub fn le(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 <= v2,
- (Value::U8(v1), Value::U8(v2)) => v1 <= v2,
- (Value::I16(v1), Value::I16(v2)) => v1 <= v2,
- (Value::U16(v1), Value::U16(v2)) => v1 <= v2,
- (Value::I32(v1), Value::I32(v2)) => v1 <= v2,
- (Value::U32(v1), Value::U32(v2)) => v1 <= v2,
- (Value::I64(v1), Value::I64(v2)) => v1 <= v2,
- (Value::U64(v1), Value::U64(v2)) => v1 <= v2,
- (Value::F32(v1), Value::F32(v2)) => v1 <= v2,
- (Value::F64(v1), Value::F64(v2)) => v1 <= v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-
- /// Perform the `< relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_lt` operation.
- pub fn lt(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 < v2,
- (Value::U8(v1), Value::U8(v2)) => v1 < v2,
- (Value::I16(v1), Value::I16(v2)) => v1 < v2,
- (Value::U16(v1), Value::U16(v2)) => v1 < v2,
- (Value::I32(v1), Value::I32(v2)) => v1 < v2,
- (Value::U32(v1), Value::U32(v2)) => v1 < v2,
- (Value::I64(v1), Value::I64(v2)) => v1 < v2,
- (Value::U64(v1), Value::U64(v2)) => v1 < v2,
- (Value::F32(v1), Value::F32(v2)) => v1 < v2,
- (Value::F64(v1), Value::F64(v2)) => v1 < v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-
- /// Perform the `!= relational operation.
- ///
- /// This operation requires matching integral types.
- /// If the value type is `Generic`, then it is interpreted as a signed value.
- ///
- /// This corresponds to the DWARF `DW_OP_ne` operation.
- pub fn ne(self, rhs: Value, addr_mask: u64) -> Result<Value> {
- let value = match (self, rhs) {
- (Value::Generic(v1), Value::Generic(v2)) => {
- sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask)
- }
- (Value::I8(v1), Value::I8(v2)) => v1 != v2,
- (Value::U8(v1), Value::U8(v2)) => v1 != v2,
- (Value::I16(v1), Value::I16(v2)) => v1 != v2,
- (Value::U16(v1), Value::U16(v2)) => v1 != v2,
- (Value::I32(v1), Value::I32(v2)) => v1 != v2,
- (Value::U32(v1), Value::U32(v2)) => v1 != v2,
- (Value::I64(v1), Value::I64(v2)) => v1 != v2,
- (Value::U64(v1), Value::U64(v2)) => v1 != v2,
- (Value::F32(v1), Value::F32(v2)) => v1 != v2,
- (Value::F64(v1), Value::F64(v2)) => v1 != v2,
- _ => return Err(Error::TypeMismatch),
- };
- Ok(Value::Generic(value as u64))
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::common::{DebugAbbrevOffset, DebugInfoOffset, Encoding, Format};
- use crate::endianity::LittleEndian;
- use crate::read::{
- Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader,
- UnitOffset, UnitType,
- };
-
- #[test]
- #[rustfmt::skip]
- fn valuetype_from_encoding() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 4,
- };
- let unit = UnitHeader::new(
- encoding,
- 7,
- UnitType::Compilation,
- DebugAbbrevOffset(0),
- DebugInfoOffset(0).into(),
- EndianSlice::new(&[], LittleEndian),
- );
-
- let abbrev = Abbreviation::new(
- 42,
- constants::DW_TAG_base_type,
- constants::DW_CHILDREN_no,
- vec![
- AttributeSpecification::new(
- constants::DW_AT_byte_size,
- constants::DW_FORM_udata,
- None,
- ),
- AttributeSpecification::new(
- constants::DW_AT_encoding,
- constants::DW_FORM_udata,
- None,
- ),
- AttributeSpecification::new(
- constants::DW_AT_endianity,
- constants::DW_FORM_udata,
- None,
- ),
- ].into(),
- );
-
- for &(attrs, result) in &[
- ([0x01, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I8),
- ([0x02, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I16),
- ([0x04, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I32),
- ([0x08, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I64),
- ([0x01, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U8),
- ([0x02, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U16),
- ([0x04, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U32),
- ([0x08, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U64),
- ([0x04, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F32),
- ([0x08, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F64),
- ] {
- let entry = DebuggingInformationEntry::new(
- UnitOffset(0),
- EndianSlice::new(&attrs, LittleEndian),
- &abbrev,
- &unit,
- );
- assert_eq!(ValueType::from_entry(&entry), Ok(Some(result)));
- }
-
- for attrs in &[
- [0x03, constants::DW_ATE_signed.0, constants::DW_END_default.0],
- [0x02, constants::DW_ATE_signed.0, constants::DW_END_big.0],
- ] {
- let entry = DebuggingInformationEntry::new(
- UnitOffset(0),
- EndianSlice::new(attrs, LittleEndian),
- &abbrev,
- &unit,
- );
- assert_eq!(ValueType::from_entry(&entry), Ok(None));
- }
- }
-
- #[test]
- fn value_convert() {
- let addr_mask = !0 >> 32;
- for &(v, t, result) in &[
- (Value::Generic(1), ValueType::I8, Ok(Value::I8(1))),
- (Value::I8(1), ValueType::U8, Ok(Value::U8(1))),
- (Value::U8(1), ValueType::I16, Ok(Value::I16(1))),
- (Value::I16(1), ValueType::U16, Ok(Value::U16(1))),
- (Value::U16(1), ValueType::I32, Ok(Value::I32(1))),
- (Value::I32(1), ValueType::U32, Ok(Value::U32(1))),
- (Value::U32(1), ValueType::F32, Ok(Value::F32(1.))),
- (Value::F32(1.), ValueType::I64, Ok(Value::I64(1))),
- (Value::I64(1), ValueType::U64, Ok(Value::U64(1))),
- (Value::U64(1), ValueType::F64, Ok(Value::F64(1.))),
- (Value::F64(1.), ValueType::Generic, Ok(Value::Generic(1))),
- ] {
- assert_eq!(v.convert(t, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_reinterpret() {
- let addr_mask = !0 >> 32;
- for &(v, t, result) in &[
- // 8-bit
- (Value::I8(-1), ValueType::U8, Ok(Value::U8(0xff))),
- (Value::U8(0xff), ValueType::I8, Ok(Value::I8(-1))),
- // 16-bit
- (Value::I16(1), ValueType::U16, Ok(Value::U16(1))),
- (Value::U16(1), ValueType::I16, Ok(Value::I16(1))),
- // 32-bit
- (Value::Generic(1), ValueType::I32, Ok(Value::I32(1))),
- (Value::I32(1), ValueType::U32, Ok(Value::U32(1))),
- (Value::U32(0x3f80_0000), ValueType::F32, Ok(Value::F32(1.0))),
- (Value::F32(1.0), ValueType::Generic, Ok(Value::Generic(0x3f80_0000))),
- // Type mismatches
- (Value::Generic(1), ValueType::U8, Err(Error::TypeMismatch)),
- (Value::U8(1), ValueType::U16, Err(Error::TypeMismatch)),
- (Value::U16(1), ValueType::U32, Err(Error::TypeMismatch)),
- (Value::U32(1), ValueType::U64, Err(Error::TypeMismatch)),
- (Value::U64(1), ValueType::Generic, Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v.reinterpret(t, addr_mask), result);
- }
-
- let addr_mask = !0;
- for &(v, t, result) in &[
- // 64-bit
- (Value::Generic(1), ValueType::I64, Ok(Value::I64(1))),
- (Value::I64(1), ValueType::U64, Ok(Value::U64(1))),
- (Value::U64(0x3ff0_0000_0000_0000), ValueType::F64, Ok(Value::F64(1.0))),
- (Value::F64(1.0), ValueType::Generic, Ok(Value::Generic(0x3ff0_0000_0000_0000))),
- ] {
- assert_eq!(v.reinterpret(t, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_abs() {
- let addr_mask = 0xffff_ffff;
- for &(v, result) in &[
- (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))),
- (Value::I8(-1), Ok(Value::I8(1))),
- (Value::U8(1), Ok(Value::U8(1))),
- (Value::I16(-1), Ok(Value::I16(1))),
- (Value::U16(1), Ok(Value::U16(1))),
- (Value::I32(-1), Ok(Value::I32(1))),
- (Value::U32(1), Ok(Value::U32(1))),
- (Value::I64(-1), Ok(Value::I64(1))),
- (Value::U64(1), Ok(Value::U64(1))),
- (Value::F32(-1.), Ok(Value::F32(1.))),
- (Value::F64(-1.), Ok(Value::F64(1.))),
- ] {
- assert_eq!(v.abs(addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_neg() {
- let addr_mask = 0xffff_ffff;
- for &(v, result) in &[
- (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))),
- (Value::I8(1), Ok(Value::I8(-1))),
- (Value::U8(1), Err(Error::UnsupportedTypeOperation)),
- (Value::I16(1), Ok(Value::I16(-1))),
- (Value::U16(1), Err(Error::UnsupportedTypeOperation)),
- (Value::I32(1), Ok(Value::I32(-1))),
- (Value::U32(1), Err(Error::UnsupportedTypeOperation)),
- (Value::I64(1), Ok(Value::I64(-1))),
- (Value::U64(1), Err(Error::UnsupportedTypeOperation)),
- (Value::F32(1.), Ok(Value::F32(-1.))),
- (Value::F64(1.), Ok(Value::F64(-1.))),
- ] {
- assert_eq!(v.neg(addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_add() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(1), Value::Generic(2), Ok(Value::Generic(3))),
- (Value::I8(-1), Value::I8(2), Ok(Value::I8(1))),
- (Value::U8(1), Value::U8(2), Ok(Value::U8(3))),
- (Value::I16(-1), Value::I16(2), Ok(Value::I16(1))),
- (Value::U16(1), Value::U16(2), Ok(Value::U16(3))),
- (Value::I32(-1), Value::I32(2), Ok(Value::I32(1))),
- (Value::U32(1), Value::U32(2), Ok(Value::U32(3))),
- (Value::I64(-1), Value::I64(2), Ok(Value::I64(1))),
- (Value::U64(1), Value::U64(2), Ok(Value::U64(3))),
- (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(1.))),
- (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(1.))),
- (Value::Generic(1), Value::U32(2), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.add(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_sub() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))),
- (Value::I8(-1), Value::I8(2), Ok(Value::I8(-3))),
- (Value::U8(3), Value::U8(2), Ok(Value::U8(1))),
- (Value::I16(-1), Value::I16(2), Ok(Value::I16(-3))),
- (Value::U16(3), Value::U16(2), Ok(Value::U16(1))),
- (Value::I32(-1), Value::I32(2), Ok(Value::I32(-3))),
- (Value::U32(3), Value::U32(2), Ok(Value::U32(1))),
- (Value::I64(-1), Value::I64(2), Ok(Value::I64(-3))),
- (Value::U64(3), Value::U64(2), Ok(Value::U64(1))),
- (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(-3.))),
- (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(-3.))),
- (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.sub(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_mul() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(2), Value::Generic(3), Ok(Value::Generic(6))),
- (Value::I8(-2), Value::I8(3), Ok(Value::I8(-6))),
- (Value::U8(2), Value::U8(3), Ok(Value::U8(6))),
- (Value::I16(-2), Value::I16(3), Ok(Value::I16(-6))),
- (Value::U16(2), Value::U16(3), Ok(Value::U16(6))),
- (Value::I32(-2), Value::I32(3), Ok(Value::I32(-6))),
- (Value::U32(2), Value::U32(3), Ok(Value::U32(6))),
- (Value::I64(-2), Value::I64(3), Ok(Value::I64(-6))),
- (Value::U64(2), Value::U64(3), Ok(Value::U64(6))),
- (Value::F32(-2.), Value::F32(3.), Ok(Value::F32(-6.))),
- (Value::F64(-2.), Value::F64(3.), Ok(Value::F64(-6.))),
- (Value::Generic(2), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.mul(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_div() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(6), Value::Generic(3), Ok(Value::Generic(2))),
- (Value::I8(-6), Value::I8(3), Ok(Value::I8(-2))),
- (Value::U8(6), Value::U8(3), Ok(Value::U8(2))),
- (Value::I16(-6), Value::I16(3), Ok(Value::I16(-2))),
- (Value::U16(6), Value::U16(3), Ok(Value::U16(2))),
- (Value::I32(-6), Value::I32(3), Ok(Value::I32(-2))),
- (Value::U32(6), Value::U32(3), Ok(Value::U32(2))),
- (Value::I64(-6), Value::I64(3), Ok(Value::I64(-2))),
- (Value::U64(6), Value::U64(3), Ok(Value::U64(2))),
- (Value::F32(-6.), Value::F32(3.), Ok(Value::F32(-2.))),
- (Value::F64(-6.), Value::F64(3.), Ok(Value::F64(-2.))),
- (Value::Generic(6), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.div(v2, addr_mask), result);
- }
- for &(v1, v2, result) in &[
- (Value::Generic(6), Value::Generic(0), Err(Error::DivisionByZero)),
- (Value::I8(-6), Value::I8(0), Err(Error::DivisionByZero)),
- (Value::U8(6), Value::U8(0), Err(Error::DivisionByZero)),
- (Value::I16(-6), Value::I16(0), Err(Error::DivisionByZero)),
- (Value::U16(6), Value::U16(0), Err(Error::DivisionByZero)),
- (Value::I32(-6), Value::I32(0), Err(Error::DivisionByZero)),
- (Value::U32(6), Value::U32(0), Err(Error::DivisionByZero)),
- (Value::I64(-6), Value::I64(0), Err(Error::DivisionByZero)),
- (Value::U64(6), Value::U64(0), Err(Error::DivisionByZero)),
- (Value::F32(-6.), Value::F32(0.), Ok(Value::F32(-6. / 0.))),
- (Value::F64(-6.), Value::F64(0.), Ok(Value::F64(-6. / 0.))),
- ] {
- assert_eq!(v1.div(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_rem() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))),
- (Value::I8(-3), Value::I8(2), Ok(Value::I8(-1))),
- (Value::U8(3), Value::U8(2), Ok(Value::U8(1))),
- (Value::I16(-3), Value::I16(2), Ok(Value::I16(-1))),
- (Value::U16(3), Value::U16(2), Ok(Value::U16(1))),
- (Value::I32(-3), Value::I32(2), Ok(Value::I32(-1))),
- (Value::U32(3), Value::U32(2), Ok(Value::U32(1))),
- (Value::I64(-3), Value::I64(2), Ok(Value::I64(-1))),
- (Value::U64(3), Value::U64(2), Ok(Value::U64(1))),
- (Value::F32(-3.), Value::F32(2.), Err(Error::IntegralTypeRequired)),
- (Value::F64(-3.), Value::F64(2.), Err(Error::IntegralTypeRequired)),
- (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.rem(v2, addr_mask), result);
- }
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(0), Err(Error::DivisionByZero)),
- (Value::I8(-3), Value::I8(0), Err(Error::DivisionByZero)),
- (Value::U8(3), Value::U8(0), Err(Error::DivisionByZero)),
- (Value::I16(-3), Value::I16(0), Err(Error::DivisionByZero)),
- (Value::U16(3), Value::U16(0), Err(Error::DivisionByZero)),
- (Value::I32(-3), Value::I32(0), Err(Error::DivisionByZero)),
- (Value::U32(3), Value::U32(0), Err(Error::DivisionByZero)),
- (Value::I64(-3), Value::I64(0), Err(Error::DivisionByZero)),
- (Value::U64(3), Value::U64(0), Err(Error::DivisionByZero)),
- ] {
- assert_eq!(v1.rem(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_not() {
- let addr_mask = 0xffff_ffff;
- for &(v, result) in &[
- (Value::Generic(1), Ok(Value::Generic(!1))),
- (Value::I8(1), Ok(Value::I8(!1))),
- (Value::U8(1), Ok(Value::U8(!1))),
- (Value::I16(1), Ok(Value::I16(!1))),
- (Value::U16(1), Ok(Value::U16(!1))),
- (Value::I32(1), Ok(Value::I32(!1))),
- (Value::U32(1), Ok(Value::U32(!1))),
- (Value::I64(1), Ok(Value::I64(!1))),
- (Value::U64(1), Ok(Value::U64(!1))),
- (Value::F32(1.), Err(Error::IntegralTypeRequired)),
- (Value::F64(1.), Err(Error::IntegralTypeRequired)),
- ] {
- assert_eq!(v.not(addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_and() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(1))),
- (Value::I8(3), Value::I8(5), Ok(Value::I8(1))),
- (Value::U8(3), Value::U8(5), Ok(Value::U8(1))),
- (Value::I16(3), Value::I16(5), Ok(Value::I16(1))),
- (Value::U16(3), Value::U16(5), Ok(Value::U16(1))),
- (Value::I32(3), Value::I32(5), Ok(Value::I32(1))),
- (Value::U32(3), Value::U32(5), Ok(Value::U32(1))),
- (Value::I64(3), Value::I64(5), Ok(Value::I64(1))),
- (Value::U64(3), Value::U64(5), Ok(Value::U64(1))),
- (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
- (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
- (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.and(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_or() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(7))),
- (Value::I8(3), Value::I8(5), Ok(Value::I8(7))),
- (Value::U8(3), Value::U8(5), Ok(Value::U8(7))),
- (Value::I16(3), Value::I16(5), Ok(Value::I16(7))),
- (Value::U16(3), Value::U16(5), Ok(Value::U16(7))),
- (Value::I32(3), Value::I32(5), Ok(Value::I32(7))),
- (Value::U32(3), Value::U32(5), Ok(Value::U32(7))),
- (Value::I64(3), Value::I64(5), Ok(Value::I64(7))),
- (Value::U64(3), Value::U64(5), Ok(Value::U64(7))),
- (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
- (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
- (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.or(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_xor() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(6))),
- (Value::I8(3), Value::I8(5), Ok(Value::I8(6))),
- (Value::U8(3), Value::U8(5), Ok(Value::U8(6))),
- (Value::I16(3), Value::I16(5), Ok(Value::I16(6))),
- (Value::U16(3), Value::U16(5), Ok(Value::U16(6))),
- (Value::I32(3), Value::I32(5), Ok(Value::I32(6))),
- (Value::U32(3), Value::U32(5), Ok(Value::U32(6))),
- (Value::I64(3), Value::I64(5), Ok(Value::I64(6))),
- (Value::U64(3), Value::U64(5), Ok(Value::U64(6))),
- (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
- (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
- (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.xor(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_shl() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- // One of each type
- (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(96))),
- (Value::I8(3), Value::U8(5), Ok(Value::I8(96))),
- (Value::U8(3), Value::I8(5), Ok(Value::U8(96))),
- (Value::I16(3), Value::U16(5), Ok(Value::I16(96))),
- (Value::U16(3), Value::I16(5), Ok(Value::U16(96))),
- (Value::I32(3), Value::U32(5), Ok(Value::I32(96))),
- (Value::U32(3), Value::I32(5), Ok(Value::U32(96))),
- (Value::I64(3), Value::U64(5), Ok(Value::I64(96))),
- (Value::U64(3), Value::I64(5), Ok(Value::U64(96))),
- (Value::F32(3.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- (Value::F64(3.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- // Invalid shifts
- (Value::U8(3), Value::I8(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(3), Value::I16(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(3), Value::I32(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(3), Value::I64(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(3), Value::F32(5.), Err(Error::InvalidShiftExpression)),
- (Value::U8(3), Value::F64(5.), Err(Error::InvalidShiftExpression)),
- // Large shifts
- (Value::Generic(3), Value::Generic(32), Ok(Value::Generic(0))),
- (Value::I8(3), Value::U8(8), Ok(Value::I8(0))),
- (Value::U8(3), Value::I8(9), Ok(Value::U8(0))),
- (Value::I16(3), Value::U16(17), Ok(Value::I16(0))),
- (Value::U16(3), Value::I16(16), Ok(Value::U16(0))),
- (Value::I32(3), Value::U32(32), Ok(Value::I32(0))),
- (Value::U32(3), Value::I32(33), Ok(Value::U32(0))),
- (Value::I64(3), Value::U64(65), Ok(Value::I64(0))),
- (Value::U64(3), Value::I64(64), Ok(Value::U64(0))),
- ] {
- assert_eq!(v1.shl(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_shr() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- // One of each type
- (Value::Generic(96), Value::Generic(5), Ok(Value::Generic(3))),
- (Value::I8(96), Value::U8(5), Err(Error::UnsupportedTypeOperation)),
- (Value::U8(96), Value::I8(5), Ok(Value::U8(3))),
- (Value::I16(96), Value::U16(5), Err(Error::UnsupportedTypeOperation)),
- (Value::U16(96), Value::I16(5), Ok(Value::U16(3))),
- (Value::I32(96), Value::U32(5), Err(Error::UnsupportedTypeOperation)),
- (Value::U32(96), Value::I32(5), Ok(Value::U32(3))),
- (Value::I64(96), Value::U64(5), Err(Error::UnsupportedTypeOperation)),
- (Value::U64(96), Value::I64(5), Ok(Value::U64(3))),
- (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- // Invalid shifts
- (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)),
- // Large shifts
- (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))),
- (Value::U8(96), Value::I8(9), Ok(Value::U8(0))),
- (Value::U16(96), Value::I16(16), Ok(Value::U16(0))),
- (Value::U32(96), Value::I32(33), Ok(Value::U32(0))),
- (Value::U64(96), Value::I64(64), Ok(Value::U64(0))),
- ] {
- assert_eq!(v1.shr(v2, addr_mask), result);
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn value_shra() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- // One of each type
- (Value::Generic(u64::from(-96i32 as u32)), Value::Generic(5), Ok(Value::Generic(-3i64 as u64))),
- (Value::I8(-96), Value::U8(5), Ok(Value::I8(-3))),
- (Value::U8(96), Value::I8(5), Err(Error::UnsupportedTypeOperation)),
- (Value::I16(-96), Value::U16(5), Ok(Value::I16(-3))),
- (Value::U16(96), Value::I16(5), Err(Error::UnsupportedTypeOperation)),
- (Value::I32(-96), Value::U32(5), Ok(Value::I32(-3))),
- (Value::U32(96), Value::I32(5), Err(Error::UnsupportedTypeOperation)),
- (Value::I64(-96), Value::U64(5), Ok(Value::I64(-3))),
- (Value::U64(96), Value::I64(5), Err(Error::UnsupportedTypeOperation)),
- (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
- // Invalid shifts
- (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)),
- (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)),
- // Large shifts
- (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))),
- (Value::I8(96), Value::U8(8), Ok(Value::I8(0))),
- (Value::I8(-96), Value::U8(8), Ok(Value::I8(-1))),
- (Value::I16(96), Value::U16(17), Ok(Value::I16(0))),
- (Value::I16(-96), Value::U16(17), Ok(Value::I16(-1))),
- (Value::I32(96), Value::U32(32), Ok(Value::I32(0))),
- (Value::I32(-96), Value::U32(32), Ok(Value::I32(-1))),
- (Value::I64(96), Value::U64(65), Ok(Value::I64(0))),
- (Value::I64(-96), Value::U64(65), Ok(Value::I64(-1))),
- ] {
- assert_eq!(v1.shra(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_eq() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(1))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
- (Value::I8(3), Value::I8(3), Ok(Value::Generic(1))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
- (Value::U8(3), Value::U8(3), Ok(Value::Generic(1))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
- (Value::I16(3), Value::I16(3), Ok(Value::Generic(1))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
- (Value::U16(3), Value::U16(3), Ok(Value::Generic(1))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
- (Value::I32(3), Value::I32(3), Ok(Value::Generic(1))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
- (Value::U32(3), Value::U32(3), Ok(Value::Generic(1))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
- (Value::I64(3), Value::I64(3), Ok(Value::Generic(1))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
- (Value::U64(3), Value::U64(3), Ok(Value::Generic(1))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
- (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(1))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
- (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(1))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.eq(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_ne() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(0))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
- (Value::I8(3), Value::I8(3), Ok(Value::Generic(0))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
- (Value::U8(3), Value::U8(3), Ok(Value::Generic(0))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
- (Value::I16(3), Value::I16(3), Ok(Value::Generic(0))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
- (Value::U16(3), Value::U16(3), Ok(Value::Generic(0))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
- (Value::I32(3), Value::I32(3), Ok(Value::Generic(0))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
- (Value::U32(3), Value::U32(3), Ok(Value::Generic(0))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
- (Value::I64(3), Value::I64(3), Ok(Value::Generic(0))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
- (Value::U64(3), Value::U64(3), Ok(Value::Generic(0))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
- (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(0))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
- (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(0))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.ne(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_ge() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
- (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
- (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
- (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
- (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
- (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
- (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
- (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
- (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
- (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
- (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.ge(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_gt() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
- (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
- (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
- (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
- (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
- (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
- (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
- (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
- (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
- (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
- (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.gt(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_le() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
- (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
- (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
- (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
- (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
- (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
- (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
- (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
- (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
- (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
- (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.le(v2, addr_mask), result);
- }
- }
-
- #[test]
- fn value_lt() {
- let addr_mask = 0xffff_ffff;
- for &(v1, v2, result) in &[
- (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))),
- (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
- (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))),
- (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
- (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))),
- (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
- (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))),
- (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
- (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))),
- (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
- (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))),
- (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
- (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))),
- (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
- (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))),
- (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
- (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))),
- (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
- (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))),
- (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
- (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))),
- (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
- (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
- ] {
- assert_eq!(v1.lt(v2, addr_mask), result);
- }
- }
-}