Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL cfi.rs   Sprache: unbekannt

 
#[cfg(feature = "read")]
use alloc::boxed::Box;

use core::cmp::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, ¶meters, &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, ¶meters, &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, ¶meters, &mut self.table)?;
        let to = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &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(self.hdr.table_enc)),
        };

        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(self.hdr.table_enc)),
        };

        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, ¶meters, &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, ¶meters, &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::Offset>>(
        &self,
        frame: &EhFrame<R>,
        bases: &BaseAddresses,
        ctx: &'ctx mut UnwindContext<R::Offset, A>,
        address: u64,
        get_cie: F,
    ) -> Result<&'ctx UnwindTableRow<R::Offset, 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::Offset>>(
        &self,
        bases: &BaseAddresses,
        ctx: &'ctx mut UnwindContext<R::Offset, A>,
        address: u64,
        get_cie: F,
    ) -> Result<&'ctx UnwindTableRow<R::Offset, 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, ¶meters, 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, ¶meters)?;
        parameters.func_base = Some(initial_address);

        let aug_data = if let Some(ref augmentation) = cie.augmentation {
            Some(AugmentationData::parse(
                augmentation,
                ¶meters,
                &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::Offset>>(
        &self,
        section: &'a Section,
        bases: &'a BaseAddresses,
        ctx: &'ctx mut UnwindContext<R::Offset, 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::Offset>,
    >(
        &self,
        section: &Section,
        bases: &BaseAddresses,
        ctx: &'ctx mut UnwindContext<R::Offset, A>,
        address: u64,
    ) -> Result<&'ctx UnwindTableRow<R::Offset, 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 [`Box`]. This is the default storage type parameter for [`UnwindContext`].

You may want to supply your own storage type for one of the following reasons:

  1. In rare cases you may run into failed unwinds due to the fixed stack size
     used by [`StoreOnHeap`], so you may want to try a larger `Box`. If denial
     of service is not a concern, then you could also try a `Vec`-based stack which
     can grow as needed.
  2. You may want to avoid heap allocations entirely. You can use a fixed-size
     stack with in-line arrays, which will place the entire storage in-line into
     [`UnwindContext`].
"
)]
///
/// Here's an implementation which uses a fixed-size stack and allocates everything in-line,
/// which will cause `UnwindContext` to be large:
///
/// ```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<T: ReaderOffset> UnwindContextStorage<T> for StoreOnStack {
///     type Rules = [(Register, RegisterRule<T>); 192];
///     type Stack = [UnwindTableRow<T, Self>; 4];
/// }
///
/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in();
///
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.42unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge