summaryrefslogtreecommitdiffstats
path: root/vendor/gimli/src/read/cfi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli/src/read/cfi.rs')
-rw-r--r--vendor/gimli/src/read/cfi.rs134
1 files changed, 128 insertions, 6 deletions
diff --git a/vendor/gimli/src/read/cfi.rs b/vendor/gimli/src/read/cfi.rs
index b6a81f3f4..2e5167349 100644
--- a/vendor/gimli/src/read/cfi.rs
+++ b/vendor/gimli/src/read/cfi.rs
@@ -63,7 +63,7 @@ where
///
/// 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 OSX, etc.
+ /// loader on macOS, etc.
///
/// ```
/// use gimli::{DebugFrame, NativeEndian};
@@ -218,6 +218,81 @@ impl<R: Reader> ParsedEhFrameHdr<R> {
}
}
+/// 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> {
@@ -225,6 +300,20 @@ pub struct EhHdrTable<'a, R: Reader> {
}
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,
@@ -423,19 +512,19 @@ where
Endian: Endianity,
{
/// Construct a new `EhFrame` instance from the data in the
- /// `.debug_frame` section.
+ /// `.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 OSX, etc.
+ /// loader on macOS, etc.
///
/// ```
/// use gimli::{EhFrame, EndianSlice, NativeEndian};
///
- /// // Use with `.debug_frame`
+ /// // Use with `.eh_frame`
/// # let buf = [0x00, 0x01, 0x02, 0x03];
- /// # let read_debug_frame_section_somehow = || &buf;
- /// let debug_frame = EhFrame::new(read_debug_frame_section_somehow(), NativeEndian);
+ /// # 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))
@@ -6211,6 +6300,39 @@ mod tests {
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));